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
}