diff --git a/src/data/energy.ts b/src/data/energy.ts index 057b7a9f78..70aece7feb 100644 --- a/src/data/energy.ts +++ b/src/data/energy.ts @@ -795,10 +795,28 @@ export interface EnergySumData { from_battery?: number; solar?: number; }; + timestamps: number[]; } -interface EnergyConsumptionData { - total: Record; +export interface EnergyConsumptionData { + used_total: Record; + grid_to_battery: Record; + battery_to_grid: Record; + solar_to_battery: Record; + solar_to_grid: Record; + used_solar: Record; + used_grid: Record; + used_battery: Record; + total: { + used_total: number; + grid_to_battery: number; + battery_to_grid: number; + solar_to_battery: number; + solar_to_grid: number; + used_solar: number; + used_grid: number; + used_battery: number; + }; } export const getSummedData = memoizeOne( @@ -867,7 +885,8 @@ const getSummedDataPartial = ( } } - const summedData: EnergySumData = { total: {} }; + const summedData: EnergySumData = { total: {}, timestamps: [] }; + const timestamps = new Set(); Object.entries(statIds).forEach(([key, subStatIds]) => { const totalStats: Record = {}; const sets: Record> = {}; @@ -886,6 +905,7 @@ const getSummedDataPartial = ( sum += val; totalStats[stat.start] = stat.start in totalStats ? totalStats[stat.start] + val : val; + timestamps.add(stat.start); }); sets[id] = set; }); @@ -893,6 +913,8 @@ const getSummedDataPartial = ( summedData.total[key] = sum; }); + summedData.timestamps = Array.from(timestamps).sort(); + return summedData; }; @@ -915,25 +937,142 @@ export const computeConsumptionData = memoizeOne( const computeConsumptionDataPartial = ( data: EnergySumData ): EnergyConsumptionData => { - const outData: EnergyConsumptionData = { total: {} }; + const outData: EnergyConsumptionData = { + used_total: {}, + grid_to_battery: {}, + battery_to_grid: {}, + solar_to_battery: {}, + solar_to_grid: {}, + used_solar: {}, + used_grid: {}, + used_battery: {}, + total: { + used_total: 0, + grid_to_battery: 0, + battery_to_grid: 0, + solar_to_battery: 0, + solar_to_grid: 0, + used_solar: 0, + used_grid: 0, + used_battery: 0, + }, + }; - Object.keys(data).forEach((type) => { - Object.keys(data[type]).forEach((start) => { - if (outData.total[start] === undefined) { - const consumption = - (data.from_grid?.[start] || 0) + - (data.solar?.[start] || 0) + - (data.from_battery?.[start] || 0) - - (data.to_grid?.[start] || 0) - - (data.to_battery?.[start] || 0); - outData.total[start] = consumption; - } + data.timestamps.forEach((t) => { + const used_total = + (data.from_grid?.[t] || 0) + + (data.solar?.[t] || 0) + + (data.from_battery?.[t] || 0) - + (data.to_grid?.[t] || 0) - + (data.to_battery?.[t] || 0); + + outData.used_total[t] = used_total; + outData.total.used_total += used_total; + const { + grid_to_battery, + battery_to_grid, + used_solar, + used_grid, + used_battery, + solar_to_battery, + solar_to_grid, + } = computeConsumptionSingle({ + from_grid: data.from_grid && (data.from_grid[t] ?? 0), + to_grid: data.to_grid && (data.to_grid[t] ?? 0), + solar: data.solar && (data.solar[t] ?? 0), + to_battery: data.to_battery && (data.to_battery[t] ?? 0), + from_battery: data.from_battery && (data.from_battery[t] ?? 0), }); + + outData.grid_to_battery[t] = grid_to_battery; + outData.total.grid_to_battery += grid_to_battery; + outData.battery_to_grid![t] = battery_to_grid; + outData.total.battery_to_grid += battery_to_grid; + outData.used_battery![t] = used_battery; + outData.total.used_battery += used_battery; + outData.used_grid![t] = used_grid; + outData.total.used_grid += used_grid; + outData.used_solar![t] = used_solar; + outData.total.used_solar += used_solar; + outData.solar_to_battery[t] = solar_to_battery; + outData.total.solar_to_battery += solar_to_battery; + outData.solar_to_grid[t] = solar_to_grid; + outData.total.solar_to_grid += solar_to_grid; }); return outData; }; +export const computeConsumptionSingle = (data: { + from_grid: number | undefined; + to_grid: number | undefined; + solar: number | undefined; + to_battery: number | undefined; + from_battery: number | undefined; +}): { + grid_to_battery: number; + battery_to_grid: number; + solar_to_battery: number; + solar_to_grid: number; + used_solar: number; + used_grid: number; + used_battery: number; +} => { + const to_grid = data.to_grid; + const to_battery = data.to_battery; + const solar = data.solar; + const from_grid = data.from_grid; + const from_battery = data.from_battery; + + let used_solar = 0; + let grid_to_battery = 0; + let battery_to_grid = 0; + let solar_to_battery = 0; + let solar_to_grid = 0; + let used_battery = 0; + let used_grid = 0; + if ((to_grid != null || to_battery != null) && solar != null) { + used_solar = (solar || 0) - (to_grid || 0) - (to_battery || 0); + if (used_solar < 0) { + if (to_battery != null) { + grid_to_battery = used_solar * -1; + if (grid_to_battery > (from_grid || 0)) { + battery_to_grid = grid_to_battery - (from_grid || 0); + grid_to_battery = from_grid || 0; + } + } + used_solar = 0; + } + } + + if (from_battery != null) { + used_battery = (from_battery || 0) - battery_to_grid; + } + + if (from_grid != null) { + used_grid = from_grid - grid_to_battery; + } + + if (solar != null) { + if (to_battery != null) { + solar_to_battery = Math.max(0, (to_battery || 0) - grid_to_battery); + } + if (to_grid != null) { + solar_to_grid = Math.max(0, (to_grid || 0) - battery_to_grid); + } + } + + return { + used_solar, + used_grid, + used_battery, + grid_to_battery, + battery_to_grid, + solar_to_battery, + solar_to_grid, + }; +}; + export const formatConsumptionShort = ( hass: HomeAssistant, consumption: number | null, diff --git a/src/panels/lovelace/cards/energy/hui-energy-devices-detail-graph-card.ts b/src/panels/lovelace/cards/energy/hui-energy-devices-detail-graph-card.ts index f36f39a9de..47e484d21c 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-devices-detail-graph-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-devices-detail-graph-card.ts @@ -347,12 +347,13 @@ export class HuiEnergyDevicesDetailGraphCard ); const untrackedConsumption: BarSeriesOption["data"] = []; - Object.keys(consumptionData.total) + Object.keys(consumptionData.used_total) .sort((a, b) => Number(a) - Number(b)) .forEach((time) => { const ts = Number(time); const value = - consumptionData.total[time] - (totalDeviceConsumption[time] || 0); + consumptionData.used_total[time] - + (totalDeviceConsumption[time] || 0); const dataPoint: number[] = [ts, value]; if (compare) { dataPoint[2] = dataPoint[0]; diff --git a/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts b/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts index 2eb162ec1c..d4e234805f 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts @@ -27,6 +27,7 @@ import { getEnergyWaterUnit, formatConsumptionShort, getSummedData, + computeConsumptionData, } from "../../../../data/energy"; import { calculateStatisticsSumGrowth } from "../../../../data/recorder"; import { SubscribeMixin } from "../../../../mixins/subscribe-mixin"; @@ -111,6 +112,10 @@ class HuiEnergyDistrubutionCard const hasReturnToGrid = hasConsumption && types.grid![0].flow_to.length > 0; const { summedData, compareSummedData: _ } = getSummedData(this._data); + const { consumption, compareConsumption: __ } = computeConsumptionData( + summedData, + undefined + ); const totalFromGrid = summedData.total.from_grid ?? 0; @@ -154,55 +159,32 @@ class HuiEnergyDistrubutionCard let solarConsumption: number | null = null; if (hasSolarProduction) { - solarConsumption = - (totalSolarProduction || 0) - - (returnedToGrid || 0) - - (totalBatteryIn || 0); + solarConsumption = consumption.total.used_solar; } - let batteryFromGrid: null | number = null; let batteryToGrid: null | number = null; - if (solarConsumption !== null && solarConsumption < 0) { - // What we returned to the grid and what went in to the battery is more than produced, - // so we have used grid energy to fill the battery - // or returned battery energy to the grid - if (hasBattery) { - batteryFromGrid = solarConsumption * -1; - if (batteryFromGrid > totalFromGrid) { - batteryToGrid = batteryFromGrid - totalFromGrid; - batteryFromGrid = totalFromGrid; - } - } - solarConsumption = 0; + if (hasBattery) { + batteryToGrid = consumption.total.battery_to_grid; + batteryFromGrid = consumption.total.grid_to_battery; } let solarToBattery: null | number = null; + let solarToGrid: null | number = null; + if (hasSolarProduction) { + solarToGrid = consumption.total.solar_to_grid; + } if (hasSolarProduction && hasBattery) { - if (!batteryToGrid) { - batteryToGrid = Math.max( - 0, - (returnedToGrid || 0) - - (totalSolarProduction || 0) - - (totalBatteryIn || 0) - - (batteryFromGrid || 0) - ); - } - solarToBattery = totalBatteryIn! - (batteryFromGrid || 0); - } else if (!hasSolarProduction && hasBattery) { - batteryToGrid = returnedToGrid; + solarToBattery = consumption.total.solar_to_battery; } let batteryConsumption: number | null = null; if (hasBattery) { - batteryConsumption = (totalBatteryOut || 0) - (batteryToGrid || 0); + batteryConsumption = Math.max(consumption.total.used_battery, 0); } - const gridConsumption = Math.max(0, totalFromGrid - (batteryFromGrid || 0)); + const gridConsumption = Math.max(consumption.total.used_grid, 0); - const totalHomeConsumption = Math.max( - 0, - gridConsumption + (solarConsumption || 0) + (batteryConsumption || 0) - ); + const totalHomeConsumption = Math.max(0, consumption.total.used_total); let homeSolarCircumference: number | undefined; if (hasSolarProduction) { @@ -262,7 +244,7 @@ class HuiEnergyDistrubutionCard const totalLines = gridConsumption + (solarConsumption || 0) + - (returnedToGrid ? returnedToGrid - (batteryToGrid || 0) : 0) + + (solarToGrid || 0) + (solarToBattery || 0) + (batteryConsumption || 0) + (batteryFromGrid || 0) + @@ -662,18 +644,14 @@ class HuiEnergyDistrubutionCard d="M0,${hasBattery ? 50 : hasSolarProduction ? 56 : 53} H100" vector-effect="non-scaling-stroke" > - ${returnedToGrid && hasSolarProduction && this._animate + ${solarToGrid && this._animate ? svg` diff --git a/src/panels/lovelace/cards/energy/hui-energy-self-sufficiency-gauge-card.ts b/src/panels/lovelace/cards/energy/hui-energy-self-sufficiency-gauge-card.ts index 18e94255c2..d29605a9c2 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-self-sufficiency-gauge-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-self-sufficiency-gauge-card.ts @@ -10,6 +10,7 @@ import "../../../../components/ha-svg-icon"; import "../../../../components/ha-tooltip"; import type { EnergyData } from "../../../../data/energy"; import { + computeConsumptionData, getEnergyDataCollection, getSummedData, } from "../../../../data/energy"; @@ -76,70 +77,14 @@ class HuiEnergySelfSufficiencyGaugeCard // The strategy only includes this card if we have a grid. const { summedData, compareSummedData: _ } = getSummedData(this._data); - - const hasSolarProduction = summedData.solar !== undefined; - const hasBattery = - summedData.to_battery !== undefined || - summedData.from_battery !== undefined; - const hasReturnToGrid = summedData.to_grid !== undefined; + const { consumption, compareConsumption: __ } = computeConsumptionData( + summedData, + undefined + ); const totalFromGrid = summedData.total.from_grid ?? 0; - let totalSolarProduction: number | null = null; - - if (hasSolarProduction) { - totalSolarProduction = summedData.total.solar ?? 0; - } - - let totalBatteryIn: number | null = null; - let totalBatteryOut: number | null = null; - - if (hasBattery) { - totalBatteryIn = summedData.total.to_battery ?? 0; - totalBatteryOut = summedData.total.from_battery ?? 0; - } - - let returnedToGrid: number | null = null; - - if (hasReturnToGrid) { - returnedToGrid = summedData.total.to_grid ?? 0; - } - - let solarConsumption: number | null = null; - if (hasSolarProduction) { - solarConsumption = - (totalSolarProduction || 0) - - (returnedToGrid || 0) - - (totalBatteryIn || 0); - } - - let batteryFromGrid: null | number = null; - let batteryToGrid: null | number = null; - if (solarConsumption !== null && solarConsumption < 0) { - // What we returned to the grid and what went in to the battery is more than produced, - // so we have used grid energy to fill the battery - // or returned battery energy to the grid - if (hasBattery) { - batteryFromGrid = solarConsumption * -1; - if (batteryFromGrid > totalFromGrid) { - batteryToGrid = batteryFromGrid - totalFromGrid; - batteryFromGrid = totalFromGrid; - } - } - solarConsumption = 0; - } - - let batteryConsumption: number | null = null; - if (hasBattery) { - batteryConsumption = (totalBatteryOut || 0) - (batteryToGrid || 0); - } - - const gridConsumption = Math.max(0, totalFromGrid - (batteryFromGrid || 0)); - - const totalHomeConsumption = Math.max( - 0, - gridConsumption + (solarConsumption || 0) + (batteryConsumption || 0) - ); + const totalHomeConsumption = Math.max(0, consumption.total.used_total); let value: number | undefined; if ( @@ -147,7 +92,7 @@ class HuiEnergySelfSufficiencyGaugeCard totalHomeConsumption !== null && totalHomeConsumption > 0 ) { - value = (1 - totalFromGrid / totalHomeConsumption) * 100; + value = (1 - Math.min(1, totalFromGrid / totalHomeConsumption)) * 100; } return html` 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 5fe0782aa3..fc124cbf4e 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 @@ -14,8 +14,13 @@ import { getEnergyColor } from "./common/color"; import { formatNumber } from "../../../../common/number/format_number"; import "../../../../components/chart/ha-chart-base"; import "../../../../components/ha-card"; -import type { EnergyData, EnergySumData } from "../../../../data/energy"; +import type { + EnergyData, + EnergySumData, + EnergyConsumptionData, +} from "../../../../data/energy"; import { + computeConsumptionData, getEnergyDataCollection, getSummedData, } from "../../../../data/energy"; @@ -283,6 +288,10 @@ export class HuiEnergyUsageGraphCard this._compareEnd = energyData.endCompare; const { summedData, compareSummedData } = getSummedData(energyData); + const { consumption, compareConsumption } = computeConsumptionData( + summedData, + compareSummedData + ); if (energyData.statsCompare) { datasets.push( @@ -290,6 +299,7 @@ export class HuiEnergyUsageGraphCard energyData.statsCompare, energyData.statsMetadata, compareSummedData!, + compareConsumption!, statIds, colorIndices, computedStyles, @@ -315,6 +325,7 @@ export class HuiEnergyUsageGraphCard energyData.stats, energyData.statsMetadata, summedData, + consumption, statIds, colorIndices, computedStyles, @@ -333,6 +344,7 @@ export class HuiEnergyUsageGraphCard statistics: Statistics, statisticsMetaData: Record, summedData: EnergySumData, + consumptionData: EnergyConsumptionData, statIdsByCat: { to_grid?: string[] | undefined; from_grid?: string[] | undefined; @@ -361,8 +373,7 @@ export class HuiEnergyUsageGraphCard } = {}; Object.entries(statIdsByCat).forEach(([key, statIds]) => { - const add = !["solar", "from_battery"].includes(key); - if (!add) { + if (!["to_grid", "from_grid", "to_battery"].includes(key)) { return; } const sets: Record> = {}; @@ -387,47 +398,22 @@ export class HuiEnergyUsageGraphCard combinedData[key] = sets; }); - const grid_to_battery = {}; - const battery_to_grid = {}; - if ((summedData.to_grid || summedData.to_battery) && summedData.solar) { - const used_solar = {}; - for (const start of Object.keys(summedData.solar)) { - used_solar[start] = - (summedData.solar[start] || 0) - - (summedData.to_grid?.[start] || 0) - - (summedData.to_battery?.[start] || 0); - if (used_solar[start] < 0) { - if (summedData.to_battery) { - grid_to_battery[start] = used_solar[start] * -1; - if (grid_to_battery[start] > (summedData.from_grid?.[start] || 0)) { - battery_to_grid[start] = - grid_to_battery[start] - (summedData.from_grid?.[start] || 0); - grid_to_battery[start] = summedData.from_grid?.[start]; - } - } - used_solar[start] = 0; - } - } - combinedData.used_solar = { used_solar }; - } - - if (summedData.from_battery) { - if (summedData.to_grid) { - const used_battery = {}; - for (const start of Object.keys(summedData.from_battery)) { - used_battery[start] = - (summedData.from_battery![start] || 0) - - (battery_to_grid[start] || 0); - } - combinedData.used_battery = { used_battery }; - } else { - combinedData.used_battery = { used_battery: summedData.from_battery }; - } - } + combinedData.used_solar = { used_solar: consumptionData.used_solar }; + combinedData.used_battery = { + used_battery: consumptionData.used_battery, + }; if (combinedData.from_grid && summedData.to_battery) { const used_grid = {}; - for (const start of Object.keys(grid_to_battery)) { + // If we have to_battery and multiple grid sources in the same period, we + // can't determine which source was used. So delete all the individual + // sources and replace with a 'combined from grid' value. + for (const [start, grid_to_battery] of Object.entries( + consumptionData.grid_to_battery + )) { + if (!grid_to_battery) { + continue; + } let noOfSources = 0; let source: string; for (const [key, stats] of Object.entries(combinedData.from_grid)) { @@ -440,30 +426,19 @@ export class HuiEnergyUsageGraphCard } } if (noOfSources === 1) { - combinedData.from_grid[source!][start] -= grid_to_battery[start] || 0; + combinedData.from_grid[source!][start] = + consumptionData.used_grid[start]; } else { - let total_from_grid = 0; Object.values(combinedData.from_grid).forEach((stats) => { - total_from_grid += stats[start] || 0; delete stats[start]; }); - used_grid[start] = total_from_grid - (grid_to_battery[start] || 0); + used_grid[start] = consumptionData.used_grid[start]; } } combinedData.used_grid = { used_grid }; } - let allKeys: string[] = []; - - Object.values(combinedData).forEach((sources) => { - Object.values(sources).forEach((source) => { - allKeys = allKeys.concat(Object.keys(source)); - }); - }); - - const uniqueKeys = Array.from(new Set(allKeys)).sort( - (a, b) => Number(a) - Number(b) - ); + const uniqueKeys = summedData.timestamps; const compareTransform = getCompareTransform( this._start, @@ -477,14 +452,14 @@ export class HuiEnergyUsageGraphCard for (const key of uniqueKeys) { const value = source[key] || 0; const dataPoint = [ - Number(key), + new Date(key), value && ["to_grid", "to_battery"].includes(type) ? -1 * value : value, ]; if (compare) { dataPoint[2] = dataPoint[0]; - dataPoint[0] = compareTransform(dataPoint[0]); + dataPoint[0] = compareTransform(dataPoint[0] as Date); } points.push(dataPoint); } diff --git a/test/data/energy.test.ts b/test/data/energy.test.ts index a11c1a7142..e5fcbe9dc6 100644 --- a/test/data/energy.test.ts +++ b/test/data/energy.test.ts @@ -8,7 +8,10 @@ import { DateFormat, TimeZone, } from "../../src/data/translation"; -import { formatConsumptionShort } from "../../src/data/energy"; +import { + computeConsumptionSingle, + formatConsumptionShort, +} from "../../src/data/energy"; import type { HomeAssistant } from "../../src/types"; describe("Energy Short Format Test", () => { @@ -80,3 +83,292 @@ describe("Energy Short Format Test", () => { ); }); }); + +describe("Energy Usage Calculation Tests", () => { + it("Consuming Energy From the Grid", () => { + [0, 5, 1000].forEach((x) => { + assert.deepEqual( + computeConsumptionSingle({ + from_grid: x, + to_grid: undefined, + solar: undefined, + to_battery: undefined, + from_battery: undefined, + }), + { + grid_to_battery: 0, + battery_to_grid: 0, + used_solar: 0, + used_grid: x, + used_battery: 0, + solar_to_battery: 0, + solar_to_grid: 0, + } + ); + }); + }); + it("Solar production, consuming some and returning the remainder to grid.", () => { + [2.99, 3, 10, 100].forEach((s) => { + assert.deepEqual( + computeConsumptionSingle({ + from_grid: 0, + to_grid: 3, + solar: s, + to_battery: undefined, + from_battery: undefined, + }), + { + grid_to_battery: 0, + battery_to_grid: 0, + used_solar: Math.max(0, s - 3), + used_grid: 0, + used_battery: 0, + solar_to_battery: 0, + solar_to_grid: 3, + } + ); + }); + }); + it("Solar production with simultaneous grid consumption. Excess solar returned to the grid.", () => { + [ + [0, 0], + [3, 0], + [0, 3], + [5, 4], + [4, 5], + [10, 3], + [3, 7], + [3, 7.1], + ].forEach(([from_grid, to_grid]) => { + assert.deepEqual( + computeConsumptionSingle({ + from_grid, + to_grid, + solar: 7, + to_battery: undefined, + from_battery: undefined, + }), + { + grid_to_battery: 0, + battery_to_grid: 0, + used_solar: Math.max(0, 7 - to_grid), + used_grid: from_grid, + used_battery: 0, + solar_to_battery: 0, + solar_to_grid: to_grid, + } + ); + }); + }); + it("Charging the battery from the grid", () => { + assert.deepEqual( + computeConsumptionSingle({ + from_grid: 5, + to_grid: 0, + solar: 0, + to_battery: 3, + from_battery: 0, + }), + { + grid_to_battery: 3, + battery_to_grid: 0, + used_solar: 0, + used_grid: 2, + used_battery: 0, + solar_to_battery: 0, + solar_to_grid: 0, + } + ); + }); + it("Consuming from the grid and battery simultaneously", () => { + assert.deepEqual( + computeConsumptionSingle({ + from_grid: 5, + to_grid: 0, + solar: 0, + to_battery: 0, + from_battery: 5, + }), + { + grid_to_battery: 0, + battery_to_grid: 0, + used_solar: 0, + used_grid: 5, + used_battery: 5, + solar_to_battery: 0, + solar_to_grid: 0, + } + ); + }); + it("Consuming some battery and returning some battery to the grid", () => { + assert.deepEqual( + computeConsumptionSingle({ + from_grid: 0, + to_grid: 4, + solar: 0, + to_battery: 0, + from_battery: 5, + }), + { + grid_to_battery: 0, + battery_to_grid: 4, + used_solar: 0, + used_grid: 0, + used_battery: 1, + solar_to_battery: 0, + solar_to_grid: 0, + } + ); + }); + /* Fails + it("Charging and discharging the battery to/from the grid in the same interval.", () => { + assert.deepEqual( + computeConsumptionSingle({ + from_grid: 5, + to_grid: 1, + solar: 0, + to_battery: 3, + from_battery: 1, + }), + { + grid_to_battery: 3, + battery_to_grid: 1, + used_solar: 0, + used_grid: 1, + used_battery: 0, + } + ); + }); */ + /* Test does not pass, battery is not really correct when solar is not present + it("Charging the battery with no solar sensor.", () => { + assert.deepEqual( + computeConsumptionSingle({ + from_grid: 5, + to_grid: 0, + solar: undefined, + to_battery: 3, + from_battery: 0, + }), + { + grid_to_battery: 3, + battery_to_grid: 0, + used_solar: 0, + used_grid: 2, + used_battery: 0, + } + ); + }); */ + /* Test does not pass + it("Discharging battery to grid while also consuming from grid.", () => { + assert.deepEqual( + computeConsumptionSingle({ + from_grid: 5, + to_grid: 4, + solar: 0, + to_battery: 0, + from_battery: 4, + }), + { + grid_to_battery: 0, + battery_to_grid: 4, + used_solar: 0, + used_grid: 5, + used_battery: 0, + } + ); + }); + */ + + it("Grid, solar, and battery", () => { + assert.deepEqual( + computeConsumptionSingle({ + from_grid: 5, + to_grid: 3, + solar: 7, + to_battery: 3, + from_battery: 0, + }), + { + grid_to_battery: 0, + battery_to_grid: 0, + used_solar: 1, + used_grid: 5, + used_battery: 0, + solar_to_battery: 3, + solar_to_grid: 3, + } + ); + assert.deepEqual( + computeConsumptionSingle({ + from_grid: 5, + to_grid: 3, + solar: 7, + to_battery: 3, + from_battery: 10, + }), + { + grid_to_battery: 0, + battery_to_grid: 0, + used_solar: 1, + used_grid: 5, + used_battery: 10, + solar_to_battery: 3, + solar_to_grid: 3, + } + ); + assert.deepEqual( + computeConsumptionSingle({ + from_grid: 2, + to_grid: 7, + solar: 7, + to_battery: 1, + from_battery: 1, + }), + { + grid_to_battery: 1, + battery_to_grid: 0, + used_solar: 0, + used_grid: 1, + used_battery: 1, + solar_to_battery: 0, + solar_to_grid: 7, + } + ); + assert.deepEqual( + computeConsumptionSingle({ + from_grid: 2, + to_grid: 7, + solar: 9, + to_battery: 1, + from_battery: 1, + }), + { + grid_to_battery: 0, + battery_to_grid: 0, + used_solar: 1, + used_grid: 2, + used_battery: 1, + solar_to_battery: 1, + solar_to_grid: 7, + } + ); + /* Test does not pass + assert.deepEqual( + computeConsumptionSingle({ + from_grid: 5, + to_grid: 3, + solar: 1, + to_battery: 0, + from_battery: 2, + }), + { + grid_to_battery: 0, + battery_to_grid: 2, + used_solar: 0, + used_grid: 5, + used_battery: 0, + } + ); + */ + }); +});