homebridge-tuya-plus 4.1.0-dev.63 → 4.1.0-dev.68

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.
@@ -538,6 +538,23 @@
538
538
  "functionBody": "return model.devices && model.devices[arrayIndices] && ['Fan', 'FanLight'].includes(model.devices[arrayIndices].type);"
539
539
  }
540
540
  },
541
+ "dpSwing": {
542
+ "title": "Swing/oscillation DP",
543
+ "description": "Data point of the fan's oscillation switch (a boolean DP). When set, a Swing (oscillation) control is shown in the Home app. Leave empty if the fan has no oscillation.",
544
+ "type": "integer",
545
+ "condition": {
546
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Fan'].includes(model.devices[arrayIndices].type);"
547
+ }
548
+ },
549
+ "noDirection": {
550
+ "title": "Hide the rotation direction control",
551
+ "description": "Enable if the fan has no forward/reverse direction, or if the direction data point is actually a mode enum. Prevents writing forward/reverse into that data point.",
552
+ "type": "boolean",
553
+ "placeholder": false,
554
+ "condition": {
555
+ "functionBody": "return model.devices && model.devices[arrayIndices] && ['Fan'].includes(model.devices[arrayIndices].type);"
556
+ }
557
+ },
541
558
  "maxSpeed": {
542
559
  "type": "integer",
543
560
  "placeholder": "3",
@@ -22,6 +22,13 @@ class SimpleFanAccessory extends BaseAccessory {
22
22
  this.dpFanOn = this._getCustomDP(this.device.context.dpFanOn) || '1';
23
23
  this.dpRotationSpeed = this._getCustomDP(this.device.context.dpRotationSpeed) || '3';
24
24
  this.dpFanDirection = this._getCustomDP(this.device.context.dpFanDirection) || '2';
25
+ // Oscillation is opt-in: SwingMode is only exposed when the fan's boolean
26
+ // swing DP is configured, so existing setups are unchanged (issue #96).
27
+ this.dpSwing = this._getCustomDP(this.device.context.dpSwing);
28
+ // Some fans use DP 2 for a mode enum (nature/sleep/…) rather than a
29
+ // rotation direction; RotationDirection would then write forward/reverse
30
+ // into that enum. noDirection drops the characteristic for those fans.
31
+ this.noDirection = this._coerceBoolean(this.device.context.noDirection, false);
25
32
 
26
33
  this.maxSpeed = parseInt(this.device.context.maxSpeed) || 3;
27
34
  this.fanDefaultSpeed = parseInt(this.device.context.fanDefaultSpeed) || 1;
@@ -44,10 +51,21 @@ class SimpleFanAccessory extends BaseAccessory {
44
51
  .onGet(() => this.getSpeed())
45
52
  .onSet(value => this.setSpeed(value));
46
53
 
47
- const characteristicFanDirection = serviceFan.getCharacteristic(Characteristic.RotationDirection)
48
- .updateValue(this._getFanDirection(dps[this.dpFanDirection]))
49
- .onGet(() => this.getFanDirection())
50
- .onSet(value => this.setFanDirection(value));
54
+ let characteristicFanDirection;
55
+ if (!this.noDirection) {
56
+ characteristicFanDirection = serviceFan.getCharacteristic(Characteristic.RotationDirection)
57
+ .updateValue(this._getFanDirection(dps[this.dpFanDirection]))
58
+ .onGet(() => this.getFanDirection())
59
+ .onSet(value => this.setFanDirection(value));
60
+ } else this._removeCharacteristic(serviceFan, Characteristic.RotationDirection);
61
+
62
+ let characteristicSwingMode;
63
+ if (this.dpSwing) {
64
+ characteristicSwingMode = serviceFan.getCharacteristic(Characteristic.SwingMode)
65
+ .updateValue(this._getSwingMode(dps[this.dpSwing]))
66
+ .onGet(() => this.getSwingMode())
67
+ .onSet(value => this.setSwingMode(value));
68
+ } else this._removeCharacteristic(serviceFan, Characteristic.SwingMode);
51
69
 
52
70
  this.device.on('change', (changes, state) => {
53
71
  if (changes.hasOwnProperty(this.dpFanOn) && characteristicFanOn.value !== changes[this.dpFanOn])
@@ -61,6 +79,11 @@ class SimpleFanAccessory extends BaseAccessory {
61
79
  if (characteristicFanDirection.value !== dir) characteristicFanDirection.updateValue(dir);
62
80
  }
63
81
 
82
+ if (characteristicSwingMode && changes.hasOwnProperty(this.dpSwing)) {
83
+ const swing = this._getSwingMode(changes[this.dpSwing]);
84
+ if (characteristicSwingMode.value !== swing) characteristicSwingMode.updateValue(swing);
85
+ }
86
+
64
87
  this.log.debug('SimpleFan changed: ' + JSON.stringify(state));
65
88
  });
66
89
  }
@@ -134,6 +157,20 @@ class SimpleFanAccessory extends BaseAccessory {
134
157
  return this.setStateAsync(this.dpFanDirection, tuyaVal);
135
158
  }
136
159
 
160
+ getSwingMode() {
161
+ return this._getSwingMode(this.getStateAsync(this.dpSwing));
162
+ }
163
+
164
+ _getSwingMode(dp) {
165
+ const {Characteristic} = this.hap;
166
+ return dp ? Characteristic.SwingMode.SWING_ENABLED : Characteristic.SwingMode.SWING_DISABLED;
167
+ }
168
+
169
+ setSwingMode(value) {
170
+ const {Characteristic} = this.hap;
171
+ return this.setStateAsync(this.dpSwing, value === Characteristic.SwingMode.SWING_ENABLED);
172
+ }
173
+
137
174
  convertRotationSpeedFromTuyaToHomeKit(value) {
138
175
  const v = parseInt(value) || 0;
139
176
  if (v <= 0) return 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homebridge-tuya-plus",
3
- "version": "4.1.0-dev.63",
3
+ "version": "4.1.0-dev.68",
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": {
@@ -0,0 +1,101 @@
1
+ 'use strict';
2
+
3
+ const SimpleFanAccessory = require('../lib/SimpleFanAccessory');
4
+ const { makeInstance, HAP } = require('./support/mocks');
5
+
6
+ const { SwingMode, RotationDirection } = HAP.Characteristic;
7
+
8
+ // The mock Fan service shares a single characteristic, so the write-path tests
9
+ // wire the DP fields manually (mirroring what _registerCharacteristics would do)
10
+ // and assert on the conversion helpers and the DP packets that go out. The
11
+ // registration tests below drive _registerCharacteristics itself.
12
+ function makeFan(state = {}, context = {}) {
13
+ const result = makeInstance(SimpleFanAccessory, state, { type: 'Fan', ...context });
14
+ const { instance } = result;
15
+
16
+ instance.dpFanOn = '1';
17
+ instance.dpRotationSpeed = '3';
18
+ instance.dpFanDirection = '2';
19
+ instance.dpSwing = instance._getCustomDP(context.dpSwing);
20
+ return result;
21
+ }
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // _getSwingMode — boolean DP maps to HomeKit SwingMode
25
+ // ---------------------------------------------------------------------------
26
+ describe('SimpleFanAccessory._getSwingMode', () => {
27
+ test('truthy DP enables swing', () => {
28
+ const { instance } = makeFan();
29
+ expect(instance._getSwingMode(true)).toBe(SwingMode.SWING_ENABLED);
30
+ expect(instance._getSwingMode(1)).toBe(SwingMode.SWING_ENABLED);
31
+ });
32
+
33
+ test('falsy DP disables swing', () => {
34
+ const { instance } = makeFan();
35
+ expect(instance._getSwingMode(false)).toBe(SwingMode.SWING_DISABLED);
36
+ expect(instance._getSwingMode(0)).toBe(SwingMode.SWING_DISABLED);
37
+ expect(instance._getSwingMode(undefined)).toBe(SwingMode.SWING_DISABLED);
38
+ });
39
+ });
40
+
41
+ // ---------------------------------------------------------------------------
42
+ // getSwingMode / setSwingMode — read and write the configured swing DP
43
+ // ---------------------------------------------------------------------------
44
+ describe('SimpleFanAccessory.getSwingMode / setSwingMode', () => {
45
+ test('getSwingMode reads and converts the swing DP', () => {
46
+ const { instance } = makeFan({ '4': true }, { dpSwing: 4 });
47
+ expect(instance.getSwingMode()).toBe(SwingMode.SWING_ENABLED);
48
+ });
49
+
50
+ test('setSwingMode writes a boolean true to the swing DP', () => {
51
+ const { instance, device } = makeFan({ '4': false }, { dpSwing: 4 });
52
+ instance.setSwingMode(SwingMode.SWING_ENABLED);
53
+ expect(device.update).toHaveBeenCalledWith({ '4': true });
54
+ });
55
+
56
+ test('setSwingMode writes a boolean false to the swing DP', () => {
57
+ const { instance, device } = makeFan({ '4': true }, { dpSwing: 4 });
58
+ instance.setSwingMode(SwingMode.SWING_DISABLED);
59
+ expect(device.update).toHaveBeenCalledWith({ '4': false });
60
+ });
61
+
62
+ test('setSwingMode rejects (No Response) and writes nothing when disconnected', async () => {
63
+ const { instance, device } = makeFan({ '4': false }, { dpSwing: 4 });
64
+ device.connected = false;
65
+ await expect(instance.setSwingMode(SwingMode.SWING_ENABLED)).rejects.toBeInstanceOf(HAP.HapStatusError);
66
+ expect(device.update).not.toHaveBeenCalled();
67
+ });
68
+ });
69
+
70
+ // ---------------------------------------------------------------------------
71
+ // Registration — SwingMode is opt-in and RotationDirection is opt-out
72
+ // ---------------------------------------------------------------------------
73
+ describe('SimpleFanAccessory._registerCharacteristics', () => {
74
+ const register = context => {
75
+ const { instance, accessory } = makeInstance(SimpleFanAccessory, {}, { type: 'Fan', ...context });
76
+ const service = accessory._mockService;
77
+ service.getCharacteristic.mockClear();
78
+ instance._registerCharacteristics(instance.device.state);
79
+ return service;
80
+ };
81
+
82
+ test('registers SwingMode when dpSwing is configured', () => {
83
+ const service = register({ dpSwing: 4 });
84
+ expect(service.getCharacteristic).toHaveBeenCalledWith(SwingMode);
85
+ });
86
+
87
+ test('does not register SwingMode when dpSwing is absent (backwards compatible)', () => {
88
+ const service = register({});
89
+ expect(service.getCharacteristic).not.toHaveBeenCalledWith(SwingMode);
90
+ });
91
+
92
+ test('registers RotationDirection by default', () => {
93
+ const service = register({});
94
+ expect(service.getCharacteristic).toHaveBeenCalledWith(RotationDirection);
95
+ });
96
+
97
+ test('drops RotationDirection when noDirection is set', () => {
98
+ const service = register({ noDirection: true });
99
+ expect(service.getCharacteristic).not.toHaveBeenCalledWith(RotationDirection);
100
+ });
101
+ });
@@ -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,19 +805,48 @@ 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",
815
+
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,
730
822
 
731
- /* Override the default datapoint identifier of rotation speed */
732
- "dpRotationSpeed": "2",
823
+ /* Speed to use when the fan is switched on from off. Default: 1 */
824
+ "fanDefaultSpeed": 1,
733
825
 
734
- /* Override the default datapoint identifier of direction control (forward/reverse) */
735
- "dpRotationDirection": 63
826
+ /* Send the speed value as a string (e.g. "3") rather than a number.
827
+ Most fans require this; turn off only if yours ignores string speeds.
828
+ Default: true */
829
+ "useStrings": true,
830
+
831
+ /* Send fan on/off and speed together in one legacy control packet.
832
+ Set false if your firmware ignores multi-DP packets. Default: true */
833
+ "useMultiState": true,
834
+
835
+ /* Data-point of the oscillation switch (a boolean DP). When set, a Swing
836
+ (oscillation) control appears in the Home app. Omit if the fan can't oscillate. */
837
+ "dpSwing": 4,
838
+
839
+ /* Drop the direction control entirely — for fans whose "direction" DP is
840
+ actually a mode enum (e.g. nature/sleep/smart), so HomeKit won't write
841
+ forward/reverse into it. Default: false */
842
+ "noDirection": true
736
843
  }
737
844
  ```
738
845
 
739
846
  ### Smart Fan with Light
740
- 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.
847
+ 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.
848
+
849
+ > **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.
741
850
 
742
851
  ```json5
743
852
  {
@@ -748,17 +857,55 @@ These are accessories that combine fan and lighting control in one device. Suppo
748
857
  "manufacturer": "Hunter Pacific International",
749
858
  "model": "Polar v2 Fan",
750
859
 
751
- "dpLight": 20,
860
+ /* --- Fan --- */
861
+
862
+ /* Data-point for fan on/off. Default: "60" */
863
+ "dpFanOn": 60,
864
+
865
+ /* Data-point for fan speed. Default: "62" */
866
+ "dpRotationSpeed": 62,
867
+
868
+ /* Data-point for direction control (forward/reverse). Default: "63" */
869
+ "dpFanDirection": 63,
870
+
871
+ /* Number of speed steps the fan supports. Default: 6 */
872
+ "maxSpeed": 6,
873
+
874
+ /* Speed used when the fan is switched on from off. Default: 1 */
875
+ "fanDefaultSpeed": 1,
876
+
877
+ /* Send the speed value as a string rather than a number. Default: true */
878
+ "useStrings": true,
879
+
880
+ /* Send each data point in its own packet instead of combining fan
881
+ power + speed into one. Default: false (see note below) */
882
+ "singleDpWrites": false,
883
+
884
+ /* --- Light --- */
885
+
886
+ /* Expose the light at all. Set false for a fan with no light. Default: true */
887
+ "useLight": true,
888
+
889
+ /* Data-point for light on/off. Default: "20" */
890
+ "dpLightOn": 20,
891
+
892
+ /* Expose a brightness slider. Default: true */
752
893
  "useBrightness": true,
894
+
895
+ /* Data-point for brightness (Tuya 10–1000 scale). Default: "22" */
753
896
  "dpBrightness": 22,
754
- "minBrightness": 1,
755
- "scaleBrightness": 9,
756
- "dpColorTemperature": 23,
757
897
 
758
- "dpActive": 60,
759
- "dpRotationSpeed": 62,
760
- "maxSpeed": 9,
761
- "dpRotationDirection": 63
898
+ /* Expose a colour-temperature control. Default: true */
899
+ "useColorTemp": true,
900
+
901
+ /* Data-point for colour temperature (Tuya 0–1000 scale). Default: "23" */
902
+ "dpColorTemp": 23,
903
+
904
+ /* Coolest colour temperature, in mireds (~6500 K). Default: 154 */
905
+ "minWhiteColor": 154,
906
+
907
+ /* Warmest colour temperature, in mireds (~2700 K). Default: 370 */
908
+ "maxWhiteColor": 370
762
909
  }
763
910
  ```
764
911
 
@@ -771,7 +918,7 @@ If the light, brightness and turning the fan **off** all work, but turning the f
771
918
  "id": "032000123456789abcde",
772
919
  "key": "0123456789abcdef",
773
920
 
774
- "dpActive": 60,
921
+ "dpFanOn": 60,
775
922
  "dpRotationSpeed": 62,
776
923
 
777
924
  /* Send each data point in its own packet instead of combining them. */
@@ -889,3 +1036,150 @@ It's deliberately carried on the system tile rather than as a separate sensor ac
889
1036
  /* "noBattery": true, */
890
1037
  }
891
1038
  ```
1039
+
1040
+ ### Air Purifiers
1041
+ 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.
1042
+
1043
+ ```json5
1044
+ {
1045
+ "name": "My Air Purifier",
1046
+ "type": "AirPurifier",
1047
+ "manufacturer": "Proscenic",
1048
+ "model": "A8",
1049
+ "id": "032000123456789abcde",
1050
+ "key": "0123456789abcdef",
1051
+
1052
+ /* Additional parameters to override defaults only if needed */
1053
+
1054
+ /* Map the fan speed onto a fixed number of discrete steps instead of a
1055
+ continuous slider. Some firmwares need this for speed changes to
1056
+ register. Default: off (continuous) */
1057
+ "noRotationSpeed": true,
1058
+
1059
+ /* Number of discrete speed steps to use when noRotationSpeed is set (1–99).
1060
+ Has no effect unless noRotationSpeed is enabled. Default: 100 */
1061
+ "fanSpeedSteps": 3,
1062
+
1063
+ /* Override the device's "auto" mode phrase (case-sensitive). Default: "AUTO" */
1064
+ "cmdAuto": "AUTO",
1065
+
1066
+ /* Add an Air Quality sensor service (PM2.5 / air-quality level). Default: false */
1067
+ "showAirQuality": true,
1068
+
1069
+ /* Name for the air-quality sensor service. Default: "Air Quality" */
1070
+ "nameAirQuality": "Air Quality",
1071
+
1072
+ /* This device has no child-lock data-point. Default: false */
1073
+ "noChildLock": true
1074
+ }
1075
+ ```
1076
+
1077
+ ### Dehumidifiers
1078
+ 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.
1079
+
1080
+ ```json5
1081
+ {
1082
+ "name": "My Dehumidifier",
1083
+ "type": "Dehumidifier",
1084
+ "manufacturer": "Generic",
1085
+ "model": "Smart Dehumidifier",
1086
+ "id": "032000123456789abcde",
1087
+ "key": "0123456789abcdef",
1088
+
1089
+ /* Additional parameters to override defaults only if needed */
1090
+
1091
+ /* Target-humidity bounds advertised to HomeKit, in %. Defaults: 40 / 80 */
1092
+ "minHumidity": 40,
1093
+ "maxHumidity": 80,
1094
+
1095
+ /* Target-humidity step, in %. Default: 5 */
1096
+ "humiditySteps": 5,
1097
+
1098
+ /* This device has no fan-speed control. Default: false */
1099
+ "noSpeed": true,
1100
+
1101
+ /* Fan-speed slider bounds and step. Defaults: 1 / 2 / 1 */
1102
+ "minSpeed": 1,
1103
+ "maxSpeed": 2,
1104
+ "speedSteps": 1,
1105
+
1106
+ /* This device has no child-lock data-point — hides the lock control entirely. Default: false */
1107
+ "noChildLock": true,
1108
+
1109
+ /* Keep the child-lock control visible but make toggling it a no-op
1110
+ (useful if the device exposes the lock DP but doesn't honour writes). Default: false */
1111
+ "noLock": true
1112
+ }
1113
+ ```
1114
+
1115
+ ### Oil Diffusers / Humidifiers
1116
+ 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.
1117
+
1118
+ ```json5
1119
+ {
1120
+ "name": "My Diffuser",
1121
+ "type": "OilDiffuser",
1122
+ "manufacturer": "Generic",
1123
+ "model": "Aroma Diffuser",
1124
+ "id": "032000123456789abcde",
1125
+ "key": "0123456789abcdef",
1126
+
1127
+ /* Additional parameters to override defaults only if needed */
1128
+
1129
+ /* Data-point for the mist (humidifier) on/off. Default: "1" */
1130
+ "dpActive": 1,
1131
+
1132
+ /* Data-point for mist intensity / speed. Default: "2" */
1133
+ "dpRotationSpeed": 2,
1134
+
1135
+ /* Number of mist-intensity steps. Default: 2 */
1136
+ "maxSpeed": 2,
1137
+
1138
+ /* Data-point for the light on/off. Default: "5" */
1139
+ "dpLight": 5,
1140
+
1141
+ /* Data-point for light mode (white vs colour). Default: "6" */
1142
+ "dpMode": 6,
1143
+
1144
+ /* Data-point for light colour / brightness value. Default: "8" */
1145
+ "dpColor": 8,
1146
+
1147
+ /* Data-point for the water-level status. Default: "9" */
1148
+ "dpWaterLevel": 9,
1149
+
1150
+ /* Override the white / colour mode phrases if your device disagrees
1151
+ (both British "cmdColour" and American "cmdColor" are accepted).
1152
+ Defaults: "white" / "colour" */
1153
+ "cmdWhite": "white",
1154
+ "cmdColor": "colour"
1155
+ }
1156
+ ```
1157
+
1158
+ ### Water Valves / Single Sprinklers
1159
+ 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.
1160
+
1161
+ ```json5
1162
+ {
1163
+ "name": "My Valve",
1164
+ "type": "watervalve",
1165
+ "manufacturer": "Generic",
1166
+ "model": "Smart Water Valve",
1167
+ "id": "032000123456789abcde",
1168
+ "key": "0123456789abcdef",
1169
+
1170
+ /* Additional parameters to override defaults only if needed */
1171
+
1172
+ /* Data-point for the valve on/off. Default: "1" */
1173
+ "dpPower": 1,
1174
+
1175
+ /* HomeKit valve type. One of "IRRIGATION", "SHOWER_HEAD", "WATER_FAUCET"
1176
+ (case-sensitive); anything else shows as a generic valve. Default: generic */
1177
+ "valveType": "IRRIGATION",
1178
+
1179
+ /* Default run time, in seconds, when the valve is switched on. Default: 600 */
1180
+ "defaultDuration": 600,
1181
+
1182
+ /* Don't expose the run timer (Set/Remaining Duration) at all. Default: false */
1183
+ "noTimer": false
1184
+ }
1185
+ ```