homebridge-tuya-plus 4.1.0-dev.64 → 4.1.0-dev.69

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.
@@ -531,7 +531,7 @@
531
531
  "functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector', 'Fan', 'FanLight'].includes(model.devices[arrayIndices].type);"
532
532
  }
533
533
  },
534
- "dpRotationDirection": {
534
+ "dpFanDirection": {
535
535
  "type": "integer",
536
536
  "placeholder": "63",
537
537
  "condition": {
@@ -585,6 +585,51 @@
585
585
  "functionBody": "return model.devices && model.devices[arrayIndices] && ['FanLight'].includes(model.devices[arrayIndices].type);"
586
586
  }
587
587
  },
588
+ "lightUseEnum": {
589
+ "title": "Light uses On/Off text values",
590
+ "description": "Enable if the light appears in HomeKit but toggling it does nothing. Some fans type the light data point as an enum of text values (e.g. \"On\"/\"Off\") rather than a boolean.",
591
+ "type": "boolean",
592
+ "placeholder": false,
593
+ "condition": {
594
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['FanLight'].includes(model.devices[arrayIndices].type);"
595
+ }
596
+ },
597
+ "lightOnCommand": {
598
+ "title": "Light \"on\" value",
599
+ "description": "The text value sent to turn the light on when \"Light uses On/Off text values\" is enabled.",
600
+ "type": "string",
601
+ "placeholder": "On",
602
+ "condition": {
603
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['FanLight'].includes(model.devices[arrayIndices].type) && model.devices[arrayIndices].lightUseEnum;"
604
+ }
605
+ },
606
+ "lightOffCommand": {
607
+ "title": "Light \"off\" value",
608
+ "description": "The text value sent to turn the light off when \"Light uses On/Off text values\" is enabled.",
609
+ "type": "string",
610
+ "placeholder": "Off",
611
+ "condition": {
612
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['FanLight'].includes(model.devices[arrayIndices].type) && model.devices[arrayIndices].lightUseEnum;"
613
+ }
614
+ },
615
+ "directionForwardCommand": {
616
+ "title": "Forward direction value",
617
+ "description": "The value sent for the normal/forward direction. Set this when direction lives on a shared \"mode\" data point (e.g. Windmode \"Normal\").",
618
+ "type": "string",
619
+ "placeholder": "forward",
620
+ "condition": {
621
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['FanLight'].includes(model.devices[arrayIndices].type);"
622
+ }
623
+ },
624
+ "directionReverseCommand": {
625
+ "title": "Reverse direction value",
626
+ "description": "The value sent for the reverse direction. Set this when direction lives on a shared \"mode\" data point (e.g. Windmode \"Reverse\").",
627
+ "type": "string",
628
+ "placeholder": "reverse",
629
+ "condition": {
630
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['FanLight'].includes(model.devices[arrayIndices].type);"
631
+ }
632
+ },
588
633
  "dpChildLock": {
589
634
  "type": "integer",
590
635
  "placeholder": "6",
@@ -46,6 +46,19 @@ class SimpleFanLightAccessory extends BaseAccessory {
46
46
  this.useBrightness = this._coerceBoolean(this.device.context.useBrightness, true);
47
47
  this.useColorTemp = this._coerceBoolean(this.device.context.useColorTemp, true);
48
48
 
49
+ // Some fans (e.g. the Orient AEON V.C.) type the light DP as an enum of
50
+ // 'On'/'Off' strings rather than a boolean. When lightUseEnum is set we
51
+ // read/write those command strings; otherwise the DP stays a plain bool.
52
+ this.lightUseEnum = this._coerceBoolean(this.device.context.lightUseEnum, false);
53
+ this.lightOnCommand = this.device.context.lightOnCommand || 'On';
54
+ this.lightOffCommand = this.device.context.lightOffCommand || 'Off';
55
+
56
+ // The direction DP's forward/reverse command strings are configurable so
57
+ // fans that carry direction on a shared "mode" DP (e.g. Windmode
58
+ // 'Normal'/'Reverse') can be mapped onto HomeKit's RotationDirection.
59
+ this.directionForwardCommand = this.device.context.directionForwardCommand || 'forward';
60
+ this.directionReverseCommand = this.device.context.directionReverseCommand || 'reverse';
61
+
49
62
  let minWhiteColor = parseInt(this.device.context.minWhiteColor);
50
63
  let maxWhiteColor = parseInt(this.device.context.maxWhiteColor);
51
64
  if (isNaN(minWhiteColor)) minWhiteColor = DEFAULT_MIN_WHITE_COLOR;
@@ -126,7 +139,8 @@ class SimpleFanLightAccessory extends BaseAccessory {
126
139
  }
127
140
 
128
141
  if (changes.hasOwnProperty(this.dpLightOn) && characteristicLightOn) {
129
- if (characteristicLightOn.value !== changes[this.dpLightOn]) characteristicLightOn.updateValue(changes[this.dpLightOn]);
142
+ const lightOn = this._getLightOn(changes[this.dpLightOn]);
143
+ if (characteristicLightOn.value !== lightOn) characteristicLightOn.updateValue(lightOn);
130
144
  }
131
145
 
132
146
  if (changes.hasOwnProperty(this.dpBrightness) && characteristicBrightness) {
@@ -204,13 +218,13 @@ class SimpleFanLightAccessory extends BaseAccessory {
204
218
 
205
219
  _getFanDirection(dp) {
206
220
  const {Characteristic} = this.hap;
207
- return dp === 'reverse'
221
+ return dp === this.directionReverseCommand
208
222
  ? Characteristic.RotationDirection.COUNTER_CLOCKWISE
209
223
  : Characteristic.RotationDirection.CLOCKWISE;
210
224
  }
211
225
 
212
226
  setFanDirection(value) {
213
- const tuyaVal = (value === 1) ? 'reverse' : 'forward';
227
+ const tuyaVal = (value === 1) ? this.directionReverseCommand : this.directionForwardCommand;
214
228
  return this.setStateAsync(this.dpFanDirection, tuyaVal);
215
229
  }
216
230
 
@@ -219,10 +233,14 @@ class SimpleFanLightAccessory extends BaseAccessory {
219
233
  }
220
234
 
221
235
  _getLightOn(dp) {
236
+ if (this.lightUseEnum) return dp === this.lightOnCommand;
222
237
  return !!dp;
223
238
  }
224
239
 
225
240
  setLightOn(value) {
241
+ if (this.lightUseEnum) {
242
+ return this.setStateAsync(this.dpLightOn, value ? this.lightOnCommand : this.lightOffCommand);
243
+ }
226
244
  return this.setStateAsync(this.dpLightOn, value);
227
245
  }
228
246
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homebridge-tuya-plus",
3
- "version": "4.1.0-dev.64",
3
+ "version": "4.1.0-dev.69",
4
4
  "description": "A community-maintained Homebridge plugin for controlling Tuya devices locally over LAN, with an optional Tuya Cloud fallback for whatever the LAN can't reach. Includes new features, fixes, and updated device support. PRs welcome: if it runs, it ships (almost).",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -14,13 +14,19 @@ function makeFanLight(state = {}, context = {}) {
14
14
 
15
15
  instance.dpFanOn = '60';
16
16
  instance.dpRotationSpeed = '62';
17
- instance.dpFanDirection = '63';
17
+ instance.dpFanDirection = device.context.dpFanDirection || '63';
18
+ instance.dpLightOn = device.context.dpLightOn || '20';
18
19
  instance.dpColorTemp = '23';
19
20
  instance.maxSpeed = parseInt(device.context.maxSpeed) || 6;
20
21
  instance.fanDefaultSpeed = parseInt(device.context.fanDefaultSpeed) || 1;
21
22
  instance.fanCurrentSpeed = 0;
22
23
  instance.useStrings = instance._coerceBoolean(device.context.useStrings, true);
23
24
  instance.singleDpWrites = instance._coerceBoolean(device.context.singleDpWrites, false);
25
+ instance.lightUseEnum = instance._coerceBoolean(device.context.lightUseEnum, false);
26
+ instance.lightOnCommand = device.context.lightOnCommand || 'On';
27
+ instance.lightOffCommand = device.context.lightOffCommand || 'Off';
28
+ instance.directionForwardCommand = device.context.directionForwardCommand || 'forward';
29
+ instance.directionReverseCommand = device.context.directionReverseCommand || 'reverse';
24
30
  if (device.context.minWhiteColor !== undefined) instance.minWhiteColor = parseInt(device.context.minWhiteColor);
25
31
  if (device.context.maxWhiteColor !== undefined) instance.maxWhiteColor = parseInt(device.context.maxWhiteColor);
26
32
 
@@ -164,6 +170,119 @@ describe('SimpleFanLightAccessory — setFanOn(false)', () => {
164
170
  });
165
171
  });
166
172
 
173
+ // ---------------------------------------------------------------------------
174
+ // Enum light on/off: fans whose Light DP is an 'On'/'Off' enum rather than a
175
+ // boolean (e.g. Orient AEON V.C.). Default stays boolean for compatibility.
176
+ // ---------------------------------------------------------------------------
177
+ describe('SimpleFanLightAccessory — enum light (lightUseEnum)', () => {
178
+ test('reads the enum command strings, not truthiness', () => {
179
+ const { instance } = makeFanLight(
180
+ { '20': 'Off' },
181
+ { lightUseEnum: true }
182
+ );
183
+ // The boolean path would read the non-empty string 'Off' as ON (the bug).
184
+ expect(instance.getLightOn()).toBe(false);
185
+ instance.device.state['20'] = 'On';
186
+ expect(instance.getLightOn()).toBe(true);
187
+ });
188
+
189
+ test('setLightOn writes the On/Off command strings', () => {
190
+ const { instance, device } = makeFanLight(
191
+ { '20': 'Off' },
192
+ { lightUseEnum: true }
193
+ );
194
+
195
+ instance.setLightOn(true);
196
+ expect(device.update).toHaveBeenCalledWith({ '20': 'On' });
197
+
198
+ device.state['20'] = 'On';
199
+ instance.setLightOn(false);
200
+ expect(device.update).toHaveBeenCalledWith({ '20': 'Off' });
201
+ });
202
+
203
+ test('honours custom on/off command strings', () => {
204
+ const { instance, device } = makeFanLight(
205
+ { '101': 'off' },
206
+ { dpLightOn: '101', lightUseEnum: true, lightOnCommand: 'on', lightOffCommand: 'off' }
207
+ );
208
+
209
+ expect(instance.getLightOn()).toBe(false);
210
+ instance.setLightOn(true);
211
+ expect(device.update).toHaveBeenCalledWith({ '101': 'on' });
212
+ });
213
+
214
+ test('default (flag off) keeps the boolean behaviour', () => {
215
+ const { instance, device } = makeFanLight({ '20': false });
216
+
217
+ expect(instance._getLightOn(true)).toBe(true);
218
+ expect(instance._getLightOn(false)).toBe(false);
219
+
220
+ instance.setLightOn(true);
221
+ expect(device.update).toHaveBeenCalledWith({ '20': true });
222
+ });
223
+ });
224
+
225
+ // ---------------------------------------------------------------------------
226
+ // Configurable direction commands: map a shared "mode" DP (Windmode
227
+ // Normal/Reverse) onto HomeKit's RotationDirection toggle.
228
+ // ---------------------------------------------------------------------------
229
+ describe('SimpleFanLightAccessory — configurable direction commands', () => {
230
+ const { RotationDirection } = HAP.Characteristic;
231
+
232
+ test('reads the reverse command as COUNTER_CLOCKWISE', () => {
233
+ const { instance } = makeFanLight(
234
+ { '3': 'Reverse' },
235
+ { dpFanDirection: '3', directionForwardCommand: 'Normal', directionReverseCommand: 'Reverse' }
236
+ );
237
+
238
+ expect(instance.getFanDirection()).toBe(RotationDirection.COUNTER_CLOCKWISE);
239
+ instance.device.state['3'] = 'Normal';
240
+ expect(instance.getFanDirection()).toBe(RotationDirection.CLOCKWISE);
241
+ // Unrelated Windmode values (e.g. Sleep set from the Tuya app) read as forward.
242
+ instance.device.state['3'] = 'Sleep';
243
+ expect(instance.getFanDirection()).toBe(RotationDirection.CLOCKWISE);
244
+ });
245
+
246
+ test('setFanDirection writes the configured command strings', () => {
247
+ const { instance, device } = makeFanLight(
248
+ { '3': 'Normal' },
249
+ { dpFanDirection: '3', directionForwardCommand: 'Normal', directionReverseCommand: 'Reverse' }
250
+ );
251
+
252
+ instance.setFanDirection(RotationDirection.COUNTER_CLOCKWISE);
253
+ expect(device.update).toHaveBeenCalledWith({ '3': 'Reverse' });
254
+
255
+ device.state['3'] = 'Reverse';
256
+ instance.setFanDirection(RotationDirection.CLOCKWISE);
257
+ expect(device.update).toHaveBeenCalledWith({ '3': 'Normal' });
258
+ });
259
+
260
+ test('defaults remain forward/reverse when unconfigured', () => {
261
+ const { instance, device } = makeFanLight({ '63': 'forward' });
262
+
263
+ expect(instance._getFanDirection('reverse')).toBe(RotationDirection.COUNTER_CLOCKWISE);
264
+ instance.setFanDirection(RotationDirection.COUNTER_CLOCKWISE);
265
+ expect(device.update).toHaveBeenCalledWith({ '63': 'reverse' });
266
+ });
267
+ });
268
+
269
+ // ---------------------------------------------------------------------------
270
+ // Direction DP resolution: dpFanDirection overrides the default DP.
271
+ // ---------------------------------------------------------------------------
272
+ describe('SimpleFanLightAccessory — direction DP resolution', () => {
273
+ test('honours the dpFanDirection config key', () => {
274
+ const { instance } = makeInstance(SimpleFanLightAccessory, {}, { type: 'FanLight', dpFanDirection: 3 });
275
+ instance._registerCharacteristics({});
276
+ expect(instance.dpFanDirection).toBe('3');
277
+ });
278
+
279
+ test('defaults to DP 63 when unset', () => {
280
+ const { instance } = makeInstance(SimpleFanLightAccessory, {}, { type: 'FanLight' });
281
+ instance._registerCharacteristics({});
282
+ expect(instance.dpFanDirection).toBe('63');
283
+ });
284
+ });
285
+
167
286
  // ---------------------------------------------------------------------------
168
287
  // convertColorTempFromTuyaToHomeKit — default range, inverted (issue #44)
169
288
  // ---------------------------------------------------------------------------
@@ -5,7 +5,7 @@ If you are looking for verified configurations for your specific device, please
5
5
 
6
6
  |Device |Type|Notes |
7
7
  |:---|:---:|:---|
8
- |Smart Plug|`Outlet`<sup>[1](#outlets)</sup>|Smart plugs that just turn on and off <small>([instructions](#outlets))</small>|
8
+ |Smart Plug|`Outlet`<sup>[1](#outlets)</sup>|Smart plugs that just turn on and off <small>([instructions](#outlets))</small>|
9
9
  |Smart Light Bulb Socket|`SimpleLight`|Light sockets that just turn on and off|
10
10
  |Simple Light Bulb|`SimpleLight`|Light bulbs that just turn on and off|
11
11
  |Tunable White Light Bulb|`TWLight`<sup>[2](#tunable-white-light-bulbs)</sup>|Bulbs with tunable white and dimming functionality <small>([instructions](#tunable-white-light-bulbs))</small>|
@@ -21,13 +21,17 @@ If you are looking for verified configurations for your specific device, please
21
21
  |Garage Door|`GarageDoor`<sup>[10](#garage-doors)</sup>|Smart garage doors or garage door openers <small>([instructions](#garage-doors))</small>|
22
22
  |Simple Garage Door|`SimpleGarageDoor`<sup>[10](#simple-garage-doors)</sup>|Sliding gate openers and garage door controllers with open/stop/close action DPs and a simple three-value status DP <small>([instructions](#simple-garage-doors))</small>|
23
23
  |Simple Blinds|`SimpleBlinds`<sup>[11](#simple-blinds)</sup>|Smart blinds and smart switches that control blinds <small>([instructions](#simple-blinds))</small>|
24
- |Simple Blinds2|`SimpleBlinds2`<sup>[11](#simple-blinds)</sup>|Smart blinds and smart switches that control blinds(Use if simple Blinds (1) doesn't work for you. <small>([instructions](#simple-blinds))</small>|
25
24
  |Vertical Blinds with Tilt|`VerticalBlindsWithTilt`<sup>[11](#vertical-blinds-with-tilt)</sup>|Smart vertical blinds with open/close and panel rotation <small>([instructions](#vertical-blinds-with-tilt))</small>|
26
25
  |Percent Control Blinds|`PercentBlinds`<sup>[11](#percent-control-blinds)</sup>|Blinds that natively report and accept a percentage position via a `percent_control` datapoint <small>([instructions](#percent-control-blinds))</small>|
27
26
  |Smart Plug w/ White and Color Lights|`RGBTWOutlet`<sup>[12](#outlets-with-white-and-color-lights)</sup>|Smart plugs that have controllable RGBTW LEDs <small>([instructions](#outlets-with-white-and-color-lights))</small>|
28
- |Smart Fan Regulator|`SimpleFanAccessory`<sup>[more](#smart-fan-regulators-and-accessories)</sup>|Smart Fan Regulators that have controllable Speeds <small>([instructions](#smart-fan-regulators-and-accessories))</small>|
29
- |Smart Fan with Light|`SimpleFanLightAccessory`<sup>[more](#smart-fan-with-light)</sup>|Smart Fan devices that have controllable Speeds, Directions and a built-in Light<small>([instructions](#smart-fan-with-light))</small>|
30
- |Smart Switch|`Switch`<sup>[13](#switch)</sup>|Smart switches that just turn on and off <small>([instructions](#switch))</small>|
27
+ |Smart Fan Regulator|`Fan`<sup>[more](#smart-fan-regulators-and-accessories)</sup>|Smart Fan Regulators that have controllable Speeds <small>([instructions](#smart-fan-regulators-and-accessories))</small>|
28
+ |Smart Fan with Light|`FanLight`<sup>[more](#smart-fan-with-light)</sup>|Smart Fan devices that have controllable Speeds, Directions and a built-in Light<small>([instructions](#smart-fan-with-light))</small>|
29
+ |Air Purifier|`AirPurifier`<sup>[more](#air-purifiers)</sup>|Air purifiers with fan-speed, auto mode and optional air-quality sensor <small>([instructions](#air-purifiers))</small>|
30
+ |Dehumidifier|`Dehumidifier`<sup>[more](#dehumidifiers)</sup>|Dehumidifiers with target humidity and fan-speed control <small>([instructions](#dehumidifiers))</small>|
31
+ |Oil Diffuser / Humidifier|`OilDiffuser`<sup>[more](#oil-diffusers--humidifiers)</sup>|Aroma diffusers / humidifiers with mist control and an optional colour light <small>([instructions](#oil-diffusers--humidifiers))</small>|
32
+ |Water Valve / Sprinkler|`watervalve`<sup>[more](#water-valves--single-sprinklers)</sup>|A single irrigation/shower/faucet valve with an optional run timer <small>([instructions](#water-valves--single-sprinklers))</small>|
33
+ |Simple Dimmer (fixed brightness DP)|`SimpleDimmer2`<sup>[more](#simple-dimmers--wled-dimmers)</sup>|Variant of `SimpleDimmer` whose brightness is fixed to DP `3` <small>([instructions](#simple-dimmers--wled-dimmers))</small>|
34
+ |Smart Switch|`Switch`<sup>[13](#switch)</sup>|Smart switches that just turn on and off <small>([instructions](#switch))</small>|
31
35
 
32
36
 
33
37
 
@@ -46,7 +50,7 @@ These are swich gangs
46
50
  "id": "032000123456789abcde",
47
51
  "key": "0123456789abcdef",
48
52
 
49
- /* Define number of switches it support */
53
+ /* Define number of switches it support. Default: 1 */
50
54
  "switchCount": 3,
51
55
  }
52
56
  ```
@@ -74,7 +78,7 @@ These are plugs with a single outlet that can only be turned on or off.
74
78
  /* Datapoint identifier for wattage reporting */
75
79
  "wattsId": 7,
76
80
 
77
- /* Often voltage is reported divided by 10; if that is
81
+ /* Often voltage is reported divided by 10; if that is
78
82
  not the case for you, override the default */
79
83
  "voltsDivisor": 10,
80
84
 
@@ -88,11 +92,13 @@ These are plugs with a single outlet that can only be turned on or off.
88
92
 
89
93
  /* Additional parameters to override defaults only if needed */
90
94
 
91
- /* Override the default datapoint identifier for power */
95
+ /* Override the default datapoint identifier for power. Default: "1" */
92
96
  "dpPower": 1
93
97
  }
94
98
  ```
95
99
 
100
+ > The energy-reporting options (`voltsId` / `ampsId` / `wattsId`) are unset by default — add them only if your plug reports those values. The divisors shown above (`10` / `1000` / `10`) are the defaults.
101
+
96
102
  ### Tunable White Light Bulbs
97
103
  These are light bulbs that let you control the brightness and tune the bulb's light from warm white to daylight white.
98
104
 
@@ -107,20 +113,20 @@ These are light bulbs that let you control the brightness and tune the bulb's li
107
113
 
108
114
  /* Additional parameters to override defaults only if needed */
109
115
 
110
- /* Override the default datapoint identifier for power */
116
+ /* Override the default datapoint identifier for power. Default: "1" */
111
117
  "dpPower": 1,
112
118
 
113
- /* Override the default datapoint identifier for brightness */
119
+ /* Override the default datapoint identifier for brightness. Default: "2" */
114
120
  "dpBrightness": 2,
115
121
 
116
- /* Override the default datapoint identifier for color-temperature */
122
+ /* Override the default datapoint identifier for color-temperature. Default: "3" */
117
123
  "dpColorTemperature": 3,
118
124
 
119
125
  /* Minimum white temperature mired value
120
- (See https://en.wikipedia.org/wiki/Mired) */
126
+ (See https://en.wikipedia.org/wiki/Mired). Default: 0 */
121
127
  "minWhiteColor": 140,
122
128
 
123
- /* Maximum white temperature mired value */
129
+ /* Maximum white temperature mired value. Default: 600 */
124
130
  "maxWhiteColor": 400
125
131
  }
126
132
  ```
@@ -130,7 +136,7 @@ These are bulbs that can produce white light as well as colors and allow you to
130
136
 
131
137
  There are two kinds of color devices: (1) the most common ones use 14 characters to represent the color (`HEXHSB`), and (2) others use 12 characters for the color (`HSB`). The `colorFunction` defaults to `HEXHSB` but can be overriden in the config block to properly use the second type.
132
138
 
133
- It is common for `HEXHSB` devices to use white color temperature and brightness values from 0 to 255 (scale of `255`). It is also common for `HSB` devices to use white color temperature and brightness values from 0 to 1000 (scale of `1000`). If a device doesn't follow these common values, `scaleWhiteColor` and `scaleBrightness` can help.
139
+ It is common for `HEXHSB` devices to use white color temperature and brightness values from 0 to 255 (scale of `255`). It is also common for `HSB` devices to use white color temperature and brightness values from 0 to 1000 (scale of `1000`). If a device doesn't follow these common values, `scaleWhiteColor` and `scaleBrightness` can help.
134
140
 
135
141
  ```json5
136
142
  {
@@ -143,26 +149,32 @@ It is common for `HEXHSB` devices to use white color temperature and brightness
143
149
 
144
150
  /* Additional parameters to override defaults only if needed */
145
151
 
146
- /* Override the default datapoint identifier for power */
152
+ /* Override the default datapoint identifier for power. Default: "1" */
147
153
  "dpPower": 1,
148
154
 
149
- /* Override the default datapoint identifier for mode (white vs color) */
155
+ /* Override the default datapoint identifier for mode (white vs color). Default: "2" */
150
156
  "dpMode": 2,
151
157
 
152
- /* Override the default datapoint identifier for brightness */
158
+ /* Override the default datapoint identifier for brightness. Default: "3" */
153
159
  "dpBrightness": 3,
154
160
 
155
- /* Override the default datapoint identifier for color-temperature of the whites */
161
+ /* Override the default datapoint identifier for color-temperature of the whites. Default: "4" */
156
162
  "dpColorTemperature": 4,
157
163
 
158
- /* Override the default datapoint identifier for color */
164
+ /* Override the default datapoint identifier for color. Default: "5" */
159
165
  "dpColor": 5,
160
166
 
167
+ /* Override the mode phrases the device uses for white vs colour
168
+ (both "cmdColour" and "cmdColor" spellings are accepted).
169
+ Defaults: "white" / "colour" */
170
+ "cmdWhite": "white",
171
+ "cmdColor": "colour",
172
+
161
173
  /* Minimum white temperature mired value
162
- (See https://en.wikipedia.org/wiki/Mired) */
174
+ (See https://en.wikipedia.org/wiki/Mired). Default: 140 */
163
175
  "minWhiteColor": 140,
164
176
 
165
- /* Maximum white temperature mired value */
177
+ /* Maximum white temperature mired value. Default: 400 */
166
178
  "maxWhiteColor": 400,
167
179
 
168
180
  /* Override the color format (default: HEXHSB)
@@ -170,10 +182,10 @@ It is common for `HEXHSB` devices to use white color temperature and brightness
170
182
  Using HSB defaults the scale of brightness and white color to 1000 */
171
183
  "colorFunction": "HEXHSB",
172
184
 
173
- /* Override the default brightness scale */
185
+ /* Override the default brightness scale. Default: 255 (1000 in HSB mode) */
174
186
  "scaleBrightness": 255,
175
-
176
- /* Override the default color temperature scale */
187
+
188
+ /* Override the default color temperature scale. Default: 255 (1000 in HSB mode) */
177
189
  "scaleWhiteColor": 255
178
190
  }
179
191
  ```
@@ -189,7 +201,7 @@ These device can have any number of controllable outlets. To let the plugin know
189
201
  "model": "Smart Wifi Power Strip",
190
202
  "id": "032000123456789abcde",
191
203
  "key": "0123456789abcdef",
192
- /* This device has 3 outlets and 2 USB ports, all individually controllable */
204
+ /* This device has 3 outlets and 2 USB ports, all individually controllable. Default: 1 */
193
205
  "outletCount": 5
194
206
  }
195
207
  ```
@@ -295,24 +307,43 @@ Additional parameters can be found in the sample below.
295
307
  /* This device has no oscillation (swinging) function */
296
308
  "noSwing": true,
297
309
 
298
- /* Minimum temperature supported, in Celsius (°C) */
310
+ /* Minimum temperature supported, in Celsius (°C). Default: 10 */
299
311
  "minTemperature": 15,
300
312
 
301
- /* Maximum temperature supported, in Celsius (°C) */
313
+ /* Maximum temperature supported, in Celsius (°C). Default: 35 */
302
314
  "maxTemperature": 40,
303
315
 
304
- /* Temperature change steps, in Celsius (°C) */
316
+ /* Temperature change steps, in Celsius (°C). Default: 1 */
305
317
  "minTemperatureSteps": 1,
306
318
 
307
- /* Only if your firmware reports/accepts temperatures scaled by 10 (e.g. 170 = 17.0 °C) */
308
- "temperatureDivisor": 10
319
+ /* Only if your firmware reports/accepts temperatures scaled by 10 (e.g. 170 = 17.0 °C). Default: 1 */
320
+ "temperatureDivisor": 10,
321
+
322
+ /* Override the temperatureDivisor for just the current temperature, if it
323
+ differs from the setpoint scale. Default: same as temperatureDivisor */
324
+ "currentTemperatureDivisor": 10,
325
+
326
+ /* Override the temperatureDivisor for just the setpoint, if it differs from
327
+ the current-temperature scale. Default: same as temperatureDivisor */
328
+ "thresholdTemperatureDivisor": 10,
329
+
330
+ /* --- Data-point overrides (only if your device differs from the defaults) --- */
331
+
332
+ "dpActive": 1, /* on/off. Default: "1" */
333
+ "dpThreshold": 2, /* target temperature setpoint. Default: "2" */
334
+ "dpCurrentTemperature": 3, /* current temperature. Default: "3" */
335
+ "dpMode": 4, /* mode (cool/heat/auto). Default: "4" */
336
+ "dpRotationSpeed": 5, /* fan speed. Default: "5" */
337
+ "dpChildLock": 6, /* child lock. Default: "6" */
338
+ "dpTempUnits": 19, /* temperature display units. Default: "19" */
339
+ "dpSwingMode": 104 /* swing / oscillation. Default: "104" */
309
340
  }
310
341
  ```
311
342
 
312
343
  ### Heat Convectors
313
344
  The heating panels have a _low_ or _high_ setting but since HomeKit's definition doesn't accommodate that, I have mapped it to `Fan Speed`; be aware that when the fan speed slider is at the lowest value, it turns the device off. By default, the plugin uses _LOW_ and _HIGH_ to request these settings and these commands can be configured using `cmdLow` and `cmdHigh`; if your device uses _Low_ and _High_, add these two additional parameters to your config. Additional parameters can be found in the sample below.
314
345
 
315
- If your signature doesn't have a variation of _low_ or _high_, `SimpleHeater` would be the correct device `type` to use and not this one.
346
+ If your signature doesn't have a variation of _low_ or _high_, `SimpleHeater` would be the correct device `type` to use and not this one.
316
347
 
317
348
  ```json5
318
349
  {
@@ -325,48 +356,56 @@ If your signature doesn't have a variation of _low_ or _high_, `SimpleHeater` wo
325
356
 
326
357
  /* Additional parameters to override defaults only if needed */
327
358
 
328
- /* Override the default datapoint identifier of activity */
359
+ /* Override the default datapoint identifier of activity. Default: "7" */
329
360
  "dpActive": 7,
330
361
 
331
- /* Override the default datapoint identifier for the desired temperature*/
362
+ /* Override the default datapoint identifier for the desired temperature. Default: "2" */
332
363
  "dpDesiredTemperature": 2,
333
364
 
334
- /* Override the default datapoint identifier for the current temperature */
365
+ /* Override the default datapoint identifier for the current temperature. Default: "3" */
335
366
  "dpCurrentTemperature": 3,
336
367
 
337
- /* Override the default datapoint identifier for rotation speed */
368
+ /* Override the default datapoint identifier for rotation speed. Default: "4" */
338
369
  "dpRotationSpeed": 4,
339
370
 
340
- /* Override the default datapoint identifier for child-lock */
371
+ /* Override the default datapoint identifier for child-lock. Default: "6" */
341
372
  "dpChildLock": 6,
342
373
 
343
- /* Override the default datapoint identifier for temperature-display units */
374
+ /* Override the default datapoint identifier for temperature-display units. Default: "19" */
344
375
  "dpTemperatureDisplayUnits": 19,
345
376
 
346
- /* Override phrase for low setting */
377
+ /* Override phrase for low setting. Default: "LOW" */
347
378
  "cmdLow": "Low",
348
379
 
349
- /* Override phrase for high setting */
380
+ /* Override phrase for high setting. Default: "HIGH" */
350
381
  "cmdHigh": "High",
351
382
 
352
- /* This device does not provide locking the physical controls */
383
+ /* Flip the speed slider so LOW sits at 1% and HIGH at 100%
384
+ (instead of the reverse). Default: false */
385
+ "enableFlipSpeedSlider": true,
386
+
387
+ /* This device does not provide locking the physical controls. Default: false */
353
388
  "noChildLock": true,
354
389
 
355
- /* This device has no function to change the temperature units */
390
+ /* This device has no function to change the temperature units. Default: false */
356
391
  "noTemperatureUnit": true,
357
392
 
358
- /* Minimum temperature supported, in Celsius (°C) */
393
+ /* Minimum temperature supported, in Celsius (°C). Default: 15 */
359
394
  "minTemperature": 15,
360
395
 
361
- /* Maximum temperature supported, in Celsius (°C) */
362
- "maxTemperature": 35
396
+ /* Maximum temperature supported, in Celsius (°C). Default: 35 */
397
+ "maxTemperature": 35,
398
+
399
+ /* Temperature step for the HomeKit slider, in °C. Default: 1 */
400
+ "minTemperatureSteps": 1
363
401
  }
364
402
  ```
365
403
 
366
404
  ### Simple Dimmers / WLED Dimmers
367
- These are switches that allow turning on and off, and dimming. Two distinct types are available:
405
+ These are switches that allow turning on and off, and dimming. Three distinct types are available:
368
406
 
369
407
  - `SimpleDimmer` — a plain dimmer with power and brightness control.
408
+ - `SimpleDimmer2` — identical to `SimpleDimmer`, but its brightness data-point is **fixed to DP `3`** (a `dpBrightness` value is ignored). Use it only if your dimmer reports brightness on DP `3` and `SimpleDimmer` doesn't work. `dpPower` (default `"1"`) is still configurable.
370
409
  - `WledDimmer` — a dimmer that can additionally drive a [WLED](https://kno.wled.ge/) controller (e.g. a Tuya-based relay/dimmer feeding power to a WLED strip). With none of the WLED options below configured, it behaves exactly like a `SimpleDimmer`.
371
410
 
372
411
  The following options apply to `WledDimmer` only (they are ignored by `SimpleDimmer`):
@@ -419,30 +458,47 @@ While defined mainly to develop a more robust device type, this can be used to c
419
458
 
420
459
  /* Additional parameters to override defaults only if needed */
421
460
 
422
- /* Override the default datapoint identifier for being active */
461
+ /* Override the default datapoint identifier for being active. Default: "1" */
423
462
  "dpActive": 1,
424
463
 
425
- /* Override the default datapoint identifier for the desired temperature */
464
+ /* Override the default datapoint identifier for the desired temperature. Default: "2" */
426
465
  "dpDesiredTemperature": 2,
427
466
 
428
- /* Override the default datapoint identifier for the current temperature */
467
+ /* Override the default datapoint identifier for the current temperature. Default: "3" */
429
468
  "dpCurrentTemperature": 3,
430
469
 
431
470
  /* If your device reports temperatures in multiples of the real value, introduce it here.
432
- e.g., if your device reports 155 for 15.5°C, use the value 10 */
471
+ e.g., if your device reports 155 for 15.5°C, use the value 10. Default: 1 */
433
472
  "temperatureDivisor": 1,
434
473
 
435
- /* Minimum temperature supported, in Celsius (°C) */
474
+ /* Divisor applied only to the desired (target) temperature, if it differs
475
+ from the current-temperature scale. Default: same as temperatureDivisor */
476
+ "thresholdTemperatureDivisor": 1,
477
+
478
+ /* Offset added to every temperature (reading and setpoint), in °C.
479
+ Use to correct a device that consistently reads high or low. Default: 0 */
480
+ "temperatureOffset": 0,
481
+
482
+ /* Offset added only to the displayed current temperature, in °C
483
+ (handy for a wall-mounted sensor). Default: same as temperatureOffset */
484
+ "currentTemperatureOffset": 0,
485
+
486
+ /* Minimum temperature supported, in Celsius (°C). Default: 15 */
436
487
  "minTemperature": 15,
437
488
 
438
- /* Maximum temperature supported, in Celsius (°C) */
439
- "maxTemperature": 35
489
+ /* Maximum temperature supported, in Celsius (°C). Default: 35 */
490
+ "maxTemperature": 35,
491
+
492
+ /* Temperature step for the HomeKit slider, in °C. Default: 1 */
493
+ "minTemperatureSteps": 1
440
494
  }
441
495
  ```
442
496
 
443
497
  ### Garage Doors
444
498
  While still in early testing, you can use this to open and close the garage doors. If your garage door or garage door opener does more that just open and close, for example reports its position or detects obstacles, please create an issue and paste your signature with any information you can provide; this is so we can build a better solution for you together.
445
499
 
500
+ The default data-points depend on the `manufacturer` you set: `dpAction`/`dpStatus` default to `"101"`/`"102"` for Kogan, `"1"`/`"101"` for Wofea, and `"1"`/`"2"` for everything else. Override them below if your device differs.
501
+
446
502
  ```json5
447
503
  {
448
504
  "name": "My Garage Door",
@@ -460,7 +516,7 @@ While still in early testing, you can use this to open and close the garage door
460
516
  /* Override the default datapoint identifier for the state of the door */
461
517
  "dpStatus": 2,
462
518
 
463
- /* If the app reports open when the door is closed,
519
+ /* If the app reports open when the door is closed,
464
520
  and reports closed when it is open */
465
521
  "flipState": true
466
522
  }
@@ -556,14 +612,29 @@ Normally the blinds don't report their position. This plugin attempts to time th
556
612
 
557
613
  /* Additional parameters to override defaults only if needed */
558
614
 
559
- /* How many seconds does it take to fully open from a fully closed state */
615
+ /* Data-point that carries the open/close/stop command. Default: "1" */
616
+ "dpAction": 1,
617
+
618
+ /* Which set of command words this blind understands. Default: 1
619
+ 1 → "open" / "close" / "stop"
620
+ 2 → "on" / "off" / "stop"
621
+ 3 → "1" / "2" / "3"
622
+ Set cmdOpen/cmdClose/cmdStop below to override individual words. */
623
+ "dpBlindType": 1,
624
+
625
+ /* Override the individual command words (defaults follow dpBlindType above) */
626
+ "cmdOpen": "open",
627
+ "cmdClose": "close",
628
+ "cmdStop": "stop",
629
+
630
+ /* How many seconds does it take to fully open from a fully closed state. Default: 45 */
560
631
  "timeToOpen": 45,
561
632
 
562
- /* How many seconds it spends tightening the blinds while closing */
633
+ /* How many seconds it spends tightening the blinds while closing. Default: 0 */
563
634
  "timeToTighten": 0,
564
635
 
565
- /* If the app reports open when the blinds are closed,
566
- and reports closed when they are open */
636
+ /* If the app reports open when the blinds are closed,
637
+ and reports closed when they are open. Default: false */
567
638
  "flipState": true
568
639
  }
569
640
  ```
@@ -582,6 +653,7 @@ Support for Tuya/Graywind Smart Vertical Blinds with open/close (retract/extend)
582
653
  ```
583
654
 
584
655
  #### Full Configuration
656
+ All of these are optional — the defaults are `dpAction: "1"`, `dpTilt: "2"`, `dpTiltState: "3"` and `timeToClose: 30` (seconds).
585
657
  ```json
586
658
  {
587
659
  "name": "Living Room Blinds",
@@ -639,7 +711,7 @@ These are plugs with a single outlet that that have controllable white and color
639
711
 
640
712
  There are two kinds of color devices: (1) the most common ones use 14 characters to represent the color (`HEXHSB`), and (2) others use 12 characters for the color (`HSB`). The `colorFunction` defaults to `HEXHSB` but can be overriden in the config block to properly use the second type.
641
713
 
642
- It is common for `HEXHSB` devices to use white color temperature and brightness values from 0 to 255 (scale of `255`). It is also common for `HSB` devices to use white color temperature and brightness values from 0 to 1000 (scale of `1000`). If a device doesn't follow these common values, `scaleWhiteColor` and `scaleBrightness` can help.
714
+ It is common for `HEXHSB` devices to use white color temperature and brightness values from 0 to 255 (scale of `255`). It is also common for `HSB` devices to use white color temperature and brightness values from 0 to 1000 (scale of `1000`). If a device doesn't follow these common values, `scaleWhiteColor` and `scaleBrightness` can help.
643
715
 
644
716
  ```json5
645
717
  {
@@ -661,7 +733,7 @@ It is common for `HEXHSB` devices to use white color temperature and brightness
661
733
  /* Datapoint identifier for wattage reporting */
662
734
  "wattsId": 7,
663
735
 
664
- /* Often voltage is reported divided by 10; if that is
736
+ /* Often voltage is reported divided by 10; if that is
665
737
  not the case for you, override the default */
666
738
  "voltsDivisor": 10,
667
739
 
@@ -675,29 +747,35 @@ It is common for `HEXHSB` devices to use white color temperature and brightness
675
747
 
676
748
  /* Additional parameters to override defaults only if needed */
677
749
 
678
- /* Override the default datapoint identifier for outlet power */
750
+ /* Override the default datapoint identifier for outlet power. Default: "101" */
679
751
  "dpPower": 101,
680
752
 
681
- /* Override the default datapoint identifier for light power */
753
+ /* Override the default datapoint identifier for light power. Default: "1" */
682
754
  "dpLight": 1,
683
755
 
684
- /* Override the default datapoint identifier for mode (white vs color) */
756
+ /* Override the default datapoint identifier for mode (white vs color). Default: "2" */
685
757
  "dpMode": 2,
686
758
 
687
- /* Override the default datapoint identifier for brightness */
759
+ /* Override the default datapoint identifier for brightness. Default: "3" */
688
760
  "dpBrightness": 3,
689
761
 
690
- /* Override the default datapoint identifier for color-temperature of the whites */
762
+ /* Override the default datapoint identifier for color-temperature of the whites. Default: "4" */
691
763
  "dpColorTemperature": 4,
692
764
 
693
- /* Override the default datapoint identifier for color */
765
+ /* Override the default datapoint identifier for color. Default: "5" */
694
766
  "dpColor": 5,
695
767
 
768
+ /* Override the mode phrases the device uses for white vs colour
769
+ (both "cmdColour" and "cmdColor" spellings are accepted).
770
+ Defaults: "white" / "colour" */
771
+ "cmdWhite": "white",
772
+ "cmdColor": "colour",
773
+
696
774
  /* Minimum white temperature mired value
697
- (See https://en.wikipedia.org/wiki/Mired) */
775
+ (See https://en.wikipedia.org/wiki/Mired). Default: 140 */
698
776
  "minWhiteColor": 140,
699
777
 
700
- /* Maximum white temperature mired value */
778
+ /* Maximum white temperature mired value. Default: 400 */
701
779
  "maxWhiteColor": 400,
702
780
 
703
781
  /* Override the color format (default: HEXHSB)
@@ -705,16 +783,18 @@ It is common for `HEXHSB` devices to use white color temperature and brightness
705
783
  Using HSB defaults the scale of brightness and white color to 1000 */
706
784
  "colorFunction": "HEXHSB",
707
785
 
708
- /* Override the default brightness scale */
786
+ /* Override the default brightness scale. Default: 255 (1000 in HSB mode) */
709
787
  "scaleBrightness": 255,
710
-
711
- /* Override the default color temperature scale */
788
+
789
+ /* Override the default color temperature scale. Default: 255 (1000 in HSB mode) */
712
790
  "scaleWhiteColor": 255
713
791
  }
714
792
  ```
715
793
 
716
794
  ### Smart Fan Regulators and Accessories
717
- These are accessories that may act as a regulator switch or an inbuilt regulator to your ceiling fan. Supported features include on/off switching, speed controls (generally managed through two buttons, one speed at a time in each direction, up and down), and direction control (forward/reverse). There are two kinds of regulator devices: (1) the most common ones use 3 speed controls, and (2) others use 5 speed controls which are found compatible with most fan regulators in India, Australia, and the UK.
795
+ These are accessories that may act as a regulator switch or an inbuilt regulator to your ceiling fan. Supported features include on/off switching, speed controls (generally managed through two buttons, one speed at a time in each direction, up and down), direction control (forward/reverse), and optional oscillation (swing). There are two kinds of regulator devices: (1) the most common ones use 3 speed controls, and (2) others use 5 speed controls which are found compatible with most fan regulators in India, Australia, and the UK.
796
+
797
+ Every option below is optional — the defaults match a common 3-speed fan. The data-point keys are **`dpFanOn` / `dpRotationSpeed` / `dpFanDirection`**.
718
798
 
719
799
  ```json5
720
800
  {
@@ -725,28 +805,51 @@ These are accessories that may act as a regulator switch or an inbuilt regulator
725
805
  "id": "032000123456789abcde",
726
806
  "key": "0123456789abcdef",
727
807
 
728
- /* Override the default datapoint identifier of activity */
729
- "dpActive": "1",
808
+ /* Additional parameters to override defaults only if needed */
809
+
810
+ /* Data-point for fan on/off. Default: "1" */
811
+ "dpFanOn": "1",
812
+
813
+ /* Data-point for fan speed. Default: "3" */
814
+ "dpRotationSpeed": "3",
730
815
 
731
- /* Override the default datapoint identifier of rotation speed */
732
- "dpRotationSpeed": "2",
816
+ /* Data-point for direction control (forward/reverse). Default: "2" */
817
+ "dpFanDirection": "2",
818
+
819
+ /* Number of speed steps the fan supports (e.g. 5 for India/AU/UK regulators).
820
+ Default: 3 */
821
+ "maxSpeed": 3,
733
822
 
734
823
  /* Override the default datapoint identifier of direction control (forward/reverse) */
735
- "dpRotationDirection": 63,
824
+ "dpFanDirection": 63,
825
+
826
+ /* Speed to use when the fan is switched on from off. Default: 1 */
827
+ "fanDefaultSpeed": 1,
736
828
 
737
- /* Datapoint of the oscillation switch (a boolean DP). When set, a Swing
738
- (oscillation) control is shown in the Home app. Omit if the fan has none. */
829
+ /* Send the speed value as a string (e.g. "3") rather than a number.
830
+ Most fans require this; turn off only if yours ignores string speeds.
831
+ Default: true */
832
+ "useStrings": true,
833
+
834
+ /* Send fan on/off and speed together in one legacy control packet.
835
+ Set false if your firmware ignores multi-DP packets. Default: true */
836
+ "useMultiState": true,
837
+
838
+ /* Data-point of the oscillation switch (a boolean DP). When set, a Swing
839
+ (oscillation) control appears in the Home app. Omit if the fan can't oscillate. */
739
840
  "dpSwing": 4,
740
841
 
741
- /* Hide the rotation direction control. Enable for fans that have no
742
- forward/reverse, or whose direction datapoint is actually a mode enum,
743
- so forward/reverse is never written into it. */
842
+ /* Drop the direction control entirely for fans whose "direction" DP is
843
+ actually a mode enum (e.g. nature/sleep/smart), so HomeKit won't write
844
+ forward/reverse into it. Default: false */
744
845
  "noDirection": true
745
846
  }
746
847
  ```
747
848
 
748
849
  ### Smart Fan with Light
749
- These are accessories that combine fan and lighting control in one device. Supported features include on/off switching, speed controls (generally managed through two buttons, one speed at a time in each direction, up and down), direction control (forward/reverse), as well as light power, brightness, and color temperature controls. There are multiple kinds of devices with different speed and light control capabilities.
850
+ These are accessories that combine fan and lighting control in one device. Supported features include on/off switching, speed control, direction control (forward/reverse), as well as light power, brightness, and color temperature controls. There are multiple kinds of devices with different speed and light control capabilities.
851
+
852
+ > **Key names.** This accessory uses **`dpFanOn`**, **`dpRotationSpeed`**, **`dpFanDirection`**, **`dpLightOn`** and **`dpColorTemp`**. Brightness is on Tuya's standard 10–1000 scale and colour temperature on Tuya's 0–1000 scale (mapped to the mired range below). Every option is optional; defaults are shown.
750
853
 
751
854
  ```json5
752
855
  {
@@ -757,17 +860,55 @@ These are accessories that combine fan and lighting control in one device. Suppo
757
860
  "manufacturer": "Hunter Pacific International",
758
861
  "model": "Polar v2 Fan",
759
862
 
760
- "dpLight": 20,
863
+ /* --- Fan --- */
864
+
865
+ /* Data-point for fan on/off. Default: "60" */
866
+ "dpFanOn": 60,
867
+
868
+ /* Data-point for fan speed. Default: "62" */
869
+ "dpRotationSpeed": 62,
870
+
871
+ /* Data-point for direction control (forward/reverse). Default: "63" */
872
+ "dpFanDirection": 63,
873
+
874
+ /* Number of speed steps the fan supports. Default: 6 */
875
+ "maxSpeed": 6,
876
+
877
+ /* Speed used when the fan is switched on from off. Default: 1 */
878
+ "fanDefaultSpeed": 1,
879
+
880
+ /* Send the speed value as a string rather than a number. Default: true */
881
+ "useStrings": true,
882
+
883
+ /* Send each data point in its own packet instead of combining fan
884
+ power + speed into one. Default: false (see note below) */
885
+ "singleDpWrites": false,
886
+
887
+ /* --- Light --- */
888
+
889
+ /* Expose the light at all. Set false for a fan with no light. Default: true */
890
+ "useLight": true,
891
+
892
+ /* Data-point for light on/off. Default: "20" */
893
+ "dpLightOn": 20,
894
+
895
+ /* Expose a brightness slider. Default: true */
761
896
  "useBrightness": true,
897
+
898
+ /* Data-point for brightness (Tuya 10–1000 scale). Default: "22" */
762
899
  "dpBrightness": 22,
763
- "minBrightness": 1,
764
- "scaleBrightness": 9,
765
- "dpColorTemperature": 23,
766
900
 
767
- "dpActive": 60,
768
- "dpRotationSpeed": 62,
769
- "maxSpeed": 9,
770
- "dpRotationDirection": 63
901
+ /* Expose a colour-temperature control. Default: true */
902
+ "useColorTemp": true,
903
+
904
+ /* Data-point for colour temperature (Tuya 0–1000 scale). Default: "23" */
905
+ "dpColorTemp": 23,
906
+
907
+ /* Coolest colour temperature, in mireds (~6500 K). Default: 154 */
908
+ "minWhiteColor": 154,
909
+
910
+ /* Warmest colour temperature, in mireds (~2700 K). Default: 370 */
911
+ "maxWhiteColor": 370
771
912
  }
772
913
  ```
773
914
 
@@ -780,7 +921,7 @@ If the light, brightness and turning the fan **off** all work, but turning the f
780
921
  "id": "032000123456789abcde",
781
922
  "key": "0123456789abcdef",
782
923
 
783
- "dpActive": 60,
924
+ "dpFanOn": 60,
784
925
  "dpRotationSpeed": 62,
785
926
 
786
927
  /* Send each data point in its own packet instead of combining them. */
@@ -788,6 +929,48 @@ If the light, brightness and turning the fan **off** all work, but turning the f
788
929
  }
789
930
  ```
790
931
 
932
+ #### Lights that use `On`/`Off` text values instead of a boolean
933
+
934
+ Some fans (e.g. the **Orient AEON V.C.**) type their light data point as an *enum of text values* — it sends `"On"` / `"Off"` strings rather than a boolean. With such a fan the light appears in HomeKit but toggling it does nothing, because the plugin's default light handling expects a boolean. Set `"lightUseEnum": true` to make the plugin read and write the text values instead. The command strings default to `"On"` / `"Off"` and can be overridden with `lightOnCommand` / `lightOffCommand`.
935
+
936
+ #### Direction carried on a shared "mode" data point
937
+
938
+ On some fans, forward/reverse is not its own data point — it is one of several values of a shared *mode* data point (e.g. a `Windmode` enum with values like `Normal`, `Reverse`, `Sleep`, `Breeze`). Point `dpFanDirection` at that data point and set `directionForwardCommand` / `directionReverseCommand` to the values it uses (they default to `"forward"` / `"reverse"`). HomeKit's clockwise/counter-clockwise direction toggle then maps onto `Normal` / `Reverse`. Any other mode value (`Sleep`, `Breeze`, …) set from the Tuya app simply reads back as the forward direction.
939
+
940
+ > Note: because direction shares the mode data point, selecting a normal speed writes `Normal` to it, so the fan can only be in one mode at a time — this mirrors how the physical fan works. Modes that HomeKit has no control for (Turbo, Sleep, Breeze) and the countdown timer are not exposed; set them from the Tuya / Smart Life app.
941
+
942
+ A full example for the Orient AEON V.C. (Power = DP 1, WindSpeed enum `"1"`–`"5"` = DP 2, Windmode = DP 3, Light enum `"On"`/`"Off"` = DP 101):
943
+
944
+ ```json5
945
+ {
946
+ "type": "FanLight",
947
+ "name": "Orient AEON Fan",
948
+ "id": "032000123456789abcde",
949
+ "key": "0123456789abcdef",
950
+
951
+ /* Power (boolean) */
952
+ "dpFanOn": 1,
953
+
954
+ /* WindSpeed enum "1".."5" — parsed as levels 1..5 and sent as strings */
955
+ "dpRotationSpeed": 2,
956
+ "maxSpeed": 5,
957
+ "useStrings": true,
958
+
959
+ /* Light is an "On"/"Off" enum, not a boolean; no brightness/colour temp */
960
+ "dpLightOn": 101,
961
+ "lightUseEnum": true,
962
+ "useBrightness": false,
963
+ "useColorTemp": false,
964
+
965
+ /* Direction lives on the Windmode data point as Normal/Reverse */
966
+ "dpFanDirection": 3,
967
+ "directionForwardCommand": "Normal",
968
+ "directionReverseCommand": "Reverse"
969
+ }
970
+ ```
971
+
972
+ > On this fan, reverse airflow only runs at the lower speeds — that limit is enforced by the fan's own firmware, not the plugin, so the HomeKit speed slider still shows the full range.
973
+
791
974
  ### Irrigation Systems / Sprinklers
792
975
 
793
976
  Multi-valve Tuya irrigation/sprinkler controllers (the battery-powered Wi-Fi "faucet timers" that expose several `switch_*` valves and a `battery_percentage`) are exposed as a single, fully-fledged HomeKit **Irrigation System** accessory:
@@ -898,3 +1081,150 @@ It's deliberately carried on the system tile rather than as a separate sensor ac
898
1081
  /* "noBattery": true, */
899
1082
  }
900
1083
  ```
1084
+
1085
+ ### Air Purifiers
1086
+ Air purifiers exposed as a HomeKit Air Purifier with on/off, an auto mode, fan-speed control and (optionally) an air-quality sensor. The data-points are fixed; only the options below are configurable.
1087
+
1088
+ ```json5
1089
+ {
1090
+ "name": "My Air Purifier",
1091
+ "type": "AirPurifier",
1092
+ "manufacturer": "Proscenic",
1093
+ "model": "A8",
1094
+ "id": "032000123456789abcde",
1095
+ "key": "0123456789abcdef",
1096
+
1097
+ /* Additional parameters to override defaults only if needed */
1098
+
1099
+ /* Map the fan speed onto a fixed number of discrete steps instead of a
1100
+ continuous slider. Some firmwares need this for speed changes to
1101
+ register. Default: off (continuous) */
1102
+ "noRotationSpeed": true,
1103
+
1104
+ /* Number of discrete speed steps to use when noRotationSpeed is set (1–99).
1105
+ Has no effect unless noRotationSpeed is enabled. Default: 100 */
1106
+ "fanSpeedSteps": 3,
1107
+
1108
+ /* Override the device's "auto" mode phrase (case-sensitive). Default: "AUTO" */
1109
+ "cmdAuto": "AUTO",
1110
+
1111
+ /* Add an Air Quality sensor service (PM2.5 / air-quality level). Default: false */
1112
+ "showAirQuality": true,
1113
+
1114
+ /* Name for the air-quality sensor service. Default: "Air Quality" */
1115
+ "nameAirQuality": "Air Quality",
1116
+
1117
+ /* This device has no child-lock data-point. Default: false */
1118
+ "noChildLock": true
1119
+ }
1120
+ ```
1121
+
1122
+ ### Dehumidifiers
1123
+ Dehumidifiers exposed as a HomeKit Humidifier/Dehumidifier with a target-humidity slider and optional fan-speed and child-lock controls. The data-points are fixed; only the options below are configurable.
1124
+
1125
+ ```json5
1126
+ {
1127
+ "name": "My Dehumidifier",
1128
+ "type": "Dehumidifier",
1129
+ "manufacturer": "Generic",
1130
+ "model": "Smart Dehumidifier",
1131
+ "id": "032000123456789abcde",
1132
+ "key": "0123456789abcdef",
1133
+
1134
+ /* Additional parameters to override defaults only if needed */
1135
+
1136
+ /* Target-humidity bounds advertised to HomeKit, in %. Defaults: 40 / 80 */
1137
+ "minHumidity": 40,
1138
+ "maxHumidity": 80,
1139
+
1140
+ /* Target-humidity step, in %. Default: 5 */
1141
+ "humiditySteps": 5,
1142
+
1143
+ /* This device has no fan-speed control. Default: false */
1144
+ "noSpeed": true,
1145
+
1146
+ /* Fan-speed slider bounds and step. Defaults: 1 / 2 / 1 */
1147
+ "minSpeed": 1,
1148
+ "maxSpeed": 2,
1149
+ "speedSteps": 1,
1150
+
1151
+ /* This device has no child-lock data-point — hides the lock control entirely. Default: false */
1152
+ "noChildLock": true,
1153
+
1154
+ /* Keep the child-lock control visible but make toggling it a no-op
1155
+ (useful if the device exposes the lock DP but doesn't honour writes). Default: false */
1156
+ "noLock": true
1157
+ }
1158
+ ```
1159
+
1160
+ ### Oil Diffusers / Humidifiers
1161
+ Aroma diffusers and humidifiers with mist on/off, mist intensity (speed) and an optional colour light. Mode/colour command phrases vary by manufacturer and are auto-detected for several known brands (BelleLife, Geeni, Asakuki); override them only if your device differs.
1162
+
1163
+ ```json5
1164
+ {
1165
+ "name": "My Diffuser",
1166
+ "type": "OilDiffuser",
1167
+ "manufacturer": "Generic",
1168
+ "model": "Aroma Diffuser",
1169
+ "id": "032000123456789abcde",
1170
+ "key": "0123456789abcdef",
1171
+
1172
+ /* Additional parameters to override defaults only if needed */
1173
+
1174
+ /* Data-point for the mist (humidifier) on/off. Default: "1" */
1175
+ "dpActive": 1,
1176
+
1177
+ /* Data-point for mist intensity / speed. Default: "2" */
1178
+ "dpRotationSpeed": 2,
1179
+
1180
+ /* Number of mist-intensity steps. Default: 2 */
1181
+ "maxSpeed": 2,
1182
+
1183
+ /* Data-point for the light on/off. Default: "5" */
1184
+ "dpLight": 5,
1185
+
1186
+ /* Data-point for light mode (white vs colour). Default: "6" */
1187
+ "dpMode": 6,
1188
+
1189
+ /* Data-point for light colour / brightness value. Default: "8" */
1190
+ "dpColor": 8,
1191
+
1192
+ /* Data-point for the water-level status. Default: "9" */
1193
+ "dpWaterLevel": 9,
1194
+
1195
+ /* Override the white / colour mode phrases if your device disagrees
1196
+ (both British "cmdColour" and American "cmdColor" are accepted).
1197
+ Defaults: "white" / "colour" */
1198
+ "cmdWhite": "white",
1199
+ "cmdColor": "colour"
1200
+ }
1201
+ ```
1202
+
1203
+ ### Water Valves / Single Sprinklers
1204
+ A single irrigation/shower/faucet valve exposed as a HomeKit Valve, with an optional auto-shutoff run timer. For multi-zone controllers use `IrrigationSystem` instead.
1205
+
1206
+ ```json5
1207
+ {
1208
+ "name": "My Valve",
1209
+ "type": "watervalve",
1210
+ "manufacturer": "Generic",
1211
+ "model": "Smart Water Valve",
1212
+ "id": "032000123456789abcde",
1213
+ "key": "0123456789abcdef",
1214
+
1215
+ /* Additional parameters to override defaults only if needed */
1216
+
1217
+ /* Data-point for the valve on/off. Default: "1" */
1218
+ "dpPower": 1,
1219
+
1220
+ /* HomeKit valve type. One of "IRRIGATION", "SHOWER_HEAD", "WATER_FAUCET"
1221
+ (case-sensitive); anything else shows as a generic valve. Default: generic */
1222
+ "valveType": "IRRIGATION",
1223
+
1224
+ /* Default run time, in seconds, when the valve is switched on. Default: 600 */
1225
+ "defaultDuration": 600,
1226
+
1227
+ /* Don't expose the run timer (Set/Remaining Duration) at all. Default: false */
1228
+ "noTimer": false
1229
+ }
1230
+ ```