diff --git a/js/beestat/api.js b/js/beestat/api.js index 9fad6bd..f7d282d 100644 --- a/js/beestat/api.js +++ b/js/beestat/api.js @@ -62,7 +62,7 @@ beestat.api.prototype.send = function(opt_api_call) { */ if (this.callback_ !== undefined) { window.setTimeout(function() { - self.callback_(self.cached_batch_api_calls_); + self.callback_(self.cached_batch_api_calls_, true); }, 0); } } else { @@ -81,7 +81,7 @@ beestat.api.prototype.send = function(opt_api_call) { * problems. */ window.setTimeout(function() { - self.callback_(cached.data); + self.callback_(cached.data, true); }, 0); } } else { @@ -262,7 +262,7 @@ beestat.api.prototype.load_ = function(response_text) { // Callback if (this.callback_ !== undefined) { - this.callback_(response.data); + this.callback_(response.data, false); } }; diff --git a/js/beestat/cache.js b/js/beestat/cache.js index 315638b..908a749 100644 --- a/js/beestat/cache.js +++ b/js/beestat/cache.js @@ -7,26 +7,36 @@ beestat.cache = { * * @param {string} key The cache key to update. * @param {object} value The data to be placed in that key. + * @param {boolean} dispatch Whether or not to dispatch the event. Default + * true. */ -beestat.cache.set = function(key, value) { +beestat.cache.set = function(key, value, dispatch) { if (key.substring(0, 5) === 'data.') { beestat.cache.data[key.substring(5)] = value; } else { beestat.cache[key] = value; } - beestat.dispatcher.dispatchEvent('cache.' + key); + + if (dispatch !== false) { + beestat.dispatcher.dispatchEvent('cache.' + key); + } }; /** * Delete data from the cache. Dispatches an event when done. * * @param {string} key The cache key to delete. + * @param {boolean} dispatch Whether or not to dispatch the event. Default + * true. */ -beestat.cache.delete = function(key) { +beestat.cache.delete = function(key, dispatch) { if (key.substring(0, 5) === 'data.') { delete beestat.cache.data[key.substring(5)]; } else { delete beestat.cache[key]; } - beestat.dispatcher.dispatchEvent('cache.' + key); + + if (dispatch !== false) { + beestat.dispatcher.dispatchEvent('cache.' + key); + } }; diff --git a/js/beestat/poll.js b/js/beestat/poll.js index 1e15099..cb50206 100644 --- a/js/beestat/poll.js +++ b/js/beestat/poll.js @@ -1,19 +1,41 @@ beestat.enable_poll = function() { window.clearTimeout(beestat.poll_timeout); - if (beestat.poll_intervals.length > 0) { - beestat.poll_timeout = window.setTimeout( - beestat.poll, - Math.min.apply(null, beestat.poll_intervals) - ); + beestat.poll_timeout = window.setTimeout( + beestat.poll, + 60000 * 5 + ); +}; + +beestat.enable_poll_watcher = function() { + window.clearTimeout(beestat.poll_watcher_timeout); + beestat.poll_watcher_timeout = window.setTimeout( + beestat.poll_watcher, + 1000 + ); +}; + +/** + * Check every second for when the last successful poll was. Used for when the + * app is sent to the background and the polling stops to ensure an update is + * run immediately. + */ +beestat.poll_watcher = function() { + if ( + beestat.poll_last !== undefined && + beestat.poll_last.isBefore(moment().subtract(6, 'minute')) === true + ) { + window.clearTimeout(beestat.poll_timeout); + beestat.poll(); } + + beestat.enable_poll_watcher(); }; /** * Poll the database for changes and update the cache. */ -window.last_poll = moment(); beestat.poll = function() { - window.last_poll = moment(); + beestat.poll_last = moment(); var api = new beestat.api(); @@ -88,14 +110,38 @@ beestat.poll = function() { beestat.cache.set('sensor', response.sensor); beestat.cache.set('ecobee_thermostat', response.ecobee_thermostat); beestat.cache.set('ecobee_sensor', response.ecobee_sensor); + beestat.enable_poll(); beestat.ecobee.notify_if_down(); }); api.send(); -}; -// Five minutes -beestat.default_poll_interval = 300000; -beestat.poll_intervals = [beestat.default_poll_interval]; + /** + * Send this every poll but don't specifically do anything with the + * response. The caching won't allow it to send every time, but it should at + * least keep up. + */ + new beestat.api() + .add_call( + 'runtime', + 'sync', + { + 'thermostat_id': beestat.setting('thermostat_id') + } + ) + .set_callback(function(response, from_cache) { + if (from_cache === false) { + // Delete this cached data so the charts update. + beestat.cache.delete('data.runtime_thermostat_detail__runtime_thermostat'); + beestat.cache.delete('data.runtime_sensor_detail__runtime_thermostat'); + beestat.cache.delete('data.runtime_sensor_detail__runtime_sensor'); + beestat.cache.delete('data.air_quality_detail__runtime_thermostat'); + beestat.cache.delete('data.air_quality_detail__runtime_sensor'); + beestat.cache.delete('data.three_d__runtime_sensor'); + beestat.cache.delete('data.three_d__runtime_thermostat'); + } + }) + .send(); +}; diff --git a/js/component/card/air_quality_detail.js b/js/component/card/air_quality_detail.js index fe7ac6b..dda9fbd 100644 --- a/js/component/card/air_quality_detail.js +++ b/js/component/card/air_quality_detail.js @@ -19,7 +19,6 @@ beestat.component.card.air_quality_detail = function(thermostat_id) { * for when rerendering. */ var change_function = beestat.debounce(function() { - self.get_data_(true); self.rerender(); }, 10); @@ -43,6 +42,8 @@ beestat.extend(beestat.component.card.air_quality_detail, beestat.component.card beestat.component.card.air_quality_detail.prototype.decorate_contents_ = function(parent) { var self = this; + delete this.data_; + this.charts_ = { 'occupancy': new beestat.component.chart.runtime_sensor_detail_occupancy( this.get_data_() @@ -347,10 +348,10 @@ beestat.component.card.air_quality_detail.prototype.has_data_ = function() { * * @return {object} The data. */ -beestat.component.card.air_quality_detail.prototype.get_data_ = function(force) { +beestat.component.card.air_quality_detail.prototype.get_data_ = function() { const self = this; - if (this.data_ === undefined || force === true) { + if (this.data_ === undefined) { var range = { 'type': beestat.setting('air_quality_detail_range_type'), 'dynamic': beestat.setting('air_quality_detail_range_dynamic'), diff --git a/js/component/card/runtime_sensor_detail.js b/js/component/card/runtime_sensor_detail.js index 38f320c..f9843c4 100644 --- a/js/component/card/runtime_sensor_detail.js +++ b/js/component/card/runtime_sensor_detail.js @@ -19,7 +19,6 @@ beestat.component.card.runtime_sensor_detail = function(thermostat_id) { * for when rerendering. */ var change_function = beestat.debounce(function() { - self.get_data_(true); self.rerender(); }, 10); @@ -43,6 +42,8 @@ beestat.extend(beestat.component.card.runtime_sensor_detail, beestat.component.c beestat.component.card.runtime_sensor_detail.prototype.decorate_contents_ = function(parent) { var self = this; + delete this.data_; + this.charts_ = { 'equipment': new beestat.component.chart.runtime_thermostat_detail_equipment( this.get_data_() @@ -356,10 +357,10 @@ beestat.component.card.runtime_sensor_detail.prototype.has_data_ = function() { * * @return {object} The data. */ -beestat.component.card.runtime_sensor_detail.prototype.get_data_ = function(force) { +beestat.component.card.runtime_sensor_detail.prototype.get_data_ = function() { const self = this; - if (this.data_ === undefined || force === true) { + if (this.data_ === undefined) { var range = { 'type': beestat.setting('runtime_sensor_detail_range_type'), 'dynamic': beestat.setting('runtime_sensor_detail_range_dynamic'), diff --git a/js/component/card/runtime_thermostat_detail.js b/js/component/card/runtime_thermostat_detail.js index eca61f8..e35d290 100644 --- a/js/component/card/runtime_thermostat_detail.js +++ b/js/component/card/runtime_thermostat_detail.js @@ -19,15 +19,11 @@ beestat.component.card.runtime_thermostat_detail = function(thermostat_id) { * for when rerendering. */ var change_function = beestat.debounce(function() { - self.get_data_(true); self.rerender(); }, 10); beestat.dispatcher.addEventListener( - [ - 'cache.data.runtime_thermostat_detail__runtime_thermostat', - 'cache.thermostat' - ], + 'cache.data.runtime_thermostat_detail__runtime_thermostat', change_function ); @@ -43,6 +39,8 @@ beestat.extend(beestat.component.card.runtime_thermostat_detail, beestat.compone beestat.component.card.runtime_thermostat_detail.prototype.decorate_contents_ = function(parent) { var self = this; + delete this.data_; + this.charts_ = { 'equipment': new beestat.component.chart.runtime_thermostat_detail_equipment( this.get_data_() @@ -339,12 +337,10 @@ beestat.component.card.runtime_thermostat_detail.prototype.has_data_ = function( * Get data. This doesn't directly or indirectly make any API calls, but it * caches the data so it doesn't have to loop over everything more than once. * - * @param {boolean} force Force get the data? - * * @return {object} The data. */ -beestat.component.card.runtime_thermostat_detail.prototype.get_data_ = function(force) { - if (this.data_ === undefined || force === true) { +beestat.component.card.runtime_thermostat_detail.prototype.get_data_ = function() { + if (this.data_ === undefined) { var range = { 'type': beestat.setting('runtime_thermostat_detail_range_type'), 'dynamic': beestat.setting('runtime_thermostat_detail_range_dynamic'), diff --git a/js/component/card/three_d.js b/js/component/card/three_d.js index e13ced9..8db06d7 100644 --- a/js/component/card/three_d.js +++ b/js/component/card/three_d.js @@ -28,7 +28,6 @@ beestat.component.card.three_d = function() { const change_function = beestat.debounce(function() { self.state_.scene_camera_state = self.scene_.get_camera_state(); - self.get_data_(true); self.rerender(); }, 10); @@ -82,6 +81,8 @@ beestat.component.card.three_d.prototype.decorate_ = function(parent) { * @param {rocket.Elements} parent */ beestat.component.card.three_d.prototype.decorate_contents_ = function(parent) { + delete this.data_; + const drawing_pane_container = document.createElement('div'); drawing_pane_container.style.overflowX = 'hidden'; @@ -883,9 +884,9 @@ beestat.component.card.three_d.prototype.decorate_legend_ = function(parent) { * * @return {object} The data. */ -beestat.component.card.three_d.prototype.get_data_ = function(force) { +beestat.component.card.three_d.prototype.get_data_ = function() { const self = this; - if (this.data_ === undefined || force === true) { + if (this.data_ === undefined) { const sensor_ids_map = beestat.floor_plan.get_sensor_ids_map(this.floor_plan_id_); const thermostat_ids_map = beestat.floor_plan.get_thermostat_ids_map(this.floor_plan_id_); diff --git a/js/component/modal/thermostat_info.js b/js/component/modal/thermostat_info.js index 0669f22..250d05f 100644 --- a/js/component/modal/thermostat_info.js +++ b/js/component/modal/thermostat_info.js @@ -38,10 +38,6 @@ beestat.component.modal.thermostat_info.prototype.decorate_contents_ = function( 'name': 'First Connected', 'value': moment.utc(ecobee_thermostat.runtime.firstConnected).local() .format('MMM Do, YYYY') - }, - { - 'name': '#', - 'value': window.last_poll.format() } ]; diff --git a/js/layer/load.js b/js/layer/load.js index 0caeb8c..d04ee05 100644 --- a/js/layer/load.js +++ b/js/layer/load.js @@ -276,6 +276,7 @@ beestat.layer.load.prototype.decorate_ = function(parent) { // Enable polling for live updates beestat.enable_poll(); + beestat.enable_poll_watcher(); (new beestat.layer.detail()).render();