@camstack/addon-provider-homeassistant 1.2.161 → 1.2.163

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-C3T2aMHG.js");
2
+ const require_dist = require("./dist-D4ygl7eZ.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
@@ -255,13 +255,13 @@ var HaEntityStateSchema = require_dist.object({
255
255
  var HaAuthConfigSchema = require_dist.discriminatedUnion("kind", [require_dist.object({
256
256
  kind: require_dist.literal("supervisor"),
257
257
  /** Token injected by the Supervisor at runtime via env. */
258
- supervisorToken: require_dist.string().min(1)
258
+ supervisorToken: require_dist.string().min(1).meta({ secret: true })
259
259
  }), require_dist.object({
260
260
  kind: require_dist.literal("long-lived"),
261
261
  /** Origin URL of the HA instance (e.g. `https://hassio.local:8123`). */
262
262
  baseUrl: require_dist.url(),
263
263
  /** Long-lived access token issued by the user in their HA profile. */
264
- accessToken: require_dist.string().min(1)
264
+ accessToken: require_dist.string().min(1).meta({ secret: true })
265
265
  })]);
266
266
  /** HA's standard domain enum — supported subset; future domains added
267
267
  * as integration coverage grows. */
@@ -486,7 +486,7 @@ var HaBaseChildDevice = class HaBaseChildDevice extends require_dist.BaseDevice
486
486
  * device's cap-state slice and persist via `this.runtimeState`.
487
487
  * Called on every WS push matching this entity. Default: no-op.
488
488
  */
489
- handleStatePush(_state) {}
489
+ handleStatePush(_state, _push) {}
490
490
  /**
491
491
  * Issue an HA service call for this device's entity. The target's
492
492
  * entity_id is pinned to `this.entityId` automatically. Returns the
@@ -566,6 +566,7 @@ var HaBaseChildDevice = class HaBaseChildDevice extends require_dist.BaseDevice
566
566
  this.lastLoggedState = state.state;
567
567
  }
568
568
  const reachable = state.state !== "unavailable" && state.state !== "unknown";
569
+ const push = { afterOutage: reachable && !this.online };
569
570
  if (this.online !== reachable) {
570
571
  this.deviceLogger.info("HA→device online transition", { meta: {
571
572
  entityId: this.entityId,
@@ -575,7 +576,7 @@ var HaBaseChildDevice = class HaBaseChildDevice extends require_dist.BaseDevice
575
576
  this.markOnline(reachable);
576
577
  }
577
578
  try {
578
- this.handleStatePush(state);
579
+ this.handleStatePush(state, push);
579
580
  } catch (err) {
580
581
  this.deviceLogger.warn("ha-child state-push handler error", { meta: {
581
582
  entityId: this.entityId,
@@ -930,6 +931,22 @@ function pickSupportedCap(capabilities) {
930
931
  function hostsNumericSensor(capabilities) {
931
932
  return capabilities.some((c) => SUPPORTED_CAP_NAMES$1.includes(c));
932
933
  }
934
+ function haChangeStamp(input) {
935
+ const prior = input.priorChangedAt;
936
+ const priorKnown = prior !== void 0 && Number.isFinite(prior) && prior > 0;
937
+ if (priorKnown && input.sameValue) return {
938
+ kind: "kept",
939
+ at: prior
940
+ };
941
+ if (!priorKnown && input.afterOutage) return {
942
+ kind: "seeded",
943
+ at: 1
944
+ };
945
+ return {
946
+ kind: "ha",
947
+ at: input.haChangedAt
948
+ };
949
+ }
933
950
  //#endregion
934
951
  //#region src/devices/ha-binary-sensor-device.ts
935
952
  var SUPPORTED_CAP_NAMES = [
@@ -968,12 +985,22 @@ var HaBinarySensorDevice = class extends HaBaseChildDevice {
968
985
  const seededChangedAt = storedChangedAt(capName, stored) ?? 0;
969
986
  this.runtimeState.setCapState(this.capName, buildSlice(capName, seededActive, seededChangedAt, stored));
970
987
  }
971
- handleStatePush(state) {
988
+ handleStatePush(state, push) {
972
989
  if (state.state === "unavailable" || state.state === "unknown") return;
973
990
  const active = state.state === "on";
974
- const lastChangedAt = Date.parse(state.last_changed) || Date.now();
975
991
  const prior = this.runtimeState.getCapState(this.capName);
976
- this.runtimeState.setCapState(this.capName, buildSlice(this.capName, active, lastChangedAt, prior));
992
+ const stamp = haChangeStamp({
993
+ sameValue: storedActiveLevel(this.capName, prior) === active,
994
+ priorChangedAt: storedChangedAt(this.capName, prior),
995
+ haChangedAt: Date.parse(state.last_changed) || Date.now(),
996
+ afterOutage: push.afterOutage
997
+ });
998
+ if (stamp.kind === "seeded") this.deviceLogger.info("HA→device recovery with no known prior value — no change time", { meta: {
999
+ entityId: this.entityId,
1000
+ cap: this.capName,
1001
+ value: state.state
1002
+ } });
1003
+ this.runtimeState.setCapState(this.capName, buildSlice(this.capName, active, stamp.at, prior));
977
1004
  }
978
1005
  registerCap(name) {
979
1006
  switch (name) {
@@ -1335,18 +1362,29 @@ var HaCoverDevice = class extends HaBaseChildDevice {
1335
1362
  this.registerCoverCap();
1336
1363
  this.runtimeState.setCapState("cover", COLD_START$18);
1337
1364
  }
1338
- handleStatePush(state) {
1365
+ handleStatePush(state, push) {
1339
1366
  if (state.state === "unavailable" || state.state === "unknown") return;
1340
- const lastChangedAt = Date.parse(state.last_changed) || Date.now();
1341
1367
  const lifecycleState = mapHaStateToCoverState(state.state);
1342
1368
  if (lifecycleState === null) return;
1343
1369
  const position = readNumericAttr$4(state.attributes, "current_position");
1344
1370
  const tilt = readNumericAttr$4(state.attributes, "current_tilt_position");
1371
+ const prior = this.runtimeState.getCapState("cover");
1372
+ const stamp = haChangeStamp({
1373
+ sameValue: prior?.state === lifecycleState,
1374
+ priorChangedAt: prior?.lastChangedAt,
1375
+ haChangedAt: Date.parse(state.last_changed) || Date.now(),
1376
+ afterOutage: push.afterOutage
1377
+ });
1378
+ if (stamp.kind === "seeded") this.deviceLogger.info("HA→device recovery with no known prior value — no change time", { meta: {
1379
+ entityId: this.entityId,
1380
+ cap: "cover",
1381
+ value: state.state
1382
+ } });
1345
1383
  this.runtimeState.setCapState("cover", {
1346
1384
  state: lifecycleState,
1347
1385
  position,
1348
1386
  tiltPosition: tilt,
1349
- lastChangedAt
1387
+ lastChangedAt: stamp.at
1350
1388
  });
1351
1389
  }
1352
1390
  registerCoverCap() {
@@ -1473,14 +1511,25 @@ var HaLockDevice = class extends HaBaseChildDevice {
1473
1511
  this.registerLockCap();
1474
1512
  this.runtimeState.setCapState("lock-control", COLD_START$16);
1475
1513
  }
1476
- handleStatePush(state) {
1514
+ handleStatePush(state, push) {
1477
1515
  if (state.state === "unavailable" || state.state === "unknown") return;
1478
- const lastChangedAt = Date.parse(state.last_changed) || Date.now();
1479
1516
  const lifecycleState = mapHaStateToLockState(state.state);
1480
1517
  if (lifecycleState === null) return;
1518
+ const prior = this.runtimeState.getCapState("lock-control");
1519
+ const stamp = haChangeStamp({
1520
+ sameValue: prior?.state === lifecycleState,
1521
+ priorChangedAt: prior?.lastChangedAt,
1522
+ haChangedAt: Date.parse(state.last_changed) || Date.now(),
1523
+ afterOutage: push.afterOutage
1524
+ });
1525
+ if (stamp.kind === "seeded") this.deviceLogger.info("HA→device recovery with no known prior value — no change time", { meta: {
1526
+ entityId: this.entityId,
1527
+ cap: "lock-control",
1528
+ value: state.state
1529
+ } });
1481
1530
  this.runtimeState.setCapState("lock-control", {
1482
1531
  state: lifecycleState,
1483
- lastChangedAt
1532
+ lastChangedAt: stamp.at
1484
1533
  });
1485
1534
  }
1486
1535
  registerLockCap() {
@@ -5311,11 +5360,11 @@ var HaBrokerEntrySchema = require_dist.object({
5311
5360
  /** Either Supervisor (token from env) or long-lived (persisted). */
5312
5361
  auth: require_dist.discriminatedUnion("kind", [require_dist.object({
5313
5362
  kind: require_dist.literal("supervisor"),
5314
- supervisorToken: require_dist.string()
5363
+ supervisorToken: require_dist.string().meta({ secret: true })
5315
5364
  }), require_dist.object({
5316
5365
  kind: require_dist.literal("long-lived"),
5317
5366
  baseUrl: require_dist.string(),
5318
- accessToken: require_dist.string()
5367
+ accessToken: require_dist.string().meta({ secret: true })
5319
5368
  })]),
5320
5369
  /** Optional FK to the integration record that spawned this broker.
5321
5370
  * Populated when the wizard's "+ New Integration" flow created the
@@ -5334,8 +5383,8 @@ var HaBrokerEntrySchema = require_dist.object({
5334
5383
  */
5335
5384
  var HaAddSettingsSchema = require_dist.union([require_dist.object({
5336
5385
  baseUrl: require_dist.url(),
5337
- accessToken: require_dist.string().min(1)
5338
- }), require_dist.object({ supervisorToken: require_dist.string().min(1) })]);
5386
+ accessToken: require_dist.string().min(1).meta({ secret: true })
5387
+ }), require_dist.object({ supervisorToken: require_dist.string().min(1).meta({ secret: true }) })]);
5339
5388
  function settingsToAuth(settings) {
5340
5389
  const parsed = HaAddSettingsSchema.parse(settings);
5341
5390
  if ("supervisorToken" in parsed) return {
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as connectivityCapability, At as record, B as floodCapability, C as buildAddonRouteProvider, Ct as _enum, D as carbonMonoxideCapability, Dt as literal, E as calendarSourceCapability, Et as discriminatedUnion, F as deviceAdoptionCapability, Ft as EventCategory, G as lawnMowerControlCapability, H as humidifierCapability, J as motionCapability, K as lockControlCapability, L as enumSensorCapability, M as controlCapability, Mt as union, N as coverCapability, Nt as unknown, O as climateControlCapability, Ot as number, P as deviceAdminLinkCapability, Pt as url, Q as numericSensorCapability, R as eventEmitterCapability, S as brokerCapability, T as buttonCapability, Tt as boolean, U as humiditySensorCapability, V as gasCapability, W as imageCapability, X as notificationOutputCapability, Y as normalizeUnit, Z as notifierCapability, _ as automationControlCapability, _t as DeviceRole, at as scriptRunnerCapability, b as binaryCapability, ct as tamperCapability, d as TargetSchema, dt as vacuumControlCapability, et as parseAdminBase, f as accessoriesCapability, ft as valveCapability, g as ambientLightSensorCapability, gt as DeviceFeature, h as alarmPanelCapability, ht as weatherCapability, it as pressureSensorCapability, j as contactCapability, jt as string, k as colorCapability, kt as object, lt as temperatureSensorCapability, m as airQualitySensorCapability, mt as waterHeaterCapability, n as BaseDevice, nt as prepareNotification, ot as smokeCapability, p as addonRoutesCapability, pt as vibrationCapability, q as mediaPlayerCapability, r as BaseDeviceProvider, rt as presenceCapability, s as EnumSensorDateTimeFormatSchema, st as switchCapability, tt as powerMeterCapability, ut as updateCapability, v as batteryCapability, vt as DeviceType, w as buildDeviceAdminUrl, wt as array, x as brightnessCapability, xt as createEvent, y as bestLocationMatch, yt as errMsg, z as fanControlCapability } from "./dist-B1FEp9mY.mjs";
1
+ import { A as connectivityCapability, At as record, B as floodCapability, C as buildAddonRouteProvider, Ct as _enum, D as carbonMonoxideCapability, Dt as literal, E as calendarSourceCapability, Et as discriminatedUnion, F as deviceAdoptionCapability, Ft as EventCategory, G as lawnMowerControlCapability, H as humidifierCapability, J as motionCapability, K as lockControlCapability, L as enumSensorCapability, M as controlCapability, Mt as union, N as coverCapability, Nt as unknown, O as climateControlCapability, Ot as number, P as deviceAdminLinkCapability, Pt as url, Q as numericSensorCapability, R as eventEmitterCapability, S as brokerCapability, T as buttonCapability, Tt as boolean, U as humiditySensorCapability, V as gasCapability, W as imageCapability, X as notificationOutputCapability, Y as normalizeUnit, Z as notifierCapability, _ as automationControlCapability, _t as DeviceRole, at as scriptRunnerCapability, b as binaryCapability, ct as tamperCapability, d as TargetSchema, dt as vacuumControlCapability, et as parseAdminBase, f as accessoriesCapability, ft as valveCapability, g as ambientLightSensorCapability, gt as DeviceFeature, h as alarmPanelCapability, ht as weatherCapability, it as pressureSensorCapability, j as contactCapability, jt as string, k as colorCapability, kt as object, lt as temperatureSensorCapability, m as airQualitySensorCapability, mt as waterHeaterCapability, n as BaseDevice, nt as prepareNotification, ot as smokeCapability, p as addonRoutesCapability, pt as vibrationCapability, q as mediaPlayerCapability, r as BaseDeviceProvider, rt as presenceCapability, s as EnumSensorDateTimeFormatSchema, st as switchCapability, tt as powerMeterCapability, ut as updateCapability, v as batteryCapability, vt as DeviceType, w as buildDeviceAdminUrl, wt as array, x as brightnessCapability, xt as createEvent, y as bestLocationMatch, yt as errMsg, z as fanControlCapability } from "./dist-CDvVJ5hh.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
@@ -254,13 +254,13 @@ var HaEntityStateSchema = object({
254
254
  var HaAuthConfigSchema = discriminatedUnion("kind", [object({
255
255
  kind: literal("supervisor"),
256
256
  /** Token injected by the Supervisor at runtime via env. */
257
- supervisorToken: string().min(1)
257
+ supervisorToken: string().min(1).meta({ secret: true })
258
258
  }), object({
259
259
  kind: literal("long-lived"),
260
260
  /** Origin URL of the HA instance (e.g. `https://hassio.local:8123`). */
261
261
  baseUrl: url(),
262
262
  /** Long-lived access token issued by the user in their HA profile. */
263
- accessToken: string().min(1)
263
+ accessToken: string().min(1).meta({ secret: true })
264
264
  })]);
265
265
  /** HA's standard domain enum — supported subset; future domains added
266
266
  * as integration coverage grows. */
@@ -485,7 +485,7 @@ var HaBaseChildDevice = class HaBaseChildDevice extends BaseDevice {
485
485
  * device's cap-state slice and persist via `this.runtimeState`.
486
486
  * Called on every WS push matching this entity. Default: no-op.
487
487
  */
488
- handleStatePush(_state) {}
488
+ handleStatePush(_state, _push) {}
489
489
  /**
490
490
  * Issue an HA service call for this device's entity. The target's
491
491
  * entity_id is pinned to `this.entityId` automatically. Returns the
@@ -565,6 +565,7 @@ var HaBaseChildDevice = class HaBaseChildDevice extends BaseDevice {
565
565
  this.lastLoggedState = state.state;
566
566
  }
567
567
  const reachable = state.state !== "unavailable" && state.state !== "unknown";
568
+ const push = { afterOutage: reachable && !this.online };
568
569
  if (this.online !== reachable) {
569
570
  this.deviceLogger.info("HA→device online transition", { meta: {
570
571
  entityId: this.entityId,
@@ -574,7 +575,7 @@ var HaBaseChildDevice = class HaBaseChildDevice extends BaseDevice {
574
575
  this.markOnline(reachable);
575
576
  }
576
577
  try {
577
- this.handleStatePush(state);
578
+ this.handleStatePush(state, push);
578
579
  } catch (err) {
579
580
  this.deviceLogger.warn("ha-child state-push handler error", { meta: {
580
581
  entityId: this.entityId,
@@ -929,6 +930,22 @@ function pickSupportedCap(capabilities) {
929
930
  function hostsNumericSensor(capabilities) {
930
931
  return capabilities.some((c) => SUPPORTED_CAP_NAMES$1.includes(c));
931
932
  }
933
+ function haChangeStamp(input) {
934
+ const prior = input.priorChangedAt;
935
+ const priorKnown = prior !== void 0 && Number.isFinite(prior) && prior > 0;
936
+ if (priorKnown && input.sameValue) return {
937
+ kind: "kept",
938
+ at: prior
939
+ };
940
+ if (!priorKnown && input.afterOutage) return {
941
+ kind: "seeded",
942
+ at: 1
943
+ };
944
+ return {
945
+ kind: "ha",
946
+ at: input.haChangedAt
947
+ };
948
+ }
932
949
  //#endregion
933
950
  //#region src/devices/ha-binary-sensor-device.ts
934
951
  var SUPPORTED_CAP_NAMES = [
@@ -967,12 +984,22 @@ var HaBinarySensorDevice = class extends HaBaseChildDevice {
967
984
  const seededChangedAt = storedChangedAt(capName, stored) ?? 0;
968
985
  this.runtimeState.setCapState(this.capName, buildSlice(capName, seededActive, seededChangedAt, stored));
969
986
  }
970
- handleStatePush(state) {
987
+ handleStatePush(state, push) {
971
988
  if (state.state === "unavailable" || state.state === "unknown") return;
972
989
  const active = state.state === "on";
973
- const lastChangedAt = Date.parse(state.last_changed) || Date.now();
974
990
  const prior = this.runtimeState.getCapState(this.capName);
975
- this.runtimeState.setCapState(this.capName, buildSlice(this.capName, active, lastChangedAt, prior));
991
+ const stamp = haChangeStamp({
992
+ sameValue: storedActiveLevel(this.capName, prior) === active,
993
+ priorChangedAt: storedChangedAt(this.capName, prior),
994
+ haChangedAt: Date.parse(state.last_changed) || Date.now(),
995
+ afterOutage: push.afterOutage
996
+ });
997
+ if (stamp.kind === "seeded") this.deviceLogger.info("HA→device recovery with no known prior value — no change time", { meta: {
998
+ entityId: this.entityId,
999
+ cap: this.capName,
1000
+ value: state.state
1001
+ } });
1002
+ this.runtimeState.setCapState(this.capName, buildSlice(this.capName, active, stamp.at, prior));
976
1003
  }
977
1004
  registerCap(name) {
978
1005
  switch (name) {
@@ -1334,18 +1361,29 @@ var HaCoverDevice = class extends HaBaseChildDevice {
1334
1361
  this.registerCoverCap();
1335
1362
  this.runtimeState.setCapState("cover", COLD_START$18);
1336
1363
  }
1337
- handleStatePush(state) {
1364
+ handleStatePush(state, push) {
1338
1365
  if (state.state === "unavailable" || state.state === "unknown") return;
1339
- const lastChangedAt = Date.parse(state.last_changed) || Date.now();
1340
1366
  const lifecycleState = mapHaStateToCoverState(state.state);
1341
1367
  if (lifecycleState === null) return;
1342
1368
  const position = readNumericAttr$4(state.attributes, "current_position");
1343
1369
  const tilt = readNumericAttr$4(state.attributes, "current_tilt_position");
1370
+ const prior = this.runtimeState.getCapState("cover");
1371
+ const stamp = haChangeStamp({
1372
+ sameValue: prior?.state === lifecycleState,
1373
+ priorChangedAt: prior?.lastChangedAt,
1374
+ haChangedAt: Date.parse(state.last_changed) || Date.now(),
1375
+ afterOutage: push.afterOutage
1376
+ });
1377
+ if (stamp.kind === "seeded") this.deviceLogger.info("HA→device recovery with no known prior value — no change time", { meta: {
1378
+ entityId: this.entityId,
1379
+ cap: "cover",
1380
+ value: state.state
1381
+ } });
1344
1382
  this.runtimeState.setCapState("cover", {
1345
1383
  state: lifecycleState,
1346
1384
  position,
1347
1385
  tiltPosition: tilt,
1348
- lastChangedAt
1386
+ lastChangedAt: stamp.at
1349
1387
  });
1350
1388
  }
1351
1389
  registerCoverCap() {
@@ -1472,14 +1510,25 @@ var HaLockDevice = class extends HaBaseChildDevice {
1472
1510
  this.registerLockCap();
1473
1511
  this.runtimeState.setCapState("lock-control", COLD_START$16);
1474
1512
  }
1475
- handleStatePush(state) {
1513
+ handleStatePush(state, push) {
1476
1514
  if (state.state === "unavailable" || state.state === "unknown") return;
1477
- const lastChangedAt = Date.parse(state.last_changed) || Date.now();
1478
1515
  const lifecycleState = mapHaStateToLockState(state.state);
1479
1516
  if (lifecycleState === null) return;
1517
+ const prior = this.runtimeState.getCapState("lock-control");
1518
+ const stamp = haChangeStamp({
1519
+ sameValue: prior?.state === lifecycleState,
1520
+ priorChangedAt: prior?.lastChangedAt,
1521
+ haChangedAt: Date.parse(state.last_changed) || Date.now(),
1522
+ afterOutage: push.afterOutage
1523
+ });
1524
+ if (stamp.kind === "seeded") this.deviceLogger.info("HA→device recovery with no known prior value — no change time", { meta: {
1525
+ entityId: this.entityId,
1526
+ cap: "lock-control",
1527
+ value: state.state
1528
+ } });
1480
1529
  this.runtimeState.setCapState("lock-control", {
1481
1530
  state: lifecycleState,
1482
- lastChangedAt
1531
+ lastChangedAt: stamp.at
1483
1532
  });
1484
1533
  }
1485
1534
  registerLockCap() {
@@ -5310,11 +5359,11 @@ var HaBrokerEntrySchema = object({
5310
5359
  /** Either Supervisor (token from env) or long-lived (persisted). */
5311
5360
  auth: discriminatedUnion("kind", [object({
5312
5361
  kind: literal("supervisor"),
5313
- supervisorToken: string()
5362
+ supervisorToken: string().meta({ secret: true })
5314
5363
  }), object({
5315
5364
  kind: literal("long-lived"),
5316
5365
  baseUrl: string(),
5317
- accessToken: string()
5366
+ accessToken: string().meta({ secret: true })
5318
5367
  })]),
5319
5368
  /** Optional FK to the integration record that spawned this broker.
5320
5369
  * Populated when the wizard's "+ New Integration" flow created the
@@ -5333,8 +5382,8 @@ var HaBrokerEntrySchema = object({
5333
5382
  */
5334
5383
  var HaAddSettingsSchema = union([object({
5335
5384
  baseUrl: url(),
5336
- accessToken: string().min(1)
5337
- }), object({ supervisorToken: string().min(1) })]);
5385
+ accessToken: string().min(1).meta({ secret: true })
5386
+ }), object({ supervisorToken: string().min(1).meta({ secret: true }) })]);
5338
5387
  function settingsToAuth(settings) {
5339
5388
  const parsed = HaAddSettingsSchema.parse(settings);
5340
5389
  if ("supervisorToken" in parsed) return {