mirror of
				https://github.com/beestat/app.git
				synced 2025-10-31 10:07:01 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			408 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			408 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * Runtime thermostat detail chart.
 | |
|  *
 | |
|  * @param {object} data The chart data.
 | |
|  */
 | |
| beestat.component.chart.runtime_thermostat_detail_temperature = function(data) {
 | |
|   this.data_ = data;
 | |
| 
 | |
|   beestat.component.chart.apply(this, arguments);
 | |
| };
 | |
| beestat.extend(beestat.component.chart.runtime_thermostat_detail_temperature, beestat.component.chart);
 | |
| 
 | |
| /**
 | |
|  * Override for get_options_xAxis_labels_formatter_.
 | |
|  *
 | |
|  * @return {Function} xAxis labels formatter.
 | |
|  */
 | |
| beestat.component.chart.runtime_thermostat_detail_temperature.prototype.get_options_xAxis_labels_formatter_ = function() {
 | |
|   var current_day;
 | |
|   var current_hour;
 | |
| 
 | |
|   return function() {
 | |
|     var hour = this.value.format('ha');
 | |
|     var day = this.value.format('ddd');
 | |
| 
 | |
|     var label_parts = [];
 | |
|     if (day !== current_day) {
 | |
|       label_parts.push(day);
 | |
|     }
 | |
|     if (hour !== current_hour) {
 | |
|       label_parts.push(hour);
 | |
|     }
 | |
| 
 | |
|     current_hour = hour;
 | |
|     current_day = day;
 | |
| 
 | |
|     return label_parts.join(' ');
 | |
|   };
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Override for get_options_series_.
 | |
|  *
 | |
|  * @return {Array} All of the series to display on the chart.
 | |
|  */
 | |
| beestat.component.chart.runtime_thermostat_detail_temperature.prototype.get_options_series_ = function() {
 | |
|   var self = this;
 | |
|   var series = [];
 | |
| 
 | |
|   // Indoor/Outdoor Temperature
 | |
|   [
 | |
|     'indoor_temperature',
 | |
|     'outdoor_temperature'
 | |
|   ].forEach(function(series_code) {
 | |
|     if (self.data_.metadata.series[series_code].active === true) {
 | |
|       series.push({
 | |
|         'name': series_code,
 | |
|         'data': self.data_.series[series_code],
 | |
|         'color': beestat.series[series_code].color,
 | |
|         'yAxis': 0,
 | |
|         'type': 'spline',
 | |
|         'dashStyle': (series_code === 'indoor_temperature') ? 'Solid' : 'ShortDash',
 | |
|         'lineWidth': (series_code === 'indoor_temperature') ? 2 : 1
 | |
|       });
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   // Setpoint Heat/Cool
 | |
|   [
 | |
|     'setpoint_heat',
 | |
|     'setpoint_cool'
 | |
|   ].forEach(function(series_code) {
 | |
|     if (self.data_.metadata.series[series_code].active === true) {
 | |
|       series.push({
 | |
|         'name': series_code,
 | |
|         'data': self.data_.series[series_code],
 | |
|         'color': beestat.series[series_code].color,
 | |
|         'yAxis': 0,
 | |
|         'type': 'line',
 | |
|         'lineWidth': 1,
 | |
|         'step': 'right',
 | |
|         'className': 'crisp_edges'
 | |
|       });
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   // Indoor/Outdoor Humidity
 | |
|   [
 | |
|     'indoor_humidity',
 | |
|     'outdoor_humidity'
 | |
|   ].forEach(function(series_code) {
 | |
|     if (self.data_.metadata.series[series_code].active === true) {
 | |
|       series.push({
 | |
|         'name': series_code,
 | |
|         'data': self.data_.series[series_code],
 | |
|         'color': beestat.series[series_code].color,
 | |
|         'yAxis': 1,
 | |
|         'type': 'spline',
 | |
|         'dashStyle': (series_code === 'indoor_humidity') ? 'Solid' : 'ShortDash',
 | |
|         'lineWidth': (series_code === 'indoor_humidity') ? 2 : 1,
 | |
|         'visible': false
 | |
|       });
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   series.push({
 | |
|     'name': '',
 | |
|     'data': self.data_.series.dummy,
 | |
|     'yAxis': 0,
 | |
|     'type': 'line',
 | |
|     'lineWidth': 0,
 | |
|     'showInLegend': false
 | |
|   });
 | |
| 
 | |
|   return series;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Override for get_options_yAxis_.
 | |
|  *
 | |
|  * @return {Array} The y-axis options.
 | |
|  */
 | |
| beestat.component.chart.runtime_thermostat_detail_temperature.prototype.get_options_yAxis_ = function() {
 | |
|   return [
 | |
|     // Temperature
 | |
|     {
 | |
|       'gridLineColor': beestat.style.color.bluegray.light,
 | |
|       'gridLineDashStyle': 'longdash',
 | |
|       'allowDecimals': false,
 | |
|       'title': {'text': null},
 | |
|       'labels': {
 | |
|         'style': {'color': beestat.style.color.gray.base},
 | |
|         'formatter': function() {
 | |
|           return this.value + beestat.setting('temperature_unit');
 | |
|         }
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     // Humidity
 | |
|     {
 | |
|       'alignTicks': false,
 | |
|       'gridLineColor': null,
 | |
|       'opposite': true,
 | |
|       'title': {'text': null},
 | |
|       'labels': {
 | |
|         'style': {'color': beestat.style.color.gray.base},
 | |
|         'formatter': function() {
 | |
|           return this.value + '%';
 | |
|         }
 | |
|       },
 | |
| 
 | |
|       // https://github.com/highcharts/highcharts/issues/3403
 | |
|       'min': 0,
 | |
|       'minRange': 100,
 | |
|       'ceiling': 100
 | |
|     }
 | |
|   ];
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Override for get_options_tooltip_formatter_.
 | |
|  *
 | |
|  * @return {Function} The tooltip formatter.
 | |
|  */
 | |
| beestat.component.chart.runtime_thermostat_detail_temperature.prototype.get_options_tooltip_formatter_ = function() {
 | |
|   var self = this;
 | |
| 
 | |
|   return function() {
 | |
|     var points = [];
 | |
|     var x = this.x;
 | |
| 
 | |
|     var sections = [];
 | |
|     var groups = {
 | |
|       'mode': [],
 | |
|       'data': [],
 | |
|       'equipment': []
 | |
|     };
 | |
| 
 | |
|     var visible_series = [];
 | |
|     self.get_chart().series.forEach(function(series) {
 | |
|       if (series.visible === true) {
 | |
|         visible_series.push(series.name);
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     // Add points which can be toggled.
 | |
|     [
 | |
|       'indoor_temperature',
 | |
|       'outdoor_temperature',
 | |
|       'setpoint_heat',
 | |
|       'setpoint_cool',
 | |
|       'indoor_humidity',
 | |
|       'outdoor_humidity'
 | |
|     ].forEach(function(series_code) {
 | |
|       if (
 | |
|         self.data_.metadata.series[series_code].data[x.valueOf()] !== undefined &&
 | |
|         visible_series.includes(series_code) === true
 | |
|       ) {
 | |
|         points.push({
 | |
|           'series_code': series_code,
 | |
|           'value': self.data_.metadata.series[series_code].data[x.valueOf()]
 | |
|         });
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     // Add points which are, more or less, always present.
 | |
|     [
 | |
|       'compressor_heat_1',
 | |
|       'compressor_heat_2',
 | |
|       'auxiliary_heat_1',
 | |
|       'auxiliary_heat_2',
 | |
|       'compressor_cool_1',
 | |
|       'compressor_cool_2',
 | |
|       'fan',
 | |
|       'humidifier',
 | |
|       'dehumidifier',
 | |
|       'ventilator',
 | |
|       'economizer',
 | |
|       'calendar_event_smartrecovery',
 | |
|       'calendar_event_home',
 | |
|       'calendar_event_away',
 | |
|       'calendar_event_sleep',
 | |
|       'calendar_event_smarthome',
 | |
|       'calendar_event_smartaway',
 | |
|       'calendar_event_hold',
 | |
|       'calendar_event_vacation',
 | |
|       'calendar_event_quicksave',
 | |
|       'calendar_event_other',
 | |
|       'calendar_event_custom'
 | |
|     ].forEach(function(series_code) {
 | |
|       if (self.data_.metadata.series[series_code].data[x.valueOf()] !== undefined) {
 | |
|         points.push({
 | |
|           'series_code': series_code,
 | |
|           'value': self.data_.metadata.series[series_code].data[x.valueOf()]
 | |
|         });
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     // HVAC Mode
 | |
|     var system_mode;
 | |
|     var system_mode_color;
 | |
| 
 | |
|     switch (self.data_.metadata.series.system_mode[this.x.valueOf()]) {
 | |
|     case 'auto':
 | |
|       system_mode = 'Auto';
 | |
|       system_mode_color = beestat.style.color.gray.base;
 | |
|       break;
 | |
|     case 'heat':
 | |
|       system_mode = 'Heat';
 | |
|       system_mode_color = beestat.series.compressor_heat_1.color;
 | |
|       break;
 | |
|     case 'cool':
 | |
|       system_mode = 'Cool';
 | |
|       system_mode_color = beestat.series.compressor_cool_1.color;
 | |
|       break;
 | |
|     case 'off':
 | |
|       system_mode = 'Off';
 | |
|       system_mode_color = beestat.style.color.gray.base;
 | |
|       break;
 | |
|     case 'auxiliary_heat':
 | |
|       system_mode = 'Aux';
 | |
|       system_mode_color = beestat.series.auxiliary_heat_1.color;
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if (system_mode !== undefined) {
 | |
|       groups.mode.push({
 | |
|         'label': 'System Mode',
 | |
|         'value': system_mode,
 | |
|         'color': system_mode_color
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     points.forEach(function(point) {
 | |
|       var label;
 | |
|       var value;
 | |
|       var color;
 | |
|       var group;
 | |
| 
 | |
|       if (
 | |
|         point.series_code.includes('temperature') === true ||
 | |
|         point.series_code.includes('setpoint') === true
 | |
|       ) {
 | |
|         group = 'data';
 | |
|         label = beestat.series[point.series_code].name;
 | |
|         color = beestat.series[point.series_code].color;
 | |
|         value = self.data_.metadata.series[point.series_code].data[x.valueOf()];
 | |
| 
 | |
|         value = beestat.temperature({
 | |
|           'temperature': value,
 | |
|           'convert': false,
 | |
|           'units': true
 | |
|         });
 | |
|       } else if (point.series_code.includes('humidity') === true) {
 | |
|         group = 'data';
 | |
|         label = beestat.series[point.series_code].name;
 | |
|         color = beestat.series[point.series_code].color;
 | |
|         value = self.data_.metadata.series[point.series_code].data[x.valueOf()];
 | |
| 
 | |
|         value = Math.round(value) + '%';
 | |
|       } else if (
 | |
|         point.series_code === 'fan' ||
 | |
|         point.series_code === 'compressor_heat_1' ||
 | |
|         point.series_code === 'auxiliary_heat_1' ||
 | |
|         point.series_code === 'compressor_cool_1' ||
 | |
|         point.series_code === 'dehumidifier' ||
 | |
|         point.series_code === 'economizer' ||
 | |
|         point.series_code === 'humidifier' ||
 | |
|         point.series_code === 'ventilator'
 | |
|       ) {
 | |
|         group = 'equipment';
 | |
|         label = beestat.series[point.series_code].name;
 | |
|         color = beestat.series[point.series_code].color;
 | |
|         value = beestat.time(
 | |
|           self.data_.metadata.series[point.series_code].durations[x.valueOf()]
 | |
|         );
 | |
|       } else if (
 | |
|         point.series_code.includes('calendar_event')
 | |
|       ) {
 | |
|         group = 'mode';
 | |
|         label = 'Comfort Profile';
 | |
|         color = beestat.series[point.series_code].color;
 | |
|         value = self.data_.metadata.series.calendar_event_name[x.valueOf()];
 | |
|       } else {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       groups[group].push({
 | |
|         'label': label,
 | |
|         'value': value,
 | |
|         'color': color
 | |
|       });
 | |
| 
 | |
|       // Show stage 2 duration on stage 1, if applicable.
 | |
|       if (
 | |
|         point.series_code === 'compressor_heat_1' &&
 | |
|         self.data_.metadata.series.compressor_heat_2.durations[x.valueOf()].seconds > 0
 | |
|       ) {
 | |
|         groups.equipment.push({
 | |
|           'label': beestat.series.compressor_heat_2.name,
 | |
|           'value': beestat.time(
 | |
|             self.data_.metadata.series.compressor_heat_2.durations[x.valueOf()]
 | |
|           ),
 | |
|           'color': beestat.series.compressor_heat_2.color
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       if (
 | |
|         point.series_code === 'auxiliary_heat_1' &&
 | |
|         self.data_.metadata.series.auxiliary_heat_2.durations[x.valueOf()].seconds > 0
 | |
|       ) {
 | |
|         groups.equipment.push({
 | |
|           'label': beestat.series.auxiliary_heat_2.name,
 | |
|           'value': beestat.time(
 | |
|             self.data_.metadata.series.auxiliary_heat_2.durations[x.valueOf()]
 | |
|           ),
 | |
|           'color': beestat.series.auxiliary_heat_2.color
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       if (
 | |
|         point.series_code === 'compressor_cool_1' &&
 | |
|         self.data_.metadata.series.compressor_cool_2.durations[x.valueOf()].seconds > 0
 | |
|       ) {
 | |
|         groups.equipment.push({
 | |
|           'label': beestat.series.compressor_cool_2.name,
 | |
|           'value': beestat.time(
 | |
|             self.data_.metadata.series.compressor_cool_2.durations[x.valueOf()]
 | |
|           ),
 | |
|           'color': beestat.series.compressor_cool_2.color
 | |
|         });
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     if (
 | |
|       groups.mode.length === 0 &&
 | |
|       groups.equipment.length === 0 &&
 | |
|       groups.data.length === 0
 | |
|     ) {
 | |
|       groups.mode.push({
 | |
|         'label': 'No data',
 | |
|         'value': '',
 | |
|         'color': beestat.style.color.gray.base
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     sections.push(groups.mode);
 | |
|     sections.push(groups.equipment);
 | |
|     sections.push(groups.data);
 | |
| 
 | |
|     var title = this.x.format('ddd, MMM D @ h:mma');
 | |
| 
 | |
|     return self.tooltip_formatter_helper_(
 | |
|       title,
 | |
|       sections
 | |
|     );
 | |
|   };
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Get the left margin for the chart.
 | |
|  *
 | |
|  * @return {number} The left margin for the chart.
 | |
|  */
 | |
| beestat.component.chart.runtime_thermostat_detail_temperature.prototype.get_options_chart_marginLeft_ = function() {
 | |
|   return 45;
 | |
| };
 |