homebridge-tydom 0.32.0 → 0.32.2

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/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { n as PLUGIN_NAME, t as PLATFORM_NAME } from "./env-B2-Dw8C2.mjs";
2
2
  //#region src/index.ts
3
3
  process.setSourceMapsEnabled(true);
4
- const { default: TydomPlatform } = await import("./platform-DmVGk0po.mjs");
4
+ const { default: TydomPlatform } = await import("./platform-CJBHeITb.mjs");
5
5
  var src_default = (homebridge) => {
6
6
  homebridge.registerPlatform(PLUGIN_NAME, PLATFORM_NAME, TydomPlatform);
7
7
  };
@@ -3875,6 +3875,12 @@ var GarageDoorAccessory = class extends BaseAccessory {
3875
3875
  /** Some drivers expose only TOGGLE and cannot be commanded to a state. */
3876
3876
  #toggleOnly;
3877
3877
  #currentDoorState;
3878
+ /**
3879
+ * Where the door was last asked to go. TargetDoorState only admits OPEN and
3880
+ * CLOSED, so it cannot mirror the current state through OPENING, CLOSING or
3881
+ * STOPPED.
3882
+ */
3883
+ #targetDoorState;
3878
3884
  #lastUpdatedAt = 0;
3879
3885
  #computedPosition = 0;
3880
3886
  #transition;
@@ -3888,6 +3894,7 @@ var GarageDoorAccessory = class extends BaseAccessory {
3888
3894
  const levelCmdValues = metadata.find((m) => m.name === "levelCmd")?.enum_values;
3889
3895
  this.#toggleOnly = levelCmdValues?.length === 1 && levelCmdValues[0] === "TOGGLE";
3890
3896
  this.#currentDoorState = CurrentDoorState.CLOSED;
3897
+ this.#targetDoorState = TargetDoorState.CLOSED;
3891
3898
  const legacy = this.accessory.getService(this.platform.Service.Switch);
3892
3899
  if (legacy) this.accessory.removeService(legacy);
3893
3900
  this.#service = this.service(this.platform.Service.GarageDoorOpener);
@@ -3905,8 +3912,8 @@ var GarageDoorAccessory = class extends BaseAccessory {
3905
3912
  this.#service.getCharacteristic(TargetDoorState).onGet(async () => {
3906
3913
  debugGet(TargetDoorState, this.#service);
3907
3914
  if (this.#toggleOnly) {
3908
- debugGetResult(TargetDoorState, this.#service, this.#currentDoorState);
3909
- return this.#currentDoorState;
3915
+ debugGetResult(TargetDoorState, this.#service, this.#targetDoorState);
3916
+ return this.#targetDoorState;
3910
3917
  }
3911
3918
  const next = await this.#readDoorState();
3912
3919
  this.#lastUpdatedAt = Date.now();
@@ -3955,6 +3962,7 @@ var GarageDoorAccessory = class extends BaseAccessory {
3955
3962
  const { CurrentDoorState } = this.platform.Characteristic;
3956
3963
  this.#lastUpdatedAt = Date.now();
3957
3964
  this.#computedPosition = this.#positionNow();
3965
+ this.#targetDoorState = targetDoorState;
3958
3966
  let next = this.#nextDoorState(targetDoorState);
3959
3967
  if (next === this.#currentDoorState) {
3960
3968
  debug(`nextCurrentDoorState=${styleNumber(next)} === currentDoorState, nothing to do`);
@@ -4026,6 +4034,7 @@ var GarageDoorAccessory = class extends BaseAccessory {
4026
4034
  #applyKnownState(doorState) {
4027
4035
  const { CurrentDoorState } = this.platform.Characteristic;
4028
4036
  this.#currentDoorState = doorState;
4037
+ this.#settleTarget(doorState);
4029
4038
  this.#lastUpdatedAt = Date.now();
4030
4039
  this.#computedPosition = doorState === CurrentDoorState.OPEN ? 100 : 0;
4031
4040
  }
@@ -4033,8 +4042,15 @@ var GarageDoorAccessory = class extends BaseAccessory {
4033
4042
  const { CurrentDoorState } = this.platform.Characteristic;
4034
4043
  debug(`assignCurrentDoorState=${styleString(this.#label(doorState))}`);
4035
4044
  this.#currentDoorState = doorState;
4045
+ this.#settleTarget(doorState);
4036
4046
  this.#service.updateCharacteristic(CurrentDoorState, doorState);
4037
4047
  }
4048
+ /** A door at rest, open or closed, was headed exactly there. */
4049
+ #settleTarget(doorState) {
4050
+ const { CurrentDoorState, TargetDoorState } = this.platform.Characteristic;
4051
+ if (doorState === CurrentDoorState.OPEN) this.#targetDoorState = TargetDoorState.OPEN;
4052
+ else if (doorState === CurrentDoorState.CLOSED) this.#targetDoorState = TargetDoorState.CLOSED;
4053
+ }
4038
4054
  /** Where the door has got to, given how long it has been travelling. */
4039
4055
  #positionNow() {
4040
4056
  const { CurrentDoorState } = this.platform.Characteristic;
@@ -4365,19 +4381,28 @@ const isZoneArmed = (alarmData, zoneProp) => {
4365
4381
  if (alarmMode === "ON") return true;
4366
4382
  return alarmData.find((prop) => prop.name === zoneProp)?.value === "ON";
4367
4383
  };
4384
+ /**
4385
+ * The arming mode a data snapshot describes, ignoring whether the siren is on.
4386
+ *
4387
+ * This is what `SecuritySystemTargetState` asks for, and the reason it cannot
4388
+ * share `getStateForAlarmData`: the target has no `ALARM_TRIGGERED`, so the
4389
+ * return type excludes it and HAP can never be handed a value it would reject.
4390
+ */
4391
+ const getTargetStateForAlarmData = (alarmData, aliases, settings) => {
4392
+ const alarmMode = alarmData.find((prop) => prop.name === "alarmMode")?.value;
4393
+ if (alarmMode === "ON") return ALARM_STATE.AWAY_ARM;
4394
+ if (typeof alarmMode === "string" && ["ZONE", "PART"].includes(alarmMode)) return getStateForActiveZones(getActiveZones(alarmData, settings), aliases);
4395
+ return ALARM_STATE.DISARMED;
4396
+ };
4368
4397
  /** The HomeKit state for a full alarm data snapshot. */
4369
4398
  const getStateForAlarmData = (alarmData, aliases, settings) => {
4370
- const find = (name) => alarmData.find((prop) => prop.name === name)?.value;
4371
- const alarmState = find("alarmState");
4372
- const alarmMode = find("alarmMode");
4399
+ const alarmState = alarmData.find((prop) => prop.name === "alarmState")?.value;
4373
4400
  if (typeof alarmState === "string" && [
4374
4401
  "DELAYED",
4375
4402
  "ON",
4376
4403
  "QUIET"
4377
4404
  ].includes(alarmState)) return ALARM_STATE.ALARM_TRIGGERED;
4378
- if (alarmMode === "ON") return ALARM_STATE.AWAY_ARM;
4379
- if (typeof alarmMode === "string" && ["ZONE", "PART"].includes(alarmMode)) return getStateForActiveZones(getActiveZones(alarmData, settings), aliases);
4380
- return ALARM_STATE.DISARMED;
4405
+ return getTargetStateForAlarmData(alarmData, aliases, settings);
4381
4406
  };
4382
4407
  //#endregion
4383
4408
  //#region src/accessories/security-system-accessory.ts
@@ -4433,7 +4458,7 @@ var SecuritySystemAccessory = class extends BaseAccessory {
4433
4458
  });
4434
4459
  service.getCharacteristic(SecuritySystemTargetState).onGet(async () => {
4435
4460
  debugGet(SecuritySystemTargetState, service);
4436
- const nextValue = await this.#currentState();
4461
+ const nextValue = await this.#targetState();
4437
4462
  debugGetResult(SecuritySystemTargetState, service, nextValue);
4438
4463
  return nextValue;
4439
4464
  }).onSet(async (value) => {
@@ -4459,6 +4484,17 @@ var SecuritySystemAccessory = class extends BaseAccessory {
4459
4484
  const data = await this.#read();
4460
4485
  return getStateForAlarmData(data, this.#settings.aliases ?? {}, this.#settings);
4461
4486
  }
4487
+ /**
4488
+ * The mode the panel is set to, which is what the target characteristic asks.
4489
+ *
4490
+ * Deliberately not `#currentState`: that one answers `ALARM_TRIGGERED` while
4491
+ * the siren is going, and the target has no such value, so HAP rejected it.
4492
+ * A ringing alarm says nothing about what the panel was armed to anyway.
4493
+ */
4494
+ async #targetState() {
4495
+ const data = await this.#read();
4496
+ return getTargetStateForAlarmData(data, this.#settings.aliases ?? {}, this.#settings);
4497
+ }
4462
4498
  async #readZoneLabels() {
4463
4499
  if (this.#legacy) {
4464
4500
  this.platform.log.warn(`Setting up legacy zones`);
@@ -4546,11 +4582,15 @@ var SecuritySystemAccessory = class extends BaseAccessory {
4546
4582
  return;
4547
4583
  }
4548
4584
  const aliases = this.#settings.aliases ?? {};
4549
- const targetZones = target === SecuritySystemTargetState.STAY_ARM ? aliases.stay : aliases.night;
4550
- if (Array.isArray(targetZones) && targetZones.length > 0) {
4551
- await this.#setZones(targetZones, "ON");
4552
- if (this.#service) debugSetResult(SecuritySystemTargetState, this.#service, target, "ON");
4585
+ const isStay = target === SecuritySystemTargetState.STAY_ARM;
4586
+ const alias = isStay ? "stay" : "night";
4587
+ const targetZones = aliases[alias];
4588
+ if (!Array.isArray(targetZones) || targetZones.length === 0) {
4589
+ this.platform.log.warn(`Cannot arm ${this.name} to ${isStay ? "Home" : "Night"}: no zones are configured for that mode, so nothing was sent and the Home app will report the change as failed. Add {"settings": {"${this.deviceId}": {"aliases": {"${alias}": [1]}}}} listing the zones it should arm, numbered as they are on the panel's keypad.`);
4590
+ return;
4553
4591
  }
4592
+ await this.#setZones(targetZones, "ON");
4593
+ if (this.#service) debugSetResult(SecuritySystemTargetState, this.#service, target, "ON");
4554
4594
  }
4555
4595
  async #setZones(zoneIds, value) {
4556
4596
  if (!this.#legacy) {
@@ -4567,15 +4607,12 @@ var SecuritySystemAccessory = class extends BaseAccessory {
4567
4607
  });
4568
4608
  }
4569
4609
  #handleData(updates) {
4570
- const { SecuritySystemCurrentState, ContactSensorState, On } = this.platform.Characteristic;
4610
+ const { ContactSensorState, On } = this.platform.Characteristic;
4571
4611
  const aliases = this.#settings.aliases ?? {};
4572
4612
  for (const { name, value } of updates) {
4573
4613
  if (name === "alarmMode") {
4574
4614
  const nextValue = value === "OFF" ? ALARM_STATE.DISARMED : value === "ON" ? ALARM_STATE.AWAY_ARM : value === "PART" || value === "ZONE" ? getStateForActiveZones(getActiveZones(updates, this.#settings), aliases) : void 0;
4575
- if (nextValue !== void 0 && this.#service) {
4576
- debugSetUpdate(SecuritySystemCurrentState, this.#service, nextValue);
4577
- this.#service.updateCharacteristic(SecuritySystemCurrentState, nextValue);
4578
- }
4615
+ if (nextValue !== void 0) this.#setState(nextValue);
4579
4616
  if (value === "OFF") this.#syncZoneSwitches([]);
4580
4617
  else if (value === "ON") this.#syncZoneSwitches(null);
4581
4618
  continue;
@@ -4653,11 +4690,22 @@ var SecuritySystemAccessory = class extends BaseAccessory {
4653
4690
  service.updateCharacteristic(On, nextValue);
4654
4691
  }
4655
4692
  }
4693
+ /**
4694
+ * Settle both arming characteristics from an authoritative mode.
4695
+ *
4696
+ * The target moves with the current state, so that arming from the panel's
4697
+ * own keypad does not leave HomeKit showing the old mode — a stale target is
4698
+ * what makes "arm away" in the Home app look like it did nothing. The
4699
+ * parameter type excludes `ALARM_TRIGGERED`, so the target can never be
4700
+ * handed a value it would reject.
4701
+ */
4656
4702
  #setState(state) {
4657
4703
  if (!this.#service) return;
4658
- const { SecuritySystemCurrentState } = this.platform.Characteristic;
4704
+ const { SecuritySystemCurrentState, SecuritySystemTargetState } = this.platform.Characteristic;
4659
4705
  debugSetUpdate(SecuritySystemCurrentState, this.#service, state);
4660
4706
  this.#service.updateCharacteristic(SecuritySystemCurrentState, state);
4707
+ debugSetUpdate(SecuritySystemTargetState, this.#service, state);
4708
+ this.#service.updateCharacteristic(SecuritySystemTargetState, state);
4661
4709
  }
4662
4710
  };
4663
4711
  const createSecuritySystemAccessory = (deps) => {
@@ -5604,4 +5652,4 @@ var TydomPlatform = class {
5604
5652
  //#endregion
5605
5653
  export { TydomPlatform as default };
5606
5654
 
5607
- //# sourceMappingURL=platform-DmVGk0po.mjs.map
5655
+ //# sourceMappingURL=platform-CJBHeITb.mjs.map