1
0
mirror of https://github.com/beestat/app.git synced 2025-05-24 02:14:03 -04:00

Changed TVOC Summary to Air Quality Summary

This better reflects the little color scale in the ecobee app.
This commit is contained in:
Jon Ziebell 2022-07-06 19:15:06 -04:00
parent 48972a8e75
commit abab24cd24
7 changed files with 81 additions and 77 deletions

View File

@ -112,6 +112,11 @@ class runtime_sensor extends cora\crud {
if ($runtime_sensor['temperature'] !== null) { if ($runtime_sensor['temperature'] !== null) {
$runtime_sensor['temperature'] /= 10; $runtime_sensor['temperature'] /= 10;
} }
// Normalize air quality from 0-350 to 0-100;
if ($runtime_sensor['air_quality'] !== null) {
$runtime_sensor['air_quality'] = round($runtime_sensor['air_quality'] / 350 * 100);
}
} }
return $runtime_sensors; return $runtime_sensors;

View File

@ -46,12 +46,12 @@ beestat.setting = function(argument_1, opt_value, opt_callback) {
'air_quality_detail_range_static_end': moment().format('MM/DD/YYYY'), 'air_quality_detail_range_static_end': moment().format('MM/DD/YYYY'),
'air_quality_detail_range_dynamic': 3, 'air_quality_detail_range_dynamic': 3,
'voc_summary_range_type': 'dynamic', 'air_quality_summary_range_type': 'dynamic',
'voc_summary_range_static_begin': moment() 'air_quality_summary_range_static_begin': moment()
.subtract(28, 'day') .subtract(28, 'day')
.format('MM/DD/YYYY'), .format('MM/DD/YYYY'),
'voc_summary_range_static_end': moment().format('MM/DD/YYYY'), 'air_quality_summary_range_static_end': moment().format('MM/DD/YYYY'),
'voc_summary_range_dynamic': 28, 'air_quality_summary_range_dynamic': 28,
'runtime_thermostat_summary_time_count': 0, 'runtime_thermostat_summary_time_count': 0,
'runtime_thermostat_summary_time_period': 'all', 'runtime_thermostat_summary_time_period': 'all',

View File

@ -70,13 +70,13 @@ beestat.component.card.air_quality_detail.prototype.decorate_contents_ = functio
this.charts_.occupancy.render(chart_container); this.charts_.occupancy.render(chart_container);
chart_container.appendChild($.createElement('p').innerText('Air Quality')); chart_container.appendChild($.createElement('p').innerText('Air Quality (%)'));
this.charts_.air_quality.render(chart_container); this.charts_.air_quality.render(chart_container);
chart_container.appendChild($.createElement('p').innerText('TVOC Concentration')); chart_container.appendChild($.createElement('p').innerText('TVOC Concentration (ppb)'));
this.charts_.voc_concentration.render(chart_container); this.charts_.voc_concentration.render(chart_container);
chart_container.appendChild($.createElement('p').innerText('CO₂ Concentration')); chart_container.appendChild($.createElement('p').innerText('CO₂ Concentration (ppm)'));
this.charts_.co2_concentration.render(chart_container); this.charts_.co2_concentration.render(chart_container);
// this.charts_.x_axis.render(chart_container); // this.charts_.x_axis.render(chart_container);

View File

@ -5,7 +5,7 @@
* @param {number} thermostat_id The thermostat_id this card is displaying * @param {number} thermostat_id The thermostat_id this card is displaying
* data for * data for
*/ */
beestat.component.card.voc_summary = function(thermostat_id) { beestat.component.card.air_quality_summary = function(thermostat_id) {
var self = this; var self = this;
this.thermostat_id_ = thermostat_id; this.thermostat_id_ = thermostat_id;
@ -24,25 +24,25 @@ beestat.component.card.voc_summary = function(thermostat_id) {
beestat.dispatcher.addEventListener( beestat.dispatcher.addEventListener(
[ [
'setting.voc_summary_range_type', 'setting.air_quality_summary_range_type',
'setting.voc_summary_range_dynamic', 'setting.air_quality_summary_range_dynamic',
'cache.data.voc_summary' 'cache.data.air_quality_summary'
], ],
change_function change_function
); );
beestat.component.card.apply(this, arguments); beestat.component.card.apply(this, arguments);
}; };
beestat.extend(beestat.component.card.voc_summary, beestat.component.card); beestat.extend(beestat.component.card.air_quality_summary, beestat.component.card);
beestat.component.card.voc_summary.prototype.rerender_on_breakpoint_ = true; beestat.component.card.air_quality_summary.prototype.rerender_on_breakpoint_ = true;
/** /**
* Decorate * Decorate
* *
* @param {rocket.Elements} parent * @param {rocket.Elements} parent
*/ */
beestat.component.card.voc_summary.prototype.decorate_contents_ = function(parent) { beestat.component.card.air_quality_summary.prototype.decorate_contents_ = function(parent) {
var self = this; var self = this;
var container = $.createElement('div').style({ var container = $.createElement('div').style({
@ -59,10 +59,10 @@ beestat.component.card.voc_summary.prototype.decorate_contents_ = function(paren
var required_begin; var required_begin;
var required_end; var required_end;
if (beestat.setting('voc_summary_range_type') === 'dynamic') { if (beestat.setting('air_quality_summary_range_type') === 'dynamic') {
required_begin = moment() required_begin = moment()
.subtract( .subtract(
beestat.setting('voc_summary_range_dynamic'), beestat.setting('air_quality_summary_range_dynamic'),
'day' 'day'
) )
.second(0); .second(0);
@ -72,10 +72,10 @@ beestat.component.card.voc_summary.prototype.decorate_contents_ = function(paren
.second(0); .second(0);
} else { } else {
required_begin = moment( required_begin = moment(
beestat.setting('voc_summary_range_static_begin') + ' 00:00:00' beestat.setting('air_quality_summary_range_static_begin') + ' 00:00:00'
); );
required_end = moment( required_end = moment(
beestat.setting('voc_summary_range_static_end') + ' 23:59:59' beestat.setting('air_quality_summary_range_static_end') + ' 23:59:59'
); );
} }
@ -97,13 +97,13 @@ beestat.component.card.voc_summary.prototype.decorate_contents_ = function(paren
* the database, check every 2 seconds until it does. * the database, check every 2 seconds until it does.
*/ */
if (beestat.thermostat.data_synced(this.thermostat_id_, required_begin, required_end) === true) { if (beestat.thermostat.data_synced(this.thermostat_id_, required_begin, required_end) === true) {
if (beestat.cache.data.voc_summary === undefined) { if (beestat.cache.data.air_quality_summary === undefined) {
this.show_loading_('Fetching'); this.show_loading_('Fetching');
var value; var value;
var operator; var operator;
if (beestat.setting('voc_summary_range_type') === 'dynamic') { if (beestat.setting('air_quality_summary_range_type') === 'dynamic') {
value = required_begin.format(); value = required_begin.format();
operator = '>='; operator = '>=';
} else { } else {
@ -143,7 +143,7 @@ beestat.component.card.voc_summary.prototype.decorate_contents_ = function(paren
var r = response[alias]; var r = response[alias];
runtime_sensors = runtime_sensors.concat(r); runtime_sensors = runtime_sensors.concat(r);
} }
beestat.cache.set('data.voc_summary', runtime_sensors); beestat.cache.set('data.air_quality_summary', runtime_sensors);
}); });
api_call.send(); api_call.send();
@ -192,16 +192,16 @@ beestat.component.card.voc_summary.prototype.decorate_contents_ = function(paren
* *
* @param {rocket.Elements} parent * @param {rocket.Elements} parent
*/ */
beestat.component.card.voc_summary.prototype.decorate_chart_ = function(parent) { beestat.component.card.air_quality_summary.prototype.decorate_chart_ = function(parent) {
var grid_data = {}; var grid_data = {};
for (var runtime_sensor_id in beestat.cache.data.voc_summary) { for (var runtime_sensor_id in beestat.cache.data.air_quality_summary) {
var runtime_sensor = beestat.cache.data.voc_summary[runtime_sensor_id]; var runtime_sensor = beestat.cache.data.air_quality_summary[runtime_sensor_id];
var key = moment(runtime_sensor.timestamp).format('d_H'); var key = moment(runtime_sensor.timestamp).format('d_H');
if (grid_data[key] === undefined) { if (grid_data[key] === undefined) {
grid_data[key] = []; grid_data[key] = [];
} }
if (runtime_sensor.voc_concentration !== null) { if (runtime_sensor.air_quality !== null) {
grid_data[key].push(runtime_sensor.voc_concentration); grid_data[key].push(runtime_sensor.air_quality);
} }
} }
@ -262,36 +262,32 @@ beestat.component.card.voc_summary.prototype.decorate_chart_ = function(parent)
average = 0; average = 0;
} }
td.setAttribute('title', Math.round(average) + ' ppb'); td.setAttribute('title', Math.round(average));
// I am normalizing Air Quality between 0 and 100.
const max_average = 100;
const colors = [
beestat.style.color.green.light,
beestat.style.color.green.base,
beestat.style.color.green.dark,
beestat.style.color.yellow.light,
beestat.style.color.yellow.base,
beestat.style.color.yellow.dark,
beestat.style.color.orange.light,
beestat.style.color.orange.base,
beestat.style.color.orange.dark,
beestat.style.color.red.light,
beestat.style.color.red.base,
beestat.style.color.red.dark
];
if (average < 1) { if (average < 1) {
background = beestat.style.color.bluegray.light; background = beestat.style.color.bluegray.light;
} else if (average < 75) { } else if (average <= max_average) {
background = beestat.style.color.green.light; background = colors[
} else if (average < 150) { Math.floor(average / (max_average / colors.length))
background = beestat.style.color.green.base; ];
} else if (average < 225) {
background = beestat.style.color.green.dark;
} else if (average < 375) {
background = beestat.style.color.yellow.light;
} else if (average < 525) {
background = beestat.style.color.yellow.base;
} else if (average < 675) {
background = beestat.style.color.yellow.dark;
} else if (average < 925) {
background = beestat.style.color.orange.light;
} else if (average < 1175) {
background = beestat.style.color.orange.base;
} else if (average < 1425) {
background = beestat.style.color.orange.dark;
} else if (average < 1675) {
background = beestat.style.color.red.light;
} else if (average < 1925) {
background = beestat.style.color.red.base;
} else if (average < 2175) {
background = beestat.style.color.red.dark;
} else { } else {
background = beestat.style.color.red.dark; background = colors[colors.length - 1];
} }
} }
@ -312,7 +308,7 @@ beestat.component.card.voc_summary.prototype.decorate_chart_ = function(parent)
* *
* @param {rocket.Elements} parent * @param {rocket.Elements} parent
*/ */
beestat.component.card.voc_summary.prototype.decorate_top_right_ = function(parent) { beestat.component.card.air_quality_summary.prototype.decorate_top_right_ = function(parent) {
var menu = (new beestat.component.menu()).render(parent); var menu = (new beestat.component.menu()).render(parent);
menu.add_menu_item(new beestat.component.menu_item() menu.add_menu_item(new beestat.component.menu_item()
@ -320,13 +316,13 @@ beestat.component.card.voc_summary.prototype.decorate_top_right_ = function(pare
.set_icon('numeric_1_box') .set_icon('numeric_1_box')
.set_callback(function() { .set_callback(function() {
if ( if (
beestat.setting('voc_summary_range_dynamic') !== 7 || beestat.setting('air_quality_summary_range_dynamic') !== 7 ||
beestat.setting('voc_summary_range_type') !== 'dynamic' beestat.setting('air_quality_summary_range_type') !== 'dynamic'
) { ) {
beestat.cache.delete('data.voc_summary'); beestat.cache.delete('data.air_quality_summary');
beestat.setting({ beestat.setting({
'voc_summary_range_dynamic': 7, 'air_quality_summary_range_dynamic': 7,
'voc_summary_range_type': 'dynamic' 'air_quality_summary_range_type': 'dynamic'
}); });
} }
})); }));
@ -336,13 +332,13 @@ beestat.component.card.voc_summary.prototype.decorate_top_right_ = function(pare
.set_icon('numeric_4_box') .set_icon('numeric_4_box')
.set_callback(function() { .set_callback(function() {
if ( if (
beestat.setting('voc_summary_range_dynamic') !== 28 || beestat.setting('air_quality_summary_range_dynamic') !== 28 ||
beestat.setting('voc_summary_range_type') !== 'dynamic' beestat.setting('air_quality_summary_range_type') !== 'dynamic'
) { ) {
beestat.cache.delete('data.voc_summary'); beestat.cache.delete('data.air_quality_summary');
beestat.setting({ beestat.setting({
'voc_summary_range_dynamic': 28, 'air_quality_summary_range_dynamic': 28,
'voc_summary_range_type': 'dynamic' 'air_quality_summary_range_type': 'dynamic'
}); });
} }
})); }));
@ -360,9 +356,9 @@ beestat.component.card.voc_summary.prototype.decorate_top_right_ = function(pare
* *
* @return {boolean} Whether or not there is data to display on the chart. * @return {boolean} Whether or not there is data to display on the chart.
*/ */
beestat.component.card.voc_summary.prototype.has_data_ = function() { beestat.component.card.air_quality_summary.prototype.has_data_ = function() {
return beestat.cache.data.voc_summary && return beestat.cache.data.air_quality_summary &&
beestat.cache.data.voc_summary.length > 0; beestat.cache.data.air_quality_summary.length > 0;
}; };
/** /**
@ -370,8 +366,8 @@ beestat.component.card.voc_summary.prototype.has_data_ = function() {
* *
* @return {string} Title * @return {string} Title
*/ */
beestat.component.card.voc_summary.prototype.get_title_ = function() { beestat.component.card.air_quality_summary.prototype.get_title_ = function() {
return 'TVOC Concentration Summary'; return 'Air Quality Summary';
}; };
/** /**
@ -379,19 +375,19 @@ beestat.component.card.voc_summary.prototype.get_title_ = function() {
* *
* @return {string} Subtitle * @return {string} Subtitle
*/ */
beestat.component.card.voc_summary.prototype.get_subtitle_ = function() { beestat.component.card.air_quality_summary.prototype.get_subtitle_ = function() {
if (beestat.setting('voc_summary_range_type') === 'dynamic') { if (beestat.setting('air_quality_summary_range_type') === 'dynamic') {
var s = ((beestat.setting('voc_summary_range_dynamic') / 7) > 1) ? 's' : ''; var s = ((beestat.setting('air_quality_summary_range_dynamic') / 7) > 1) ? 's' : '';
return 'Past ' + return 'Past ' +
(beestat.setting('voc_summary_range_dynamic') / 7) + (beestat.setting('air_quality_summary_range_dynamic') / 7) +
' week' + ' week' +
s; s;
} }
var begin = moment(beestat.setting('voc_summary_range_static_begin')) var begin = moment(beestat.setting('air_quality_summary_range_static_begin'))
.format('MMM D, YYYY'); .format('MMM D, YYYY');
var end = moment(beestat.setting('voc_summary_range_static_end')) var end = moment(beestat.setting('air_quality_summary_range_static_end'))
.format('MMM D, YYYY'); .format('MMM D, YYYY');
return begin + ' to ' + end; return begin + ' to ' + end;

View File

@ -73,7 +73,10 @@ beestat.component.chart.air_quality.prototype.get_options_yAxis_ = function() {
'formatter': function() { 'formatter': function() {
return this.value; return this.value;
} }
} },
'min': 0,
'max': 100,
'tickInterval': 100
} }
]; ];
}; };

View File

@ -69,7 +69,7 @@ if($setting->get('environment') === 'dev' || $setting->get('environment') === 'd
echo '<script src="/js/component/card/metrics.js"></script>' . PHP_EOL; echo '<script src="/js/component/card/metrics.js"></script>' . PHP_EOL;
echo '<script src="/js/component/card/settings.js"></script>' . PHP_EOL; echo '<script src="/js/component/card/settings.js"></script>' . PHP_EOL;
echo '<script src="/js/component/card/air_quality_detail.js"></script>' . PHP_EOL; echo '<script src="/js/component/card/air_quality_detail.js"></script>' . PHP_EOL;
echo '<script src="/js/component/card/voc_summary.js"></script>' . PHP_EOL; echo '<script src="/js/component/card/air_quality_summary.js"></script>' . PHP_EOL;
echo '<script src="/js/component/card/air_quality_not_supported.js"></script>' . PHP_EOL; echo '<script src="/js/component/card/air_quality_not_supported.js"></script>' . PHP_EOL;
echo '<script src="/js/component/chart.js"></script>' . PHP_EOL; echo '<script src="/js/component/chart.js"></script>' . PHP_EOL;
echo '<script src="/js/component/chart/runtime_thermostat_summary.js"></script>' . PHP_EOL; echo '<script src="/js/component/chart/runtime_thermostat_summary.js"></script>' . PHP_EOL;

View File

@ -53,7 +53,7 @@ beestat.layer.air_quality.prototype.decorate_ = function(parent) {
cards.push([ cards.push([
{ {
'card': new beestat.component.card.voc_summary( 'card': new beestat.component.card.air_quality_summary(
beestat.setting('thermostat_id') beestat.setting('thermostat_id')
), ),
'size': 12 'size': 12