homebridge-tuya-plus 3.9.0 → 3.10.0

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.
@@ -1,7 +1,5 @@
1
1
  const BaseAccessory = require('./BaseAccessory');
2
2
 
3
- const STATE_OTHER = 9;
4
-
5
3
  class AirConditionerAccessory extends BaseAccessory {
6
4
  static getCategory(Categories) {
7
5
  return Categories.AIR_CONDITIONER;
@@ -28,8 +26,6 @@ class AirConditionerAccessory extends BaseAccessory {
28
26
  else throw new Error('The cmdAuto doesn\'t appear to be valid: ' + this.device.context.cmdAuto);
29
27
  }
30
28
 
31
- this.device.context.noAuto = true;
32
-
33
29
  if (!this.device.context.noRotationSpeed) {
34
30
  const fanSpeedSteps = (this.device.context.fanSpeedSteps && isFinite(this.device.context.fanSpeedSteps) && this.device.context.fanSpeedSteps > 0 && this.device.context.fanSpeedSteps < 100) ? this.device.context.fanSpeedSteps : 100;
35
31
  this._rotationSteps = [0];
@@ -65,7 +61,7 @@ class AirConditionerAccessory extends BaseAccessory {
65
61
  this.dpSwingMode = this._getCustomDP(this.device.context.dpSwingMode) || '104';
66
62
 
67
63
  const characteristicActive = service.getCharacteristic(Characteristic.Active)
68
- .updateValue(this._getActive(this.dpActive))
64
+ .updateValue(this._getActive(dps[this.dpActive]))
69
65
  .onGet(() => this.getActive())
70
66
  .onSet(value => this.setActive(value));
71
67
 
@@ -73,13 +69,13 @@ class AirConditionerAccessory extends BaseAccessory {
73
69
  .updateValue(this._getCurrentHeaterCoolerState(dps))
74
70
  .onGet(() => this.getCurrentHeaterCoolerState());
75
71
 
76
- const _validTargetHeaterCoolerStateValues = [STATE_OTHER];
77
- if (!this.device.context.noCool) _validTargetHeaterCoolerStateValues.unshift(Characteristic.TargetHeaterCoolerState.COOL);
78
- if (!this.device.context.noHeat) _validTargetHeaterCoolerStateValues.unshift(Characteristic.TargetHeaterCoolerState.HEAT);
79
- if (!this.device.context.noAuto) _validTargetHeaterCoolerStateValues.unshift(Characteristic.TargetHeaterCoolerState.AUTO);
72
+ const _validTargetHeaterCoolerStateValues = [];
73
+ if (!this.device.context.noAuto) _validTargetHeaterCoolerStateValues.push(Characteristic.TargetHeaterCoolerState.AUTO);
74
+ if (!this.device.context.noHeat) _validTargetHeaterCoolerStateValues.push(Characteristic.TargetHeaterCoolerState.HEAT);
75
+ if (!this.device.context.noCool) _validTargetHeaterCoolerStateValues.push(Characteristic.TargetHeaterCoolerState.COOL);
80
76
 
81
77
  const characteristicTargetHeaterCoolerState = service.getCharacteristic(Characteristic.TargetHeaterCoolerState)
82
- .setProps({ maxValue: 9, validValues: _validTargetHeaterCoolerStateValues })
78
+ .setProps({ validValues: _validTargetHeaterCoolerStateValues })
83
79
  .updateValue(this._getTargetHeaterCoolerState(dps[this.dpMode]))
84
80
  .onGet(() => this.getTargetHeaterCoolerState())
85
81
  .onSet(value => this.setTargetHeaterCoolerState(value));
@@ -112,7 +108,7 @@ class AirConditionerAccessory extends BaseAccessory {
112
108
  maxValue: this.device.context.maxTemperature || 35,
113
109
  minStep: this.device.context.minTemperatureSteps || 1
114
110
  })
115
- .updateValue(this.dpThreshold)
111
+ .updateValue(dps[this.dpThreshold])
116
112
  .onGet(() => this.getStateAsync(this.dpThreshold))
117
113
  .onSet(value => this.setTargetThresholdTemperature('cool', value));
118
114
  } else this._removeCharacteristic(service, Characteristic.CoolingThresholdTemperature);
@@ -256,17 +252,20 @@ class AirConditionerAccessory extends BaseAccessory {
256
252
  const {Characteristic} = this.hap;
257
253
  switch (dp) {
258
254
  case this.cmdCool:
259
- if (this.device.context.noCool) return STATE_OTHER;
260
- return Characteristic.TargetHeaterCoolerState.COOL;
255
+ if (!this.device.context.noCool) return Characteristic.TargetHeaterCoolerState.COOL;
256
+ break;
261
257
  case this.cmdHeat:
262
- if (this.device.context.noHeat) return STATE_OTHER;
263
- return Characteristic.TargetHeaterCoolerState.HEAT;
258
+ if (!this.device.context.noHeat) return Characteristic.TargetHeaterCoolerState.HEAT;
259
+ break;
264
260
  case this.cmdAuto:
265
- if (this.device.context.noAuto) return STATE_OTHER;
266
- return Characteristic.TargetHeaterCoolerState.AUTO;
267
- default:
268
- return STATE_OTHER;
261
+ if (!this.device.context.noAuto) return Characteristic.TargetHeaterCoolerState.AUTO;
262
+ break;
269
263
  }
264
+ // Fall back to the first allowed mode rather than publishing a value
265
+ // that isn't in validValues — HomeKit would reject it otherwise.
266
+ if (!this.device.context.noCool) return Characteristic.TargetHeaterCoolerState.COOL;
267
+ if (!this.device.context.noHeat) return Characteristic.TargetHeaterCoolerState.HEAT;
268
+ return Characteristic.TargetHeaterCoolerState.AUTO;
270
269
  }
271
270
 
272
271
  setTargetHeaterCoolerState(value) {
@@ -274,13 +273,13 @@ class AirConditionerAccessory extends BaseAccessory {
274
273
  switch (value) {
275
274
  case Characteristic.TargetHeaterCoolerState.COOL:
276
275
  if (this.device.context.noCool) return;
277
- return this.setStateAsync(this.dpMode, this.cmdCool);
276
+ return this.setMultiStateLegacyAsync({[this.dpActive]: true, [this.dpMode]: this.cmdCool});
278
277
  case Characteristic.TargetHeaterCoolerState.HEAT:
279
278
  if (this.device.context.noHeat) return;
280
- return this.setStateAsync(this.dpMode, this.cmdHeat);
279
+ return this.setMultiStateLegacyAsync({[this.dpActive]: true, [this.dpMode]: this.cmdHeat});
281
280
  case Characteristic.TargetHeaterCoolerState.AUTO:
282
281
  if (this.device.context.noAuto) return;
283
- return this.setStateAsync(this.dpMode, this.cmdAuto);
282
+ return this.setMultiStateLegacyAsync({[this.dpActive]: true, [this.dpMode]: this.cmdAuto});
284
283
  }
285
284
  }
286
285
 
@@ -305,7 +304,7 @@ class AirConditionerAccessory extends BaseAccessory {
305
304
  }
306
305
 
307
306
  async setTargetThresholdTemperature(mode, value) {
308
- await this.setStateAsync(this.dpThreshold, value);
307
+ await this.setMultiStateLegacyAsync({[this.dpActive]: true, [this.dpThreshold]: value});
309
308
  if (mode === 'cool' && !this.device.context.noHeat && this.characteristicHeatingThresholdTemperature) {
310
309
  this.characteristicHeatingThresholdTemperature.updateValue(value);
311
310
  } else if (mode === 'heat' && !this.device.context.noCool && this.characteristicCoolingThresholdTemperature) {
@@ -29,6 +29,14 @@ class SimpleHeaterAccessory extends BaseAccessory {
29
29
  this.temperatureDivisor = parseInt(this.device.context.temperatureDivisor) || 1;
30
30
  this.thresholdTemperatureDivisor = parseInt(this.device.context.thresholdTemperatureDivisor) || 1;
31
31
  this.temperatureOffset = parseInt(this.device.context.temperatureOffset) || 0;
32
+ // currentTemperatureOffset shifts only the displayed current temperature
33
+ // (not the threshold/setpoint). Use for devices whose onboard sensor
34
+ // reads systematically off from real ambient (e.g. wall-mounted patio
35
+ // heaters with sensor against the housing/wall). Defaults to
36
+ // temperatureOffset for backwards compatibility.
37
+ this.currentTemperatureOffset = this.device.context.currentTemperatureOffset !== undefined
38
+ ? parseInt(this.device.context.currentTemperatureOffset)
39
+ : this.temperatureOffset;
32
40
 
33
41
  const characteristicActive = service.getCharacteristic(Characteristic.Active)
34
42
  .updateValue(this._getActive(dps[this.dpActive]))
@@ -50,8 +58,8 @@ class SimpleHeaterAccessory extends BaseAccessory {
50
58
  .onSet(() => this.setStateAsync(this.dpActive, true));
51
59
 
52
60
  const characteristicCurrentTemperature = service.getCharacteristic(Characteristic.CurrentTemperature)
53
- .updateValue(this._getDividedState(dps[this.dpCurrentTemperature], this.temperatureDivisor))
54
- .onGet(() => this.getDividedStateAsync(this.dpCurrentTemperature, this.temperatureDivisor));
61
+ .updateValue(this._getDividedState(dps[this.dpCurrentTemperature], this.temperatureDivisor, this.currentTemperatureOffset))
62
+ .onGet(() => this._getCurrentTempAsync());
55
63
 
56
64
  const characteristicHeatingThresholdTemperature = service.getCharacteristic(Characteristic.HeatingThresholdTemperature)
57
65
  .setProps({
@@ -79,7 +87,7 @@ class SimpleHeaterAccessory extends BaseAccessory {
79
87
  }
80
88
 
81
89
  if (changes.hasOwnProperty(this.dpCurrentTemperature) && characteristicCurrentTemperature.value !== changes[this.dpCurrentTemperature])
82
- characteristicCurrentTemperature.updateValue(this._getDividedState(changes[this.dpCurrentTemperature], this.temperatureDivisor));
90
+ characteristicCurrentTemperature.updateValue(this._getDividedState(changes[this.dpCurrentTemperature], this.temperatureDivisor, this.currentTemperatureOffset));
83
91
 
84
92
  characteristicCurrentHeaterCoolerState.updateValue(this._getCurrentHeaterCoolerState(state));
85
93
  this.log.info('SimpleHeater changed: ' + JSON.stringify(state));
@@ -132,8 +140,15 @@ class SimpleHeaterAccessory extends BaseAccessory {
132
140
  }
133
141
  }
134
142
 
135
- _getDividedState(dp, divisor) {
136
- return ((parseFloat(dp) / divisor) + this.temperatureOffset) || 0;
143
+ _getDividedState(dp, divisor, offsetOverride) {
144
+ const offset = offsetOverride !== undefined ? offsetOverride : this.temperatureOffset;
145
+ return ((parseFloat(dp) / divisor) + offset) || 0;
146
+ }
147
+
148
+ _getCurrentTempAsync() {
149
+ const data = this.getStateAsync(this.dpCurrentTemperature);
150
+ if (!isFinite(data)) throw new Error('Invalid state');
151
+ return this._getDividedState(data, this.temperatureDivisor, this.currentTemperatureOffset);
137
152
  }
138
153
  }
139
154
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homebridge-tuya-plus",
3
- "version": "3.9.0",
3
+ "version": "3.10.0",
4
4
  "description": "A community-maintained Homebridge plugin for controlling Tuya devices locally over LAN. Includes new features, fixes, and updated device support.",
5
5
  "main": "index.js",
6
6
  "scripts": {