Compare commits

...

6 Commits

Author SHA1 Message Date
J. Nick Koston
23ba92e4ad avoid downloading the whole entity registry again as well 2023-02-24 18:29:30 -06:00
J. Nick Koston
c636eacc51 Merge branch 'energy_no_ids' into ii2 2023-02-24 17:34:27 -06:00
J. Nick Koston
f75d17e10c Avoid fetching all stats metadata when there are no entities
Fetch all the data at once since it is not dependant
2023-02-24 17:26:29 -06:00
J. Nick Koston
2c6acecb60 Merge branch 'dupe_calls' into ii2 2023-02-24 17:14:15 -06:00
J. Nick Koston
225a3c3f50 Avoid fetching all stats metadata when there are no entities
Fetch all the data at once since it is not dependant
2023-02-24 17:12:01 -06:00
J. Nick Koston
19c125f7be Fix duplicate fetch of stats metadata in more info 2023-02-24 16:51:18 -06:00
3 changed files with 131 additions and 74 deletions

View File

@@ -332,7 +332,10 @@ class StatisticsChart extends LitElement {
prevEndTime = end; prevEndTime = end;
}; };
const color = getGraphColorByIndex(colorIndex, this._computedStyle!); const color = getGraphColorByIndex(
colorIndex,
this._computedStyle || getComputedStyle(this)
);
colorIndex++; colorIndex++;
const statTypes: this["statTypes"] = []; const statTypes: this["statTypes"] = [];

View File

@@ -11,10 +11,8 @@ import {
} from "date-fns/esm"; } from "date-fns/esm";
import { Collection, getCollection } from "home-assistant-js-websocket"; import { Collection, getCollection } from "home-assistant-js-websocket";
import { groupBy } from "../common/util/group-by"; import { groupBy } from "../common/util/group-by";
import { subscribeOne } from "../common/util/subscribe-one";
import { HomeAssistant } from "../types"; import { HomeAssistant } from "../types";
import { ConfigEntry, getConfigEntries } from "./config_entries"; import { ConfigEntry, getConfigEntries } from "./config_entries";
import { subscribeEntityRegistry } from "./entity_registry";
import { import {
fetchStatistics, fetchStatistics,
getStatisticMetadata, getStatisticMetadata,
@@ -341,9 +339,8 @@ const getEnergyData = async (
end?: Date, end?: Date,
compare?: boolean compare?: boolean
): Promise<EnergyData> => { ): Promise<EnergyData> => {
const [configEntries, entityRegistryEntries, info] = await Promise.all([ const [configEntries, info] = await Promise.all([
getConfigEntries(hass, { domain: "co2signal" }), getConfigEntries(hass, { domain: "co2signal" }),
subscribeOne(hass.connection, subscribeEntityRegistry),
getEnergyInfo(hass), getEnergyInfo(hass),
]); ]);
@@ -352,15 +349,15 @@ const getEnergyData = async (
: undefined; : undefined;
let co2SignalEntity: string | undefined; let co2SignalEntity: string | undefined;
if (co2SignalConfigEntry) { if (co2SignalConfigEntry) {
for (const entry of entityRegistryEntries) { for (const entityId of Object.keys(hass.entities)) {
if (entry.config_entry_id !== co2SignalConfigEntry.entry_id) { const entity = hass.entities[entityId];
if (entity.platform !== "co2signal") {
continue; continue;
} }
// The integration offers 2 entities. We want the % one. // The integration offers 2 entities. We want the % one.
const co2State = hass.states[entry.entity_id]; const co2State = hass.states[entityId];
if (!co2State || co2State.attributes.unit_of_measurement !== "%") { if (!co2State || co2State.attributes.unit_of_measurement !== "%") {
continue; continue;
} }
@@ -405,34 +402,35 @@ const getEnergyData = async (
volume: lengthUnit === "km" ? "L" : "gal", volume: lengthUnit === "km" ? "L" : "gal",
}; };
const stats = { const _energyStats = energyStatIds.length
...(energyStatIds.length ? fetchStatistics(
? await fetchStatistics( hass!,
hass!, startMinHour,
startMinHour, end,
end, energyStatIds,
energyStatIds, period,
period, energyUnits,
energyUnits, ["sum"]
["sum"] )
) : Promise.resolve({});
: {}), const _waterStats = waterStatIds.length
...(waterStatIds.length ? await fetchStatistics(
? await fetchStatistics( hass!,
hass!, startMinHour,
startMinHour, end,
end, waterStatIds,
waterStatIds, period,
period, waterUnits,
waterUnits, ["sum"]
["sum"] )
) : Promise.resolve({});
: {}),
};
let statsCompare; let statsCompare;
let startCompare; let startCompare;
let endCompare; let endCompare;
let _energyStatsCompare = Promise.resolve({});
let _waterStatsCompare = Promise.resolve({});
if (compare) { if (compare) {
if (dayDifference > 27 && dayDifference < 32) { if (dayDifference > 27 && dayDifference < 32) {
// When comparing a month, we want to start at the begining of the month // When comparing a month, we want to start at the begining of the month
@@ -443,38 +441,38 @@ const getEnergyData = async (
const compareStartMinHour = addHours(startCompare, -1); const compareStartMinHour = addHours(startCompare, -1);
endCompare = addMilliseconds(start, -1); endCompare = addMilliseconds(start, -1);
if (energyStatIds.length) {
statsCompare = { _energyStatsCompare = fetchStatistics(
...(energyStatIds.length hass!,
? await fetchStatistics( compareStartMinHour,
hass!, endCompare,
compareStartMinHour, energyStatIds,
endCompare, period,
energyStatIds, energyUnits,
period, ["sum"]
energyUnits, );
["sum"] }
) if (waterStatIds.length) {
: {}), _waterStatsCompare = fetchStatistics(
...(waterStatIds.length hass!,
? await fetchStatistics( compareStartMinHour,
hass!, endCompare,
compareStartMinHour, waterStatIds,
endCompare, period,
waterStatIds, waterUnits,
period, ["sum"]
waterUnits, );
["sum"] }
)
: {}),
};
} }
let fossilEnergyConsumption: FossilEnergyConsumption | undefined; let _fossilEnergyConsumption:
let fossilEnergyConsumptionCompare: FossilEnergyConsumption | undefined; | Promise<undefined>
| Promise<FossilEnergyConsumption> = Promise.resolve(undefined);
let _fossilEnergyConsumptionCompare:
| Promise<undefined>
| Promise<FossilEnergyConsumption> = Promise.resolve(undefined);
if (co2SignalEntity !== undefined) { if (co2SignalEntity !== undefined) {
fossilEnergyConsumption = await getFossilEnergyConsumption( _fossilEnergyConsumption = getFossilEnergyConsumption(
hass!, hass!,
start, start,
consumptionStatIDs, consumptionStatIDs,
@@ -483,7 +481,7 @@ const getEnergyData = async (
dayDifference > 35 ? "month" : dayDifference > 2 ? "day" : "hour" dayDifference > 35 ? "month" : dayDifference > 2 ? "day" : "hour"
); );
if (compare) { if (compare) {
fossilEnergyConsumptionCompare = await getFossilEnergyConsumption( _fossilEnergyConsumptionCompare = getFossilEnergyConsumption(
hass!, hass!,
startCompare, startCompare,
consumptionStatIDs, consumptionStatIDs,
@@ -494,6 +492,37 @@ const getEnergyData = async (
} }
} }
const statsMetadata: Record<string, StatisticsMetaData> = {};
const _getStatisticMetadata: Promise<StatisticsMetaData[]> = allStatIDs.length
? getStatisticMetadata(hass, allStatIDs)
: Promise.resolve([]);
const [
energyStats,
waterStats,
energyStatsCompare,
waterStatsCompare,
statsMetadataArray,
fossilEnergyConsumption,
fossilEnergyConsumptionCompare,
] = await Promise.all([
_energyStats,
_waterStats,
_energyStatsCompare,
_waterStatsCompare,
_getStatisticMetadata,
_fossilEnergyConsumption,
_fossilEnergyConsumptionCompare,
]);
const stats = { ...energyStats, ...waterStats };
if (compare) {
statsCompare = { ...energyStatsCompare, ...waterStatsCompare };
}
if (allStatIDs.length) {
statsMetadataArray.forEach((x) => {
statsMetadata[x.statistic_id] = x;
});
}
Object.values(stats).forEach((stat) => { Object.values(stats).forEach((stat) => {
// if the start of the first value is after the requested period, we have the first data point, and should add a zero point // if the start of the first value is after the requested period, we have the first data point, and should add a zero point
if (stat.length && new Date(stat[0].start) > startMinHour) { if (stat.length && new Date(stat[0].start) > startMinHour) {
@@ -507,12 +536,6 @@ const getEnergyData = async (
} }
}); });
const statsMetadataArray = await getStatisticMetadata(hass, allStatIDs);
const statsMetadata: Record<string, StatisticsMetaData> = {};
statsMetadataArray.forEach((x) => {
statsMetadata[x.statistic_id] = x;
});
const data: EnergyData = { const data: EnergyData = {
start, start,
end, end,

View File

@@ -14,6 +14,7 @@ import {
getStatisticMetadata, getStatisticMetadata,
Statistics, Statistics,
StatisticsTypes, StatisticsTypes,
StatisticsMetaData,
} from "../../data/recorder"; } from "../../data/recorder";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import "../../components/chart/statistics-chart"; import "../../components/chart/statistics-chart";
@@ -47,6 +48,8 @@ export class MoreInfoHistory extends LitElement {
private _error?: string; private _error?: string;
private _metadata?: Record<string, StatisticsMetaData>;
protected render(): TemplateResult { protected render(): TemplateResult {
if (!this.entityId) { if (!this.entityId) {
return html``; return html``;
@@ -70,6 +73,7 @@ export class MoreInfoHistory extends LitElement {
.hass=${this.hass} .hass=${this.hass}
.isLoadingData=${!this._statistics} .isLoadingData=${!this._statistics}
.statisticsData=${this._statistics} .statisticsData=${this._statistics}
.metadata=${this._metadata}
.statTypes=${statTypes} .statTypes=${statTypes}
.names=${this._statNames} .names=${this._statNames}
hideLegend hideLegend
@@ -136,15 +140,33 @@ export class MoreInfoHistory extends LitElement {
this._interval = window.setInterval(() => this._redrawGraph(), 1000 * 60); this._interval = window.setInterval(() => this._redrawGraph(), 1000 * 60);
} }
private async _getStatisticsMetaData(statisticIds: string[] | undefined) {
const statsMetadataArray = await getStatisticMetadata(
this.hass,
statisticIds
);
const statisticsMetaData = {};
statsMetadataArray.forEach((x) => {
statisticsMetaData[x.statistic_id] = x;
});
return statisticsMetaData;
}
private async _getStateHistory(): Promise<void> { private async _getStateHistory(): Promise<void> {
if ( if (
isComponentLoaded(this.hass, "recorder") && isComponentLoaded(this.hass, "recorder") &&
computeDomain(this.entityId) === "sensor" computeDomain(this.entityId) === "sensor"
) { ) {
const metadata = await getStatisticMetadata(this.hass, [this.entityId]); const stateObj = this.hass.states[this.entityId];
this._statNames = { [this.entityId]: "" }; // If there is no state class, the integration providing the entity
if (metadata.length) { // has not opted into statistics so there is no need to check as it
this._statistics = await fetchStatistics( // requires another round-trip to the server.
if (stateObj && stateObj.attributes.state_class) {
// Fire off the metadata and fetch at the same time
// to avoid waiting in sequence so the UI responds
// faster.
const _metadata = this._getStatisticsMetaData([this.entityId]);
const _statistics = fetchStatistics(
this.hass!, this.hass!,
subHours(new Date(), 24), subHours(new Date(), 24),
undefined, undefined,
@@ -153,7 +175,16 @@ export class MoreInfoHistory extends LitElement {
undefined, undefined,
statTypes statTypes
); );
return; const [metadata, statistics] = await Promise.all([
_metadata,
_statistics,
]);
if (metadata && Object.keys(metadata).length) {
this._metadata = metadata;
this._statistics = statistics;
this._statNames = { [this.entityId]: "" };
return;
}
} }
} }
if (!isComponentLoaded(this.hass, "history") || this._subscribed) { if (!isComponentLoaded(this.hass, "history") || this._subscribed) {