homebridge-tuya-plus 3.14.0-dev.5 → 3.14.0-dev.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish-dev.yml +298 -31
- package/AGENTS.md +162 -0
- package/CLAUDE.md +1 -0
- package/Changelog.md +16 -3
- package/Readme.MD +8 -32
- package/config.schema.json +79 -79
- package/index.js +599 -358
- package/lib/AirPurifierAccessory.js +1 -1
- package/lib/BaseAccessory.js +54 -17
- package/lib/ConvectorAccessory.js +1 -1
- package/lib/CustomMultiOutletAccessory.js +2 -1
- package/lib/DoorbellAccessory.js +9 -16
- package/lib/GarageDoorAccessory.js +1 -1
- package/lib/IrrigationSystemAccessory.js +260 -120
- package/lib/MultiOutletAccessory.js +3 -2
- package/lib/OilDiffuserAccessory.js +10 -8
- package/lib/RGBTWLightAccessory.js +13 -11
- package/lib/RGBTWOutletAccessory.js +11 -9
- package/lib/SimpleBlindsAccessory.js +5 -5
- package/lib/SimpleDimmer2Accessory.js +1 -1
- package/lib/SimpleDimmerAccessory.js +10 -6
- package/lib/SimpleGarageDoorAccessory.js +122 -26
- package/lib/SimpleHeaterAccessory.js +4 -4
- package/lib/SimpleLightAccessory.js +1 -1
- package/lib/SwitchAccessory.js +3 -2
- package/lib/TWLightAccessory.js +2 -2
- package/lib/TuyaAccessory.js +75 -42
- package/lib/TuyaCloudApi.js +121 -8
- package/lib/TuyaCloudDevice.js +434 -31
- package/lib/TuyaCloudMessaging.js +34 -41
- package/lib/TuyaDevice.js +269 -0
- package/lib/TuyaDiscovery.js +25 -9
- package/lib/ValveAccessory.js +16 -12
- package/lib/VerticalBlindsWithTilt.js +27 -25
- package/lib/WledDimmerAccessory.js +46 -81
- package/package.json +5 -6
- package/scripts/cleanup-pr-tags.js +122 -0
- package/test/BaseAccessory.test.js +94 -15
- package/test/IrrigationSystemAccessory.test.js +293 -67
- package/test/MultiOutletAccessory.test.js +18 -3
- package/test/RGBTWLightAccessory.test.js +3 -3
- package/test/SimpleFanLightAccessory.test.js +3 -3
- package/test/SimpleGarageDoorAccessory.test.js +193 -19
- package/test/TuyaAccessory.protocol.test.js +76 -3
- package/test/TuyaCloudApi.test.js +110 -1
- package/test/TuyaCloudDevice.test.js +564 -2
- package/test/TuyaCloudMessaging.test.js +24 -5
- package/test/TuyaDevice.test.js +266 -0
- package/test/getCategory.test.js +1 -0
- package/test/index.test.js +271 -0
- package/test/support/mocks.js +13 -0
- package/wiki/Supported-Device-Types.md +64 -34
- package/wiki/Tuya-Cloud-Setup.md +31 -108
package/Readme.MD
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
A community-maintained Homebridge plugin for controlling Tuya devices locally over LAN. Control your supported Tuya accessories locally in HomeKit.
|
|
17
|
+
A community-maintained Homebridge plugin for controlling Tuya devices locally over LAN. Control your supported Tuya accessories locally in HomeKit, with an optional Tuya Cloud fallback for devices the LAN can't reach.
|
|
18
18
|
|
|
19
19
|
* [Supported Device Types](#supported-device-types)
|
|
20
20
|
* [Supported Tuya Protocol Versions](#supported-tuya-protocol-versions)
|
|
@@ -38,7 +38,7 @@ A community-maintained Homebridge plugin for controlling Tuya devices locally ov
|
|
|
38
38
|
* Fan v2<sup>[7](https://github.com/adrianjagielak/homebridge-tuya-plus/blob/main/wiki/Supported-Device-Types.md)</sup>
|
|
39
39
|
* Garages<sup>[8](https://github.com/adrianjagielak/homebridge-tuya-plus/blob/main/wiki/Supported-Device-Types.md#garage-doors)</sup>
|
|
40
40
|
* Heaters<sup>[9](https://github.com/adrianjagielak/homebridge-tuya-plus/blob/main/wiki/Supported-Device-Types.md)</sup>
|
|
41
|
-
* Irrigation Systems / Sprinklers<sup>[17](https://github.com/adrianjagielak/homebridge-tuya-plus/blob/main/wiki/Supported-Device-Types.md#irrigation-systems--sprinklers)</sup> (multi-valve, per-zone timers,
|
|
41
|
+
* Irrigation Systems / Sprinklers<sup>[17](https://github.com/adrianjagielak/homebridge-tuya-plus/blob/main/wiki/Supported-Device-Types.md#irrigation-systems--sprinklers)</sup> (multi-valve, per-zone timers, battery)
|
|
42
42
|
* Lights
|
|
43
43
|
* On/Off<sup>[10](https://github.com/adrianjagielak/homebridge-tuya-plus/blob/main/wiki/Supported-Device-Types.md)</sup>
|
|
44
44
|
* Brightness<sup>[11](https://github.com/adrianjagielak/homebridge-tuya-plus/blob/main/wiki/Supported-Device-Types.md#tunable-white-light-bulbs)</sup>
|
|
@@ -48,34 +48,11 @@ A community-maintained Homebridge plugin for controlling Tuya devices locally ov
|
|
|
48
48
|
* Switches<sup>[15](https://github.com/adrianjagielak/homebridge-tuya-plus/blob/main/wiki/Supported-Device-Types.md#switch)</sup>
|
|
49
49
|
* Vertical Blinds<sup>[16](https://github.com/adrianjagielak/homebridge-tuya-plus/blob/main/wiki/Supported-Device-Types.md#vertical-blinds-with-tilt)</sup>
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
## Cloud fallback
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
The plugin is LAN-first — everything is controlled locally by default. If you add Tuya Cloud credentials in a top-level `cloud` block, it keeps a cloud session in the background and uses it as a fallback: each device is tried on the LAN first, and only falls back to the cloud when it can't be reached locally — a brief LAN hiccup, or hardware that never appears on the LAN at all (e.g. battery-powered "sleepy" devices). It's opt-in and local always comes first, and existing configs need no changes — so it's also a handy fix if some devices occasionally show as "No Response".
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
| Tuya LAN protocol | Framing | Encryption | Status |
|
|
58
|
-
|---|---|---|---|
|
|
59
|
-
| 3.1 | `0x55AA` | AES-128-ECB (base64, control only) | ✅ Supported |
|
|
60
|
-
| 3.2 | `0x55AA` | AES-128-ECB | ✅ Supported |
|
|
61
|
-
| 3.3 | `0x55AA` | AES-128-ECB | ✅ Supported |
|
|
62
|
-
| 3.4 | `0x55AA` | AES-128-ECB, session key, HMAC-SHA256 | ✅ Supported |
|
|
63
|
-
| 3.5 | `0x6699` | AES-128-GCM, session key | ✅ Supported |
|
|
64
|
-
| 3.6 and newer | — | — | ✅ Forward-compatible (see below) |
|
|
65
|
-
|
|
66
|
-
The protocol version is auto-detected from the device's discovery broadcast, so you normally don't need to configure anything.
|
|
67
|
-
|
|
68
|
-
Protocol **3.5** is currently the newest Tuya LAN protocol in existence: it is the latest version implemented by Tuya's own open-source device SDK ([TuyaOpen](https://github.com/tuya/TuyaOpen)) and by the reference reverse-engineered implementations ([tinytuya](https://github.com/jasonacox/tinytuya/blob/master/PROTOCOL.md)). No device firmware speaking a "3.6" protocol has been observed in the wild so far.
|
|
69
|
-
|
|
70
|
-
This plugin is nevertheless **3.6-ready**: if a device reports a newer protocol version (e.g. `3.6`) in its broadcast, the plugin automatically talks to it using the newest (3.5/GCM) protocol stack while tagging payloads with the device's reported version — the same forward-compatibility strategy used by tinytuya. Should such a device misbehave, you can pin it to a specific protocol with the `forceVersion` device option (e.g. `"forceVersion": "3.5"`), or use `version` to set a protocol for devices that can't be discovered (e.g. on another subnet).
|
|
71
|
-
|
|
72
|
-
## Cloud devices (for hardware that can't be controlled locally)
|
|
73
|
-
|
|
74
|
-
This is a **LAN-first** plugin — virtually every Tuya device is controlled locally, which is faster, more private, and keeps working without internet. A few devices, though, simply **can't** be reached over the LAN: battery-powered "sleepy" devices — for example the **irrigation / faucet timers** — sleep almost all the time and only ever connect out to Tuya's cloud, so they never answer on the local network.
|
|
75
|
-
|
|
76
|
-
For exactly these cases the plugin can talk to a device through the **Tuya Cloud** instead — strictly **opt-in, per device**. You add your Tuya Cloud project credentials once and set `"cloud": true` on the device; everything else works the same.
|
|
77
|
-
|
|
78
|
-
👉 **[Tuya Cloud Setup guide](https://github.com/adrianjagielak/homebridge-tuya-plus/blob/main/wiki/Tuya-Cloud-Setup.md)** — how to get credentials and configure a cloud device.
|
|
55
|
+
See the **[Tuya Cloud Setup guide](https://github.com/adrianjagielak/homebridge-tuya-plus/blob/main/wiki/Tuya-Cloud-Setup.md)** for credentials and setup.
|
|
79
56
|
|
|
80
57
|
## Installation Instructions
|
|
81
58
|
|
|
@@ -92,14 +69,13 @@ sudo npm install -g homebridge-tuya-plus
|
|
|
92
69
|
#### Bleeding-edge (`dev`) builds:
|
|
93
70
|
|
|
94
71
|
Every commit to `main` is automatically published to npm under the `dev` tag — a
|
|
95
|
-
separate, unstable channel.
|
|
96
|
-
won't affect normal installs. To try the latest in-development build:
|
|
72
|
+
separate, unstable channel. To try the latest in-development build:
|
|
97
73
|
|
|
98
74
|
```
|
|
99
75
|
sudo npm install -g homebridge-tuya-plus@dev
|
|
100
76
|
```
|
|
101
77
|
|
|
102
|
-
These are versioned like `3.
|
|
78
|
+
These are versioned like `3.14.0-dev.<n>` and may be unstable; use the default
|
|
103
79
|
install above for production.
|
|
104
80
|
|
|
105
81
|
## Configuration
|
|
@@ -134,7 +110,7 @@ If you have new accessory logic for a new device, please add a function defined
|
|
|
134
110
|
|
|
135
111
|
#
|
|
136
112
|
|
|
137
|
-
|
|
113
|
+
Check out my other Homebridge plugins:
|
|
138
114
|
|
|
139
115
|
* [homebridge-futurehome](https://github.com/adrianjagielak/homebridge-futurehome) ([npm](https://npmjs.com/package/homebridge-futurehome))
|
|
140
116
|
* [homebridge-tuya-plus](https://github.com/adrianjagielak/homebridge-tuya-plus) ([npm](https://npmjs.com/package/homebridge-tuya-plus))
|
package/config.schema.json
CHANGED
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
},
|
|
22
22
|
"cloud": {
|
|
23
23
|
"type": "object",
|
|
24
|
-
"title": "Tuya Cloud (optional
|
|
25
|
-
"description": "
|
|
24
|
+
"title": "Tuya Cloud fallback (optional)",
|
|
25
|
+
"description": "<a href='https://github.com/adrianjagielak/homebridge-tuya-plus/blob/main/wiki/Tuya-Cloud-Setup.md'>Tuya Cloud API Setup</a>.",
|
|
26
26
|
"properties": {
|
|
27
27
|
"accessId": {
|
|
28
28
|
"type": "string",
|
|
@@ -69,12 +69,6 @@
|
|
|
69
69
|
{ "title": "Tuya Smart", "enum": ["tuyaSmart"] },
|
|
70
70
|
{ "title": "Smart Life", "enum": ["smartlife"] }
|
|
71
71
|
]
|
|
72
|
-
},
|
|
73
|
-
"realtime": {
|
|
74
|
-
"type": "boolean",
|
|
75
|
-
"title": "Realtime updates (MQTT)",
|
|
76
|
-
"default": true,
|
|
77
|
-
"description": "Receive instant updates over Tuya's MQTT message service (uses the 'mqtt' package, installed automatically). If disabled, devices stay controllable and show their state at startup, but external changes (physical buttons, the device's own timers) won't be reflected until restart."
|
|
78
72
|
}
|
|
79
73
|
}
|
|
80
74
|
},
|
|
@@ -96,7 +90,7 @@
|
|
|
96
90
|
{
|
|
97
91
|
"title": "Switch Gang / Basic Switch",
|
|
98
92
|
"enum": ["Switch"]
|
|
99
|
-
},
|
|
93
|
+
},
|
|
100
94
|
{
|
|
101
95
|
"title": "Smart Plug / Barely Smart Power Strip",
|
|
102
96
|
"enum": ["Outlet"]
|
|
@@ -197,16 +191,7 @@
|
|
|
197
191
|
"key": {
|
|
198
192
|
"title": "Tuya Key (local key — required for LAN devices)",
|
|
199
193
|
"type": "string",
|
|
200
|
-
"description": "The device's local key. Required for normal (LAN) devices.
|
|
201
|
-
"condition": {
|
|
202
|
-
"functionBody": "return model.devices && model.devices[arrayIndices].type !== 'null';"
|
|
203
|
-
}
|
|
204
|
-
},
|
|
205
|
-
"cloud": {
|
|
206
|
-
"type": ["boolean", "object"],
|
|
207
|
-
"title": "Control via Tuya Cloud (instead of the LAN)",
|
|
208
|
-
"default": false,
|
|
209
|
-
"description": "Enable for devices that can't be reached locally (e.g. battery-powered irrigation timers). Uses the platform-level 'cloud' credentials above. Advanced: instead of a checkbox you can set this to an object with per-device { accessId, accessKey, region, … } to use different credentials for this one device.",
|
|
194
|
+
"description": "The device's local key. Required for normal (LAN) devices. A device with no key is treated as cloud-only and is reached through the Tuya Cloud session configured above (e.g. a battery-powered 'sleepy' irrigation timer).",
|
|
210
195
|
"condition": {
|
|
211
196
|
"functionBody": "return model.devices && model.devices[arrayIndices].type !== 'null';"
|
|
212
197
|
}
|
|
@@ -318,9 +303,9 @@
|
|
|
318
303
|
"title": "Sync brightness to WLED (IP[:port])",
|
|
319
304
|
"placeholder": "192.168.1.100",
|
|
320
305
|
"condition": {
|
|
321
|
-
"functionBody": "return model.devices && model.devices[arrayIndices] && ['WledDimmer'
|
|
306
|
+
"functionBody": "return model.devices && model.devices[arrayIndices] && ['WledDimmer'].includes(model.devices[arrayIndices].type);"
|
|
322
307
|
}
|
|
323
|
-
},
|
|
308
|
+
},
|
|
324
309
|
"dpColorTemperature": {
|
|
325
310
|
"type": "integer",
|
|
326
311
|
"placeholder": "3",
|
|
@@ -421,6 +406,12 @@
|
|
|
421
406
|
"functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner'].includes(model.devices[arrayIndices].type);"
|
|
422
407
|
}
|
|
423
408
|
},
|
|
409
|
+
"noAuto": {
|
|
410
|
+
"type": "boolean",
|
|
411
|
+
"condition": {
|
|
412
|
+
"functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner'].includes(model.devices[arrayIndices].type);"
|
|
413
|
+
}
|
|
414
|
+
},
|
|
424
415
|
"cmdCool": {
|
|
425
416
|
"type": "string",
|
|
426
417
|
"placeholder": "COOL",
|
|
@@ -435,6 +426,32 @@
|
|
|
435
426
|
"functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner'].includes(model.devices[arrayIndices].type);"
|
|
436
427
|
}
|
|
437
428
|
},
|
|
429
|
+
"cmdAuto": {
|
|
430
|
+
"type": "string",
|
|
431
|
+
"placeholder": "AUTO",
|
|
432
|
+
"condition": {
|
|
433
|
+
"functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner'].includes(model.devices[arrayIndices].type);"
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
"noRotationSpeed": {
|
|
437
|
+
"type": "boolean",
|
|
438
|
+
"condition": {
|
|
439
|
+
"functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner'].includes(model.devices[arrayIndices].type);"
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
"fanSpeedSteps": {
|
|
443
|
+
"type": "integer",
|
|
444
|
+
"placeholder": "3",
|
|
445
|
+
"condition": {
|
|
446
|
+
"functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner'].includes(model.devices[arrayIndices].type);"
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
"noChildLock": {
|
|
450
|
+
"type": "boolean",
|
|
451
|
+
"condition": {
|
|
452
|
+
"functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner', 'Convector'].includes(model.devices[arrayIndices].type);"
|
|
453
|
+
}
|
|
454
|
+
},
|
|
438
455
|
"noSwing": {
|
|
439
456
|
"type": "boolean",
|
|
440
457
|
"condition": {
|
|
@@ -569,30 +586,31 @@
|
|
|
569
586
|
"functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector'].includes(model.devices[arrayIndices].type);"
|
|
570
587
|
}
|
|
571
588
|
},
|
|
572
|
-
"
|
|
589
|
+
"noTemperatureUnit": {
|
|
573
590
|
"type": "boolean",
|
|
574
591
|
"condition": {
|
|
575
592
|
"functionBody": "return model.devices && model.devices[arrayIndices] && ['Convector'].includes(model.devices[arrayIndices].type);"
|
|
576
593
|
}
|
|
577
594
|
},
|
|
578
|
-
"
|
|
579
|
-
"type": "
|
|
595
|
+
"temperatureDivisor": {
|
|
596
|
+
"type": "integer",
|
|
597
|
+
"placeholder": "1",
|
|
580
598
|
"condition": {
|
|
581
|
-
"functionBody": "return model.devices && model.devices[arrayIndices] && ['
|
|
599
|
+
"functionBody": "return model.devices && model.devices[arrayIndices] && ['SimpleHeater', 'AirConditioner'].includes(model.devices[arrayIndices].type);"
|
|
582
600
|
}
|
|
583
601
|
},
|
|
584
|
-
"
|
|
602
|
+
"currentTemperatureDivisor": {
|
|
585
603
|
"type": "integer",
|
|
586
604
|
"placeholder": "1",
|
|
587
605
|
"condition": {
|
|
588
|
-
"functionBody": "return model.devices && model.devices[arrayIndices] && ['
|
|
606
|
+
"functionBody": "return model.devices && model.devices[arrayIndices] && ['AirConditioner'].includes(model.devices[arrayIndices].type);"
|
|
589
607
|
}
|
|
590
608
|
},
|
|
591
609
|
"thresholdTemperatureDivisor": {
|
|
592
610
|
"type": "integer",
|
|
593
611
|
"placeholder": "1",
|
|
594
612
|
"condition": {
|
|
595
|
-
"functionBody": "return model.devices && model.devices[arrayIndices] && ['SimpleHeater'].includes(model.devices[arrayIndices].type);"
|
|
613
|
+
"functionBody": "return model.devices && model.devices[arrayIndices] && ['SimpleHeater', 'AirConditioner'].includes(model.devices[arrayIndices].type);"
|
|
596
614
|
}
|
|
597
615
|
},
|
|
598
616
|
"temperatureOffset": {
|
|
@@ -717,7 +735,7 @@
|
|
|
717
735
|
"type": "integer",
|
|
718
736
|
"title": "Number of Valves / Zones",
|
|
719
737
|
"placeholder": 4,
|
|
720
|
-
"description": "How many valves/zones the controller has. They are assumed to be on data-points 1, 2, 3, … (
|
|
738
|
+
"description": "How many valves/zones the controller has. They are assumed to be on data-points 1, 2, 3, … (over the cloud these map to the codes switch_1, switch_2, … automatically). For non-sequential data-points use the 'valves' list instead.",
|
|
721
739
|
"condition": {
|
|
722
740
|
"functionBody": "return model.devices && model.devices[arrayIndices] && ['IrrigationSystem'].includes(model.devices[arrayIndices].type);"
|
|
723
741
|
}
|
|
@@ -730,9 +748,27 @@
|
|
|
730
748
|
"items": {
|
|
731
749
|
"type": "object",
|
|
732
750
|
"properties": {
|
|
733
|
-
"name": {
|
|
734
|
-
|
|
735
|
-
|
|
751
|
+
"name": {
|
|
752
|
+
"type": "string",
|
|
753
|
+
"title": "Zone name",
|
|
754
|
+
"placeholder": "Lawn"
|
|
755
|
+
},
|
|
756
|
+
"dp": {
|
|
757
|
+
"type": ["integer", "string"],
|
|
758
|
+
"title": "Data-point (numeric id, or cloud code)",
|
|
759
|
+
"placeholder": "1 or switch_1"
|
|
760
|
+
},
|
|
761
|
+
"dpCountdown": {
|
|
762
|
+
"type": ["integer", "string"],
|
|
763
|
+
"title": "Countdown data-point (numeric id, or cloud code)",
|
|
764
|
+
"description": "Optional. The device's built-in auto-off timer for this zone. Defaults to the switch data-point + 16 (so switch 1 → countdown 17). Set this only for code-addressed or non-standard zones.",
|
|
765
|
+
"placeholder": "17 or countdown_1"
|
|
766
|
+
},
|
|
767
|
+
"defaultDuration": {
|
|
768
|
+
"type": "integer",
|
|
769
|
+
"title": "Default run time (seconds, 0 = run indefinitely)",
|
|
770
|
+
"placeholder": 600
|
|
771
|
+
}
|
|
736
772
|
}
|
|
737
773
|
},
|
|
738
774
|
"condition": {
|
|
@@ -752,7 +788,16 @@
|
|
|
752
788
|
"type": "integer",
|
|
753
789
|
"title": "Maximum Run Time (seconds)",
|
|
754
790
|
"placeholder": 7200,
|
|
755
|
-
"description": "Upper bound advertised to HomeKit for the duration picker (HAP default is 3600 / 1h). Apple's Home app only offers presets up to 1h regardless; longer values can be set from the config or apps like Eve.",
|
|
791
|
+
"description": "Upper bound advertised to HomeKit for the duration picker (HAP default is 3600 / 1h). Apple's Home app only offers presets up to 1h regardless; longer values can be set from the config or apps like Eve. Also bounds the hardware countdown: a device countdown longer than this (or the 120-min hardware cap) is corrected on connect.",
|
|
792
|
+
"condition": {
|
|
793
|
+
"functionBody": "return model.devices && model.devices[arrayIndices] && ['IrrigationSystem'].includes(model.devices[arrayIndices].type);"
|
|
794
|
+
}
|
|
795
|
+
},
|
|
796
|
+
"nativeCountdown": {
|
|
797
|
+
"type": "boolean",
|
|
798
|
+
"title": "Use the device's built-in countdown timer",
|
|
799
|
+
"placeholder": true,
|
|
800
|
+
"description": "When the controller exposes per-zone countdown data-points (countdown_1.., DP 17.. by default), mirror each zone's duration to the hardware timer so a zone still auto-closes on schedule even if Homebridge or the network drops out mid-run. Disable to fall back to the software-timer-only behaviour. Has no effect on devices that don't report a countdown data-point.",
|
|
756
801
|
"condition": {
|
|
757
802
|
"functionBody": "return model.devices && model.devices[arrayIndices] && ['IrrigationSystem'].includes(model.devices[arrayIndices].type);"
|
|
758
803
|
}
|
|
@@ -817,55 +862,10 @@
|
|
|
817
862
|
"condition": {
|
|
818
863
|
"functionBody": "return model.devices && model.devices[arrayIndices] && ['IrrigationSystem'].includes(model.devices[arrayIndices].type) && !model.devices[arrayIndices].noBattery;"
|
|
819
864
|
}
|
|
820
|
-
},
|
|
821
|
-
"noRainSensor": {
|
|
822
|
-
"type": "boolean",
|
|
823
|
-
"title": "No rain sensor",
|
|
824
|
-
"description": "Disable the rain sensor (use if your controller doesn't report 'rain_sensor_state').",
|
|
825
|
-
"condition": {
|
|
826
|
-
"functionBody": "return model.devices && model.devices[arrayIndices] && ['IrrigationSystem'].includes(model.devices[arrayIndices].type);"
|
|
827
|
-
}
|
|
828
|
-
},
|
|
829
|
-
"rainSensorType": {
|
|
830
|
-
"type": "string",
|
|
831
|
-
"title": "Rain sensor type",
|
|
832
|
-
"default": "contact",
|
|
833
|
-
"oneOf": [
|
|
834
|
-
{ "title": "Contact sensor (Open / Closed)", "enum": ["contact"] },
|
|
835
|
-
{ "title": "Leak sensor (Leak Detected / Dry — note: fires critical alerts)", "enum": ["leak"] }
|
|
836
|
-
],
|
|
837
|
-
"condition": {
|
|
838
|
-
"functionBody": "return model.devices && model.devices[arrayIndices] && ['IrrigationSystem'].includes(model.devices[arrayIndices].type) && !model.devices[arrayIndices].noRainSensor;"
|
|
839
|
-
}
|
|
840
|
-
},
|
|
841
|
-
"rainInverted": {
|
|
842
|
-
"type": "boolean",
|
|
843
|
-
"title": "Invert rain sensor",
|
|
844
|
-
"description": "Flip the reported state if 'raining' and 'dry' appear reversed in HomeKit.",
|
|
845
|
-
"condition": {
|
|
846
|
-
"functionBody": "return model.devices && model.devices[arrayIndices] && ['IrrigationSystem'].includes(model.devices[arrayIndices].type) && !model.devices[arrayIndices].noRainSensor;"
|
|
847
|
-
}
|
|
848
|
-
},
|
|
849
|
-
"dpRain": {
|
|
850
|
-
"type": ["integer", "string"],
|
|
851
|
-
"placeholder": "49 or rain_sensor_state",
|
|
852
|
-
"title": "Rain sensor data-point (numeric id, or cloud code)",
|
|
853
|
-
"condition": {
|
|
854
|
-
"functionBody": "return model.devices && model.devices[arrayIndices] && ['IrrigationSystem'].includes(model.devices[arrayIndices].type) && !model.devices[arrayIndices].noRainSensor;"
|
|
855
|
-
}
|
|
856
|
-
},
|
|
857
|
-
"rainOnValue": {
|
|
858
|
-
"type": "string",
|
|
859
|
-
"placeholder": "rain",
|
|
860
|
-
"title": "Rain sensor 'raining' value",
|
|
861
|
-
"description": "The enum value the device reports when it is raining (default 'rain').",
|
|
862
|
-
"condition": {
|
|
863
|
-
"functionBody": "return model.devices && model.devices[arrayIndices] && ['IrrigationSystem'].includes(model.devices[arrayIndices].type) && !model.devices[arrayIndices].noRainSensor;"
|
|
864
|
-
}
|
|
865
865
|
}
|
|
866
866
|
}
|
|
867
867
|
}
|
|
868
868
|
}
|
|
869
869
|
}
|
|
870
870
|
}
|
|
871
|
-
}
|
|
871
|
+
}
|