@camstack/addon-provider-homeassistant 1.2.151 → 1.2.153

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/dist/addon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("./dist-Cn_fSOpM.js");
2
+ const require_dist = require("./dist-DMn4t1u_.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
@@ -960,7 +960,9 @@ var HaBinarySensorDevice = class extends HaBaseChildDevice {
960
960
  this.capName = capName;
961
961
  this.registerCap(capName);
962
962
  const stored = this.runtimeState.getCapState(capName);
963
- this.runtimeState.setCapState(this.capName, buildSlice(capName, false, 0, stored));
963
+ const seededActive = storedActiveLevel(capName, stored) ?? false;
964
+ const seededChangedAt = storedChangedAt(capName, stored) ?? 0;
965
+ this.runtimeState.setCapState(this.capName, buildSlice(capName, seededActive, seededChangedAt, stored));
964
966
  }
965
967
  handleStatePush(state) {
966
968
  if (state.state === "unavailable" || state.state === "unknown") return;
@@ -1052,6 +1054,32 @@ function priorLastDetectedAt(prior) {
1052
1054
  const raw = prior?.["lastDetectedAt"];
1053
1055
  return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : null;
1054
1056
  }
1057
+ /** The boolean field this cap's slice uses as "active". */
1058
+ function activeFieldName(capName) {
1059
+ switch (capName) {
1060
+ case "contact": return "entryOpen";
1061
+ case "flood": return "flooded";
1062
+ case "tamper": return "tampered";
1063
+ case "connectivity": return "connected";
1064
+ case "binary": return "on";
1065
+ case "smoke":
1066
+ case "carbon-monoxide":
1067
+ case "gas":
1068
+ case "vibration":
1069
+ case "motion": return "detected";
1070
+ }
1071
+ }
1072
+ function storedActiveLevel(capName, stored) {
1073
+ if (stored === void 0) return void 0;
1074
+ const raw = stored[activeFieldName(capName)];
1075
+ return typeof raw === "boolean" ? raw : void 0;
1076
+ }
1077
+ function storedChangedAt(capName, stored) {
1078
+ if (stored === void 0) return void 0;
1079
+ if (capName === "motion") return priorLastDetectedAt(stored) ?? void 0;
1080
+ const raw = stored["lastChangedAt"];
1081
+ return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : void 0;
1082
+ }
1055
1083
  function buildSlice(capName, active, lastChangedAt, prior) {
1056
1084
  switch (capName) {
1057
1085
  case "contact": return {
@@ -7371,11 +7399,14 @@ function buildFreshStandaloneSpec(entity) {
7371
7399
  /** Stable key over the class-affecting fields — drives the drift decision.
7372
7400
  * Excludes `type` (compared directly) but folds it in so a pure type change
7373
7401
  * (same caps, different DeviceType — shouldn't happen but defensively safe)
7374
- * still counts. */
7402
+ * still counts. **Role is deliberately omitted**: after adopt, Role is
7403
+ * operator-owned (`setRole` in the UI). Including it here made every mapping
7404
+ * / capability drift re-push the derived role via `applyDerivedSpec` and
7405
+ * revert the Role select by itself.
7406
+ */
7375
7407
  function standaloneDerivedKey(s) {
7376
7408
  return JSON.stringify({
7377
7409
  type: s.type,
7378
- role: s.role ?? null,
7379
7410
  capabilities: [...s.capabilities],
7380
7411
  unitOfMeasurement: s.unitOfMeasurement ?? null,
7381
7412
  deviceClass: s.deviceClass ?? null,
@@ -7385,7 +7416,8 @@ function standaloneDerivedKey(s) {
7385
7416
  });
7386
7417
  }
7387
7418
  /** The config patch pushed via `applyDerivedSpec` on drift — the class-affecting
7388
- * fields only (mirrors the Container reconcile's `childConfigPatch`). */
7419
+ * fields only (mirrors the Container reconcile's `childConfigPatch`), minus
7420
+ * `role` which is operator-owned after adopt and must not be clobbered. */
7389
7421
  function standaloneConfigPatch(s) {
7390
7422
  return {
7391
7423
  capabilities: [...s.capabilities],
@@ -7393,22 +7425,21 @@ function standaloneConfigPatch(s) {
7393
7425
  ...s.deviceClass !== void 0 ? { deviceClass: s.deviceClass } : {},
7394
7426
  ...s.options !== void 0 ? { options: [...s.options] } : {},
7395
7427
  ...s.features !== void 0 ? { features: [...s.features] } : {},
7396
- ...s.role !== void 0 ? { role: s.role } : {},
7397
7428
  ...s.dateTimeFormat !== void 0 ? { dateTimeFormat: s.dateTimeFormat } : {}
7398
7429
  };
7399
7430
  }
7400
7431
  /**
7401
7432
  * Diff a persisted standalone entity device against the fresh HA mapping. Pure —
7402
- * no I/O. On drift the caller pushes `{ type, role?, config }` through
7433
+ * no I/O. On drift the caller pushes `{ type, config }` through
7403
7434
  * `kernel.devices.applyDerivedSpec(deviceId, …)`; the captured cap-re-derive
7404
7435
  * factory rebuilds the concrete per-domain class from the new `capabilities`.
7436
+ * Role is never part of the patch — it is operator-owned after adopt.
7405
7437
  */
7406
7438
  function diffStandaloneEntity(persisted, fresh) {
7407
7439
  if (standaloneDerivedKey(persisted) === standaloneDerivedKey(fresh)) return { changed: false };
7408
7440
  return {
7409
7441
  changed: true,
7410
7442
  type: fresh.type,
7411
- ...fresh.role !== void 0 ? { role: fresh.role } : {},
7412
7443
  config: standaloneConfigPatch(fresh)
7413
7444
  };
7414
7445
  }
@@ -7438,7 +7469,7 @@ function standaloneEntityId(device) {
7438
7469
  * Pure re-sync planner. Given the broker's live registry `devices` and the
7439
7470
  * FRESH entity inventory (by entityId), enumerate the broker's STANDALONE entity
7440
7471
  * devices and produce one `applyDerivedSpec` action per device whose
7441
- * capability/class/role drifted. No I/O.
7472
+ * capability/class drifted. Role is never re-derived (operator-owned). No I/O.
7442
7473
  *
7443
7474
  * - Non-standalone / other-broker / Container / accessory-child devices →
7444
7475
  * skipped (via {@link isStandaloneEntityDevice}).
@@ -7460,7 +7491,6 @@ function planStandaloneReconcile(devices, freshById, brokerId) {
7460
7491
  actions.push({
7461
7492
  deviceId: device.id,
7462
7493
  ...diff.type !== void 0 ? { type: diff.type } : {},
7463
- ...diff.role !== void 0 ? { role: diff.role } : {},
7464
7494
  ...diff.config !== void 0 ? { config: diff.config } : {}
7465
7495
  });
7466
7496
  }
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as parseAdminBase, A as contactCapability, At as union, B as gasCapability, C as buildAddonRouteProvider, Ct as array, D as climateControlCapability, Dt as object, E as carbonMonoxideCapability, Et as number, G as lockControlCapability, H as humiditySensorCapability, I as enumSensorCapability, J as normalizeUnit, K as mediaPlayerCapability, L as eventEmitterCapability, M as coverCapability, Mt as url, N as deviceAdminLinkCapability, Nt as EventCategory, O as colorCapability, Ot as record, P as deviceAdoptionCapability, R as fanControlCapability, S as brokerCapability, St as _enum, T as buttonCapability, Tt as literal, U as imageCapability, V as humidifierCapability, W as lawnMowerControlCapability, X as notifierCapability, Y as notificationOutputCapability, Z as numericSensorCapability, _ as automationControlCapability, _t as DeviceType, at as smokeCapability, b as binaryCapability, bt as createEvent, ct as temperatureSensorCapability, d as TargetSchema, dt as valveCapability, et as powerMeterCapability, f as accessoriesCapability, ft as vibrationCapability, g as ambientLightSensorCapability, gt as DeviceRole, h as alarmPanelCapability, ht as DeviceFeature, it as scriptRunnerCapability, j as controlCapability, jt as unknown, k as connectivityCapability, kt as string, lt as updateCapability, m as airQualitySensorCapability, mt as weatherCapability, n as BaseDevice, nt as presenceCapability, ot as switchCapability, p as addonRoutesCapability, pt as waterHeaterCapability, q as motionCapability, r as BaseDeviceProvider, rt as pressureSensorCapability, s as EnumSensorDateTimeFormatSchema, st as tamperCapability, tt as prepareNotification, ut as vacuumControlCapability, v as batteryCapability, vt as errMsg, w as buildDeviceAdminUrl, wt as discriminatedUnion, x as brightnessCapability, y as bestLocationMatch, z as floodCapability } from "./dist-DFsf2z4Q.mjs";
1
+ import { $ as parseAdminBase, A as contactCapability, At as union, B as gasCapability, C as buildAddonRouteProvider, Ct as array, D as climateControlCapability, Dt as object, E as carbonMonoxideCapability, Et as number, G as lockControlCapability, H as humiditySensorCapability, I as enumSensorCapability, J as normalizeUnit, K as mediaPlayerCapability, L as eventEmitterCapability, M as coverCapability, Mt as url, N as deviceAdminLinkCapability, Nt as EventCategory, O as colorCapability, Ot as record, P as deviceAdoptionCapability, R as fanControlCapability, S as brokerCapability, St as _enum, T as buttonCapability, Tt as literal, U as imageCapability, V as humidifierCapability, W as lawnMowerControlCapability, X as notifierCapability, Y as notificationOutputCapability, Z as numericSensorCapability, _ as automationControlCapability, _t as DeviceType, at as smokeCapability, b as binaryCapability, bt as createEvent, ct as temperatureSensorCapability, d as TargetSchema, dt as valveCapability, et as powerMeterCapability, f as accessoriesCapability, ft as vibrationCapability, g as ambientLightSensorCapability, gt as DeviceRole, h as alarmPanelCapability, ht as DeviceFeature, it as scriptRunnerCapability, j as controlCapability, jt as unknown, k as connectivityCapability, kt as string, lt as updateCapability, m as airQualitySensorCapability, mt as weatherCapability, n as BaseDevice, nt as presenceCapability, ot as switchCapability, p as addonRoutesCapability, pt as waterHeaterCapability, q as motionCapability, r as BaseDeviceProvider, rt as pressureSensorCapability, s as EnumSensorDateTimeFormatSchema, st as tamperCapability, tt as prepareNotification, ut as vacuumControlCapability, v as batteryCapability, vt as errMsg, w as buildDeviceAdminUrl, wt as discriminatedUnion, x as brightnessCapability, y as bestLocationMatch, z as floodCapability } from "./dist-evNLjXgk.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
4
4
  //#region src/ha-admin-link.ts
@@ -959,7 +959,9 @@ var HaBinarySensorDevice = class extends HaBaseChildDevice {
959
959
  this.capName = capName;
960
960
  this.registerCap(capName);
961
961
  const stored = this.runtimeState.getCapState(capName);
962
- this.runtimeState.setCapState(this.capName, buildSlice(capName, false, 0, stored));
962
+ const seededActive = storedActiveLevel(capName, stored) ?? false;
963
+ const seededChangedAt = storedChangedAt(capName, stored) ?? 0;
964
+ this.runtimeState.setCapState(this.capName, buildSlice(capName, seededActive, seededChangedAt, stored));
963
965
  }
964
966
  handleStatePush(state) {
965
967
  if (state.state === "unavailable" || state.state === "unknown") return;
@@ -1051,6 +1053,32 @@ function priorLastDetectedAt(prior) {
1051
1053
  const raw = prior?.["lastDetectedAt"];
1052
1054
  return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : null;
1053
1055
  }
1056
+ /** The boolean field this cap's slice uses as "active". */
1057
+ function activeFieldName(capName) {
1058
+ switch (capName) {
1059
+ case "contact": return "entryOpen";
1060
+ case "flood": return "flooded";
1061
+ case "tamper": return "tampered";
1062
+ case "connectivity": return "connected";
1063
+ case "binary": return "on";
1064
+ case "smoke":
1065
+ case "carbon-monoxide":
1066
+ case "gas":
1067
+ case "vibration":
1068
+ case "motion": return "detected";
1069
+ }
1070
+ }
1071
+ function storedActiveLevel(capName, stored) {
1072
+ if (stored === void 0) return void 0;
1073
+ const raw = stored[activeFieldName(capName)];
1074
+ return typeof raw === "boolean" ? raw : void 0;
1075
+ }
1076
+ function storedChangedAt(capName, stored) {
1077
+ if (stored === void 0) return void 0;
1078
+ if (capName === "motion") return priorLastDetectedAt(stored) ?? void 0;
1079
+ const raw = stored["lastChangedAt"];
1080
+ return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : void 0;
1081
+ }
1054
1082
  function buildSlice(capName, active, lastChangedAt, prior) {
1055
1083
  switch (capName) {
1056
1084
  case "contact": return {
@@ -7370,11 +7398,14 @@ function buildFreshStandaloneSpec(entity) {
7370
7398
  /** Stable key over the class-affecting fields — drives the drift decision.
7371
7399
  * Excludes `type` (compared directly) but folds it in so a pure type change
7372
7400
  * (same caps, different DeviceType — shouldn't happen but defensively safe)
7373
- * still counts. */
7401
+ * still counts. **Role is deliberately omitted**: after adopt, Role is
7402
+ * operator-owned (`setRole` in the UI). Including it here made every mapping
7403
+ * / capability drift re-push the derived role via `applyDerivedSpec` and
7404
+ * revert the Role select by itself.
7405
+ */
7374
7406
  function standaloneDerivedKey(s) {
7375
7407
  return JSON.stringify({
7376
7408
  type: s.type,
7377
- role: s.role ?? null,
7378
7409
  capabilities: [...s.capabilities],
7379
7410
  unitOfMeasurement: s.unitOfMeasurement ?? null,
7380
7411
  deviceClass: s.deviceClass ?? null,
@@ -7384,7 +7415,8 @@ function standaloneDerivedKey(s) {
7384
7415
  });
7385
7416
  }
7386
7417
  /** The config patch pushed via `applyDerivedSpec` on drift — the class-affecting
7387
- * fields only (mirrors the Container reconcile's `childConfigPatch`). */
7418
+ * fields only (mirrors the Container reconcile's `childConfigPatch`), minus
7419
+ * `role` which is operator-owned after adopt and must not be clobbered. */
7388
7420
  function standaloneConfigPatch(s) {
7389
7421
  return {
7390
7422
  capabilities: [...s.capabilities],
@@ -7392,22 +7424,21 @@ function standaloneConfigPatch(s) {
7392
7424
  ...s.deviceClass !== void 0 ? { deviceClass: s.deviceClass } : {},
7393
7425
  ...s.options !== void 0 ? { options: [...s.options] } : {},
7394
7426
  ...s.features !== void 0 ? { features: [...s.features] } : {},
7395
- ...s.role !== void 0 ? { role: s.role } : {},
7396
7427
  ...s.dateTimeFormat !== void 0 ? { dateTimeFormat: s.dateTimeFormat } : {}
7397
7428
  };
7398
7429
  }
7399
7430
  /**
7400
7431
  * Diff a persisted standalone entity device against the fresh HA mapping. Pure —
7401
- * no I/O. On drift the caller pushes `{ type, role?, config }` through
7432
+ * no I/O. On drift the caller pushes `{ type, config }` through
7402
7433
  * `kernel.devices.applyDerivedSpec(deviceId, …)`; the captured cap-re-derive
7403
7434
  * factory rebuilds the concrete per-domain class from the new `capabilities`.
7435
+ * Role is never part of the patch — it is operator-owned after adopt.
7404
7436
  */
7405
7437
  function diffStandaloneEntity(persisted, fresh) {
7406
7438
  if (standaloneDerivedKey(persisted) === standaloneDerivedKey(fresh)) return { changed: false };
7407
7439
  return {
7408
7440
  changed: true,
7409
7441
  type: fresh.type,
7410
- ...fresh.role !== void 0 ? { role: fresh.role } : {},
7411
7442
  config: standaloneConfigPatch(fresh)
7412
7443
  };
7413
7444
  }
@@ -7437,7 +7468,7 @@ function standaloneEntityId(device) {
7437
7468
  * Pure re-sync planner. Given the broker's live registry `devices` and the
7438
7469
  * FRESH entity inventory (by entityId), enumerate the broker's STANDALONE entity
7439
7470
  * devices and produce one `applyDerivedSpec` action per device whose
7440
- * capability/class/role drifted. No I/O.
7471
+ * capability/class drifted. Role is never re-derived (operator-owned). No I/O.
7441
7472
  *
7442
7473
  * - Non-standalone / other-broker / Container / accessory-child devices →
7443
7474
  * skipped (via {@link isStandaloneEntityDevice}).
@@ -7459,7 +7490,6 @@ function planStandaloneReconcile(devices, freshById, brokerId) {
7459
7490
  actions.push({
7460
7491
  deviceId: device.id,
7461
7492
  ...diff.type !== void 0 ? { type: diff.type } : {},
7462
- ...diff.role !== void 0 ? { role: diff.role } : {},
7463
7493
  ...diff.config !== void 0 ? { config: diff.config } : {}
7464
7494
  });
7465
7495
  }