From de87c5b19ba02ede3e1751fc797aed3aa05b1c12 Mon Sep 17 00:00:00 2001 From: Klaas Hoekema Date: Tue, 14 Nov 2017 23:44:24 -0500 Subject: [PATCH] Add shaded area to show when calling for heat (#617) Adds a series to the climate graph to shade the area under the current temperature line red when the thermostat is calling for heat. Uses the current temperature because it's guaranteed to be in the right temperature range for the graph and it should minimize overlap since by definition when the thermostat is calling for heat the current temp would be below the target temp. Uses `steppedArea` because most other series types don't handle intermittent (i.e. with sections of `null` throughout) data very well. --- src/components/state-history-chart-line.html | 53 +++++++++++++------- src/data/ha-state-history-data.html | 2 +- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/components/state-history-chart-line.html b/src/components/state-history-chart-line.html index 290a1943ad..bff4b4a9b6 100644 --- a/src/components/state-history-chart-line.html +++ b/src/components/state-history-chart-line.html @@ -79,7 +79,7 @@ } if (!this.chartEngine) { - this.chartEngine = new window.google.visualization.LineChart(this); + this.chartEngine = new window.google.visualization.ComboChart(this); } if (deviceStates.length === 0) { @@ -105,6 +105,12 @@ axis: 'horizontal', maxZoomIn: 0.1, }, + seriesType: 'line', + // The "heating" series uses steppedArea to shade the area below the current + // temperature when the thermostat is calling for heat. It would be nice to + // apply this config in a more direct way than by column index, but it + // doesn't seem to be possible. + series: { 1: { type: 'steppedArea' } } }; if (this.isSingleDevice) { @@ -146,6 +152,7 @@ var hasTargetRange; var processState; var noInterpolations; + var series; dataTable.addColumn({ type: 'datetime', id: 'Time' }); function pushData(values, noInterpolationValues) { @@ -175,33 +182,41 @@ }, false); dataTable.addColumn('number', name + ' current temperature'); - + dataTable.addColumn('number', name + ' heating'); if (hasTargetRange) { dataTable.addColumn('number', name + ' target temperature high'); dataTable.addColumn('number', name + ' target temperature low'); - - noInterpolations = [false, true, true]; - - processState = function (state) { - var curTemp = saveParseFloat(state.attributes.current_temperature); - var targetHigh = saveParseFloat(state.attributes.target_temp_high); - var targetLow = saveParseFloat(state.attributes.target_temp_low); - pushData( - [new Date(state.last_changed), curTemp, targetHigh, targetLow], - noInterpolations - ); - }; } else { dataTable.addColumn('number', name + ' target temperature'); + } + processState = function (state) { + var curTemp = saveParseFloat(state.attributes.current_temperature); + // Drawing the 'heating' area up to the current temp should keep it from + // overlapping but avoid any weird gaps or range mismatches + var heating = state.attributes.operation === 'heat' ? curTemp : null; + + series = [curTemp, heating]; noInterpolations = [false, true]; - processState = function (state) { - var curTemp = saveParseFloat(state.attributes.current_temperature); + if (hasTargetRange) { + var targetHigh = saveParseFloat(state.attributes.target_temp_high); + var targetLow = saveParseFloat(state.attributes.target_temp_low); + + series = series.concat([targetHigh, targetLow]); + noInterpolations = noInterpolations.concat([true, true]); + } else { var target = saveParseFloat(state.attributes.temperature); - pushData([new Date(state.last_changed), curTemp, target], noInterpolations); - }; - } + + series.push(target); + noInterpolations.push(true); + } + + pushData( + [new Date(state.last_changed)].concat(series), + noInterpolations + ); + }; states.states.forEach(processState); } else { diff --git a/src/data/ha-state-history-data.html b/src/data/ha-state-history-data.html index 51a1db0e53..5362390626 100644 --- a/src/data/ha-state-history-data.html +++ b/src/data/ha-state-history-data.html @@ -5,7 +5,7 @@ const RECENT_THRESHOLD = 60000; // 1 minute const RECENT_CACHE = {}; const DOMAINS_USE_LAST_UPDATED = ['thermostat', 'climate']; - const LINE_ATTRIBUTES_TO_KEEP = ['temperature', 'current_temperature', 'target_temp_low', 'target_temp_high']; + const LINE_ATTRIBUTES_TO_KEEP = ['temperature', 'current_temperature', 'target_temp_low', 'target_temp_high', 'operation']; window.stateHistoryCache = window.stateHistoryCache || {}; function computeHistory(stateHistory) {