From 6ed95a6036c3982674b8e5d7a4dbbac5679f7e1c Mon Sep 17 00:00:00 2001 From: karwosts Date: Thu, 28 Dec 2023 16:46:52 -0800 Subject: [PATCH] Infer a limited history chart from state object --- .../chart/state-history-chart-line.ts | 2 +- .../chart/state-history-chart-timeline.ts | 2 +- .../timeline-chart/timeline-controller.ts | 4 ++- .../chart/timeline-chart/timeline-scale.ts | 4 +-- src/data/history.ts | 27 ++++++++++++++++--- src/dialogs/more-info/ha-more-info-history.ts | 1 + src/panels/history/ha-panel-history.ts | 2 ++ .../lovelace/cards/hui-history-graph-card.ts | 1 + 8 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/components/chart/state-history-chart-line.ts b/src/components/chart/state-history-chart-line.ts index e712762470cd..3c5c6d1edb2d 100644 --- a/src/components/chart/state-history-chart-line.ts +++ b/src/components/chart/state-history-chart-line.ts @@ -102,7 +102,7 @@ export class StateHistoryChartLine extends LitElement { config: this.hass.config, }, }, - suggestedMin: this.startTime, + min: this.startTime, suggestedMax: this.endTime, ticks: { maxRotation: 0, diff --git a/src/components/chart/state-history-chart-timeline.ts b/src/components/chart/state-history-chart-timeline.ts index d1c535e23cc4..31727ba1d790 100644 --- a/src/components/chart/state-history-chart-timeline.ts +++ b/src/components/chart/state-history-chart-timeline.ts @@ -114,7 +114,7 @@ export class StateHistoryChartTimeline extends LitElement { config: this.hass.config, }, }, - suggestedMin: this.startTime, + min: this.startTime.getTime(), suggestedMax: this.endTime, ticks: { autoSkip: true, diff --git a/src/components/chart/timeline-chart/timeline-controller.ts b/src/components/chart/timeline-chart/timeline-controller.ts index 5aeadc6e0049..b6b1d88af31c 100644 --- a/src/components/chart/timeline-chart/timeline-controller.ts +++ b/src/components/chart/timeline-chart/timeline-controller.ts @@ -205,7 +205,9 @@ export class TimelineController extends BarController { const y = vScale.getPixelForValue(this.index); - const xStart = iScale.getPixelForValue(data.start.getTime()); + const xStart = iScale.getPixelForValue( + Math.max(iScale.min, data.start.getTime()) + ); const xEnd = iScale.getPixelForValue(data.end.getTime()); const width = xEnd - xStart; diff --git a/src/components/chart/timeline-chart/timeline-scale.ts b/src/components/chart/timeline-chart/timeline-scale.ts index 8d5086dafc34..e987456f8e31 100644 --- a/src/components/chart/timeline-chart/timeline-scale.ts +++ b/src/components/chart/timeline-chart/timeline-scale.ts @@ -49,7 +49,7 @@ export class TimeLineScale extends TimeScale { max = isFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit); // Make sure that max is strictly higher than min (required by the lookup table) - this.min = Math.min(min, max - 1); - this.max = Math.max(min + 1, max); + this.min = adapter.parse(options.min, this) ?? Math.min(min, max - 1); + this.max = adapter.parse(options.max, this) ?? Math.max(min + 1, max); } } diff --git a/src/data/history.ts b/src/data/history.ts index a110c8c6347d..9832d4bdc508 100644 --- a/src/data/history.ts +++ b/src/data/history.ts @@ -81,7 +81,7 @@ export interface EntityHistoryState { /** attributes */ a: { [key: string]: any }; /** last_changed; if set, also applies to lu */ - lc: number; + lc?: number; /** last_updated */ lu: number; } @@ -419,17 +419,36 @@ const BLANK_UNIT = " "; export const computeHistory = ( hass: HomeAssistant, stateHistory: HistoryStates, + entityIds: string[], localize: LocalizeFunc, sensorNumericalDeviceClasses: string[], splitDeviceClasses = false ): HistoryResult => { const lineChartDevices: { [unit: string]: HistoryStates } = {}; const timelineDevices: TimelineEntity[] = []; - if (!stateHistory) { + + const localStateHistory: HistoryStates = {}; + + // Create a limited history from stateObj if entity has no recorded history. + entityIds.forEach((entity) => { + if (entity in stateHistory) { + localStateHistory[entity] = stateHistory[entity]; + } else if (hass.states[entity]) { + localStateHistory[entity] = [ + { + s: hass.states[entity].state, + a: hass.states[entity].attributes, + lu: new Date(hass.states[entity].last_updated).getTime() / 1000, + }, + ]; + } + }); + + if (!localStateHistory) { return { line: [], timeline: [] }; } - Object.keys(stateHistory).forEach((entityId) => { - const stateInfo = stateHistory[entityId]; + Object.keys(localStateHistory).forEach((entityId) => { + const stateInfo = localStateHistory[entityId]; if (stateInfo.length === 0) { return; } diff --git a/src/dialogs/more-info/ha-more-info-history.ts b/src/dialogs/more-info/ha-more-info-history.ts index 2adeb515c4ca..dc5c32f8a10b 100644 --- a/src/dialogs/more-info/ha-more-info-history.ts +++ b/src/dialogs/more-info/ha-more-info-history.ts @@ -228,6 +228,7 @@ export class MoreInfoHistory extends LitElement { this._stateHistory = computeHistory( this.hass!, combinedHistory, + [this.entityId], this.hass!.localize, sensorNumericDeviceClasses ); diff --git a/src/panels/history/ha-panel-history.ts b/src/panels/history/ha-panel-history.ts index 75a2b99265ee..3b7b579e13ca 100644 --- a/src/panels/history/ha-panel-history.ts +++ b/src/panels/history/ha-panel-history.ts @@ -408,6 +408,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { this._statisticsHistory = computeHistory( this.hass, statsHistoryStates, + [], this.hass.localize, sensorNumericDeviceClasses, true @@ -459,6 +460,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { this._stateHistory = computeHistory( this.hass, history, + entityIds, this.hass.localize, sensorNumericDeviceClasses, true diff --git a/src/panels/lovelace/cards/hui-history-graph-card.ts b/src/panels/lovelace/cards/hui-history-graph-card.ts index b79da32bb661..d53e628395a5 100644 --- a/src/panels/lovelace/cards/hui-history-graph-card.ts +++ b/src/panels/lovelace/cards/hui-history-graph-card.ts @@ -117,6 +117,7 @@ export class HuiHistoryGraphCard extends LitElement implements LovelaceCard { this._stateHistory = computeHistory( this.hass!, combinedHistory, + this._entityIds, this.hass!.localize, sensorNumericDeviceClasses, this._config?.split_device_classes