homebridge-tydom 0.31.2 → 0.32.1

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-BjoGoTvF.mjs");
4
+ const { default: TydomPlatform } = await import("./platform-BssMTVVc.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;
@@ -4770,34 +4786,86 @@ var ThermostatAccessory = class extends BaseAccessory {
4770
4786
  #service;
4771
4787
  /** Thermic-level switches, by the Tydom value each one selects. */
4772
4788
  #levelSwitches = /* @__PURE__ */ new Map();
4789
+ /**
4790
+ * Whether this device can cool as well as heat.
4791
+ *
4792
+ * Read from the endpoint's own metadata rather than configured: reversible
4793
+ * hardware — a heat pump that runs in reverse — advertises `COOLING` among
4794
+ * the values its `authorization` property accepts, and a radiator does not.
4795
+ * Offering HomeKit a cool mode on a radiator would put a button in the Home
4796
+ * app that silently does nothing.
4797
+ */
4798
+ #canCool;
4799
+ /**
4800
+ * Which property carries the operating mode on this device.
4801
+ *
4802
+ * Delta Dore replaced `hvacMode` with `localMode` on newer thermostats — the
4803
+ * Tybox 5100 and relatives carry no `hvacMode` at all. Reading a property
4804
+ * that is not there throws, so on that hardware every
4805
+ * `TargetHeatingCoolingState` query failed: the accessory was discovered and
4806
+ * registered, then errored on every read. The values are the same apart from
4807
+ * an added `ABSENCE`, so resolving the name is the whole fix.
4808
+ *
4809
+ * `hvacMode` wins when both are present, so nothing changes for hardware that
4810
+ * already worked.
4811
+ */
4812
+ #modeProp;
4773
4813
  constructor(deps) {
4774
4814
  super(deps);
4815
+ const metadata = deps.accessory.context.metadata;
4816
+ const hasProp = (name) => metadata.some((entry) => entry.name === name);
4817
+ this.#modeProp = hasProp("hvacMode") ? "hvacMode" : hasProp("localMode") ? "localMode" : "hvacMode";
4818
+ if (!hasProp("hvacMode") && !hasProp("localMode")) deps.platform.log.warn(`Thermostat ${deps.accessory.displayName} advertises neither "hvacMode" nor "localMode"; its mode controls will not work.`);
4819
+ this.#canCool = Boolean(deps.accessory.context.metadata.find(({ name }) => name === "authorization")?.enum_values?.includes("COOLING"));
4775
4820
  const { TargetHeatingCoolingState, CurrentHeatingCoolingState, TargetTemperature, CurrentTemperature } = this.platform.Characteristic;
4776
4821
  this.#service = this.service(this.platform.Service.Thermostat);
4777
- this.#service.getCharacteristic(CurrentHeatingCoolingState).setProps({ validValues: [0, 1] }).onGet(async () => {
4822
+ this.#service.getCharacteristic(CurrentHeatingCoolingState).setProps({ validValues: this.#canCool ? [
4823
+ 0,
4824
+ 1,
4825
+ 2
4826
+ ] : [0, 1] }).onGet(async () => {
4778
4827
  debugGet(CurrentHeatingCoolingState, this.#service);
4779
4828
  const data = await this.#read();
4780
4829
  const authorization = getTydomDataPropValue(data, "authorization");
4781
4830
  const setpoint = getTydomDataPropValue(data, "setpoint");
4782
4831
  const temperature = getTydomDataPropValue(data, "temperature");
4783
- const nextValue = authorization === "HEATING" && setpoint > temperature ? CurrentHeatingCoolingState.HEAT : CurrentHeatingCoolingState.OFF;
4832
+ let nextValue = CurrentHeatingCoolingState.OFF;
4833
+ if (authorization === "HEATING" && setpoint > temperature) nextValue = CurrentHeatingCoolingState.HEAT;
4834
+ else if (authorization === "COOLING" && temperature > setpoint) nextValue = CurrentHeatingCoolingState.COOL;
4784
4835
  debugGetResult(CurrentHeatingCoolingState, this.#service, nextValue);
4785
4836
  return nextValue;
4786
4837
  });
4787
- this.#service.getCharacteristic(TargetHeatingCoolingState).setProps({ validValues: [0, 1] }).onGet(async () => {
4838
+ this.#service.getCharacteristic(TargetHeatingCoolingState).setProps({ validValues: this.#canCool ? [
4839
+ 0,
4840
+ 1,
4841
+ 2
4842
+ ] : [0, 1] }).onGet(async () => {
4788
4843
  debugGet(TargetHeatingCoolingState, this.#service);
4789
4844
  const data = await this.#read();
4790
- const hvacMode = getTydomDataPropValue(data, "hvacMode");
4791
- const nextValue = getTydomDataPropValue(data, "authorization") === "HEATING" && hvacMode === "NORMAL" ? TargetHeatingCoolingState.HEAT : TargetHeatingCoolingState.OFF;
4845
+ const hvacMode = getTydomDataPropValue(data, this.#modeProp);
4846
+ const authorization = getTydomDataPropValue(data, "authorization");
4847
+ let nextValue = TargetHeatingCoolingState.OFF;
4848
+ if (hvacMode === "NORMAL" && authorization === "HEATING") nextValue = TargetHeatingCoolingState.HEAT;
4849
+ else if (hvacMode === "NORMAL" && authorization === "COOLING") nextValue = TargetHeatingCoolingState.COOL;
4792
4850
  debugGetResult(TargetHeatingCoolingState, this.#service, nextValue);
4793
4851
  return nextValue;
4794
4852
  }).onSet(async (value) => {
4795
4853
  debugSet(TargetHeatingCoolingState, this.#service, value);
4796
- const shouldHeat = [TargetHeatingCoolingState.HEAT, TargetHeatingCoolingState.AUTO].includes(value);
4797
- const tydomValue = shouldHeat ? "NORMAL" : "STOP";
4798
- await this.#writeHvacMode(tydomValue);
4799
- debugSetResult(TargetHeatingCoolingState, this.#service, value, tydomValue);
4800
- this.#service.getCharacteristic(CurrentHeatingCoolingState).updateValue(shouldHeat ? CurrentHeatingCoolingState.HEAT : CurrentHeatingCoolingState.OFF);
4854
+ const wantsCool = this.#canCool && value === TargetHeatingCoolingState.COOL;
4855
+ const isOn = wantsCool || [TargetHeatingCoolingState.HEAT, TargetHeatingCoolingState.AUTO].includes(value);
4856
+ const hvacMode = isOn ? "NORMAL" : "STOP";
4857
+ const values = [{
4858
+ name: this.#modeProp,
4859
+ value: hvacMode
4860
+ }];
4861
+ if (this.#canCool) values.push({
4862
+ name: "authorization",
4863
+ value: isOn ? wantsCool ? "COOLING" : "HEATING" : "STOP"
4864
+ });
4865
+ await this.api.putDeviceData(this.deviceId, this.endpointId, values);
4866
+ debugSetResult(TargetHeatingCoolingState, this.#service, value, hvacMode);
4867
+ const current = wantsCool ? CurrentHeatingCoolingState.COOL : isOn ? CurrentHeatingCoolingState.HEAT : CurrentHeatingCoolingState.OFF;
4868
+ this.#service.getCharacteristic(CurrentHeatingCoolingState).updateValue(current);
4801
4869
  });
4802
4870
  this.#service.getCharacteristic(CurrentTemperature).onGet(async () => {
4803
4871
  debugGet(CurrentTemperature, this.#service);
@@ -4825,13 +4893,21 @@ var ThermostatAccessory = class extends BaseAccessory {
4825
4893
  const { TargetHeatingCoolingState, CurrentHeatingCoolingState, TargetTemperature, CurrentTemperature } = this.platform.Characteristic;
4826
4894
  for (const { name, value } of updates) switch (name) {
4827
4895
  case "authorization":
4828
- if (value !== "STOP") break;
4896
+ if (value !== "STOP") {
4897
+ if (this.#canCool && (value === "COOLING" || value === "HEATING")) {
4898
+ const next = value === "COOLING" ? TargetHeatingCoolingState.COOL : TargetHeatingCoolingState.HEAT;
4899
+ debugSetUpdate(TargetHeatingCoolingState, this.#service, next);
4900
+ this.#service.updateCharacteristic(TargetHeatingCoolingState, next);
4901
+ }
4902
+ break;
4903
+ }
4829
4904
  debugSetUpdate(CurrentHeatingCoolingState, this.#service, CurrentHeatingCoolingState.OFF);
4830
4905
  this.#service.updateCharacteristic(CurrentHeatingCoolingState, CurrentHeatingCoolingState.OFF);
4831
4906
  debugSetUpdate(TargetHeatingCoolingState, this.#service, TargetHeatingCoolingState.OFF);
4832
4907
  this.#service.updateCharacteristic(TargetHeatingCoolingState, TargetHeatingCoolingState.OFF);
4833
4908
  break;
4834
- case "hvacMode": {
4909
+ case "hvacMode":
4910
+ case "localMode": {
4835
4911
  const hvacMode = value;
4836
4912
  if (hvacMode === "NORMAL") break;
4837
4913
  this.#service.updateCharacteristic(TargetHeatingCoolingState, TargetHeatingCoolingState.OFF);
@@ -4863,7 +4939,7 @@ var ThermostatAccessory = class extends BaseAccessory {
4863
4939
  }
4864
4940
  async #writeHvacMode(value) {
4865
4941
  await this.api.putDeviceData(this.deviceId, this.endpointId, [{
4866
- name: "hvacMode",
4942
+ name: this.#modeProp,
4867
4943
  value
4868
4944
  }]);
4869
4945
  }
@@ -4904,7 +4980,7 @@ var ThermostatAccessory = class extends BaseAccessory {
4904
4980
  service.getCharacteristic(On).onGet(async () => {
4905
4981
  debugGet(On, service);
4906
4982
  const data = await this.#read();
4907
- const nextValue = subtype === "hvacMode_absence" ? getTydomDataPropValue(data, "hvacMode") === "ANTI_FROST" : getTydomDataPropValue(data, "thermicLevel") === tydomValue;
4983
+ const nextValue = subtype === "hvacMode_absence" ? getTydomDataPropValue(data, this.#modeProp) === "ANTI_FROST" : getTydomDataPropValue(data, "thermicLevel") === tydomValue;
4908
4984
  debugGetResult(On, service, nextValue);
4909
4985
  return nextValue;
4910
4986
  }).onSet(async (value) => {
@@ -5544,4 +5620,4 @@ var TydomPlatform = class {
5544
5620
  //#endregion
5545
5621
  export { TydomPlatform as default };
5546
5622
 
5547
- //# sourceMappingURL=platform-BjoGoTvF.mjs.map
5623
+ //# sourceMappingURL=platform-BssMTVVc.mjs.map