Skip to content

Commit 31603ea

Browse files
authored
20251203.1 (#28383)
2 parents d77bebe + 17c1043 commit 31603ea

23 files changed

+295
-121
lines changed

build-scripts/gulp/translations.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,9 @@ const createTestTranslation = () =>
156156
*/
157157
const createMasterTranslation = () =>
158158
gulp
159-
.src([EN_SRC, ...(mergeBackend ? [`${inBackendDir}/en.json`] : [])])
159+
.src([EN_SRC, ...(mergeBackend ? [`${inBackendDir}/en.json`] : [])], {
160+
allowEmpty: true,
161+
})
160162
.pipe(new CustomJSON(lokaliseTransform))
161163
.pipe(new MergeJSON("en"))
162164
.pipe(gulp.dest(workDir));

demo/src/stubs/energy.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,47 +44,73 @@ export const mockEnergy = (hass: MockHomeAssistant) => {
4444
number_energy_price: null,
4545
},
4646
],
47+
power: [
48+
{ stat_rate: "sensor.power_grid" },
49+
{ stat_rate: "sensor.power_grid_return" },
50+
],
4751
cost_adjustment_day: 0,
4852
},
4953
{
5054
type: "solar",
5155
stat_energy_from: "sensor.solar_production",
56+
stat_rate: "sensor.power_solar",
5257
config_entry_solar_forecast: ["solar_forecast"],
5358
},
54-
/* {
59+
{
5560
type: "battery",
5661
stat_energy_from: "sensor.battery_output",
5762
stat_energy_to: "sensor.battery_input",
58-
}, */
63+
stat_rate: "sensor.power_battery",
64+
},
5965
{
6066
type: "gas",
6167
stat_energy_from: "sensor.energy_gas",
6268
stat_cost: "sensor.energy_gas_cost",
6369
entity_energy_price: null,
6470
number_energy_price: null,
6571
},
72+
{
73+
type: "water",
74+
stat_energy_from: "sensor.energy_water",
75+
stat_cost: "sensor.energy_water_cost",
76+
entity_energy_price: null,
77+
number_energy_price: null,
78+
},
6679
],
6780
device_consumption: [
6881
{
6982
stat_consumption: "sensor.energy_car",
83+
stat_rate: "sensor.power_car",
7084
},
7185
{
7286
stat_consumption: "sensor.energy_ac",
87+
stat_rate: "sensor.power_ac",
7388
},
7489
{
7590
stat_consumption: "sensor.energy_washing_machine",
91+
stat_rate: "sensor.power_washing_machine",
7692
},
7793
{
7894
stat_consumption: "sensor.energy_dryer",
95+
stat_rate: "sensor.power_dryer",
7996
},
8097
{
8198
stat_consumption: "sensor.energy_heat_pump",
99+
stat_rate: "sensor.power_heat_pump",
82100
},
83101
{
84102
stat_consumption: "sensor.energy_boiler",
103+
stat_rate: "sensor.power_boiler",
104+
},
105+
],
106+
device_consumption_water: [
107+
{
108+
stat_consumption: "sensor.water_kitchen",
109+
},
110+
{
111+
stat_consumption: "sensor.water_garden",
85112
},
86113
],
87-
device_consumption_water: [],
88114
})
89115
);
90116
hass.mockWS(

demo/src/stubs/entities.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,38 @@ export const energyEntities = () =>
154154
unit_of_measurement: "EUR",
155155
},
156156
},
157+
"sensor.power_grid": {
158+
entity_id: "sensor.power_grid",
159+
state: "500",
160+
attributes: {
161+
state_class: "measurement",
162+
unit_of_measurement: "W",
163+
},
164+
},
165+
"sensor.power_grid_return": {
166+
entity_id: "sensor.power_grid_return",
167+
state: "-100",
168+
attributes: {
169+
state_class: "measurement",
170+
unit_of_measurement: "W",
171+
},
172+
},
173+
"sensor.power_solar": {
174+
entity_id: "sensor.power_solar",
175+
state: "200",
176+
attributes: {
177+
state_class: "measurement",
178+
unit_of_measurement: "W",
179+
},
180+
},
181+
"sensor.power_battery": {
182+
entity_id: "sensor.power_battery",
183+
state: "100",
184+
attributes: {
185+
state_class: "measurement",
186+
unit_of_measurement: "W",
187+
},
188+
},
157189
"sensor.energy_gas_cost": {
158190
entity_id: "sensor.energy_gas_cost",
159191
state: "2",
@@ -171,6 +203,15 @@ export const energyEntities = () =>
171203
unit_of_measurement: "m³",
172204
},
173205
},
206+
"sensor.energy_water": {
207+
entity_id: "sensor.energy_water",
208+
state: "4000",
209+
attributes: {
210+
last_reset: "1970-01-01T00:00:00:00+00",
211+
friendly_name: "Water",
212+
unit_of_measurement: "L",
213+
},
214+
},
174215
"sensor.energy_car": {
175216
entity_id: "sensor.energy_car",
176217
state: "4",
@@ -225,4 +266,58 @@ export const energyEntities = () =>
225266
unit_of_measurement: "kWh",
226267
},
227268
},
269+
"sensor.power_car": {
270+
entity_id: "sensor.power_car",
271+
state: "40",
272+
attributes: {
273+
state_class: "measurement",
274+
friendly_name: "Electric car",
275+
unit_of_measurement: "W",
276+
},
277+
},
278+
"sensor.power_ac": {
279+
entity_id: "sensor.power_ac",
280+
state: "30",
281+
attributes: {
282+
state_class: "measurement",
283+
friendly_name: "Air conditioning",
284+
unit_of_measurement: "W",
285+
},
286+
},
287+
"sensor.power_washing_machine": {
288+
entity_id: "sensor.power_washing_machine",
289+
state: "60",
290+
attributes: {
291+
state_class: "measurement",
292+
friendly_name: "Washing machine",
293+
unit_of_measurement: "W",
294+
},
295+
},
296+
"sensor.power_dryer": {
297+
entity_id: "sensor.power_dryer",
298+
state: "55",
299+
attributes: {
300+
state_class: "measurement",
301+
friendly_name: "Dryer",
302+
unit_of_measurement: "W",
303+
},
304+
},
305+
"sensor.power_heat_pump": {
306+
entity_id: "sensor.power_heat_pump",
307+
state: "60",
308+
attributes: {
309+
state_class: "measurement",
310+
friendly_name: "Heat pump",
311+
unit_of_measurement: "W",
312+
},
313+
},
314+
"sensor.power_boiler": {
315+
entity_id: "sensor.power_boiler",
316+
state: "70",
317+
attributes: {
318+
state_class: "measurement",
319+
friendly_name: "Boiler",
320+
unit_of_measurement: "W",
321+
},
322+
},
228323
});

demo/src/stubs/recorder.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,15 @@ const generateMeanStatistics = (
1717
end: Date,
1818
// eslint-disable-next-line default-param-last
1919
period: "5minute" | "hour" | "day" | "month" = "hour",
20-
initValue: number,
2120
maxDiff: number
2221
): StatisticValue[] => {
2322
const statistics: StatisticValue[] = [];
2423
let currentDate = new Date(start);
2524
currentDate.setMinutes(0, 0, 0);
26-
let lastVal = initValue;
2725
const now = new Date();
2826
while (end > currentDate && currentDate < now) {
2927
const delta = Math.random() * maxDiff;
30-
const mean = lastVal + delta;
28+
const mean = delta;
3129
statistics.push({
3230
start: currentDate.getTime(),
3331
end: currentDate.getTime(),
@@ -38,7 +36,6 @@ const generateMeanStatistics = (
3836
state: mean,
3937
sum: null,
4038
});
41-
lastVal = mean;
4239
currentDate =
4340
period === "day"
4441
? addDays(currentDate, 1)
@@ -336,7 +333,6 @@ export const mockRecorder = (mockHass: MockHomeAssistant) => {
336333
start,
337334
end,
338335
period,
339-
state,
340336
state * (state > 80 ? 0.05 : 0.1)
341337
);
342338
}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "home-assistant-frontend"
7-
version = "20251203.0"
7+
version = "20251203.1"
88
license = "Apache-2.0"
99
license-files = ["LICENSE*"]
1010
description = "The Home Assistant frontend"

src/components/ha-markdown-element.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,7 @@ class HaMarkdownElement extends ReactiveElement {
9999
}
100100
);
101101

102-
render(
103-
elements.map((e) => h(unsafeHTML(e))),
104-
this.renderRoot
105-
);
102+
render(h(unsafeHTML(elements.join(""))), this.renderRoot);
106103

107104
this._resize();
108105

src/components/ha-markdown.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ export class HaMarkdown extends LitElement {
2525

2626
@property({ type: Boolean }) public cache = false;
2727

28-
@query("ha-markdown-element") private _markdownElement!: ReactiveElement;
28+
@query("ha-markdown-element") private _markdownElement?: ReactiveElement;
2929

3030
protected async getUpdateComplete() {
3131
const result = await super.getUpdateComplete();
32-
await this._markdownElement.updateComplete;
32+
await this._markdownElement?.updateComplete;
3333
return result;
3434
}
3535

src/components/ha-snowflakes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ export class HaSnowflakes extends SubscribeMixin(LitElement) {
3131
this.hass!.connection,
3232
"frontend",
3333
"winter_mode",
34-
(enabled) => {
35-
this._enabled = enabled;
34+
(feature) => {
35+
this._enabled = feature.enabled;
3636
}
3737
),
3838
];

src/data/energy.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
isLastDayOfMonth,
1212
addYears,
1313
} from "date-fns";
14-
import type { Collection } from "home-assistant-js-websocket";
14+
import type { Collection, HassEntity } from "home-assistant-js-websocket";
1515
import { getCollection } from "home-assistant-js-websocket";
1616
import memoizeOne from "memoize-one";
1717
import {
@@ -1361,3 +1361,37 @@ export const calculateSolarConsumedGauge = (
13611361
}
13621362
return undefined;
13631363
};
1364+
1365+
/**
1366+
* Get current power value from entity state, normalized to kW
1367+
* @param stateObj - The entity state object to get power value from
1368+
* @returns Power value in kW, or 0 if entity not found or invalid
1369+
*/
1370+
export const getPowerFromState = (stateObj: HassEntity): number | undefined => {
1371+
if (!stateObj) {
1372+
return undefined;
1373+
}
1374+
const value = parseFloat(stateObj.state);
1375+
if (isNaN(value)) {
1376+
return undefined;
1377+
}
1378+
1379+
// Normalize to kW based on unit of measurement (case-sensitive)
1380+
// Supported units: GW, kW, MW, mW, TW, W
1381+
const unit = stateObj.attributes.unit_of_measurement;
1382+
switch (unit) {
1383+
case "W":
1384+
return value / 1000;
1385+
case "mW":
1386+
return value / 1000000;
1387+
case "MW":
1388+
return value * 1000;
1389+
case "GW":
1390+
return value * 1000000;
1391+
case "TW":
1392+
return value * 1000000000;
1393+
default:
1394+
// Assume kW if no unit or unit is kW
1395+
return value;
1396+
}
1397+
};

src/data/labs.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,22 +101,18 @@ export const subscribeLabFeatures = (
101101
* Subscribe to a specific lab feature
102102
* @param conn - The connection to the Home Assistant instance
103103
* @param domain - The domain of the lab feature
104-
* @param previewFeature - The preview feature of the lab feature
104+
* @param previewFeature - The preview feature identifier
105105
* @param onChange - The function to call when the lab feature changes
106-
* @returns The unsubscribe function
106+
* @returns A promise that resolves to the unsubscribe function
107107
*/
108108
export const subscribeLabFeature = (
109109
conn: Connection,
110110
domain: string,
111111
previewFeature: string,
112-
onChange: (enabled: boolean) => void
113-
) =>
114-
subscribeLabFeatures(conn, (features) => {
115-
const enabled =
116-
features.find(
117-
(feature) =>
118-
feature.domain === domain &&
119-
feature.preview_feature === previewFeature
120-
)?.enabled ?? false;
121-
onChange(enabled);
112+
onChange: (feature: LabPreviewFeature) => void
113+
): Promise<() => void> =>
114+
conn.subscribeMessage<LabPreviewFeature>(onChange, {
115+
type: "labs/subscribe",
116+
domain,
117+
preview_feature: previewFeature,
122118
});

0 commit comments

Comments
 (0)