From 0bfb2b4a56aded5bbb0cb885fd9c82bd9195cff4 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 21 Nov 2022 16:24:57 +0100 Subject: [PATCH] Don't fetch unneeded statistics from core (#14423) --- demo/src/stubs/recorder.ts | 85 +++++-------------- src/components/chart/statistics-chart.ts | 33 +++---- src/data/energy.ts | 16 ++-- src/data/recorder.ts | 45 ++++++---- src/dialogs/more-info/ha-more-info-history.ts | 7 +- .../energy/hui-energy-devices-graph-card.ts | 8 +- .../cards/energy/hui-energy-gas-graph-card.ts | 6 +- .../energy/hui-energy-solar-graph-card.ts | 6 +- .../energy/hui-energy-usage-graph-card.ts | 2 +- .../energy/hui-energy-water-graph-card.ts | 6 +- .../cards/hui-statistics-graph-card.ts | 18 ++-- 11 files changed, 107 insertions(+), 125 deletions(-) diff --git a/demo/src/stubs/recorder.ts b/demo/src/stubs/recorder.ts index 9472772ce1..3d367cdc0e 100644 --- a/demo/src/stubs/recorder.ts +++ b/demo/src/stubs/recorder.ts @@ -13,7 +13,6 @@ import { import { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; const generateMeanStatistics = ( - id: string, start: Date, end: Date, period: "5minute" | "hour" | "day" | "month" = "hour", @@ -29,13 +28,12 @@ const generateMeanStatistics = ( const delta = Math.random() * maxDiff; const mean = lastVal + delta; statistics.push({ - statistic_id: id, - start: currentDate.toISOString(), - end: currentDate.toISOString(), + start: currentDate.getTime(), + end: currentDate.getTime(), mean, min: mean - Math.random() * maxDiff, max: mean + Math.random() * maxDiff, - last_reset: "1970-01-01T00:00:00+00:00", + last_reset: 0, state: mean, sum: null, }); @@ -51,7 +49,6 @@ const generateMeanStatistics = ( }; const generateSumStatistics = ( - id: string, start: Date, end: Date, period: "5minute" | "hour" | "day" | "month" = "hour", @@ -67,13 +64,12 @@ const generateSumStatistics = ( const add = Math.random() * maxDiff; sum += add; statistics.push({ - statistic_id: id, - start: currentDate.toISOString(), - end: currentDate.toISOString(), + start: currentDate.getTime(), + end: currentDate.getTime(), mean: null, min: null, max: null, - last_reset: "1970-01-01T00:00:00+00:00", + last_reset: 0, state: initValue + sum, sum, }); @@ -88,7 +84,6 @@ const generateSumStatistics = ( }; const generateCurvedStatistics = ( - id: string, start: Date, end: Date, _period: "5minute" | "hour" | "day" | "month" = "hour", @@ -108,13 +103,12 @@ const generateCurvedStatistics = ( const add = Math.random() * maxDiff; sum += i * add; statistics.push({ - statistic_id: id, - start: currentDate.toISOString(), - end: currentDate.toISOString(), + start: currentDate.getTime(), + end: currentDate.getTime(), mean: null, min: null, max: null, - last_reset: "1970-01-01T00:00:00+00:00", + last_reset: 0, state: initValue + sum, sum: metered ? sum : null, }); @@ -137,14 +131,13 @@ const statisticsFunctions: Record< ) => StatisticValue[] > = { "sensor.energy_consumption_tarif_1": ( - id: string, + _id: string, start: Date, end: Date, period = "hour" ) => { if (period !== "hour") { return generateSumStatistics( - id, start, end, period, @@ -153,20 +146,12 @@ const statisticsFunctions: Record< ); } const morningEnd = new Date(start.getTime() + 10 * 60 * 60 * 1000); - const morningLow = generateSumStatistics( - id, - start, - morningEnd, - period, - 0, - 0.7 - ); + const morningLow = generateSumStatistics(start, morningEnd, period, 0, 0.7); const eveningStart = new Date(start.getTime() + 20 * 60 * 60 * 1000); const morningFinalVal = morningLow.length ? morningLow[morningLow.length - 1].sum! : 0; const empty = generateSumStatistics( - id, morningEnd, eveningStart, period, @@ -174,7 +159,6 @@ const statisticsFunctions: Record< 0 ); const eveningLow = generateSumStatistics( - id, eveningStart, end, period, @@ -184,14 +168,13 @@ const statisticsFunctions: Record< return [...morningLow, ...empty, ...eveningLow]; }, "sensor.energy_consumption_tarif_2": ( - id: string, + _id: string, start: Date, end: Date, period = "hour" ) => { if (period !== "hour") { return generateSumStatistics( - id, start, end, period, @@ -202,7 +185,6 @@ const statisticsFunctions: Record< const morningEnd = new Date(start.getTime() + 9 * 60 * 60 * 1000); const eveningStart = new Date(start.getTime() + 20 * 60 * 60 * 1000); const highTarif = generateSumStatistics( - id, morningEnd, eveningStart, period, @@ -212,9 +194,8 @@ const statisticsFunctions: Record< const highTarifFinalVal = highTarif.length ? highTarif[highTarif.length - 1].sum! : 0; - const morning = generateSumStatistics(id, start, morningEnd, period, 0, 0); + const morning = generateSumStatistics(start, morningEnd, period, 0, 0); const evening = generateSumStatistics( - id, eveningStart, end, period, @@ -223,18 +204,17 @@ const statisticsFunctions: Record< ); return [...morning, ...highTarif, ...evening]; }, - "sensor.energy_production_tarif_1": (id, start, end, period = "hour") => - generateSumStatistics(id, start, end, period, 0, 0), + "sensor.energy_production_tarif_1": (_id, start, end, period = "hour") => + generateSumStatistics(start, end, period, 0, 0), "sensor.energy_production_tarif_1_compensation": ( - id, + _id, start, end, period = "hour" - ) => generateSumStatistics(id, start, end, period, 0, 0), - "sensor.energy_production_tarif_2": (id, start, end, period = "hour") => { + ) => generateSumStatistics(start, end, period, 0, 0), + "sensor.energy_production_tarif_2": (_id, start, end, period = "hour") => { if (period !== "hour") { return generateSumStatistics( - id, start, end, period, @@ -246,7 +226,6 @@ const statisticsFunctions: Record< const productionEnd = new Date(start.getTime() + 21 * 60 * 60 * 1000); const dayEnd = new Date(endOfDay(productionEnd)); const production = generateCurvedStatistics( - id, productionStart, productionEnd, period, @@ -257,16 +236,8 @@ const statisticsFunctions: Record< const productionFinalVal = production.length ? production[production.length - 1].sum! : 0; - const morning = generateSumStatistics( - id, - start, - productionStart, - period, - 0, - 0 - ); + const morning = generateSumStatistics(start, productionStart, period, 0, 0); const evening = generateSumStatistics( - id, productionEnd, dayEnd, period, @@ -274,7 +245,6 @@ const statisticsFunctions: Record< 0 ); const rest = generateSumStatistics( - id, dayEnd, end, period, @@ -283,10 +253,9 @@ const statisticsFunctions: Record< ); return [...morning, ...production, ...evening, ...rest]; }, - "sensor.solar_production": (id, start, end, period = "hour") => { + "sensor.solar_production": (_id, start, end, period = "hour") => { if (period !== "hour") { return generateSumStatistics( - id, start, end, period, @@ -298,7 +267,6 @@ const statisticsFunctions: Record< const productionEnd = new Date(start.getTime() + 23 * 60 * 60 * 1000); const dayEnd = new Date(endOfDay(productionEnd)); const production = generateCurvedStatistics( - id, productionStart, productionEnd, period, @@ -309,16 +277,8 @@ const statisticsFunctions: Record< const productionFinalVal = production.length ? production[production.length - 1].sum! : 0; - const morning = generateSumStatistics( - id, - start, - productionStart, - period, - 0, - 0 - ); + const morning = generateSumStatistics(start, productionStart, period, 0, 0); const evening = generateSumStatistics( - id, productionEnd, dayEnd, period, @@ -326,7 +286,6 @@ const statisticsFunctions: Record< 0 ); const rest = generateSumStatistics( - id, dayEnd, end, period, @@ -362,7 +321,6 @@ export const mockRecorder = (mockHass: MockHomeAssistant) => { statistics[id] = entityState && "last_reset" in entityState.attributes ? generateSumStatistics( - id, start, end, period, @@ -370,7 +328,6 @@ export const mockRecorder = (mockHass: MockHomeAssistant) => { state * (state > 80 ? 0.01 : 0.05) ) : generateMeanStatistics( - id, start, end, period, diff --git a/src/components/chart/statistics-chart.ts b/src/components/chart/statistics-chart.ts index d187dfa1ea..0b603dab3c 100644 --- a/src/components/chart/statistics-chart.ts +++ b/src/components/chart/statistics-chart.ts @@ -233,7 +233,7 @@ class StatisticsChart extends LitElement { (await this._getStatisticsMetaData(Object.keys(this.statisticsData))); let colorIndex = 0; - const statisticsData = Object.values(this.statisticsData); + const statisticsData = Object.entries(this.statisticsData); const totalDataSets: ChartDataset<"line">[] = []; let endTime: Date; @@ -246,7 +246,7 @@ class StatisticsChart extends LitElement { // Get the highest date from the last date of each statistic new Date( Math.max( - ...statisticsData.map((stats) => + ...statisticsData.map(([_, stats]) => new Date(stats[stats.length - 1].start).getTime() ) ) @@ -259,20 +259,19 @@ class StatisticsChart extends LitElement { let unit: string | undefined | null; const names = this.names || {}; - statisticsData.forEach((stats) => { - const firstStat = stats[0]; - const meta = statisticsMetaData?.[firstStat.statistic_id]; - let name = names[firstStat.statistic_id]; + statisticsData.forEach(([statistic_id, stats]) => { + const meta = statisticsMetaData?.[statistic_id]; + let name = names[statistic_id]; if (name === undefined) { - name = getStatisticLabel(this.hass, firstStat.statistic_id, meta); + name = getStatisticLabel(this.hass, statistic_id, meta); } if (!this.unit) { if (unit === undefined) { - unit = getDisplayUnit(this.hass, firstStat.statistic_id, meta); + unit = getDisplayUnit(this.hass, statistic_id, meta); } else if ( unit !== null && - unit !== getDisplayUnit(this.hass, firstStat.statistic_id, meta) + unit !== getDisplayUnit(this.hass, statistic_id, meta) ) { // Clear unit if not all statistics have same unit unit = null; @@ -363,8 +362,8 @@ class StatisticsChart extends LitElement { let prevDate: Date | null = null; // Process chart data. - let firstSum: number | null = null; - let prevSum: number | null = null; + let firstSum: number | null | undefined = null; + let prevSum: number | null | undefined = null; stats.forEach((stat) => { const date = new Date(stat.start); if (prevDate === date) { @@ -373,16 +372,16 @@ class StatisticsChart extends LitElement { prevDate = date; const dataValues: Array = []; statTypes.forEach((type) => { - let val: number | null; + let val: number | null | undefined; if (type === "sum") { - if (firstSum === null) { + if (firstSum === null || firstSum === undefined) { val = 0; firstSum = stat.sum; } else { val = (stat.sum || 0) - firstSum; } } else if (type === "change") { - if (prevSum === null) { + if (prevSum === null || prevSum === undefined) { prevSum = stat.sum; return; } @@ -391,7 +390,11 @@ class StatisticsChart extends LitElement { } else { val = stat[type]; } - dataValues.push(val !== null ? Math.round(val * 100) / 100 : null); + dataValues.push( + val !== null && val !== undefined + ? Math.round(val * 100) / 100 + : null + ); }); pushData(date, dataValues); }); diff --git a/src/data/energy.ts b/src/data/energy.ts index c0aac9ed0b..11435ffc69 100644 --- a/src/data/energy.ts +++ b/src/data/energy.ts @@ -410,7 +410,8 @@ const getEnergyData = async ( end, energyStatIds, period, - energyUnits + energyUnits, + ["sum"] )), ...(await fetchStatistics( hass!, @@ -418,7 +419,8 @@ const getEnergyData = async ( end, waterStatIds, period, - waterUnits + waterUnits, + ["sum"] )), }; @@ -443,7 +445,8 @@ const getEnergyData = async ( endCompare, energyStatIds, period, - energyUnits + energyUnits, + ["sum"] )), ...(await fetchStatistics( hass!, @@ -451,7 +454,8 @@ const getEnergyData = async ( end, waterStatIds, period, - waterUnits + waterUnits, + ["sum"] )), }; } @@ -485,8 +489,8 @@ const getEnergyData = async ( if (stat.length && new Date(stat[0].start) > startMinHour) { stat.unshift({ ...stat[0], - start: startMinHour.toISOString(), - end: startMinHour.toISOString(), + start: startMinHour.getTime(), + end: startMinHour.getTime(), sum: 0, state: 0, }); diff --git a/src/data/recorder.ts b/src/data/recorder.ts index f9a1711afd..510212c1e8 100644 --- a/src/data/recorder.ts +++ b/src/data/recorder.ts @@ -9,15 +9,14 @@ export interface Statistics { } export interface StatisticValue { - statistic_id: string; - start: string; - end: string; - last_reset: string | null; - max: number | null; - mean: number | null; - min: number | null; - sum: number | null; - state: number | null; + start: number; + end: number; + last_reset?: number | null; + max?: number | null; + mean?: number | null; + min?: number | null; + sum?: number | null; + state?: number | null; } export interface Statistic { @@ -91,6 +90,16 @@ export interface StatisticsUnitConfiguration { volume?: "L" | "gal" | "ft³" | "m³"; } +const statisticTypes = [ + "last_reset", + "max", + "mean", + "min", + "state", + "sum", +] as const; +export type StatisticsTypes = typeof statisticTypes[number][]; + export interface StatisticsValidationResults { [statisticId: string]: StatisticsValidationResult[]; } @@ -119,7 +128,8 @@ export const fetchStatistics = ( endTime?: Date, statistic_ids?: string[], period: "5minute" | "hour" | "day" | "week" | "month" = "hour", - units?: StatisticsUnitConfiguration + units?: StatisticsUnitConfiguration, + types?: StatisticsTypes ) => hass.callWS({ type: "recorder/statistics_during_period", @@ -128,6 +138,7 @@ export const fetchStatistics = ( statistic_ids, period, units, + types, }); export const fetchStatistic = ( @@ -189,11 +200,11 @@ export const calculateStatisticSumGrowth = ( return null; } const endSum = values[values.length - 1].sum; - if (endSum === null) { + if (endSum === null || endSum === undefined) { return null; } const startSum = values[0].sum; - if (startSum === null) { + if (startSum === null || startSum === undefined) { return endSum; } return endSum - startSum; @@ -248,17 +259,19 @@ export const statisticsMetaHasType = ( export const adjustStatisticsSum = ( hass: HomeAssistant, statistic_id: string, - start_time: string, + start_time: number, adjustment: number, adjustment_unit_of_measurement: string | null -): Promise => - hass.callWS({ +): Promise => { + const start_time_iso = new Date(start_time).toISOString(); + return hass.callWS({ type: "recorder/adjust_sum_statistics", statistic_id, - start_time, + start_time_iso, adjustment, adjustment_unit_of_measurement, }); +}; export const getStatisticLabel = ( hass: HomeAssistant, diff --git a/src/dialogs/more-info/ha-more-info-history.ts b/src/dialogs/more-info/ha-more-info-history.ts index bd6c3236db..f28edba8dc 100644 --- a/src/dialogs/more-info/ha-more-info-history.ts +++ b/src/dialogs/more-info/ha-more-info-history.ts @@ -11,6 +11,7 @@ import { fetchStatistics, getStatisticMetadata, Statistics, + StatisticsTypes, } from "../../data/recorder"; import { HomeAssistant } from "../../types"; import "../../components/chart/statistics-chart"; @@ -22,7 +23,7 @@ declare global { } } -const statTypes = ["state", "min", "mean", "max"]; +const statTypes: StatisticsTypes = ["state", "min", "mean", "max"]; @customElement("ha-more-info-history") export class MoreInfoHistory extends LitElement { @@ -124,7 +125,9 @@ export class MoreInfoHistory extends LitElement { subHours(new Date(), 24), undefined, [this.entityId], - "5minute" + "5minute", + undefined, + statTypes ); return; } diff --git a/src/panels/lovelace/cards/energy/hui-energy-devices-graph-card.ts b/src/panels/lovelace/cards/energy/hui-energy-devices-graph-card.ts index a83e9ca54c..3c50fbef12 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-devices-graph-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-devices-graph-card.ts @@ -202,8 +202,8 @@ export class HuiEnergyDevicesGraphCard if (stat.length && new Date(stat[0].start) > startMinHour) { stat.unshift({ ...stat[0], - start: startMinHour.toISOString(), - end: startMinHour.toISOString(), + start: startMinHour.getTime(), + end: startMinHour.getTime(), sum: 0, state: 0, }); @@ -228,8 +228,8 @@ export class HuiEnergyDevicesGraphCard if (stat.length && new Date(stat[0].start) > startMinHour) { stat.unshift({ ...stat[0], - start: startCompareMinHour.toISOString(), - end: startCompareMinHour.toISOString(), + start: startCompareMinHour.getTime(), + end: startCompareMinHour.getTime(), sum: 0, state: 0, }); diff --git a/src/panels/lovelace/cards/energy/hui-energy-gas-graph-card.ts b/src/panels/lovelace/cards/energy/hui-energy-gas-graph-card.ts index 2bd6855782..d7be7e2c09 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-gas-graph-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-gas-graph-card.ts @@ -348,7 +348,7 @@ export class HuiEnergyGasGraphCard : gasColor; let prevValue: number | null = null; - let prevStart: string | null = null; + let prevStart: number | null = null; const gasConsumptionData: ScatterDataPoint[] = []; @@ -357,10 +357,10 @@ export class HuiEnergyGasGraphCard const stats = statistics[source.stat_energy_from]; for (const point of stats) { - if (point.sum === null) { + if (point.sum === null || point.sum === undefined) { continue; } - if (prevValue === null) { + if (prevValue === null || prevValue === undefined) { prevValue = point.sum; continue; } diff --git a/src/panels/lovelace/cards/energy/hui-energy-solar-graph-card.ts b/src/panels/lovelace/cards/energy/hui-energy-solar-graph-card.ts index ac985edef9..4c683666ac 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-solar-graph-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-solar-graph-card.ts @@ -368,7 +368,7 @@ export class HuiEnergySolarGraphCard : solarColor; let prevValue: number | null = null; - let prevStart: string | null = null; + let prevStart: number | null = null; const solarProductionData: ScatterDataPoint[] = []; @@ -377,10 +377,10 @@ export class HuiEnergySolarGraphCard const stats = statistics[source.stat_energy_from]; for (const point of stats) { - if (point.sum === null) { + if (point.sum === null || point.sum === undefined) { continue; } - if (prevValue === null) { + if (prevValue === null || prevValue === undefined) { prevValue = point.sum; continue; } diff --git a/src/panels/lovelace/cards/energy/hui-energy-usage-graph-card.ts b/src/panels/lovelace/cards/energy/hui-energy-usage-graph-card.ts index ebae24dfca..8b031f668e 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-usage-graph-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-usage-graph-card.ts @@ -484,7 +484,7 @@ export class HuiEnergyUsageGraphCard const set = {}; let prevValue: number; stats.forEach((stat) => { - if (stat.sum === null) { + if (stat.sum === null || stat.sum === undefined) { return; } if (prevValue === undefined) { diff --git a/src/panels/lovelace/cards/energy/hui-energy-water-graph-card.ts b/src/panels/lovelace/cards/energy/hui-energy-water-graph-card.ts index 17cdb690aa..95af9f95f0 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-water-graph-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-water-graph-card.ts @@ -346,7 +346,7 @@ export class HuiEnergyWaterGraphCard : waterColor; let prevValue: number | null = null; - let prevStart: string | null = null; + let prevStart: number | null = null; const waterConsumptionData: ScatterDataPoint[] = []; @@ -355,10 +355,10 @@ export class HuiEnergyWaterGraphCard const stats = statistics[source.stat_energy_from]; for (const point of stats) { - if (point.sum === null) { + if (point.sum === null || point.sum === undefined) { continue; } - if (prevValue === null) { + if (prevValue === null || prevValue === undefined) { prevValue = point.sum; continue; } diff --git a/src/panels/lovelace/cards/hui-statistics-graph-card.ts b/src/panels/lovelace/cards/hui-statistics-graph-card.ts index 6572c82fec..640b4cf5ff 100644 --- a/src/panels/lovelace/cards/hui-statistics-graph-card.ts +++ b/src/panels/lovelace/cards/hui-statistics-graph-card.ts @@ -17,6 +17,7 @@ import { getStatisticMetadata, Statistics, StatisticsMetaData, + StatisticsTypes, } from "../../../data/recorder"; import { HomeAssistant } from "../../../types"; import { findEntities } from "../common/find-entities"; @@ -69,6 +70,8 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard { private _interval?: number; + private _statTypes?: StatisticsTypes; + public disconnectedCallback() { super.disconnectedCallback(); if (this._interval) { @@ -117,15 +120,13 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard { }); if (typeof config.stat_types === "string") { - this._config = { ...config, stat_types: [config.stat_types] }; + this._statTypes = [config.stat_types]; } else if (!config.stat_types) { - this._config = { - ...config, - stat_types: ["state", "sum", "min", "max", "mean"], - }; + this._statTypes = ["state", "sum", "min", "max", "mean"]; } else { - this._config = config; + this._statTypes = config.stat_types; } + this._config = config; } protected shouldUpdate(changedProps: PropertyValues): boolean { @@ -191,7 +192,7 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard { .statisticsData=${this._statistics} .metadata=${this._metadata} .chartType=${this._config.chart_type || "line"} - .statTypes=${this._config.stat_types!} + .statTypes=${this._statTypes!} .names=${this._names} .unit=${this._unit} > @@ -250,7 +251,8 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard { undefined, this._entities, this._config!.period, - unitconfig + unitconfig, + this._statTypes ); } catch (err) { this._statistics = undefined;