Skip to content

Commit f69a0b5

Browse files
authored
Merge pull request #315 from MindFreeze/fix-314
fix(#314): handle grid export in new energy format without flow_to
2 parents f3c1c6d + 5333d1b commit f69a0b5

File tree

2 files changed

+73
-3
lines changed

2 files changed

+73
-3
lines changed

__tests__/autoconfig.test.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,72 @@ describe('SankeyChart autoconfig', () => {
3838
sankeyChart.setConfig({ ...DEFAULT_CONFIG, autoconfig: {} }, true);
3939
});
4040

41+
it('creates grid export entity for new format with stat_energy_to', async () => {
42+
hass.states['sensor.grid_out'] = { entity_id: 'sensor.grid_out', state: '3' } as any;
43+
(getEnergyPreferences as jest.Mock).mockResolvedValue({
44+
energy_sources: [
45+
{ type: 'grid', stat_energy_from: 'sensor.grid_in', stat_energy_to: 'sensor.grid_out' },
46+
{ type: 'solar', stat_energy_from: 'sensor.solar' },
47+
],
48+
device_consumption: [
49+
{ stat_consumption: 'sensor.device1', name: 'Device 1' },
50+
],
51+
});
52+
(getEntitiesByArea as jest.Mock).mockResolvedValue({
53+
area1: { area: { area_id: 'area1', name: 'Area 1' }, entities: ['sensor.device1'] },
54+
});
55+
(fetchFloorRegistry as jest.Mock).mockResolvedValue([]);
56+
57+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
58+
await (sankeyChart as any)['autoconfig']();
59+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
60+
const config = (sankeyChart as any).config;
61+
const allEntities = config.sections.flatMap((s: { entities: { entity_id: string }[] }) => s.entities);
62+
const gridExport = allEntities.find((e: { entity_id: string }) => e.entity_id === 'sensor.grid_out');
63+
expect(gridExport).toBeDefined();
64+
expect(gridExport.subtract_entities).toEqual(['sensor.grid_in']);
65+
// all source entities should have grid export as a child
66+
const sourceEntities = config.sections[0].entities;
67+
sourceEntities.forEach((e: { children: string[] }) => {
68+
expect(e.children).toContain('sensor.grid_out');
69+
});
70+
});
71+
72+
it('creates grid export entity for old format with flow_to', async () => {
73+
hass.states['sensor.grid_out'] = { entity_id: 'sensor.grid_out', state: '3' } as any;
74+
(getEnergyPreferences as jest.Mock).mockResolvedValue({
75+
energy_sources: [
76+
{
77+
type: 'grid',
78+
flow_from: [{ stat_energy_from: 'sensor.grid_in' }],
79+
flow_to: [{ stat_energy_to: 'sensor.grid_out' }],
80+
},
81+
{ type: 'solar', stat_energy_from: 'sensor.solar' },
82+
],
83+
device_consumption: [
84+
{ stat_consumption: 'sensor.device1', name: 'Device 1' },
85+
],
86+
});
87+
(getEntitiesByArea as jest.Mock).mockResolvedValue({
88+
area1: { area: { area_id: 'area1', name: 'Area 1' }, entities: ['sensor.device1'] },
89+
});
90+
(fetchFloorRegistry as jest.Mock).mockResolvedValue([]);
91+
92+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
93+
await (sankeyChart as any)['autoconfig']();
94+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
95+
const config = (sankeyChart as any).config;
96+
const allEntities = config.sections.flatMap((s: { entities: { entity_id: string }[] }) => s.entities);
97+
const gridExport = allEntities.find((e: { entity_id: string }) => e.entity_id === 'sensor.grid_out');
98+
expect(gridExport).toBeDefined();
99+
expect(gridExport.subtract_entities).toEqual(['sensor.grid_in']);
100+
// all source entities should have grid export as a child
101+
const sourceEntities = config.sections[0].entities;
102+
sourceEntities.forEach((e: { children: string[] }) => {
103+
expect(e.children).toContain('sensor.grid_out');
104+
});
105+
});
106+
41107
it('creates sections from energy preferences', async () => {
42108
(getEnergyPreferences as jest.Mock).mockResolvedValue({
43109
energy_sources: [

src/ha-sankey-chart.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,14 +290,18 @@ class SankeyChart extends SubscribeMixin(LitElement) {
290290
const gridSources = sources.filter(s => s.type === 'grid');
291291
const seenFlowTo = new Set<string>();
292292
gridSources.forEach(grid => {
293-
if (grid?.flow_to?.length) {
293+
const exportEntities = grid.flow_to?.map(e => e.stat_energy_to) ??
294+
(grid.stat_energy_to ? [grid.stat_energy_to] : []);
295+
const importEntities = grid.flow_from?.map(e => e.stat_energy_from) ??
296+
(grid.stat_energy_from ? [grid.stat_energy_from] : []);
297+
if (exportEntities.length) {
294298
// grid export
295-
grid.flow_to.forEach(({ stat_energy_to }) => {
299+
exportEntities.forEach(stat_energy_to => {
296300
if (seenFlowTo.has(stat_energy_to)) return;
297301
seenFlowTo.add(stat_energy_to);
298302
sections[1].entities.unshift({
299303
entity_id: stat_energy_to,
300-
subtract_entities: (grid.flow_from || []).map(e => e.stat_energy_from),
304+
subtract_entities: importEntities,
301305
type: 'entity',
302306
color: getEnergySourceColor(grid.type),
303307
children: [],

0 commit comments

Comments
 (0)