mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-20 07:46:37 +00:00
Use backend for day month stats in energy dashboard (#10728)
This commit is contained in:
parent
d5fc751da6
commit
fd6785b593
@ -82,6 +82,9 @@ export const mockEnergy = (hass: MockHomeAssistant) => {
|
|||||||
],
|
],
|
||||||
}));
|
}));
|
||||||
hass.mockWS("energy/info", () => ({ cost_sensors: [] }));
|
hass.mockWS("energy/info", () => ({ cost_sensors: [] }));
|
||||||
|
hass.mockWS("energy/fossil_energy_consumption", ({ period }) => ({
|
||||||
|
start: period === "month" ? 500 : period === "day" ? 20 : 5,
|
||||||
|
}));
|
||||||
const todayString = format(startOfToday(), "yyyy-MM-dd");
|
const todayString = format(startOfToday(), "yyyy-MM-dd");
|
||||||
const tomorrowString = format(startOfTomorrow(), "yyyy-MM-dd");
|
const tomorrowString = format(startOfTomorrow(), "yyyy-MM-dd");
|
||||||
hass.mockWS(
|
hass.mockWS(
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
import { addHours, differenceInHours, endOfDay } from "date-fns";
|
import {
|
||||||
|
addDays,
|
||||||
|
addHours,
|
||||||
|
addMonths,
|
||||||
|
differenceInHours,
|
||||||
|
endOfDay,
|
||||||
|
} from "date-fns";
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { StatisticValue } from "../../../src/data/history";
|
import { StatisticValue } from "../../../src/data/history";
|
||||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
@ -70,6 +76,7 @@ const generateMeanStatistics = (
|
|||||||
id: string,
|
id: string,
|
||||||
start: Date,
|
start: Date,
|
||||||
end: Date,
|
end: Date,
|
||||||
|
period: "5minute" | "hour" | "day" | "month" = "hour",
|
||||||
initValue: number,
|
initValue: number,
|
||||||
maxDiff: number
|
maxDiff: number
|
||||||
) => {
|
) => {
|
||||||
@ -84,6 +91,7 @@ const generateMeanStatistics = (
|
|||||||
statistics.push({
|
statistics.push({
|
||||||
statistic_id: id,
|
statistic_id: id,
|
||||||
start: currentDate.toISOString(),
|
start: currentDate.toISOString(),
|
||||||
|
end: currentDate.toISOString(),
|
||||||
mean,
|
mean,
|
||||||
min: mean - Math.random() * maxDiff,
|
min: mean - Math.random() * maxDiff,
|
||||||
max: mean + Math.random() * maxDiff,
|
max: mean + Math.random() * maxDiff,
|
||||||
@ -92,7 +100,12 @@ const generateMeanStatistics = (
|
|||||||
sum: null,
|
sum: null,
|
||||||
});
|
});
|
||||||
lastVal = mean;
|
lastVal = mean;
|
||||||
currentDate = addHours(currentDate, 1);
|
currentDate =
|
||||||
|
period === "day"
|
||||||
|
? addDays(currentDate, 1)
|
||||||
|
: period === "month"
|
||||||
|
? addMonths(currentDate, 1)
|
||||||
|
: addHours(currentDate, 1);
|
||||||
}
|
}
|
||||||
return statistics;
|
return statistics;
|
||||||
};
|
};
|
||||||
@ -101,6 +114,7 @@ const generateSumStatistics = (
|
|||||||
id: string,
|
id: string,
|
||||||
start: Date,
|
start: Date,
|
||||||
end: Date,
|
end: Date,
|
||||||
|
period: "5minute" | "hour" | "day" | "month" = "hour",
|
||||||
initValue: number,
|
initValue: number,
|
||||||
maxDiff: number
|
maxDiff: number
|
||||||
) => {
|
) => {
|
||||||
@ -115,6 +129,7 @@ const generateSumStatistics = (
|
|||||||
statistics.push({
|
statistics.push({
|
||||||
statistic_id: id,
|
statistic_id: id,
|
||||||
start: currentDate.toISOString(),
|
start: currentDate.toISOString(),
|
||||||
|
end: currentDate.toISOString(),
|
||||||
mean: null,
|
mean: null,
|
||||||
min: null,
|
min: null,
|
||||||
max: null,
|
max: null,
|
||||||
@ -122,7 +137,12 @@ const generateSumStatistics = (
|
|||||||
state: initValue + sum,
|
state: initValue + sum,
|
||||||
sum,
|
sum,
|
||||||
});
|
});
|
||||||
currentDate = addHours(currentDate, 1);
|
currentDate =
|
||||||
|
period === "day"
|
||||||
|
? addDays(currentDate, 1)
|
||||||
|
: period === "month"
|
||||||
|
? addMonths(currentDate, 1)
|
||||||
|
: addHours(currentDate, 1);
|
||||||
}
|
}
|
||||||
return statistics;
|
return statistics;
|
||||||
};
|
};
|
||||||
@ -131,6 +151,7 @@ const generateCurvedStatistics = (
|
|||||||
id: string,
|
id: string,
|
||||||
start: Date,
|
start: Date,
|
||||||
end: Date,
|
end: Date,
|
||||||
|
_period: "5minute" | "hour" | "day" | "month" = "hour",
|
||||||
initValue: number,
|
initValue: number,
|
||||||
maxDiff: number,
|
maxDiff: number,
|
||||||
metered: boolean
|
metered: boolean
|
||||||
@ -149,6 +170,7 @@ const generateCurvedStatistics = (
|
|||||||
statistics.push({
|
statistics.push({
|
||||||
statistic_id: id,
|
statistic_id: id,
|
||||||
start: currentDate.toISOString(),
|
start: currentDate.toISOString(),
|
||||||
|
end: currentDate.toISOString(),
|
||||||
mean: null,
|
mean: null,
|
||||||
min: null,
|
min: null,
|
||||||
max: null,
|
max: null,
|
||||||
@ -167,11 +189,38 @@ const generateCurvedStatistics = (
|
|||||||
|
|
||||||
const statisticsFunctions: Record<
|
const statisticsFunctions: Record<
|
||||||
string,
|
string,
|
||||||
(id: string, start: Date, end: Date) => StatisticValue[]
|
(
|
||||||
|
id: string,
|
||||||
|
start: Date,
|
||||||
|
end: Date,
|
||||||
|
period: "5minute" | "hour" | "day" | "month"
|
||||||
|
) => StatisticValue[]
|
||||||
> = {
|
> = {
|
||||||
"sensor.energy_consumption_tarif_1": (id: string, start: Date, end: Date) => {
|
"sensor.energy_consumption_tarif_1": (
|
||||||
|
id: string,
|
||||||
|
start: Date,
|
||||||
|
end: Date,
|
||||||
|
period = "hour"
|
||||||
|
) => {
|
||||||
|
if (period !== "hour") {
|
||||||
|
return generateSumStatistics(
|
||||||
|
id,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
period === "day" ? 17 : 504
|
||||||
|
);
|
||||||
|
}
|
||||||
const morningEnd = new Date(start.getTime() + 10 * 60 * 60 * 1000);
|
const morningEnd = new Date(start.getTime() + 10 * 60 * 60 * 1000);
|
||||||
const morningLow = generateSumStatistics(id, start, morningEnd, 0, 0.7);
|
const morningLow = generateSumStatistics(
|
||||||
|
id,
|
||||||
|
start,
|
||||||
|
morningEnd,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
0.7
|
||||||
|
);
|
||||||
const eveningStart = new Date(start.getTime() + 20 * 60 * 60 * 1000);
|
const eveningStart = new Date(start.getTime() + 20 * 60 * 60 * 1000);
|
||||||
const morningFinalVal = morningLow.length
|
const morningFinalVal = morningLow.length
|
||||||
? morningLow[morningLow.length - 1].sum!
|
? morningLow[morningLow.length - 1].sum!
|
||||||
@ -180,6 +229,7 @@ const statisticsFunctions: Record<
|
|||||||
id,
|
id,
|
||||||
morningEnd,
|
morningEnd,
|
||||||
eveningStart,
|
eveningStart,
|
||||||
|
period,
|
||||||
morningFinalVal,
|
morningFinalVal,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
@ -187,39 +237,71 @@ const statisticsFunctions: Record<
|
|||||||
id,
|
id,
|
||||||
eveningStart,
|
eveningStart,
|
||||||
end,
|
end,
|
||||||
|
period,
|
||||||
morningFinalVal,
|
morningFinalVal,
|
||||||
0.7
|
0.7
|
||||||
);
|
);
|
||||||
return [...morningLow, ...empty, ...eveningLow];
|
return [...morningLow, ...empty, ...eveningLow];
|
||||||
},
|
},
|
||||||
"sensor.energy_consumption_tarif_2": (id: string, start: Date, end: Date) => {
|
"sensor.energy_consumption_tarif_2": (
|
||||||
|
id: string,
|
||||||
|
start: Date,
|
||||||
|
end: Date,
|
||||||
|
period = "hour"
|
||||||
|
) => {
|
||||||
|
if (period !== "hour") {
|
||||||
|
return generateSumStatistics(
|
||||||
|
id,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
period === "day" ? 17 : 504
|
||||||
|
);
|
||||||
|
}
|
||||||
const morningEnd = new Date(start.getTime() + 9 * 60 * 60 * 1000);
|
const morningEnd = new Date(start.getTime() + 9 * 60 * 60 * 1000);
|
||||||
const eveningStart = new Date(start.getTime() + 20 * 60 * 60 * 1000);
|
const eveningStart = new Date(start.getTime() + 20 * 60 * 60 * 1000);
|
||||||
const highTarif = generateSumStatistics(
|
const highTarif = generateSumStatistics(
|
||||||
id,
|
id,
|
||||||
morningEnd,
|
morningEnd,
|
||||||
eveningStart,
|
eveningStart,
|
||||||
|
period,
|
||||||
0,
|
0,
|
||||||
0.3
|
0.3
|
||||||
);
|
);
|
||||||
const highTarifFinalVal = highTarif.length
|
const highTarifFinalVal = highTarif.length
|
||||||
? highTarif[highTarif.length - 1].sum!
|
? highTarif[highTarif.length - 1].sum!
|
||||||
: 0;
|
: 0;
|
||||||
const morning = generateSumStatistics(id, start, morningEnd, 0, 0);
|
const morning = generateSumStatistics(id, start, morningEnd, period, 0, 0);
|
||||||
const evening = generateSumStatistics(
|
const evening = generateSumStatistics(
|
||||||
id,
|
id,
|
||||||
eveningStart,
|
eveningStart,
|
||||||
end,
|
end,
|
||||||
|
period,
|
||||||
highTarifFinalVal,
|
highTarifFinalVal,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
return [...morning, ...highTarif, ...evening];
|
return [...morning, ...highTarif, ...evening];
|
||||||
},
|
},
|
||||||
"sensor.energy_production_tarif_1": (id, start, end) =>
|
"sensor.energy_production_tarif_1": (id, start, end, period = "hour") =>
|
||||||
generateSumStatistics(id, start, end, 0, 0),
|
generateSumStatistics(id, start, end, period, 0, 0),
|
||||||
"sensor.energy_production_tarif_1_compensation": (id, start, end) =>
|
"sensor.energy_production_tarif_1_compensation": (
|
||||||
generateSumStatistics(id, start, end, 0, 0),
|
id,
|
||||||
"sensor.energy_production_tarif_2": (id, start, end) => {
|
start,
|
||||||
|
end,
|
||||||
|
period = "hour"
|
||||||
|
) => generateSumStatistics(id, start, end, period, 0, 0),
|
||||||
|
"sensor.energy_production_tarif_2": (id, start, end, period = "hour") => {
|
||||||
|
if (period !== "hour") {
|
||||||
|
return generateSumStatistics(
|
||||||
|
id,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
period === "day" ? 17 : 504
|
||||||
|
);
|
||||||
|
}
|
||||||
const productionStart = new Date(start.getTime() + 9 * 60 * 60 * 1000);
|
const productionStart = new Date(start.getTime() + 9 * 60 * 60 * 1000);
|
||||||
const productionEnd = new Date(start.getTime() + 21 * 60 * 60 * 1000);
|
const productionEnd = new Date(start.getTime() + 21 * 60 * 60 * 1000);
|
||||||
const dayEnd = new Date(endOfDay(productionEnd));
|
const dayEnd = new Date(endOfDay(productionEnd));
|
||||||
@ -227,6 +309,7 @@ const statisticsFunctions: Record<
|
|||||||
id,
|
id,
|
||||||
productionStart,
|
productionStart,
|
||||||
productionEnd,
|
productionEnd,
|
||||||
|
period,
|
||||||
0,
|
0,
|
||||||
0.15,
|
0.15,
|
||||||
true
|
true
|
||||||
@ -234,18 +317,43 @@ const statisticsFunctions: Record<
|
|||||||
const productionFinalVal = production.length
|
const productionFinalVal = production.length
|
||||||
? production[production.length - 1].sum!
|
? production[production.length - 1].sum!
|
||||||
: 0;
|
: 0;
|
||||||
const morning = generateSumStatistics(id, start, productionStart, 0, 0);
|
const morning = generateSumStatistics(
|
||||||
|
id,
|
||||||
|
start,
|
||||||
|
productionStart,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
const evening = generateSumStatistics(
|
const evening = generateSumStatistics(
|
||||||
id,
|
id,
|
||||||
productionEnd,
|
productionEnd,
|
||||||
dayEnd,
|
dayEnd,
|
||||||
|
period,
|
||||||
productionFinalVal,
|
productionFinalVal,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
const rest = generateSumStatistics(id, dayEnd, end, productionFinalVal, 1);
|
const rest = generateSumStatistics(
|
||||||
|
id,
|
||||||
|
dayEnd,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
productionFinalVal,
|
||||||
|
1
|
||||||
|
);
|
||||||
return [...morning, ...production, ...evening, ...rest];
|
return [...morning, ...production, ...evening, ...rest];
|
||||||
},
|
},
|
||||||
"sensor.solar_production": (id, start, end) => {
|
"sensor.solar_production": (id, start, end, period = "hour") => {
|
||||||
|
if (period !== "hour") {
|
||||||
|
return generateSumStatistics(
|
||||||
|
id,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
period === "day" ? 17 : 504
|
||||||
|
);
|
||||||
|
}
|
||||||
const productionStart = new Date(start.getTime() + 7 * 60 * 60 * 1000);
|
const productionStart = new Date(start.getTime() + 7 * 60 * 60 * 1000);
|
||||||
const productionEnd = new Date(start.getTime() + 23 * 60 * 60 * 1000);
|
const productionEnd = new Date(start.getTime() + 23 * 60 * 60 * 1000);
|
||||||
const dayEnd = new Date(endOfDay(productionEnd));
|
const dayEnd = new Date(endOfDay(productionEnd));
|
||||||
@ -253,6 +361,7 @@ const statisticsFunctions: Record<
|
|||||||
id,
|
id,
|
||||||
productionStart,
|
productionStart,
|
||||||
productionEnd,
|
productionEnd,
|
||||||
|
period,
|
||||||
0,
|
0,
|
||||||
0.3,
|
0.3,
|
||||||
true
|
true
|
||||||
@ -260,19 +369,32 @@ const statisticsFunctions: Record<
|
|||||||
const productionFinalVal = production.length
|
const productionFinalVal = production.length
|
||||||
? production[production.length - 1].sum!
|
? production[production.length - 1].sum!
|
||||||
: 0;
|
: 0;
|
||||||
const morning = generateSumStatistics(id, start, productionStart, 0, 0);
|
const morning = generateSumStatistics(
|
||||||
|
id,
|
||||||
|
start,
|
||||||
|
productionStart,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
const evening = generateSumStatistics(
|
const evening = generateSumStatistics(
|
||||||
id,
|
id,
|
||||||
productionEnd,
|
productionEnd,
|
||||||
dayEnd,
|
dayEnd,
|
||||||
|
period,
|
||||||
productionFinalVal,
|
productionFinalVal,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
const rest = generateSumStatistics(id, dayEnd, end, productionFinalVal, 2);
|
const rest = generateSumStatistics(
|
||||||
|
id,
|
||||||
|
dayEnd,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
productionFinalVal,
|
||||||
|
2
|
||||||
|
);
|
||||||
return [...morning, ...production, ...evening, ...rest];
|
return [...morning, ...production, ...evening, ...rest];
|
||||||
},
|
},
|
||||||
"sensor.grid_fossil_fuel_percentage": (id, start, end) =>
|
|
||||||
generateMeanStatistics(id, start, end, 35, 1.3),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mockHistory = (mockHass: MockHomeAssistant) => {
|
export const mockHistory = (mockHass: MockHomeAssistant) => {
|
||||||
@ -347,7 +469,7 @@ export const mockHistory = (mockHass: MockHomeAssistant) => {
|
|||||||
mockHass.mockWS("history/list_statistic_ids", () => []);
|
mockHass.mockWS("history/list_statistic_ids", () => []);
|
||||||
mockHass.mockWS(
|
mockHass.mockWS(
|
||||||
"history/statistics_during_period",
|
"history/statistics_during_period",
|
||||||
({ statistic_ids, start_time, end_time }, hass) => {
|
({ statistic_ids, start_time, end_time, period }, hass) => {
|
||||||
const start = new Date(start_time);
|
const start = new Date(start_time);
|
||||||
const end = end_time ? new Date(end_time) : new Date();
|
const end = end_time ? new Date(end_time) : new Date();
|
||||||
|
|
||||||
@ -355,7 +477,7 @@ export const mockHistory = (mockHass: MockHomeAssistant) => {
|
|||||||
|
|
||||||
statistic_ids.forEach((id: string) => {
|
statistic_ids.forEach((id: string) => {
|
||||||
if (id in statisticsFunctions) {
|
if (id in statisticsFunctions) {
|
||||||
statistics[id] = statisticsFunctions[id](id, start, end);
|
statistics[id] = statisticsFunctions[id](id, start, end, period);
|
||||||
} else {
|
} else {
|
||||||
const entityState = hass.states[id];
|
const entityState = hass.states[id];
|
||||||
const state = entityState ? Number(entityState.state) : 1;
|
const state = entityState ? Number(entityState.state) : 1;
|
||||||
@ -365,6 +487,7 @@ export const mockHistory = (mockHass: MockHomeAssistant) => {
|
|||||||
id,
|
id,
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
|
period,
|
||||||
state,
|
state,
|
||||||
state * (state > 80 ? 0.01 : 0.05)
|
state * (state > 80 ? 0.01 : 0.05)
|
||||||
)
|
)
|
||||||
@ -372,6 +495,7 @@ export const mockHistory = (mockHass: MockHomeAssistant) => {
|
|||||||
id,
|
id,
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
|
period,
|
||||||
state,
|
state,
|
||||||
state * (state > 80 ? 0.05 : 0.1)
|
state * (state > 80 ? 0.05 : 0.1)
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
addHours,
|
addHours,
|
||||||
|
differenceInDays,
|
||||||
endOfToday,
|
endOfToday,
|
||||||
endOfYesterday,
|
endOfYesterday,
|
||||||
startOfToday,
|
startOfToday,
|
||||||
@ -191,6 +192,27 @@ export const saveEnergyPreferences = async (
|
|||||||
return newPrefs;
|
return newPrefs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface FossilEnergyConsumption {
|
||||||
|
[date: string]: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getFossilEnergyConsumption = async (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
startTime: Date,
|
||||||
|
energy_statistic_ids: string[],
|
||||||
|
co2_statistic_id: string,
|
||||||
|
endTime?: Date,
|
||||||
|
period: "5minute" | "hour" | "day" | "month" = "hour"
|
||||||
|
) =>
|
||||||
|
hass.callWS<FossilEnergyConsumption>({
|
||||||
|
type: "energy/fossil_energy_consumption",
|
||||||
|
start_time: startTime.toISOString(),
|
||||||
|
end_time: endTime?.toISOString(),
|
||||||
|
energy_statistic_ids,
|
||||||
|
co2_statistic_id,
|
||||||
|
period,
|
||||||
|
});
|
||||||
|
|
||||||
interface EnergySourceByType {
|
interface EnergySourceByType {
|
||||||
grid?: GridSourceTypeEnergyPreference[];
|
grid?: GridSourceTypeEnergyPreference[];
|
||||||
solar?: SolarSourceTypeEnergyPreference[];
|
solar?: SolarSourceTypeEnergyPreference[];
|
||||||
@ -209,6 +231,7 @@ export interface EnergyData {
|
|||||||
stats: Statistics;
|
stats: Statistics;
|
||||||
co2SignalConfigEntry?: ConfigEntry;
|
co2SignalConfigEntry?: ConfigEntry;
|
||||||
co2SignalEntity?: string;
|
co2SignalEntity?: string;
|
||||||
|
fossilEnergyConsumption?: FossilEnergyConsumption;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getEnergyData = async (
|
const getEnergyData = async (
|
||||||
@ -246,12 +269,9 @@ const getEnergyData = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const consumptionStatIDs: string[] = [];
|
||||||
const statIDs: string[] = [];
|
const statIDs: string[] = [];
|
||||||
|
|
||||||
if (co2SignalEntity !== undefined) {
|
|
||||||
statIDs.push(co2SignalEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const source of prefs.energy_sources) {
|
for (const source of prefs.energy_sources) {
|
||||||
if (source.type === "solar") {
|
if (source.type === "solar") {
|
||||||
statIDs.push(source.stat_energy_from);
|
statIDs.push(source.stat_energy_from);
|
||||||
@ -278,6 +298,7 @@ const getEnergyData = async (
|
|||||||
|
|
||||||
// grid source
|
// grid source
|
||||||
for (const flowFrom of source.flow_from) {
|
for (const flowFrom of source.flow_from) {
|
||||||
|
consumptionStatIDs.push(flowFrom.stat_energy_from);
|
||||||
statIDs.push(flowFrom.stat_energy_from);
|
statIDs.push(flowFrom.stat_energy_from);
|
||||||
if (flowFrom.stat_cost) {
|
if (flowFrom.stat_cost) {
|
||||||
statIDs.push(flowFrom.stat_cost);
|
statIDs.push(flowFrom.stat_cost);
|
||||||
@ -299,7 +320,44 @@ const getEnergyData = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const stats = await fetchStatistics(hass!, addHours(start, -1), end, statIDs); // Subtract 1 hour from start to get starting point data
|
const dayDifference = differenceInDays(end || new Date(), start);
|
||||||
|
|
||||||
|
// Subtract 1 hour from start to get starting point data
|
||||||
|
const startMinHour = addHours(start, -1);
|
||||||
|
|
||||||
|
const stats = await fetchStatistics(
|
||||||
|
hass!,
|
||||||
|
startMinHour,
|
||||||
|
end,
|
||||||
|
statIDs,
|
||||||
|
dayDifference > 35 ? "month" : dayDifference > 2 ? "day" : "hour"
|
||||||
|
);
|
||||||
|
|
||||||
|
let fossilEnergyConsumption: FossilEnergyConsumption | undefined;
|
||||||
|
|
||||||
|
if (co2SignalEntity !== undefined) {
|
||||||
|
fossilEnergyConsumption = await getFossilEnergyConsumption(
|
||||||
|
hass!,
|
||||||
|
start,
|
||||||
|
consumptionStatIDs,
|
||||||
|
co2SignalEntity,
|
||||||
|
end,
|
||||||
|
dayDifference > 35 ? "month" : dayDifference > 2 ? "day" : "hour"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (stat.length && new Date(stat[0].start) > startMinHour) {
|
||||||
|
stat.unshift({
|
||||||
|
...stat[0],
|
||||||
|
start: startMinHour.toISOString(),
|
||||||
|
end: startMinHour.toISOString(),
|
||||||
|
sum: 0,
|
||||||
|
state: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
start,
|
start,
|
||||||
@ -309,6 +367,7 @@ const getEnergyData = async (
|
|||||||
stats,
|
stats,
|
||||||
co2SignalConfigEntry,
|
co2SignalConfigEntry,
|
||||||
co2SignalEntity,
|
co2SignalEntity,
|
||||||
|
fossilEnergyConsumption,
|
||||||
};
|
};
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { addDays, addMonths, startOfDay, startOfMonth } from "date-fns";
|
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { computeStateDisplay } from "../common/entity/compute_state_display";
|
import { computeStateDisplay } from "../common/entity/compute_state_display";
|
||||||
import { computeStateDomain } from "../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../common/entity/compute_state_domain";
|
||||||
@ -63,6 +62,7 @@ export interface Statistics {
|
|||||||
export interface StatisticValue {
|
export interface StatisticValue {
|
||||||
statistic_id: string;
|
statistic_id: string;
|
||||||
start: string;
|
start: string;
|
||||||
|
end: string;
|
||||||
last_reset: string | null;
|
last_reset: string | null;
|
||||||
max: number | null;
|
max: number | null;
|
||||||
mean: number | null;
|
mean: number | null;
|
||||||
@ -350,7 +350,7 @@ export const fetchStatistics = (
|
|||||||
startTime: Date,
|
startTime: Date,
|
||||||
endTime?: Date,
|
endTime?: Date,
|
||||||
statistic_ids?: string[],
|
statistic_ids?: string[],
|
||||||
period: "hour" | "5minute" = "hour"
|
period: "5minute" | "hour" | "day" | "month" = "hour"
|
||||||
) =>
|
) =>
|
||||||
hass.callWS<Statistics>({
|
hass.callWS<Statistics>({
|
||||||
type: "history/statistics_during_period",
|
type: "history/statistics_during_period",
|
||||||
@ -428,151 +428,3 @@ export const statisticsHaveType = (
|
|||||||
stats: StatisticValue[],
|
stats: StatisticValue[],
|
||||||
type: StatisticType
|
type: StatisticType
|
||||||
) => stats.some((stat) => stat[type] !== null);
|
) => stats.some((stat) => stat[type] !== null);
|
||||||
|
|
||||||
// Merge the growth of multiple sum statistics into one
|
|
||||||
const mergeSumGrowthStatistics = (stats: StatisticValue[][]) => {
|
|
||||||
const result = {};
|
|
||||||
|
|
||||||
stats.forEach((stat) => {
|
|
||||||
if (stat.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let prevSum: number | null = null;
|
|
||||||
stat.forEach((statVal) => {
|
|
||||||
if (statVal.sum === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (prevSum === null) {
|
|
||||||
prevSum = statVal.sum;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const growth = statVal.sum - prevSum;
|
|
||||||
if (statVal.start in result) {
|
|
||||||
result[statVal.start] += growth;
|
|
||||||
} else {
|
|
||||||
result[statVal.start] = growth;
|
|
||||||
}
|
|
||||||
prevSum = statVal.sum;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the growth of a statistic over the given period while applying a
|
|
||||||
* per-period percentage.
|
|
||||||
*/
|
|
||||||
export const calculateStatisticsSumGrowthWithPercentage = (
|
|
||||||
percentageStat: StatisticValue[],
|
|
||||||
sumStats: StatisticValue[][]
|
|
||||||
): number | null => {
|
|
||||||
let sum: number | null = null;
|
|
||||||
|
|
||||||
if (sumStats.length === 0 || percentageStat.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sumGrowthToProcess = mergeSumGrowthStatistics(sumStats);
|
|
||||||
|
|
||||||
percentageStat.forEach((percentageStatValue) => {
|
|
||||||
const sumGrowth = sumGrowthToProcess[percentageStatValue.start];
|
|
||||||
if (sumGrowth === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (sum === null) {
|
|
||||||
sum = sumGrowth * (percentageStatValue.mean! / 100);
|
|
||||||
} else {
|
|
||||||
sum += sumGrowth * (percentageStatValue.mean! / 100);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return sum;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const reduceSumStatisticsByDay = (
|
|
||||||
values: StatisticValue[]
|
|
||||||
): StatisticValue[] => {
|
|
||||||
if (!values?.length) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const result: StatisticValue[] = [];
|
|
||||||
if (
|
|
||||||
values.length > 1 &&
|
|
||||||
new Date(values[0].start).getDate() === new Date(values[1].start).getDate()
|
|
||||||
) {
|
|
||||||
// add init value if the first value isn't end of previous period
|
|
||||||
result.push({
|
|
||||||
...values[0]!,
|
|
||||||
start: startOfDay(addDays(new Date(values[0].start), -1)).toISOString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let lastValue: StatisticValue;
|
|
||||||
let prevDate: number | undefined;
|
|
||||||
for (const value of values) {
|
|
||||||
const date = new Date(value.start).getDate();
|
|
||||||
if (prevDate === undefined) {
|
|
||||||
prevDate = date;
|
|
||||||
}
|
|
||||||
if (prevDate !== date) {
|
|
||||||
// Last value of the day
|
|
||||||
result.push({
|
|
||||||
...lastValue!,
|
|
||||||
start: startOfDay(new Date(lastValue!.start)).toISOString(),
|
|
||||||
});
|
|
||||||
prevDate = date;
|
|
||||||
}
|
|
||||||
lastValue = value;
|
|
||||||
}
|
|
||||||
// Add final value
|
|
||||||
result.push({
|
|
||||||
...lastValue!,
|
|
||||||
start: startOfDay(new Date(lastValue!.start)).toISOString(),
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const reduceSumStatisticsByMonth = (
|
|
||||||
values: StatisticValue[]
|
|
||||||
): StatisticValue[] => {
|
|
||||||
if (!values?.length) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const result: StatisticValue[] = [];
|
|
||||||
if (
|
|
||||||
values.length > 1 &&
|
|
||||||
new Date(values[0].start).getMonth() ===
|
|
||||||
new Date(values[1].start).getMonth()
|
|
||||||
) {
|
|
||||||
// add init value if the first value isn't end of previous period
|
|
||||||
result.push({
|
|
||||||
...values[0]!,
|
|
||||||
start: startOfMonth(
|
|
||||||
addMonths(new Date(values[0].start), -1)
|
|
||||||
).toISOString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let lastValue: StatisticValue;
|
|
||||||
let prevMonth: number | undefined;
|
|
||||||
for (const value of values) {
|
|
||||||
const month = new Date(value.start).getMonth();
|
|
||||||
if (prevMonth === undefined) {
|
|
||||||
prevMonth = month;
|
|
||||||
}
|
|
||||||
if (prevMonth !== month) {
|
|
||||||
// Last value of the month
|
|
||||||
result.push({
|
|
||||||
...lastValue!,
|
|
||||||
start: startOfMonth(new Date(lastValue!.start)).toISOString(),
|
|
||||||
});
|
|
||||||
prevMonth = month;
|
|
||||||
}
|
|
||||||
lastValue = value;
|
|
||||||
}
|
|
||||||
// Add final value
|
|
||||||
result.push({
|
|
||||||
...lastValue!,
|
|
||||||
start: startOfMonth(new Date(lastValue!.start)).toISOString(),
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
@ -13,10 +13,7 @@ import {
|
|||||||
energySourcesByType,
|
energySourcesByType,
|
||||||
getEnergyDataCollection,
|
getEnergyDataCollection,
|
||||||
} from "../../../../data/energy";
|
} from "../../../../data/energy";
|
||||||
import {
|
import { calculateStatisticsSumGrowth } from "../../../../data/history";
|
||||||
calculateStatisticsSumGrowth,
|
|
||||||
calculateStatisticsSumGrowthWithPercentage,
|
|
||||||
} from "../../../../data/history";
|
|
||||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import { createEntityNotFoundWarning } from "../../components/hui-warning";
|
import { createEntityNotFoundWarning } from "../../components/hui-warning";
|
||||||
@ -90,19 +87,13 @@ class HuiEnergyCarbonGaugeCard
|
|||||||
value = 100;
|
value = 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (this._data.fossilEnergyConsumption && totalGridConsumption) {
|
||||||
this._data.co2SignalEntity in this._data.stats &&
|
const highCarbonEnergy = this._data.fossilEnergyConsumption
|
||||||
totalGridConsumption
|
? Object.values(this._data.fossilEnergyConsumption).reduce(
|
||||||
) {
|
(sum, a) => sum + a,
|
||||||
const highCarbonEnergy =
|
0
|
||||||
calculateStatisticsSumGrowthWithPercentage(
|
)
|
||||||
this._data.stats[this._data.co2SignalEntity],
|
: 0;
|
||||||
types
|
|
||||||
.grid![0].flow_from.map(
|
|
||||||
(flow) => this._data!.stats![flow.stat_energy_from]
|
|
||||||
)
|
|
||||||
.filter(Boolean)
|
|
||||||
) || 0;
|
|
||||||
|
|
||||||
const totalSolarProduction = types.solar
|
const totalSolarProduction = types.solar
|
||||||
? calculateStatisticsSumGrowth(
|
? calculateStatisticsSumGrowth(
|
||||||
|
@ -6,7 +6,7 @@ import {
|
|||||||
ScatterDataPoint,
|
ScatterDataPoint,
|
||||||
} from "chart.js";
|
} from "chart.js";
|
||||||
import { getRelativePosition } from "chart.js/helpers";
|
import { getRelativePosition } from "chart.js/helpers";
|
||||||
import { addHours } from "date-fns";
|
import { addHours, differenceInDays } from "date-fns";
|
||||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
@ -155,13 +155,19 @@ export class HuiEnergyDevicesGraphCard
|
|||||||
);
|
);
|
||||||
|
|
||||||
private async _getStatistics(energyData: EnergyData): Promise<void> {
|
private async _getStatistics(energyData: EnergyData): Promise<void> {
|
||||||
|
const dayDifference = differenceInDays(
|
||||||
|
energyData.end || new Date(),
|
||||||
|
energyData.start
|
||||||
|
);
|
||||||
|
|
||||||
this._data = await fetchStatistics(
|
this._data = await fetchStatistics(
|
||||||
this.hass,
|
this.hass,
|
||||||
addHours(energyData.start, -1),
|
addHours(energyData.start, -1),
|
||||||
energyData.end,
|
energyData.end,
|
||||||
energyData.prefs.device_consumption.map(
|
energyData.prefs.device_consumption.map(
|
||||||
(device) => device.stat_consumption
|
(device) => device.stat_consumption
|
||||||
)
|
),
|
||||||
|
dayDifference > 35 ? "month" : dayDifference > 2 ? "day" : "hour"
|
||||||
);
|
);
|
||||||
|
|
||||||
const data: Array<ChartDataset<"bar", ParsedDataType<"bar">>["data"]> = [];
|
const data: Array<ChartDataset<"bar", ParsedDataType<"bar">>["data"]> = [];
|
||||||
|
@ -24,10 +24,7 @@ import {
|
|||||||
getEnergyDataCollection,
|
getEnergyDataCollection,
|
||||||
getEnergyGasUnit,
|
getEnergyGasUnit,
|
||||||
} from "../../../../data/energy";
|
} from "../../../../data/energy";
|
||||||
import {
|
import { calculateStatisticsSumGrowth } from "../../../../data/history";
|
||||||
calculateStatisticsSumGrowth,
|
|
||||||
calculateStatisticsSumGrowthWithPercentage,
|
|
||||||
} from "../../../../data/history";
|
|
||||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||||
import { HomeAssistant } from "../../../../types";
|
import { HomeAssistant } from "../../../../types";
|
||||||
import { LovelaceCard } from "../../types";
|
import { LovelaceCard } from "../../types";
|
||||||
@ -209,19 +206,11 @@ class HuiEnergyDistrubutionCard
|
|||||||
// This fallback is used in the demo
|
// This fallback is used in the demo
|
||||||
let electricityMapUrl = "https://www.electricitymap.org";
|
let electricityMapUrl = "https://www.electricitymap.org";
|
||||||
|
|
||||||
if (
|
if (this._data.co2SignalEntity && this._data.fossilEnergyConsumption) {
|
||||||
this._data.co2SignalEntity &&
|
|
||||||
this._data.co2SignalEntity in this._data.stats
|
|
||||||
) {
|
|
||||||
// Calculate high carbon consumption
|
// Calculate high carbon consumption
|
||||||
const highCarbonEnergy = calculateStatisticsSumGrowthWithPercentage(
|
const highCarbonEnergy = Object.values(
|
||||||
this._data.stats[this._data.co2SignalEntity],
|
this._data.fossilEnergyConsumption
|
||||||
types
|
).reduce((sum, a) => sum + a, 0);
|
||||||
.grid![0].flow_from.map(
|
|
||||||
(flow) => this._data!.stats[flow.stat_energy_from]
|
|
||||||
)
|
|
||||||
.filter(Boolean)
|
|
||||||
);
|
|
||||||
|
|
||||||
const co2State = this.hass.states[this._data.co2SignalEntity];
|
const co2State = this.hass.states[this._data.co2SignalEntity];
|
||||||
|
|
||||||
|
@ -41,10 +41,6 @@ import {
|
|||||||
} from "../../../../common/number/format_number";
|
} from "../../../../common/number/format_number";
|
||||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||||
import { FrontendLocaleData } from "../../../../data/translation";
|
import { FrontendLocaleData } from "../../../../data/translation";
|
||||||
import {
|
|
||||||
reduceSumStatisticsByMonth,
|
|
||||||
reduceSumStatisticsByDay,
|
|
||||||
} from "../../../../data/history";
|
|
||||||
import { formatTime } from "../../../../common/datetime/format_time";
|
import { formatTime } from "../../../../common/datetime/format_time";
|
||||||
|
|
||||||
@customElement("hui-energy-gas-graph-card")
|
@customElement("hui-energy-gas-graph-card")
|
||||||
@ -247,11 +243,6 @@ export class HuiEnergyGasGraphCard
|
|||||||
.getPropertyValue("--energy-gas-color")
|
.getPropertyValue("--energy-gas-color")
|
||||||
.trim();
|
.trim();
|
||||||
|
|
||||||
const dayDifference = differenceInDays(
|
|
||||||
energyData.end || new Date(),
|
|
||||||
energyData.start
|
|
||||||
);
|
|
||||||
|
|
||||||
gasSources.forEach((source, idx) => {
|
gasSources.forEach((source, idx) => {
|
||||||
const data: ChartDataset<"bar" | "line">[] = [];
|
const data: ChartDataset<"bar" | "line">[] = [];
|
||||||
const entity = this.hass.states[source.stat_energy_from];
|
const entity = this.hass.states[source.stat_energy_from];
|
||||||
@ -268,16 +259,7 @@ export class HuiEnergyGasGraphCard
|
|||||||
|
|
||||||
// Process gas consumption data.
|
// Process gas consumption data.
|
||||||
if (source.stat_energy_from in energyData.stats) {
|
if (source.stat_energy_from in energyData.stats) {
|
||||||
const stats =
|
const stats = energyData.stats[source.stat_energy_from];
|
||||||
dayDifference > 35
|
|
||||||
? reduceSumStatisticsByMonth(
|
|
||||||
energyData.stats[source.stat_energy_from]
|
|
||||||
)
|
|
||||||
: dayDifference > 2
|
|
||||||
? reduceSumStatisticsByDay(
|
|
||||||
energyData.stats[source.stat_energy_from]
|
|
||||||
)
|
|
||||||
: energyData.stats[source.stat_energy_from];
|
|
||||||
|
|
||||||
for (const point of stats) {
|
for (const point of stats) {
|
||||||
if (point.sum === null) {
|
if (point.sum === null) {
|
||||||
|
@ -42,10 +42,6 @@ import {
|
|||||||
} from "../../../../common/number/format_number";
|
} from "../../../../common/number/format_number";
|
||||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||||
import { FrontendLocaleData } from "../../../../data/translation";
|
import { FrontendLocaleData } from "../../../../data/translation";
|
||||||
import {
|
|
||||||
reduceSumStatisticsByMonth,
|
|
||||||
reduceSumStatisticsByDay,
|
|
||||||
} from "../../../../data/history";
|
|
||||||
import { formatTime } from "../../../../common/datetime/format_time";
|
import { formatTime } from "../../../../common/datetime/format_time";
|
||||||
|
|
||||||
@customElement("hui-energy-solar-graph-card")
|
@customElement("hui-energy-solar-graph-card")
|
||||||
@ -274,16 +270,7 @@ export class HuiEnergySolarGraphCard
|
|||||||
|
|
||||||
// Process solar production data.
|
// Process solar production data.
|
||||||
if (source.stat_energy_from in energyData.stats) {
|
if (source.stat_energy_from in energyData.stats) {
|
||||||
const stats =
|
const stats = energyData.stats[source.stat_energy_from];
|
||||||
dayDifference > 35
|
|
||||||
? reduceSumStatisticsByMonth(
|
|
||||||
energyData.stats[source.stat_energy_from]
|
|
||||||
)
|
|
||||||
: dayDifference > 2
|
|
||||||
? reduceSumStatisticsByDay(
|
|
||||||
energyData.stats[source.stat_energy_from]
|
|
||||||
)
|
|
||||||
: energyData.stats[source.stat_energy_from];
|
|
||||||
|
|
||||||
for (const point of stats) {
|
for (const point of stats) {
|
||||||
if (point.sum === null) {
|
if (point.sum === null) {
|
||||||
|
@ -27,10 +27,6 @@ import {
|
|||||||
import "../../../../components/chart/ha-chart-base";
|
import "../../../../components/chart/ha-chart-base";
|
||||||
import "../../../../components/ha-card";
|
import "../../../../components/ha-card";
|
||||||
import { EnergyData, getEnergyDataCollection } from "../../../../data/energy";
|
import { EnergyData, getEnergyDataCollection } from "../../../../data/energy";
|
||||||
import {
|
|
||||||
reduceSumStatisticsByDay,
|
|
||||||
reduceSumStatisticsByMonth,
|
|
||||||
} from "../../../../data/history";
|
|
||||||
import { FrontendLocaleData } from "../../../../data/translation";
|
import { FrontendLocaleData } from "../../../../data/translation";
|
||||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||||
import { HomeAssistant } from "../../../../types";
|
import { HomeAssistant } from "../../../../types";
|
||||||
@ -298,11 +294,6 @@ export class HuiEnergyUsageGraphCard
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const dayDifference = differenceInDays(
|
|
||||||
energyData.end || new Date(),
|
|
||||||
energyData.start
|
|
||||||
);
|
|
||||||
|
|
||||||
this._start = energyData.start;
|
this._start = energyData.start;
|
||||||
this._end = energyData.end || endOfToday();
|
this._end = energyData.end || endOfToday();
|
||||||
|
|
||||||
@ -368,12 +359,7 @@ export class HuiEnergyUsageGraphCard
|
|||||||
const totalStats: { [start: string]: number } = {};
|
const totalStats: { [start: string]: number } = {};
|
||||||
const sets: { [statId: string]: { [start: string]: number } } = {};
|
const sets: { [statId: string]: { [start: string]: number } } = {};
|
||||||
statIds!.forEach((id) => {
|
statIds!.forEach((id) => {
|
||||||
const stats =
|
const stats = energyData.stats[id];
|
||||||
dayDifference > 35
|
|
||||||
? reduceSumStatisticsByMonth(energyData.stats[id])
|
|
||||||
: dayDifference > 2
|
|
||||||
? reduceSumStatisticsByDay(energyData.stats[id])
|
|
||||||
: energyData.stats[id];
|
|
||||||
if (!stats) {
|
if (!stats) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,576 +0,0 @@
|
|||||||
import { assert } from "chai";
|
|
||||||
|
|
||||||
import { calculateStatisticsSumGrowthWithPercentage } from "../../src/data/history";
|
|
||||||
|
|
||||||
describe("calculateStatisticsSumGrowthWithPercentage", () => {
|
|
||||||
it("Returns null if not enough values", async () => {
|
|
||||||
assert.strictEqual(
|
|
||||||
calculateStatisticsSumGrowthWithPercentage([], []),
|
|
||||||
null
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Returns null if not enough sum stat values", async () => {
|
|
||||||
assert.strictEqual(
|
|
||||||
calculateStatisticsSumGrowthWithPercentage(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.carbon_intensity",
|
|
||||||
start: "2021-07-28T05:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: 75,
|
|
||||||
mean: 50,
|
|
||||||
min: 25,
|
|
||||||
sum: null,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.carbon_intensity",
|
|
||||||
start: "2021-07-28T07:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: 100,
|
|
||||||
mean: 75,
|
|
||||||
min: 50,
|
|
||||||
sum: null,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[]
|
|
||||||
),
|
|
||||||
null
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Returns null if not enough percentage stat values", async () => {
|
|
||||||
assert.strictEqual(
|
|
||||||
calculateStatisticsSumGrowthWithPercentage(
|
|
||||||
[],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.peak_consumption",
|
|
||||||
start: "2021-07-28T04:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 50,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.peak_consumption",
|
|
||||||
start: "2021-07-28T05:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 100,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.peak_consumption",
|
|
||||||
start: "2021-07-28T07:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 200,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
]
|
|
||||||
),
|
|
||||||
null
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Returns a percentage of the growth", async () => {
|
|
||||||
assert.strictEqual(
|
|
||||||
calculateStatisticsSumGrowthWithPercentage(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.carbon_intensity",
|
|
||||||
start: "2021-07-28T05:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: 75,
|
|
||||||
mean: 50,
|
|
||||||
min: 25,
|
|
||||||
sum: null,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.carbon_intensity",
|
|
||||||
start: "2021-07-28T07:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: 100,
|
|
||||||
mean: 75,
|
|
||||||
min: 50,
|
|
||||||
sum: null,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.peak_consumption",
|
|
||||||
start: "2021-07-28T04:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 50,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.peak_consumption",
|
|
||||||
start: "2021-07-28T05:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 100,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.peak_consumption",
|
|
||||||
start: "2021-07-28T07:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 200,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.off_peak_consumption",
|
|
||||||
start: "2021-07-28T04:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 50,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.off_peak_consumption",
|
|
||||||
start: "2021-07-28T05:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 100,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.off_peak_consumption",
|
|
||||||
start: "2021-07-28T07:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 200,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
]
|
|
||||||
),
|
|
||||||
200
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("It ignores sum data that doesnt match start", async () => {
|
|
||||||
assert.strictEqual(
|
|
||||||
calculateStatisticsSumGrowthWithPercentage(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.carbon_intensity",
|
|
||||||
start: "2021-07-28T05:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: 75,
|
|
||||||
mean: 50,
|
|
||||||
min: 25,
|
|
||||||
sum: null,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.carbon_intensity",
|
|
||||||
start: "2021-07-28T07:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: 100,
|
|
||||||
mean: 75,
|
|
||||||
min: 50,
|
|
||||||
sum: null,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.peak_consumption",
|
|
||||||
start: "2021-07-28T04:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 50,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.peak_consumption",
|
|
||||||
start: "2021-07-28T04:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 50,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.peak_consumption",
|
|
||||||
start: "2021-07-28T05:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 100,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.peak_consumption",
|
|
||||||
start: "2021-07-28T07:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 200,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
]
|
|
||||||
),
|
|
||||||
100
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("It ignores percentage data that doesnt match start", async () => {
|
|
||||||
assert.strictEqual(
|
|
||||||
calculateStatisticsSumGrowthWithPercentage(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.carbon_intensity",
|
|
||||||
start: "2021-07-28T04:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: 25,
|
|
||||||
mean: 25,
|
|
||||||
min: 25,
|
|
||||||
sum: null,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.carbon_intensity",
|
|
||||||
start: "2021-07-28T05:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: 75,
|
|
||||||
mean: 50,
|
|
||||||
min: 25,
|
|
||||||
sum: null,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.carbon_intensity",
|
|
||||||
start: "2021-07-28T07:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: 100,
|
|
||||||
mean: 75,
|
|
||||||
min: 50,
|
|
||||||
sum: null,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.peak_consumption",
|
|
||||||
start: "2021-07-28T04:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 50,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.peak_consumption",
|
|
||||||
start: "2021-07-28T05:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 100,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.peak_consumption",
|
|
||||||
start: "2021-07-28T07:00:00Z",
|
|
||||||
last_reset: null,
|
|
||||||
max: null,
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
sum: 200,
|
|
||||||
state: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
]
|
|
||||||
),
|
|
||||||
100
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Returns a percentage of the growth", async () => {
|
|
||||||
assert.strictEqual(
|
|
||||||
calculateStatisticsSumGrowthWithPercentage(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
start: "2021-08-03T06:00:00.000Z",
|
|
||||||
mean: 10,
|
|
||||||
min: 10,
|
|
||||||
max: 10,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 10,
|
|
||||||
sum: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
start: "2021-08-03T07:00:00.000Z",
|
|
||||||
mean: 20,
|
|
||||||
min: 20,
|
|
||||||
max: 20,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 20,
|
|
||||||
sum: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
start: "2021-08-03T08:00:00.000Z",
|
|
||||||
mean: 30,
|
|
||||||
min: 30,
|
|
||||||
max: 30,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 30,
|
|
||||||
sum: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
start: "2021-08-03T09:00:00.000Z",
|
|
||||||
mean: 40,
|
|
||||||
min: 40,
|
|
||||||
max: 40,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 40,
|
|
||||||
sum: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
start: "2021-08-03T10:00:00.000Z",
|
|
||||||
mean: 50,
|
|
||||||
min: 50,
|
|
||||||
max: 50,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 50,
|
|
||||||
sum: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
start: "2021-08-03T11:00:00.000Z",
|
|
||||||
mean: 60,
|
|
||||||
min: 60,
|
|
||||||
max: 60,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 60,
|
|
||||||
sum: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
start: "2021-08-03T12:00:00.000Z",
|
|
||||||
mean: 70,
|
|
||||||
min: 70,
|
|
||||||
max: 70,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 70,
|
|
||||||
sum: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
start: "2021-08-03T13:00:00.000Z",
|
|
||||||
mean: 80,
|
|
||||||
min: 80,
|
|
||||||
max: 80,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 80,
|
|
||||||
sum: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
start: "2021-08-03T14:00:00.000Z",
|
|
||||||
mean: 90,
|
|
||||||
min: 90,
|
|
||||||
max: 90,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 90,
|
|
||||||
sum: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
start: "2021-08-03T15:00:00.000Z",
|
|
||||||
mean: 100,
|
|
||||||
min: 100,
|
|
||||||
max: 100,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 100,
|
|
||||||
sum: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
start: "2021-08-03T16:00:00.000Z",
|
|
||||||
mean: 110,
|
|
||||||
min: 110,
|
|
||||||
max: 110,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 120,
|
|
||||||
sum: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.energy_consumption_tarif_1",
|
|
||||||
start: "2021-08-03T06:00:00.000Z",
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 10,
|
|
||||||
sum: 10,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.energy_consumption_tarif_1",
|
|
||||||
start: "2021-08-03T07:00:00.000Z",
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 20,
|
|
||||||
sum: 20,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.energy_consumption_tarif_1",
|
|
||||||
start: "2021-08-03T08:00:00.000Z",
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 30,
|
|
||||||
sum: 30,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.energy_consumption_tarif_1",
|
|
||||||
start: "2021-08-03T09:00:00.000Z",
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 40,
|
|
||||||
sum: 40,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.energy_consumption_tarif_1",
|
|
||||||
start: "2021-08-03T10:00:00.000Z",
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 50,
|
|
||||||
sum: 50,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.energy_consumption_tarif_1",
|
|
||||||
start: "2021-08-03T11:00:00.000Z",
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 60,
|
|
||||||
sum: 60,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.energy_consumption_tarif_1",
|
|
||||||
start: "2021-08-03T12:00:00.000Z",
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 70,
|
|
||||||
sum: 70,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.energy_consumption_tarif_1",
|
|
||||||
start: "2021-08-03T13:00:00.000Z",
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 80,
|
|
||||||
sum: 80,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.energy_consumption_tarif_1",
|
|
||||||
start: "2021-08-03T14:00:00.000Z",
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 90,
|
|
||||||
sum: 90,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.energy_consumption_tarif_1",
|
|
||||||
start: "2021-08-03T15:00:00.000Z",
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 100,
|
|
||||||
sum: 100,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.energy_consumption_tarif_2",
|
|
||||||
start: "2021-08-03T15:00:00.000Z",
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 10,
|
|
||||||
sum: 10,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statistic_id: "sensor.energy_consumption_tarif_2",
|
|
||||||
start: "2021-08-03T16:00:00.000Z",
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: 20,
|
|
||||||
sum: 20,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
]
|
|
||||||
),
|
|
||||||
65
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
x
Reference in New Issue
Block a user