@camstack/addon-provider-homeassistant 1.2.632 → 1.2.634
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -1
- package/README.md +31 -11
- package/dist/addon.js +83 -60
- package/dist/addon.mjs +83 -60
- package/dist/{dist-CPkvghX8.mjs → dist-6sCUdAUD.mjs} +845 -240
- package/dist/{dist-D0ZiJUPy.js → dist-DSRitvmZ.js} +845 -240
- package/dist/ha-export/ha-export.addon.js +24 -24
- package/dist/ha-export/ha-export.addon.mjs +24 -24
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.634] - 2026-10-28
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Device value fields are named after their quantity instead of their unit; run the quantity-field migration after updating
|
|
15
|
+
|
|
16
|
+
## [1.2.633] - 2026-10-27
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Shown as "Home Assistant" (was "Home Assistant Provider").
|
|
21
|
+
|
|
22
|
+
## [1.2.632] - 2026-10-27
|
|
23
|
+
|
|
10
24
|
### Added
|
|
11
25
|
|
|
12
|
-
-
|
|
26
|
+
- Home Assistant: Home Assistant device provider addon for CamStack.
|
|
27
|
+
- Provides the addons Home Assistant, Home Assistant Export.
|
package/README.md
CHANGED
|
@@ -1,22 +1,42 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Home Assistant
|
|
2
2
|
|
|
3
|
-
Home Assistant device provider addon for CamStack
|
|
3
|
+
Home Assistant device provider addon for CamStack. Device provider (import) + native entity export (push). Two addons, one bundle, separate processes.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<!-- readme:generated:start (derived from the manifest; edit outside this block) -->
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
|
|
7
|
+
Package `@camstack/addon-provider-homeassistant` on npm.
|
|
8
|
+
|
|
9
|
+
## What it provides
|
|
10
|
+
|
|
11
|
+
- **Home Assistant** (`provider-homeassistant`): Adopt Home Assistant devices into CamStack via WebSocket. Category: messaging.
|
|
9
12
|
- Capabilities: `broker`, `device-adoption`, `vacuum-control`, `lawn-mower-control`, `running-state`, `valve`, `humidifier`, `water-heater`, `weather`, `image`, `update`, `notification-output`, `addon-routes`, `calendar-source`.
|
|
10
|
-
- **Home Assistant Export** (`homeassistant-export`): Pushes CamStack entities to the CamStack Home Assistant custom component over HTTP. Chooses which devices reach which Home Assistant instance; Home Assistant never polls the hub for a value.
|
|
11
|
-
- Node placement: `hub-only`.
|
|
13
|
+
- **Home Assistant Export** (`homeassistant-export`): Pushes CamStack entities to the CamStack Home Assistant custom component over HTTP. Chooses which devices reach which Home Assistant instance; Home Assistant never polls the hub for a value. Category: exports.
|
|
12
14
|
- Capabilities: `device-export`, `addon-routes`, `oauth-integration`.
|
|
13
15
|
|
|
14
|
-
##
|
|
16
|
+
## Configuration
|
|
17
|
+
|
|
18
|
+
Edit these from System, Addons, this addon, Settings (a device's own settings are on its device page). A password field is stored in the keychain.
|
|
19
|
+
|
|
20
|
+
**Addon settings**
|
|
15
21
|
|
|
16
|
-
|
|
22
|
+
- Calendars to import: Calendars
|
|
23
|
+
- Home Assistant broker: Brokers are managed separately
|
|
24
|
+
- Home Assistant connection: Auth mode, HA base URL, Long-lived access token, Supervisor token
|
|
25
|
+
- Home Assistant instances: No brokers
|
|
26
|
+
- Connection: Hub URL Home Assistant can reach
|
|
27
|
+
- Advanced: Reconcile interval (s)
|
|
17
28
|
|
|
18
29
|
## Requirements
|
|
19
30
|
|
|
20
|
-
-
|
|
21
|
-
- A CamStack hub. An agent is used only
|
|
31
|
+
- Placement: hub-only.
|
|
32
|
+
- A CamStack hub. An agent is used only where the placement above allows it.
|
|
33
|
+
|
|
34
|
+
## Documentation
|
|
35
|
+
|
|
36
|
+
- [docs/addons/addon-provider-homeassistant.md](https://github.com/camstack/server/blob/main/docs/addons/addon-provider-homeassistant.md)
|
|
37
|
+
- [docs/architecture/device-model.md](https://github.com/camstack/server/blob/main/docs/architecture/device-model.md)
|
|
38
|
+
- [packages/addon-provider-homeassistant/AGENTS.md](https://github.com/camstack/server/blob/main/packages/addon-provider-homeassistant/AGENTS.md)
|
|
39
|
+
|
|
40
|
+
See [CHANGELOG.md](./CHANGELOG.md) for what changed in each version.
|
|
22
41
|
|
|
42
|
+
<!-- readme:generated:end -->
|
package/dist/addon.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-DSRitvmZ.js");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
let node_zlib = require("node:zlib");
|
|
5
5
|
//#region src/ha-admin-link.ts
|
|
@@ -129,10 +129,10 @@ var haSourceSchemaFields = {
|
|
|
129
129
|
features: require_dist.array(require_dist.string()).optional(),
|
|
130
130
|
/** Sibling meter sensors whose readings this entity carries as `power-meter` (D951). */
|
|
131
131
|
meterEntities: require_dist.object({
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
132
|
+
power: require_dist.string().optional(),
|
|
133
|
+
energy: require_dist.string().optional(),
|
|
134
|
+
voltage: require_dist.string().optional(),
|
|
135
|
+
current: require_dist.string().optional()
|
|
136
136
|
}).optional()
|
|
137
137
|
};
|
|
138
138
|
/** Project a persisted config blob into a typed source, or null when the
|
|
@@ -332,26 +332,26 @@ function takeReading(logger, deviceId, value, rawUnit, quantity) {
|
|
|
332
332
|
*/
|
|
333
333
|
/** The `power-meter` status field a reading lands in. */
|
|
334
334
|
var METER_FIELDS = [
|
|
335
|
-
"
|
|
336
|
-
"
|
|
337
|
-
"
|
|
338
|
-
"
|
|
335
|
+
"power",
|
|
336
|
+
"energy",
|
|
337
|
+
"voltage",
|
|
338
|
+
"current"
|
|
339
339
|
];
|
|
340
340
|
var METER_BY_DEVICE_CLASS = {
|
|
341
341
|
power: {
|
|
342
|
-
field: "
|
|
342
|
+
field: "power",
|
|
343
343
|
quantity: "power"
|
|
344
344
|
},
|
|
345
345
|
energy: {
|
|
346
|
-
field: "
|
|
346
|
+
field: "energy",
|
|
347
347
|
quantity: "energy"
|
|
348
348
|
},
|
|
349
349
|
voltage: {
|
|
350
|
-
field: "
|
|
350
|
+
field: "voltage",
|
|
351
351
|
quantity: "voltage"
|
|
352
352
|
},
|
|
353
353
|
current: {
|
|
354
|
-
field: "
|
|
354
|
+
field: "current",
|
|
355
355
|
quantity: "current"
|
|
356
356
|
}
|
|
357
357
|
};
|
|
@@ -953,10 +953,10 @@ var SUPPORTED_CAP_NAMES$1 = [
|
|
|
953
953
|
];
|
|
954
954
|
/** Map a supported cap to its canonical "value" field. */
|
|
955
955
|
var VALUE_FIELD = {
|
|
956
|
-
"temperature-sensor": "
|
|
957
|
-
"humidity-sensor": "
|
|
958
|
-
"ambient-light-sensor": "
|
|
959
|
-
"pressure-sensor": "
|
|
956
|
+
"temperature-sensor": "temperature",
|
|
957
|
+
"humidity-sensor": "humidity",
|
|
958
|
+
"ambient-light-sensor": "illuminance",
|
|
959
|
+
"pressure-sensor": "pressure",
|
|
960
960
|
"numeric-sensor": "value"
|
|
961
961
|
};
|
|
962
962
|
/** Typed sensors already name their quantity. The generic sensor learns it. */
|
|
@@ -1080,7 +1080,7 @@ var HaNumericSensorDevice = class extends HaBaseChildDevice {
|
|
|
1080
1080
|
switch (name) {
|
|
1081
1081
|
case "temperature-sensor": {
|
|
1082
1082
|
const COLD_START = {
|
|
1083
|
-
|
|
1083
|
+
temperature: 0,
|
|
1084
1084
|
lastFetchedAt: 0
|
|
1085
1085
|
};
|
|
1086
1086
|
this.ctx.registerNativeCap(require_dist.temperatureSensorCapability, { getStatus: async () => this.readSlice(COLD_START) });
|
|
@@ -1088,7 +1088,7 @@ var HaNumericSensorDevice = class extends HaBaseChildDevice {
|
|
|
1088
1088
|
}
|
|
1089
1089
|
case "humidity-sensor": {
|
|
1090
1090
|
const COLD_START = {
|
|
1091
|
-
|
|
1091
|
+
humidity: 0,
|
|
1092
1092
|
lastFetchedAt: 0
|
|
1093
1093
|
};
|
|
1094
1094
|
this.ctx.registerNativeCap(require_dist.humiditySensorCapability, { getStatus: async () => this.readSlice(COLD_START) });
|
|
@@ -1096,7 +1096,7 @@ var HaNumericSensorDevice = class extends HaBaseChildDevice {
|
|
|
1096
1096
|
}
|
|
1097
1097
|
case "ambient-light-sensor": {
|
|
1098
1098
|
const COLD_START = {
|
|
1099
|
-
|
|
1099
|
+
illuminance: 0,
|
|
1100
1100
|
lastFetchedAt: 0
|
|
1101
1101
|
};
|
|
1102
1102
|
this.ctx.registerNativeCap(require_dist.ambientLightSensorCapability, { getStatus: async () => this.readSlice(COLD_START) });
|
|
@@ -1104,7 +1104,7 @@ var HaNumericSensorDevice = class extends HaBaseChildDevice {
|
|
|
1104
1104
|
}
|
|
1105
1105
|
case "pressure-sensor": {
|
|
1106
1106
|
const COLD_START = {
|
|
1107
|
-
|
|
1107
|
+
pressure: 0,
|
|
1108
1108
|
lastFetchedAt: 0
|
|
1109
1109
|
};
|
|
1110
1110
|
this.ctx.registerNativeCap(require_dist.pressureSensorCapability, { getStatus: async () => this.readSlice(COLD_START) });
|
|
@@ -1400,7 +1400,7 @@ var HaLightDevice = class extends HaBaseChildDevice {
|
|
|
1400
1400
|
lastChangedAt: 0
|
|
1401
1401
|
});
|
|
1402
1402
|
if (this.capSet.has("brightness")) this.runtimeState.setCapState("brightness", {
|
|
1403
|
-
|
|
1403
|
+
level: 0,
|
|
1404
1404
|
lastChangedAt: 0
|
|
1405
1405
|
});
|
|
1406
1406
|
if (this.capSet.has("color")) this.runtimeState.setCapState("color", {
|
|
@@ -1420,7 +1420,7 @@ var HaLightDevice = class extends HaBaseChildDevice {
|
|
|
1420
1420
|
if (haBrightness !== null) {
|
|
1421
1421
|
const percentage = Math.max(0, Math.min(100, Math.round(haBrightness / 255 * 100)));
|
|
1422
1422
|
this.runtimeState.setCapState("brightness", {
|
|
1423
|
-
percentage,
|
|
1423
|
+
level: percentage,
|
|
1424
1424
|
lastChangedAt
|
|
1425
1425
|
});
|
|
1426
1426
|
}
|
|
@@ -1450,11 +1450,11 @@ var HaLightDevice = class extends HaBaseChildDevice {
|
|
|
1450
1450
|
this.ctx.registerNativeCap(require_dist.brightnessCapability, {
|
|
1451
1451
|
getStatus: async () => {
|
|
1452
1452
|
return this.runtimeState.getCapState("brightness") ?? {
|
|
1453
|
-
|
|
1453
|
+
level: 0,
|
|
1454
1454
|
lastChangedAt: 0
|
|
1455
1455
|
};
|
|
1456
1456
|
},
|
|
1457
|
-
setBrightness: async ({ percentage }) => {
|
|
1457
|
+
setBrightness: async ({ level: percentage }) => {
|
|
1458
1458
|
await this.callHaService("light", "turn_on", { brightness_pct: percentage });
|
|
1459
1459
|
}
|
|
1460
1460
|
});
|
|
@@ -1513,7 +1513,7 @@ function decodeColorSlice(colorMode, attrs, lastChangedAt) {
|
|
|
1513
1513
|
const mireds = readNumberAttr$6(attrs, "color_temp");
|
|
1514
1514
|
if (mireds !== null) return {
|
|
1515
1515
|
mode: "mired",
|
|
1516
|
-
mireds,
|
|
1516
|
+
colorTemperature: mireds,
|
|
1517
1517
|
lastChangedAt
|
|
1518
1518
|
};
|
|
1519
1519
|
return null;
|
|
@@ -1531,7 +1531,7 @@ function colorInputToHaServiceData(color) {
|
|
|
1531
1531
|
hs_color: [color.hsv.h, color.hsv.s],
|
|
1532
1532
|
brightness_pct: color.hsv.v
|
|
1533
1533
|
};
|
|
1534
|
-
case "mired": return { color_temp: color.
|
|
1534
|
+
case "mired": return { color_temp: color.colorTemperature };
|
|
1535
1535
|
}
|
|
1536
1536
|
}
|
|
1537
1537
|
//#endregion
|
|
@@ -2159,7 +2159,7 @@ function readNumberAttr$3(attrs, key) {
|
|
|
2159
2159
|
//#endregion
|
|
2160
2160
|
//#region src/devices/ha-fan-device.ts
|
|
2161
2161
|
var FAN_COLD_START = {
|
|
2162
|
-
|
|
2162
|
+
speed: null,
|
|
2163
2163
|
preset: "",
|
|
2164
2164
|
availablePresets: [],
|
|
2165
2165
|
direction: null,
|
|
@@ -2195,7 +2195,7 @@ var HaFanDevice = class extends HaBaseChildDevice {
|
|
|
2195
2195
|
});
|
|
2196
2196
|
const attrs = state.attributes;
|
|
2197
2197
|
const slice = {
|
|
2198
|
-
|
|
2198
|
+
speed: readNumberAttr$2(attrs, "percentage"),
|
|
2199
2199
|
percentageStep: readNumberAttr$2(attrs, "percentage_step") ?? void 0,
|
|
2200
2200
|
preset: readStringAttr$4(attrs, "preset_mode") ?? "",
|
|
2201
2201
|
availablePresets: readStringArray$1(attrs, "preset_modes"),
|
|
@@ -2223,7 +2223,7 @@ var HaFanDevice = class extends HaBaseChildDevice {
|
|
|
2223
2223
|
getStatus: async () => {
|
|
2224
2224
|
return this.runtimeState.getCapState("fan-control") ?? FAN_COLD_START;
|
|
2225
2225
|
},
|
|
2226
|
-
setPercentage: async ({ percentage }) => {
|
|
2226
|
+
setPercentage: async ({ speed: percentage }) => {
|
|
2227
2227
|
await this.callHaService("fan", "set_percentage", { percentage });
|
|
2228
2228
|
},
|
|
2229
2229
|
setPreset: async ({ preset }) => {
|
|
@@ -2265,7 +2265,7 @@ var COLD_START$12 = {
|
|
|
2265
2265
|
batteryLevel: null,
|
|
2266
2266
|
fanSpeed: null,
|
|
2267
2267
|
availableFanSpeeds: [],
|
|
2268
|
-
|
|
2268
|
+
progress: null,
|
|
2269
2269
|
errorCode: null,
|
|
2270
2270
|
errorLabel: null,
|
|
2271
2271
|
lastChangedAt: 0
|
|
@@ -2302,7 +2302,7 @@ var HaVacuumDevice = class extends HaBaseChildDevice {
|
|
|
2302
2302
|
batteryLevel,
|
|
2303
2303
|
fanSpeed,
|
|
2304
2304
|
availableFanSpeeds,
|
|
2305
|
-
|
|
2305
|
+
progress: null,
|
|
2306
2306
|
errorCode: null,
|
|
2307
2307
|
errorLabel: lifecycleState === "error" ? readStringAttr$3(state.attributes, "error") : null,
|
|
2308
2308
|
lastChangedAt
|
|
@@ -2367,7 +2367,7 @@ function readStringArrayAttr(attrs, key) {
|
|
|
2367
2367
|
var COLD_START$11 = {
|
|
2368
2368
|
activity: "idle",
|
|
2369
2369
|
batteryLevel: null,
|
|
2370
|
-
|
|
2370
|
+
progress: null,
|
|
2371
2371
|
currentCode: null,
|
|
2372
2372
|
currentCodeLabel: null,
|
|
2373
2373
|
severity: "info",
|
|
@@ -2397,7 +2397,7 @@ var HaLawnMowerDevice = class extends HaBaseChildDevice {
|
|
|
2397
2397
|
if (activity !== null) this.runtimeState.setCapState("lawn-mower-control", {
|
|
2398
2398
|
activity,
|
|
2399
2399
|
batteryLevel,
|
|
2400
|
-
|
|
2400
|
+
progress: readNumericAttr$1(state.attributes, "mowing_progress"),
|
|
2401
2401
|
currentCode: null,
|
|
2402
2402
|
currentCodeLabel: null,
|
|
2403
2403
|
severity: activity === "error" ? "error" : "info",
|
|
@@ -2448,8 +2448,8 @@ var COLD_START$10 = {
|
|
|
2448
2448
|
source: "",
|
|
2449
2449
|
availableSources: [],
|
|
2450
2450
|
currentMedia: null,
|
|
2451
|
-
|
|
2452
|
-
|
|
2451
|
+
position: null,
|
|
2452
|
+
duration: null,
|
|
2453
2453
|
shuffle: null,
|
|
2454
2454
|
repeat: null,
|
|
2455
2455
|
lastChangedAt: 0
|
|
@@ -2479,8 +2479,8 @@ var HaMediaPlayerDevice = class extends HaBaseChildDevice {
|
|
|
2479
2479
|
source: readStringAttr$2(attrs, "source") ?? "",
|
|
2480
2480
|
availableSources: readStringArray(attrs, "source_list"),
|
|
2481
2481
|
currentMedia: buildCurrentMedia(attrs),
|
|
2482
|
-
|
|
2483
|
-
|
|
2482
|
+
position: readDurationMs(attrs, "media_position"),
|
|
2483
|
+
duration: readDurationMs(attrs, "media_duration"),
|
|
2484
2484
|
shuffle: readBooleanAttr(attrs, "shuffle"),
|
|
2485
2485
|
repeat: readRepeat(attrs["repeat"]),
|
|
2486
2486
|
lastChangedAt
|
|
@@ -2513,7 +2513,7 @@ var HaMediaPlayerDevice = class extends HaBaseChildDevice {
|
|
|
2513
2513
|
previous: async () => {
|
|
2514
2514
|
await this.callHaService("media_player", "media_previous_track");
|
|
2515
2515
|
},
|
|
2516
|
-
seek: async ({ positionMs }) => {
|
|
2516
|
+
seek: async ({ position: positionMs }) => {
|
|
2517
2517
|
await this.callHaService("media_player", "media_seek", { seek_position: positionMs / 1e3 });
|
|
2518
2518
|
},
|
|
2519
2519
|
setVolume: async ({ volumeLevel }) => {
|
|
@@ -2682,11 +2682,17 @@ function deriveAvailableModes(attrs) {
|
|
|
2682
2682
|
}
|
|
2683
2683
|
//#endregion
|
|
2684
2684
|
//#region src/devices/ha-presence-device.ts
|
|
2685
|
+
/** No reading yet: unknown, never 0 % (D393). */
|
|
2686
|
+
var COLD_BATTERY = {
|
|
2687
|
+
level: null,
|
|
2688
|
+
charging: "unknown",
|
|
2689
|
+
sleeping: false,
|
|
2690
|
+
lastUpdated: 0
|
|
2691
|
+
};
|
|
2685
2692
|
var COLD_START$8 = {
|
|
2686
2693
|
state: "unknown",
|
|
2687
2694
|
location: null,
|
|
2688
2695
|
gps: null,
|
|
2689
|
-
batteryPercent: null,
|
|
2690
2696
|
lastChangedAt: 0
|
|
2691
2697
|
};
|
|
2692
2698
|
/**
|
|
@@ -2696,14 +2702,17 @@ var COLD_START$8 = {
|
|
|
2696
2702
|
*
|
|
2697
2703
|
* HA attributes consumed:
|
|
2698
2704
|
* - `latitude` / `longitude` / `gps_accuracy` → gps envelope
|
|
2699
|
-
* - `battery_level` →
|
|
2705
|
+
* - `battery_level` → the `battery` cap (a presence provider never reports
|
|
2706
|
+
* battery on the presence status)
|
|
2700
2707
|
* - `friendly_name` and the state value drive the `location` label
|
|
2701
2708
|
*/
|
|
2702
2709
|
var HaPresenceDevice = class extends HaBaseChildDevice {
|
|
2703
2710
|
constructor(ctx) {
|
|
2704
2711
|
super(ctx);
|
|
2705
2712
|
this.registerPresenceCap();
|
|
2713
|
+
this.registerBatteryCap();
|
|
2706
2714
|
this.runtimeState.setCapState("presence", COLD_START$8);
|
|
2715
|
+
if (this.runtimeState.getCapState("battery") === void 0) this.runtimeState.setCapState("battery", COLD_BATTERY);
|
|
2707
2716
|
}
|
|
2708
2717
|
handleStatePush(state) {
|
|
2709
2718
|
if (state.state === "unavailable") return;
|
|
@@ -2721,10 +2730,24 @@ var HaPresenceDevice = class extends HaBaseChildDevice {
|
|
|
2721
2730
|
longitude: lon,
|
|
2722
2731
|
accuracyMeters: acc ?? 0
|
|
2723
2732
|
} : null,
|
|
2724
|
-
batteryPercent: battery,
|
|
2725
2733
|
lastChangedAt
|
|
2726
2734
|
};
|
|
2727
2735
|
this.runtimeState.setCapState("presence", slice);
|
|
2736
|
+
if (battery !== null) this.runtimeState.setCapState("battery", {
|
|
2737
|
+
level: Math.min(100, Math.max(0, battery)),
|
|
2738
|
+
charging: "unknown",
|
|
2739
|
+
sleeping: false,
|
|
2740
|
+
lastUpdated: lastChangedAt
|
|
2741
|
+
});
|
|
2742
|
+
}
|
|
2743
|
+
registerBatteryCap() {
|
|
2744
|
+
this.ctx.registerNativeCap(require_dist.batteryCapability, {
|
|
2745
|
+
getStatus: async () => this.runtimeState.getCapState("battery") ?? COLD_BATTERY,
|
|
2746
|
+
wakeForStream: async () => ({
|
|
2747
|
+
awoke: true,
|
|
2748
|
+
durationMs: 0
|
|
2749
|
+
})
|
|
2750
|
+
});
|
|
2728
2751
|
}
|
|
2729
2752
|
registerPresenceCap() {
|
|
2730
2753
|
this.ctx.registerNativeCap(require_dist.presenceCapability, { getStatus: async () => {
|
|
@@ -3200,7 +3223,7 @@ var HaNotifierDevice = class extends HaBaseChildDevice {
|
|
|
3200
3223
|
var COLD_START$4 = { lastFetchedAt: 0 };
|
|
3201
3224
|
/**
|
|
3202
3225
|
* HA-backed power-meter sensor child. Multi-field cap — the slice
|
|
3203
|
-
* carries `
|
|
3226
|
+
* carries `power` / `voltage` / `current` / `energy` etc., but each HA
|
|
3204
3227
|
* `sensor.*` entity surfaces ONE metric (device_class = `power` /
|
|
3205
3228
|
* `voltage` / `current` / `energy`). The class populates the field
|
|
3206
3229
|
* corresponding to the entity's device_class.
|
|
@@ -3263,22 +3286,22 @@ function applyDeviceClass$1(prev, deviceClass, value, lastFetchedAt) {
|
|
|
3263
3286
|
switch (deviceClass) {
|
|
3264
3287
|
case "power": return {
|
|
3265
3288
|
...prev,
|
|
3266
|
-
|
|
3289
|
+
power: value,
|
|
3267
3290
|
lastFetchedAt
|
|
3268
3291
|
};
|
|
3269
3292
|
case "energy": return {
|
|
3270
3293
|
...prev,
|
|
3271
|
-
|
|
3294
|
+
energy: value,
|
|
3272
3295
|
lastFetchedAt
|
|
3273
3296
|
};
|
|
3274
3297
|
case "voltage": return {
|
|
3275
3298
|
...prev,
|
|
3276
|
-
|
|
3299
|
+
voltage: value,
|
|
3277
3300
|
lastFetchedAt
|
|
3278
3301
|
};
|
|
3279
3302
|
case "current": return {
|
|
3280
3303
|
...prev,
|
|
3281
|
-
|
|
3304
|
+
current: value,
|
|
3282
3305
|
lastFetchedAt
|
|
3283
3306
|
};
|
|
3284
3307
|
default: return null;
|
|
@@ -3344,12 +3367,12 @@ function applyDeviceClass(prev, deviceClass, value, lastFetchedAt) {
|
|
|
3344
3367
|
switch (deviceClass) {
|
|
3345
3368
|
case "co2": return {
|
|
3346
3369
|
...prev,
|
|
3347
|
-
|
|
3370
|
+
co2: value,
|
|
3348
3371
|
lastFetchedAt
|
|
3349
3372
|
};
|
|
3350
3373
|
case "volatile_organic_compounds": return {
|
|
3351
3374
|
...prev,
|
|
3352
|
-
|
|
3375
|
+
voc: value,
|
|
3353
3376
|
lastFetchedAt
|
|
3354
3377
|
};
|
|
3355
3378
|
case "pm25":
|
|
@@ -3854,10 +3877,10 @@ var containerEntitySchema = require_dist.object({
|
|
|
3854
3877
|
dateTimeFormat: require_dist.EnumSensorDateTimeFormatSchema.optional(),
|
|
3855
3878
|
entityCategory: require_dist._enum(["config", "diagnostic"]).optional(),
|
|
3856
3879
|
meterEntities: require_dist.object({
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3880
|
+
power: require_dist.string().optional(),
|
|
3881
|
+
energy: require_dist.string().optional(),
|
|
3882
|
+
voltage: require_dist.string().optional(),
|
|
3883
|
+
current: require_dist.string().optional()
|
|
3861
3884
|
}).optional(),
|
|
3862
3885
|
foldedInto: require_dist.string().optional()
|
|
3863
3886
|
});
|
|
@@ -4041,10 +4064,10 @@ var haEntitySchema = require_dist.object({
|
|
|
4041
4064
|
entityCategory: require_dist._enum(["config", "diagnostic"]).optional(),
|
|
4042
4065
|
/** Sibling meter sensors this entity reads as its own power-meter (D951). */
|
|
4043
4066
|
meterEntities: require_dist.object({
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4067
|
+
power: require_dist.string().optional(),
|
|
4068
|
+
energy: require_dist.string().optional(),
|
|
4069
|
+
voltage: require_dist.string().optional(),
|
|
4070
|
+
current: require_dist.string().optional()
|
|
4048
4071
|
}).optional(),
|
|
4049
4072
|
/** Set on a meter sensor folded into another entity: sectioned as Diagnostic. */
|
|
4050
4073
|
foldedInto: require_dist.string().optional()
|
|
@@ -4119,7 +4142,7 @@ function deriveBatteryStatus(entities, entityId, state, now) {
|
|
|
4119
4142
|
if (isBinaryBattery(battery)) {
|
|
4120
4143
|
if (state.state !== "on" && state.state !== "off") return null;
|
|
4121
4144
|
return {
|
|
4122
|
-
|
|
4145
|
+
level: state.state === "on" ? BINARY_BATTERY_LOW_PCT : BINARY_BATTERY_NORMAL_PCT,
|
|
4123
4146
|
charging: "none",
|
|
4124
4147
|
sleeping: false,
|
|
4125
4148
|
lastUpdated: now,
|
|
@@ -4129,7 +4152,7 @@ function deriveBatteryStatus(entities, entityId, state, now) {
|
|
|
4129
4152
|
const raw = Number(state.state);
|
|
4130
4153
|
if (!Number.isFinite(raw)) return null;
|
|
4131
4154
|
return {
|
|
4132
|
-
|
|
4155
|
+
level: Math.min(100, Math.max(0, raw)),
|
|
4133
4156
|
charging: "none",
|
|
4134
4157
|
sleeping: false,
|
|
4135
4158
|
lastUpdated: now
|
|
@@ -4186,7 +4209,7 @@ var HaContainerDevice = class HaContainerDevice extends require_dist.BaseDevice
|
|
|
4186
4209
|
this.batteryEntityId = batteryEntityId(cfg.entities);
|
|
4187
4210
|
if (this.batteryEntityId !== null) {
|
|
4188
4211
|
const COLD = {
|
|
4189
|
-
|
|
4212
|
+
level: null,
|
|
4190
4213
|
charging: "unknown",
|
|
4191
4214
|
sleeping: false,
|
|
4192
4215
|
lastUpdated: 0
|