diff --git a/css/dashboard.css b/css/dashboard.css index da3027c..b9b1a6f 100644 --- a/css/dashboard.css +++ b/css/dashboard.css @@ -425,6 +425,7 @@ input[type=checkbox] { .icon.numeric_4_box:before { content: "\F03AD"; } .icon.numeric_3_box:before { content: "\F03AA"; } .icon.numeric_7_box:before { content: "\F03B6"; } +.icon.open_in_new:before { content: "\F03CC"; } .icon.patreon:before { content: "\F0882"; } .icon.pound:before { content: "\F0423"; } .icon.refresh:before { content: "\F0450"; } diff --git a/js/beestat/setting.js b/js/beestat/setting.js index 128dd61..329667c 100644 --- a/js/beestat/setting.js +++ b/js/beestat/setting.js @@ -51,7 +51,7 @@ beestat.setting = function(argument_1, opt_value, opt_callback) { .subtract(28, 'day') .format('MM/DD/YYYY'), 'voc_summary_range_static_end': moment().format('MM/DD/YYYY'), - 'voc_summary_range_dynamic': 30, + 'voc_summary_range_dynamic': 28, 'runtime_thermostat_summary_time_count': 0, 'runtime_thermostat_summary_time_period': 'all', diff --git a/js/beestat/thermostat.js b/js/beestat/thermostat.js index 7e976b8..58a886e 100644 --- a/js/beestat/thermostat.js +++ b/js/beestat/thermostat.js @@ -175,3 +175,17 @@ beestat.thermostat.get_current_climate = function(thermostat_id) { return null; }; + +/** + * Get whether or not the thermostat supports air quality. + * + * @param {number} thermostat_id + * @param {string} climate_ref The ecobee climateRef + * + * @return {boolean} Whether or not the thermostat supports air quality. + */ +beestat.thermostat.supports_air_quality = function(thermostat_id) { + const thermostat = beestat.cache.thermostat[thermostat_id]; + const ecobee_thermostat = beestat.cache.ecobee_thermostat[thermostat.ecobee_thermostat_id]; + return ecobee_thermostat.model_number === 'aresSmart'; +}; diff --git a/js/component/card/air_quality_detail.js b/js/component/card/air_quality_detail.js index 1b49b85..ad42f14 100644 --- a/js/component/card/air_quality_detail.js +++ b/js/component/card/air_quality_detail.js @@ -368,6 +368,21 @@ beestat.component.card.air_quality_detail.prototype.get_data_ = function(force) this.data_ = sensor_data; + if (beestat.thermostat.supports_air_quality(this.thermostat_id_) === false) { + // Override with 0s for unsupported thermostats so the charts look ok. + for (let i = 0; i < sensor_data.series['voc_concentration_' + this.thermostat_id_].length; i++) { + sensor_data.series['air_quality_' + this.thermostat_id_][i] = 0; + sensor_data.series['voc_concentration_' + this.thermostat_id_][i] = 0; + sensor_data.series['co2_concentration_' + this.thermostat_id_][i] = 0; + } + + for (let timestamp in sensor_data.metadata.series['air_quality_' + this.thermostat_id_].data) { + sensor_data.metadata.series['air_quality_' + this.thermostat_id_].data[timestamp] = 0; + sensor_data.metadata.series['voc_concentration_' + this.thermostat_id_].data[timestamp] = 0; + sensor_data.metadata.series['co2_concentration_' + this.thermostat_id_].data[timestamp] = 0; + } + } + Object.assign(this.data_.series, thermostat_data.series); Object.assign(this.data_.metadata.series, thermostat_data.metadata.series); diff --git a/js/component/card/air_quality_not_supported.js b/js/component/card/air_quality_not_supported.js new file mode 100644 index 0000000..2b7531d --- /dev/null +++ b/js/component/card/air_quality_not_supported.js @@ -0,0 +1,36 @@ +/** + * Air Quality Not Supported + */ +beestat.component.card.air_quality_not_supported = function() { + beestat.component.card.apply(this, arguments); +}; +beestat.extend(beestat.component.card.air_quality_not_supported, beestat.component.card); + +/** + * Decorate + * + * @param {rocket.Elements} parent + */ +beestat.component.card.air_quality_not_supported.prototype.decorate_contents_ = function(parent) { + parent.style('background', beestat.style.color.blue.light); + parent.appendChild($.createElement('p').innerText('Access to Air Quality information requires a compatible thermostat. Support beestat by buying through this affiliate link.')); + + new beestat.component.button() + .set_icon('open_in_new') + .set_text('Buy an ecobee Smart Thermostat Premium on Amazon') + .set_background_color(beestat.style.color.green.dark) + .set_background_hover_color(beestat.style.color.green.light) + .addEventListener('click', function() { + window.open('https://amzn.to/3A7vv3S'); + }) + .render(parent); +}; + +/** + * Get the title of the card. + * + * @return {string} The title. + */ +beestat.component.card.air_quality_not_supported.prototype.get_title_ = function() { + return 'Unsupported Thermostat'; +}; diff --git a/js/component/card/voc_summary.js b/js/component/card/voc_summary.js index c4fb565..7554030 100644 --- a/js/component/card/voc_summary.js +++ b/js/component/card/voc_summary.js @@ -253,9 +253,14 @@ beestat.component.card.voc_summary.prototype.decorate_chart_ = function(parent) var background = beestat.style.color.bluegray.light; if (cell_value !== undefined) { - var average = grid_data[day + '_' + hour].reduce(function(a, b) { - return a + b; - }) / grid_data[day + '_' + hour].length; + var average; + if (grid_data[day + '_' + hour].length > 0) { + average = grid_data[day + '_' + hour].reduce(function(a, b) { + return a + b; + }) / grid_data[day + '_' + hour].length; + } else { + average = 0; + } td.setAttribute('title', Math.round(average) + ' ppb'); @@ -366,7 +371,7 @@ beestat.component.card.voc_summary.prototype.has_data_ = function() { * @return {string} Title */ beestat.component.card.voc_summary.prototype.get_title_ = function() { - return 'TVOC Summary'; + return 'TVOC Concentration Summary'; }; /** diff --git a/js/component/header.js b/js/component/header.js index 687eb36..41a9a52 100644 --- a/js/component/header.js +++ b/js/component/header.js @@ -24,11 +24,6 @@ beestat.component.header.prototype.rerender_on_breakpoint_ = true; beestat.component.header.prototype.decorate_ = function(parent) { var self = this; - const thermostat = beestat.cache.thermostat[beestat.setting('thermostat_id')]; - const ecobee_thermostat = beestat.cache.ecobee_thermostat[ - thermostat.ecobee_thermostat_id - ]; - var pages; pages = [ @@ -49,16 +44,11 @@ beestat.component.header.prototype.decorate_ = function(parent) { } ]; - if ( - beestat.user.has_early_access() === true && - ecobee_thermostat.model_number === 'aresSmart' - ) { - pages.push({ - 'layer': 'air_quality', - 'text': 'Air Quality', - 'icon': 'weather_windy' - }); - } + pages.push({ + 'layer': 'air_quality', + 'text': 'Air Quality', + 'icon': 'weather_windy' + }); var gutter = beestat.style.size.gutter; diff --git a/js/js.php b/js/js.php index 577096d..52ce409 100755 --- a/js/js.php +++ b/js/js.php @@ -70,6 +70,7 @@ if($setting->get('environment') === 'dev' || $setting->get('environment') === 'd echo '' . PHP_EOL; echo '' . PHP_EOL; echo '' . PHP_EOL; + echo '' . PHP_EOL; echo '' . PHP_EOL; echo '' . PHP_EOL; echo '' . PHP_EOL; diff --git a/js/layer/air_quality.js b/js/layer/air_quality.js index 8240895..52d342e 100644 --- a/js/layer/air_quality.js +++ b/js/layer/air_quality.js @@ -7,8 +7,6 @@ beestat.layer.air_quality = function() { beestat.extend(beestat.layer.air_quality, beestat.layer); beestat.layer.air_quality.prototype.decorate_ = function(parent) { - const thermostat = beestat.cache.thermostat[beestat.setting('thermostat_id')]; - /* * Set the overflow on the body so the scrollbar is always present so * highcharts graphs render properly. @@ -33,19 +31,21 @@ beestat.layer.air_quality.prototype.decorate_ = function(parent) { ]); } - cards.push([ - { - 'card': new beestat.component.card.early_access( - thermostat.thermostat_id - ), - 'size': 12 - } - ]); + if (beestat.thermostat.supports_air_quality(beestat.setting('thermostat_id')) === false) { + cards.push([ + { + 'card': new beestat.component.card.air_quality_not_supported( + beestat.setting('thermostat_id') + ), + 'size': 12 + } + ]); + } cards.push([ { 'card': new beestat.component.card.air_quality_detail( - thermostat.thermostat_id + beestat.setting('thermostat_id') ), 'size': 12 } @@ -54,7 +54,7 @@ beestat.layer.air_quality.prototype.decorate_ = function(parent) { cards.push([ { 'card': new beestat.component.card.voc_summary( - thermostat.thermostat_id + beestat.setting('thermostat_id') ), 'size': 12 }