diff --git a/app/css/ui.css b/app/css/ui.css new file mode 100644 index 0000000..5d3baae --- /dev/null +++ b/app/css/ui.css @@ -0,0 +1,384 @@ +/* by ericftremblay.com */ + +body { + background: #d1d1d1; + height: 100%; + padding: 20px; + font: 13px/50px sans-serif; + color: #666; + -webkit-box-sizing: border-box; +} + +h1 { font: 30px sans-serif; } +h3 { font: 1em sans-serif; color: #888; } +p { font: 12px/20px sans-serif; padding-bottom: 10px; } + +input { + display: block; + margin: 0 0 20px 5px; +} + +/* Toggle */ + +input[type="checkbox"] { + background-image: -webkit-linear-gradient(hsla(0,0%,0%,.1), hsla(0,0%,100%,.1)), + -webkit-linear-gradient(right, #b0c43c 50%, #999 50%); + background-size: 100% 100%, 200% 100%; + background-position: 0 0, 5px 0; + border-radius: 25px; + box-shadow: inset 0 1px 4px hsla(0,0%,0%,.5), + inset 0 0 10px hsla(0,0%,0%,.5), + 0 0 0 1px hsla(0,0%,0%,.1), + 0 -1px 2px 1px hsla(0,0%,0%,.25), + 0 2px 2px 1px hsla(0,0%,100%,.5), + 0 -2px 10px 2px hsla(0,0%,100%,.75), + 0 2px 10px 2px hsla(0,0%,0%,.25); + cursor: pointer; + height: 30px; + padding-right: 10px; + position: relative; + width: 63px; + -webkit-appearance: none; + -webkit-transition: .15s; +} + +input[type="checkbox"]:after { + background-color: #eee; + background-image: -webkit-linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,0%,.1)); + box-shadow: inset 0 1px 1px 1px hsla(0,0%,100%,1), + inset 0 -1px 1px 1px hsla(0,0%,0%,.25), + 0 1px 3px 1px hsla(0,0%,0%,.5), + 0 0 2px hsla(0,0%,0%,.25); + content: ''; + display: block; + height: 30px; + left: 0; + position: relative; + top: 0; + width: 30px; + border-radius: 100%; +} +input[type="checkbox"]:checked { + background-position: 0 0, 45px 0; + padding-left: 33px; + padding-right: 0; +} +input[type="checkbox"]:before { + color: #eee; + content: 'Off'; + font: 12.5px/20px sans-serif; + height: 20px; + left: 33px; + letter-spacing: 1px; + position: absolute; + text-align: center; + top: 6px; + width: 20px; + text-shadow: 0 -1px 1px rgba(0,0,0,0.5); +} +input[type="checkbox"]:checked:before { + content: 'On'; + left: 9px; +} + +/* Slider */ + +input[type="range"] { + background-image: -webkit-linear-gradient(left, hsla(0,0%,100%,.1) 45%, transparent 45%), + -webkit-linear-gradient(hsla(0,0%,0%,.1), hsla(0,0%,100%,.1)), + -webkit-linear-gradient(left, #b0c43c, #f66); + background-size: 3px 3px, 100% 100%, 100% 100%; + border-radius: 25px; + box-shadow: inset 0 1px 4px hsla(0,0%,0%,.5), + inset 0 0 10px hsla(0,0%,0%,.5), + 0 0 0 1px hsla(0,0%,0%,.1), + 0 -1px 2px 1px hsla(0,0%,0%,.25), + 0 2px 2px 1px hsla(0,0%,100%,.5), + 0 -2px 10px 2px hsla(0,0%,100%,.75), + 0 2px 10px 2px hsla(0,0%,0%,.25); + cursor: ew-resize; + height: 10px; + position: relative; + width: 250px; + -webkit-appearance: none; + -webkit-transition: .15s; +} + +input[type="range"]::-webkit-slider-thumb { + background-color: #eee; + background-image: -webkit-linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,0%,.1)); + border-radius: 25px; + box-shadow: inset 0 1px 1px 1px hsla(0,0%,100%,1), + inset 0 -1px 1px 1px hsla(0,0%,0%,.25), + 0 1px 3px 1px hsla(0,0%,0%,.5), + 0 0 2px hsla(0,0%,0%,.25); + content: ''; + display: block; + height: 20px; + left: 0; + position: relative; + top: 0; + width: 20px; + -webkit-appearance: none; +} + +/* Radio */ + +input[type="radio"] { + background-color: #ddd; + background-image: -webkit-linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,0%,.1)); + border-radius: 100%; + box-shadow: inset 0 1px 1px 1px hsla(0,0%,100%,1), + inset 0 -1px 1px 1px hsla(0,0%,0%,.25), + 0 1px 3px 1px hsla(0,0%,0%,.5), + 0 0 2px hsla(0,0%,0%,.25); + cursor: pointer; + display: inline-block; + height: 20px; + margin-right: 15px; + position: relative; + width: 20px; + -webkit-appearance: none; +} + +input[type="radio"]:after { + background-color: #666; + border-radius: 100%; + box-shadow: inset 0 0 0 1px hsla(0,0%,0%,.4), + 0 1px 1px hsla(0,0%,100%,.8); + content: ''; + display: block; + height: 12px; + width: 12px; + left: 4px; + position: relative; + top: 4px; +} + +input[type="radio"]:checked:after { + background-color: #b0c43c; + box-shadow: inset 0 0 0 1px hsla(0,0%,0%,.4), + inset 0 2px 2px hsla(0,0%,100%,.4), + 0 1px 1px hsla(0,0%,100%,.8), + 0 0 2px 2px hsla(68,69%,76%,.4); +} + +/* Input Text */ + +input[type="text"], input[type="password"] { + background: #eee; + background-size: 100% 100%, 200% 100%; + background-position: 0 0, 5px 0; + border-radius: 5px; + box-shadow: inset 0 1px 4px hsla(0,0%,0%,.1), + inset 0 0 10px hsla(0,0%,0%,.1), + 0 0 0 1px hsla(0,0%,0%,.1), + 0 -1px 2px 1px hsla(0,0%,0%,.25), + 0 2px 2px 1px hsla(0,0%,100%,.5), + 0 -2px 10px 2px hsla(0,0%,100%,.75), + 0 2px 10px 2px hsla(0,0%,0%,.25); + cursor: pointer; + border: 0; + width: 200px; + padding: 10px 15px; + font: 13px/20px sans-serif; + color: #888; + position: relative; + -webkit-appearance: none; + -webkit-transition: .15s; +} + +input[type="text"]:focus, input[type="password"]:focus { + background: #fff; + outline: 0 none; +} + +/* Submit */ + +input[type="submit"] { + background-color: #eee; + background-image: -webkit-linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,0%,.1)); + border-radius: 8px; + box-shadow: inset 0 1px 1px 1px hsla(0,0%,100%,1), + inset 0 -1px 1px 1px hsla(0,0%,0%,.25), + 0 1px 3px 1px hsla(0,0%,0%,.25), + 0 0 2px hsla(0,0%,0%,.25); + cursor: pointer; + display: inline-block; + padding: 10px 20px; + font: 15px/20px sans-serif; + color: #999; + border: 0; + position: relative; + -webkit-appearance: none; +} + +input[type="submit"]:hover { + color: #666; + background-color: #fff; +} + +input[type="submit"]:active { + color: #888; + background-color: #fff; + position: relative; + top: 2px; + box-shadow: inset 0 1px 1px 1px hsla(0,0%,100%,1), + inset 0 -1px 1px 1px hsla(0,0%,0%,.15), + 0 1px 3px 1px hsla(0,0%,0%,.15)} + +/* Scrollbar */ + +::-webkit-scrollbar { + -webkit-appearance: none; + width: 10px; + height: 10px; + background: #d1d1d1; +} + +::-webkit-scrollbar-thumb { + background-color: #999; + border-radius: 25px; +} + +/* Tabs */ + +.tabs { + position: relative; + margin: 40px auto; + width: 750px; +} + +.tabs input[id*="tab"] { + position: absolute; + z-index: 1000; + width: 120px; + left: 0px; + top: 0px; + opacity: 0; + -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + cursor: pointer; +} +.tabs input[id*="tab"]#tab-2 { + left: 120px; +} + +.tabs input[id*="tab"]#tab-3 { + left: 240px; +} + +.tabs label { + background: -webkit-linear-gradient(bottom, #ededed 0%,#ddd 100%); + height: 40px; + width: 80px; + font: 16px/40px sans-serif; + position: relative; + padding: 0 20px; + float: left; + display: block; + margin: 0 2px 0 0; + color: #666; + text-align: center; + border-radius: 6px 6px 0 0; + box-shadow: 2px 0 1px rgba(0,0,0,0.1), -2px 0 2px rgba(0,0,0,0.1); + cursor: pointer; +} + +.tabs label:after { + content: ''; + background: #d1d1d1; + position: absolute; + bottom: -2px; + left: 0; + width: 100%; + height: 2px; + display: block; +} + +.tabs input[id*="tab"]:hover + label { + background: #eee; +} + +.tabs label:first-of-type { + z-index: 4; + box-shadow: 0 0 4px rgba(0,0,0,0.2); +} + +.tab-label-2 { + z-index: 3; +} + +.tab-label-3 { + z-index: 2; +} + +.tabs input[id*="tab"]:checked + label { + background: -webkit-linear-gradient(top, #ededed 0%,#d1d1d1 100%); + z-index: 6; +} + +.clear-shadow { + clear: both; +} + +.content { + position: relative; + width: 100%; + height: 1px; + z-index: 5; + border-top: solid 1px #eee; +} + +.content div { + position: absolute; + top: 0; + left: 0; + z-index: 1; + opacity: 0; + height: 350px; + width: 800px; + padding: 30px; + -webkit-transition: opacity linear 0.1s; +} + +.tabs input.tab-selector-1[id*="tab"]:checked ~ .content .content-1, +.tabs input.tab-selector-2[id*="tab"]:checked ~ .content .content-2, +.tabs input.tab-selector-3[id*="tab"]:checked ~ .content .content-3{ + z-index: 100; + -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; + filter: alpha(opacity=100); + opacity: 1; + + -webkit-transition: opacity ease-out 0.2s 0.1s; + -moz-transition: opacity ease-out 0.2s 0.1s; + -o-transition: opacity ease-out 0.2s 0.1s; + -ms-transition: opacity ease-out 0.2s 0.1s; + transition: opacity ease-out 0.2s 0.1s; +} + + +/* Dropdown list */ + +select[name*="menu"] { + background: #eee; + border-radius: 5px; + cursor: pointer; + border: 0; + padding: 10px 15px; + font: 13px/20px sans-serif; + color: #888; + position: relative; + -webkit-appearance: none; + -webkit-transition: .15s; + background-image: -webkit-linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,0%,.1)); + box-shadow: inset 0 1px 1px 1px hsla(0,0%,100%,.25), + inset 0 -1px 1px 1px hsla(0,0%,0%,.1), + 0 1px 3px 1px hsla(0,0%,0%,.1), + 0 0 2px hsla(0,0%,0%,.1); +} + +select[name*="menu"]:focus { + background: #fff; + outline: 0 none; +}​ diff --git a/app/js/app.js b/app/js/app.js index 4e6019f..bc5c001 100644 --- a/app/js/app.js +++ b/app/js/app.js @@ -10,14 +10,14 @@ */ (function($) { - let TodayDataModel = Backbone.Model.extend({ + /* let TodayDataModel = Backbone.Model.extend({ initialize: function () { this.set('url', '/today/data'); console.log(this.get('url')); //This.update(); } - }); + });*/ const webSocketModel = new SOCKETMANAGER(); diff --git a/app/js/modules/clock.js b/app/js/modules/clock.js index 4c202f4..848d367 100644 --- a/app/js/modules/clock.js +++ b/app/js/modules/clock.js @@ -35,7 +35,7 @@ let Clock = Backbone.View.extend({ render: function () { const now = this.model.get('now'); //var curTime = now.format('{24hr}{mm}'); - const curTime = now.format('{24hr} {mm}'); + const curTime = now.format('{24hr}:{mm}'); const curDate = now.format('{yyyy}-{MM}-{dd}'); if (this.prevTime !== curTime) { diff --git a/app/js/modules/weather.js b/app/js/modules/weather.js index ba3fd6e..32ba3bd 100644 --- a/app/js/modules/weather.js +++ b/app/js/modules/weather.js @@ -5,72 +5,71 @@ * Time: 14:20 * */ - -var WeatherModel = Backbone.Model.extend({ - initialize: function() { - this.set('url','https://api.darksky.net/forecast/9ad2a41d420f3cf4960571bb886f710c/' + this.get('lat').toString() + ',' + this.get('long').toString() + '?units=uk2&exclude=minutely,hourly,daily,alerts,flags'); +let WeatherModel = Backbone.Model.extend({ + initialize: function () { + this.set('url', 'https://api.darksky.net/forecast/9ad2a41d420f3cf4960571bb886f710c/' + this.get('lat').toString() + ',' + this.get('long').toString() + '?units=uk2&exclude=minutely,hourly,daily,alerts,flags'); console.log(this.get('url')); - // this.update(); + // this.update(); }, - update: function() { + update: function () { this.getWeather(); - var now = new Date; - var mod = 1800000 - (now.getTime() % 1800000); - var weatherTrigger = function() { + const now = new Date; + let mod = 1800000 - (now.getTime() % 1800000); + let weatherTrigger = function () { this.update(); }; }, - getWeather: function() { - var self = this; + getWeather: function () { + const self = this; $.ajax({ - type: 'GET', - url: self.get('url'), - data: '', - dataType: 'json', - timeout: 10000, - context: $('body'), - contentType: ('application/json'), - headers: { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'PUT, GET, POST, DELETE, OPTIONS', - 'Access-Control-Allow-Headers': 'Content-Type' - }, - success: function(data) { - var stored = { - temperature: data.currently.temperature, - icon: data.currently.icon, - summary: data.currently.summary - }; - self.set(stored); - }, - error: function(xhr, type) { - console.error('ajax error'); - console.error(xhr); - console.error(type); - } - }); + type: 'GET', + url: self.get('url'), + data: '', + dataType: 'json', + timeout: 10000, + context: $('body'), + contentType: ('application/json'), + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'PUT, GET, POST, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type' + }, + success: function (data) { + const stored = { + temperature: data.currently.temperature, + icon: data.currently.icon, + summary: data.currently.summary + }; + self.set(stored); + }, + error: function (xhr, type) { + console.error('ajax error'); + console.error(xhr); + console.error(type); + } + }); } }); -var Weather = Backbone.View.extend({ +let Weather = Backbone.View.extend({ tagName: 'div', - initialize: function() { + initialize: function () { _.bindAll(this, 'render'); this.model.bind('change', this.render); this.$weatherText = $('#weatherDescription'); this.$weatherTemp = $('#temp'); this.$weatherIcon = $('#weatherIcon'); }, - render: function() { + render: function () { console.log('Weather:Render'); - var ws = ''; + const ws = ''; - this.$weatherTemp.empty().html(parseInt(this.model.get('temperature')) + '°c '); - this.$weatherText.empty().html(this.model.get('summary')); + this.$weatherTemp.empty().html(parseInt(this.model.get('temperature')) + '°c '); + this.$weatherText.empty().html(this.model.get('summary')); - this.$weatherIcon.empty().html(ws); + this.$weatherIcon.empty().html(ws); } }); diff --git a/app/ui.html b/app/ui.html new file mode 100644 index 0000000..19f83a8 --- /dev/null +++ b/app/ui.html @@ -0,0 +1,61 @@ + + + + + Title + + +

Clean Webkit CSS3 UI

+ +
+ + + + + + + + + +
+ +
+
+ + Slider (Range) + + Toggles (Checkboxes) + + + Radio buttons
+ + +
+ +
+ Text Fields + + Password Fields + + + +
+ +
+

The Clean Webkit CSS3 UI inclued:

+

Form Inputs +
- Range +
- Checkboxes +
- Radio buttons +
- Submit button +
- Text and password fields

+

CSS3 Tabs with radio buttons +
Custom scrollbar

+
+

ericftremblay.com

+

github.com/ericft

+
+
+
​ + + diff --git a/lib/mqtt/mqttClient.js b/lib/mqtt/mqttClient.js index 961ea16..5d14ff4 100644 --- a/lib/mqtt/mqttClient.js +++ b/lib/mqtt/mqttClient.js @@ -25,8 +25,13 @@ const mqttClient = function (events) { this.livingRoom = { temp: 0, - last: 0 + last: 0, + data: [] }; + + this.first = false; + this.maxLength = 99; + let mode = 'FanOff'; const d = new Date(); @@ -50,13 +55,39 @@ const mqttClient = function (events) { } }); + this.storeData = function (data, alt) { + if (!this.first) { + this.first = true; + return []; + } + let target = alt || this.livingRoom.data; + if (target.length === this.maxLength) { + target = target.slice(1); + } + target.push(data); + if (alt) { + return target; + } + this.livingRoom.data = target; + }; + + this.logTemp = function () { + const now = new Date; + const mod = 60000 - (now.getTime() % 60000); + this.storeData(this.livingRoom.temp); + const data = {id: 'graph', data: this.livingRoom.data}; + events.emit('sendSocket', data); + + setTimeout(this.logTemp.bind(this), mod + 10); + }; + this.fanTimer = function () { let n; const now = new Date; const mod = 900000 - (now.getTime() % 900000); const day = now.getDay(); - const daytimeLimits = {low:27900000,high:63000000}; + const daytimeLimits = {low: 27900000, high: 63000000}; const nowMS = (now.getHours() * 3600000) + (now.getMinutes() * 60000); if (globalMode === 'FanOff') { @@ -67,7 +98,7 @@ const mqttClient = function (events) { mode = (parseFloat(this.livingRoom.temp) <= 22.5) ? 'FanOn' : 'FanOff'; } - if ((globalMode !== 'FanOff' || mode !== 'FanOff') && ((day >=1 && day <=5) && (nowMS >= daytimeLimits.low && nowMS <= daytimeLimits.high))) { + if ((globalMode !== 'FanOff' || mode !== 'FanOff') && ((day >= 1 && day <= 5) && (nowMS >= daytimeLimits.low && nowMS <= daytimeLimits.high))) { logger.info('Week day'); mode = 'FanOff' } @@ -79,14 +110,16 @@ const mqttClient = function (events) { logger.error('No message received for over 10 minutes'); mode = 'FanOff'; logger.warn('Setting quit for 15 seconds.'); - setTimeout(()=>{throw new error('Ejecting for restart');}, 15000); + setTimeout(() => { + throw new error('Ejecting for restart'); + }, 15000); } logger.info('LR temp:', this.livingRoom.temp); + const data = {id: 'temperature', data: {mode: globalMode, temp: this.livingRoom.temp}}; events.emit('sendIFTTT', mode); - const data = {id: 'temperature', data: {mode: globalMode, temp: this.livingRoom.temp}}; events.emit('sendSocket', data); setTimeout(this.fanTimer.bind(this), mod + 10); @@ -110,6 +143,7 @@ const mqttClient = function (events) { this.connected = true; logger.info('Connected to Silvr Broker'); this.fanTimer(); + this.logTemp(); }.bind(this)); this.client.subscribe('livingroomTemp');