homebridge-tuya-plus 3.14.0-dev.5 → 3.14.0-dev.51
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 +114 -25
- 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 +146 -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
|
@@ -15,7 +15,8 @@ If you are looking for verified configurations for your specific device, please
|
|
|
15
15
|
|Barely Smart Power Strip|`Outlet`|Smart power strips that don't allow individual control of the outlets|
|
|
16
16
|
|Air Conditioner|`AirConditioner`<sup>[6](#air-conditioners)</sup>|Cooling and heating devices <small>([instructions](#air-conditioners))</small>|
|
|
17
17
|
|Heat Convector|`Convector`<sup>[7](#heat-convectors)</sup>|Heating panels <small>([instructions](#heat-convectors))</small>|
|
|
18
|
-
|
|
|
18
|
+
|Simple Dimmer|`SimpleDimmer`<sup>[8](#simple-dimmers)</sup>|Dimmer switches with power control <small>([instructions](#simple-dimmers))</small>|
|
|
19
|
+
|WLED Dimmer|`WledDimmer`<sup>[8](#simple-dimmers)</sup>|Dimmer switches with power control, plus optional WLED brightness sync and preset-effect switches <small>([instructions](#simple-dimmers))</small>|
|
|
19
20
|
|Simple Heater|`SimpleHeater`<sup>[9](#simple-heaters)</sup>|Heating solutions with only temperature control <small>([instructions](#simple-heaters))</small>|
|
|
20
21
|
|Garage Door|`GarageDoor`<sup>[10](#garage-doors)</sup>|Smart garage doors or garage door openers <small>([instructions](#garage-doors))</small>|
|
|
21
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>|
|
|
@@ -223,7 +224,17 @@ Some smart power strips don't have sequential data-points. Using `CustomMultiOut
|
|
|
223
224
|
```
|
|
224
225
|
|
|
225
226
|
### Air Conditioners
|
|
226
|
-
These devices have cooling and/or heating capabilities; they could also have _dry_, _fan_, or others modes but HomeKit's definition doesn't facilitate modes other than _heat_, _cool_, and _auto_. By default, _heat_ and
|
|
227
|
+
These devices have cooling and/or heating capabilities; they could also have _dry_, _fan_, or others modes but HomeKit's definition doesn't facilitate modes other than _heat_, _cool_, and _auto_. By default, _heat_, _cool_ and _auto_ modes are enabled; to let the plugin know that a device doesn't have heating, cooling or auto capabilities, add an additional parameter named `noHeat`, `noCool` or `noAuto` and set it to `true`.
|
|
228
|
+
|
|
229
|
+
Tuya devices don't follow a unified pattern for naming the modes, for example cooling mode is called _COOL_ on Kogan's KAPRA14WFGA but _cold_ on Igenix's IG9901WIFI and most "standard" Tuya AC (category `kt`) firmwares. The phrases are also **case-sensitive**. By default, the plugin uses the phrases _COOL_, _HEAT_ and _AUTO_ while communicating with your device; if your device uses different phrases (a very common case — many ACs report lowercase `cold` / `hot` / `auto` / `wet` / `wind`), override them with `cmdCool`, `cmdHeat` and `cmdAuto`. If the modes don't switch at all, this is almost always the reason.
|
|
230
|
+
|
|
231
|
+
> **Tip — finding the exact phrases.** The phrases are the raw values of the `mode` data-point (DP `4`). You can read them from the [Tuya IoT Platform](https://iot.tuya.com) → _Cloud → API Explorer → Query Things Data Model_ (or _Get Device Specification_) for your device. For example, a device whose `mode` enum range is `["auto","cold","wet","wind","hot"]` needs `cmdCool: "cold"`, `cmdHeat: "hot"`, `cmdAuto: "auto"`.
|
|
232
|
+
|
|
233
|
+
The fan speed data-point (DP `5`, `windspeed`) is usually an **enum of string values** like `"1"`, `"2"`, `"3"`. Set `fanSpeedSteps` to the number of speeds (e.g. `3`); this both maps HomeKit's 0–100 % slider onto the right number of steps and — importantly — sends the speed as a string, which these firmwares require. Without it the fan may silently ignore speed changes.
|
|
234
|
+
|
|
235
|
+
Many ACs have no child-lock data-point; if yours doesn't, set `noChildLock: true` so the plugin doesn't add a (non-functional) lock control. Likewise, set `noRotationSpeed: true` if the device has no fan-speed control.
|
|
236
|
+
|
|
237
|
+
Additional parameters can be found in the sample below.
|
|
227
238
|
|
|
228
239
|
```json5
|
|
229
240
|
{
|
|
@@ -242,12 +253,27 @@ These devices have cooling and/or heating capabilities; they could also have _dr
|
|
|
242
253
|
/* This device has no heating function */
|
|
243
254
|
"noHeat": true ,
|
|
244
255
|
|
|
245
|
-
/*
|
|
256
|
+
/* This device has no auto function */
|
|
257
|
+
"noAuto": true,
|
|
258
|
+
|
|
259
|
+
/* Override cooling phrase (case-sensitive; e.g. "cold" on many devices) */
|
|
246
260
|
"cmdCool": "COOL",
|
|
247
261
|
|
|
248
|
-
/* Override heating phrase */
|
|
262
|
+
/* Override heating phrase (case-sensitive; e.g. "hot" on many devices) */
|
|
249
263
|
"cmdHeat": "HEAT",
|
|
250
264
|
|
|
265
|
+
/* Override auto phrase (case-sensitive; e.g. "auto" on many devices) */
|
|
266
|
+
"cmdAuto": "AUTO",
|
|
267
|
+
|
|
268
|
+
/* Number of fan speeds; also sends the speed as a string (required by most ACs) */
|
|
269
|
+
"fanSpeedSteps": 3,
|
|
270
|
+
|
|
271
|
+
/* This device has no fan-speed control */
|
|
272
|
+
"noRotationSpeed": true,
|
|
273
|
+
|
|
274
|
+
/* This device has no child-lock data-point */
|
|
275
|
+
"noChildLock": true,
|
|
276
|
+
|
|
251
277
|
/* This device has no oscillation (swinging) function */
|
|
252
278
|
"noSwing": true,
|
|
253
279
|
|
|
@@ -258,7 +284,10 @@ These devices have cooling and/or heating capabilities; they could also have _dr
|
|
|
258
284
|
"maxTemperature": 40,
|
|
259
285
|
|
|
260
286
|
/* Temperature change steps, in Celsius (°C) */
|
|
261
|
-
"minTemperatureSteps": 1
|
|
287
|
+
"minTemperatureSteps": 1,
|
|
288
|
+
|
|
289
|
+
/* Only if your firmware reports/accepts temperatures scaled by 10 (e.g. 170 = 17.0 °C) */
|
|
290
|
+
"temperatureDivisor": 10
|
|
262
291
|
}
|
|
263
292
|
```
|
|
264
293
|
|
|
@@ -317,14 +346,15 @@ If your signature doesn't have a variation of _low_ or _high_, `SimpleHeater` wo
|
|
|
317
346
|
```
|
|
318
347
|
|
|
319
348
|
### Simple Dimmers / WLED Dimmers
|
|
320
|
-
These are switches that allow turning on and off, and dimming.
|
|
349
|
+
These are switches that allow turning on and off, and dimming. Two distinct types are available:
|
|
321
350
|
|
|
322
|
-
|
|
351
|
+
- `SimpleDimmer` — a plain dimmer with power and brightness control.
|
|
352
|
+
- `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`.
|
|
323
353
|
|
|
324
|
-
|
|
325
|
-
- `presetEffects`: array of effect configs to expose as switches in HomeKit (each turns on a WLED fx preset, optionally with staticColor).
|
|
354
|
+
The following options apply to `WledDimmer` only (they are ignored by `SimpleDimmer`):
|
|
326
355
|
|
|
327
|
-
|
|
356
|
+
- `syncBrightnessToWled`: set to the WLED device IP (e.g. "192.168.1.50" or "192.168.1.50:80") to sync HomeKit brightness changes directly to WLED over HTTP, keeping the Tuya dimmer at 100%. This talks to the WLED controller directly on your **LAN**, independently of how the Tuya dimmer is reached — so if the Tuya dimmer is ever on the cloud fallback (because the LAN is down), the WLED sync is best-effort and may not go through until the LAN is back.
|
|
357
|
+
- `presetEffects`: array of effect configs to expose as switches in HomeKit (each turns on a WLED fx preset, optionally with staticColor).
|
|
328
358
|
|
|
329
359
|
```json5
|
|
330
360
|
{
|
|
@@ -470,9 +500,10 @@ external stop, where close is accepted immediately), a close is sent as
|
|
|
470
500
|
/* Optional. If set, exposes an extra stateful switch that mirrors
|
|
471
501
|
whether the gate is currently open in HomeKit's view. Tapping it
|
|
472
502
|
ON triggers a partial-open: the gate opens and then stops itself
|
|
473
|
-
this many milliseconds
|
|
474
|
-
Tapping it OFF triggers a standard full close.
|
|
475
|
-
someone pass through briefly. Leave unset to skip
|
|
503
|
+
this many milliseconds after it actually starts moving, leaving the
|
|
504
|
+
gate partially open. Tapping it OFF triggers a standard full close.
|
|
505
|
+
Useful for letting someone pass through briefly. Leave unset to skip
|
|
506
|
+
the switch. */
|
|
476
507
|
"partialOpenMs": 2000,
|
|
477
508
|
|
|
478
509
|
/* Optional. Exposes extra Force Open and Force Close momentary
|
|
@@ -723,12 +754,11 @@ If the light, brightness and turning the fan **off** all work, but turning the f
|
|
|
723
754
|
|
|
724
755
|
### Irrigation Systems / Sprinklers
|
|
725
756
|
|
|
726
|
-
Multi-valve Tuya irrigation/sprinkler controllers (the battery-powered Wi-Fi "faucet timers" that expose several `switch_*` valves
|
|
757
|
+
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:
|
|
727
758
|
|
|
728
759
|
* one **Irrigation System** tile that contains every zone,
|
|
729
760
|
* one **Valve** per zone (`ValveType = Irrigation`) — each with its own on/off, its own **Duration** picker and a live countdown,
|
|
730
|
-
* an optional **Battery** service (level, low-battery warning, and — for solar/USB-C rechargeable units that report it — live charging status)
|
|
731
|
-
* an optional **rain sensor** (a Contact sensor by default).
|
|
761
|
+
* an optional **Battery** service (level, low-battery warning, and — for solar/USB-C rechargeable units that report it — live charging status).
|
|
732
762
|
|
|
733
763
|
Because these devices are slow to respond, all zone changes that happen close together — turning the whole system on/off, or running a scene that toggles several zones — are merged into a **single** Tuya command instead of a burst of them.
|
|
734
764
|
|
|
@@ -741,14 +771,13 @@ Because these devices are slow to respond, all zone changes that happen close to
|
|
|
741
771
|
"type": "IrrigationSystem",
|
|
742
772
|
"id": "bfae6739xxxxxxxxxxxxxx", // the cloud Device ID
|
|
743
773
|
"cloud": true,
|
|
744
|
-
"valveCount": 4
|
|
745
|
-
"noRainSensor": true // many battery timers have no rain sensor
|
|
774
|
+
"valveCount": 4
|
|
746
775
|
}
|
|
747
776
|
```
|
|
748
777
|
|
|
749
778
|
#### Minimal Configuration
|
|
750
779
|
|
|
751
|
-
The defaults match the common 4-zone layout (valves A–D on data-points `1`–`4`, battery on `46
|
|
780
|
+
The defaults match the common 4-zone layout (valves A–D on data-points `1`–`4`, battery on `46`):
|
|
752
781
|
|
|
753
782
|
```json5
|
|
754
783
|
{
|
|
@@ -763,19 +792,21 @@ The defaults match the common 4-zone layout (valves A–D on data-points `1`–`
|
|
|
763
792
|
|
|
764
793
|
#### Per-zone timers and "indefinite" mode
|
|
765
794
|
|
|
766
|
-
Each zone has its own **Duration**. When a zone is switched on it runs for that duration and
|
|
795
|
+
Each zone has its own **Duration**. When a zone is switched on it runs for that duration and is then closed automatically. Two mechanisms enforce this together:
|
|
767
796
|
|
|
768
|
-
*
|
|
797
|
+
* a **software timer** in the plugin drives HomeKit's live countdown and the precise (sub-minute) shut-off while Homebridge is connected — it also closes a zone that was switched on at the device or that was already running when Homebridge restarted; and
|
|
798
|
+
* the device's **own countdown timer**, when the controller exposes one (`countdown_1..n`, DP `17..` by default). When a zone is switched **on**, its run length (whole minutes) is sent to the hardware countdown in the *same command* as the switch, so the valve still closes on schedule **even if Homebridge or the network drops out while it's running** — the hardware closes itself. This is on by default whenever the device reports these data-points; set `nativeCountdown: false` to fall back to the software timer alone.
|
|
799
|
+
|
|
800
|
+
> On these controllers the countdown is **not** a passive setting — *writing it starts a run and opens the zone*. So the plugin only ever sets it while switching a zone on (or for a zone that's already running); it is **never** written on connect or while a zone is off. The two mechanisms are belt-and-suspenders: the hardware countdown handles the offline case, and the software timer still switches the zone off after its Duration if the hardware countdown is unreliable. A zone switched on at the device with no usable countdown is given one (so it still auto-closes offline); a valid countdown the device set itself (e.g. a duration chosen in the Tuya app) is left alone.
|
|
801
|
+
|
|
802
|
+
* Set a zone's duration to **`0`** to make it run **indefinitely** (until it is switched off again) — handy for long, manual watering tasks. (No finite hardware countdown is sent, so the device won't auto-close it either.)
|
|
803
|
+
* The hardware countdown is whole **minutes**, capped by the device at **120 min**; HomeKit's Duration is in seconds. The value written is bounded by `maxDuration` (default `7200`s = 120 min) — lower `maxDuration` to e.g. `3600` to cap zone runs at 60 minutes.
|
|
769
804
|
* Apple's Home app only offers duration presets up to **1 hour**. For longer runs (up to `maxDuration`) or to preset "indefinite" zones, set `defaultDuration` / the per-valve `defaultDuration` in the config, or use the Eve app.
|
|
770
805
|
|
|
771
806
|
#### Master ("toggle all") switch
|
|
772
807
|
|
|
773
808
|
Switching the whole Irrigation System tile **off** closes every open zone, and switching it **on** opens every zone — each as one combined command (mirroring the physical "all" button many of these controllers have). Either direction can be disabled with `masterTurnsOffAllZones` / `masterTurnsOnAllZones`.
|
|
774
809
|
|
|
775
|
-
#### Rain sensor: Contact vs Leak
|
|
776
|
-
|
|
777
|
-
By default the rain sensor is a **Contact sensor** (`raining → Open`). You can switch it to a **Leak sensor** (`raining → Leak Detected`) with `"rainSensorType": "leak"` — leak sensors read more naturally for rain and make "when it starts raining" automations obvious, **but HomeKit treats them as safety accessories and raises critical alerts that bypass Do-Not-Disturb on every rainfall**, which many people find too noisy. Use `rainInverted` if the wet/dry states appear reversed.
|
|
778
|
-
|
|
779
810
|
#### Full Configuration
|
|
780
811
|
|
|
781
812
|
```json5
|
|
@@ -791,17 +822,23 @@ By default the rain sensor is a **Contact sensor** (`raining → Open`). You can
|
|
|
791
822
|
/* Simple: number of valves on sequential data-points 1, 2, 3, … */
|
|
792
823
|
"valveCount": 4,
|
|
793
824
|
/* …or, for custom names / non-sequential data-points, define them explicitly
|
|
794
|
-
(this overrides valveCount). defaultDuration is in seconds; 0 = indefinite.
|
|
825
|
+
(this overrides valveCount). defaultDuration is in seconds; 0 = indefinite.
|
|
826
|
+
dpCountdown is the device's built-in auto-off timer for the zone; it
|
|
827
|
+
defaults to the switch dp + 16 (so switch 1 → countdown 17) and only needs
|
|
828
|
+
setting for code-addressed or non-standard zones. */
|
|
795
829
|
"valves": [
|
|
796
830
|
{ "name": "Front Lawn", "dp": 1, "defaultDuration": 900 },
|
|
797
831
|
{ "name": "Back Lawn", "dp": 2, "defaultDuration": 900 },
|
|
798
832
|
{ "name": "Flower Beds","dp": 3, "defaultDuration": 600 },
|
|
799
|
-
{ "name": "Drip Line", "dp": 4, "defaultDuration": 0 }
|
|
833
|
+
{ "name": "Drip Line", "dp": 4, "defaultDuration": 0, "dpCountdown": 20 }
|
|
800
834
|
],
|
|
801
835
|
|
|
802
836
|
/* --- Timers --- */
|
|
803
837
|
"defaultDuration": 600, /* default per-zone run time, seconds (0 = indefinite) */
|
|
804
838
|
"maxDuration": 7200, /* upper bound advertised to HomeKit, seconds */
|
|
839
|
+
"nativeCountdown": true, /* mirror durations to the device's own countdown timer
|
|
840
|
+
(countdown_1.., DP 17..) so zones still auto-close
|
|
841
|
+
offline; set false for software-timer-only */
|
|
805
842
|
|
|
806
843
|
/* --- Master switch behaviour --- */
|
|
807
844
|
"masterTurnsOnAllZones": true,
|
|
@@ -813,12 +850,5 @@ By default the rain sensor is a **Contact sensor** (`raining → Open`). You can
|
|
|
813
850
|
"lowBatteryThreshold": 20,
|
|
814
851
|
"dpCharging": 101, /* boolean charging-status DP (solar / USB-C); omit if not reported */
|
|
815
852
|
/* "noBattery": true, */
|
|
816
|
-
|
|
817
|
-
/* --- Rain sensor (omit / set noRainSensor:true if not present) --- */
|
|
818
|
-
"dpRain": 49,
|
|
819
|
-
"rainSensorType": "contact", /* or "leak" */
|
|
820
|
-
"rainOnValue": "rain", /* enum value reported while raining */
|
|
821
|
-
"rainInverted": false
|
|
822
|
-
/* "noRainSensor": true, */
|
|
823
853
|
}
|
|
824
854
|
```
|
package/wiki/Tuya-Cloud-Setup.md
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
# Tuya Cloud Setup
|
|
2
2
|
|
|
3
|
-
This plugin is **LAN-first** —
|
|
3
|
+
This plugin is **LAN-first** — every Tuya device is controlled locally whenever it can be. Adding your Tuya Cloud credentials turns the cloud into a **transparent fallback for every device**: each accessory tries the LAN first, and only falls back to the cloud when the device can't be reached locally. It's **opt-in** (nothing happens unless you add credentials) and **local stays the preferred path**.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It helps in two situations:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
> **Devices that are never on the LAN.** Some devices, most notably some battery-powered **"sleepy"** ones, never keep the local port open and never answer LAN discovery, so the local protocol can't reach them. (Tuya's own developer docs state LAN control is unavailable in low-power mode.)
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
* Live updates (including physical button presses) arrive over Tuya's **MQTT** message service — no polling.
|
|
9
|
+
> **Devices that occasionally drop off the LAN.** If a normally-local device sometimes shows "No Response" in HomeKit, the cloud fallback quietly covers those moments.
|
|
11
10
|
|
|
12
11
|
---
|
|
13
12
|
|
|
@@ -21,32 +20,33 @@ For these devices the plugin can talk to the **Tuya Cloud** instead. It is **opt
|
|
|
21
20
|
|
|
22
21
|
## 2. Authorize the required API services
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
* **IoT Core**
|
|
27
|
-
* **Authorization**
|
|
28
|
-
* **Smart Home Basic Service**
|
|
29
|
-
* **Device Status Notification** ← needed for realtime MQTT updates
|
|
30
|
-
|
|
31
|
-
> ⚠️ The free trial of *IoT Core* lasts ~6 months, after which you must click **Extend Trial Period** (Cloud → My Services). If it lapses you'll see *"No permissions. Your subscription … has expired."*
|
|
23
|
+
There are two types of projects: `Custom` and `Smart Home`. The difference between them is:
|
|
32
24
|
|
|
33
|
-
|
|
25
|
+
* The `Custom` project pulls devices from the project's assets.
|
|
26
|
+
* The `Smart Home` project pulls devices from the user's home in the Tuya app.
|
|
34
27
|
|
|
35
|
-
|
|
28
|
+
If you are a personal user and are unsure which one to choose, please use the Smart Home project.
|
|
36
29
|
|
|
37
|
-
|
|
30
|
+
In the project, go to **Service API → Go to Authorize** and make sure these are subscribed (all free):
|
|
38
31
|
|
|
39
|
-
|
|
32
|
+
* Authorization Token Management
|
|
33
|
+
* Device Status Notification
|
|
34
|
+
* IoT Core
|
|
35
|
+
* IoT Video Live Stream (for cameras)
|
|
36
|
+
* Industry Project Client Service (for the `Custom` project)
|
|
37
|
+
* IR Control Hub Open Service (for IR devices)
|
|
38
|
+
* Smart Home Scene Linkage (for scenes)
|
|
39
|
+
* Smart Lock Open Service (for Lock devices)
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
> **⚠️Remember to extend the API trial period every 6 months here: [Tuya IoT Platform > Cloud > Cloud Services > IoT Core](https://iot.tuya.com/cloud/products/detail?abilityId=1442730014117204014&id=p1668587814138nv4h3n&abilityAuth=0&tab=1) (the first-time subscription only gives you 1 month).**
|
|
42
42
|
|
|
43
|
-
##
|
|
43
|
+
## 3. Link your app account (so the project can see your devices)
|
|
44
44
|
|
|
45
|
-
Add
|
|
45
|
+
Still in the project: **Devices → Link App Account → Add App Account**, then in the **Tuya Smart / Smart Life** app go to **Me → ⊞ (scan icon, top-right)** and scan the QR code. Your irrigation timer should now appear under **Devices → All Devices**.
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
## 4. Configure the plugin
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Add a **top-level `cloud` block** with your credentials:
|
|
50
50
|
|
|
51
51
|
```json5
|
|
52
52
|
{
|
|
@@ -61,100 +61,23 @@ Authenticates as your app account (username/password), so it sees exactly the de
|
|
|
61
61
|
"schema": "tuyaSmart" // or "smartlife" if you use the Smart Life app
|
|
62
62
|
},
|
|
63
63
|
"devices": [
|
|
64
|
-
|
|
65
|
-
"name": "Garden Irrigation",
|
|
66
|
-
"type": "IrrigationSystem",
|
|
67
|
-
"id": "bfae6739xxxxxxxxxxxxxx", // the cloud Device ID
|
|
68
|
-
"cloud": true,
|
|
69
|
-
"valveCount": 4,
|
|
70
|
-
"noRainSensor": true // most battery timers have no rain DP
|
|
71
|
-
}
|
|
64
|
+
// ...
|
|
72
65
|
]
|
|
73
66
|
}
|
|
74
67
|
```
|
|
75
68
|
|
|
76
|
-
###
|
|
77
|
-
|
|
78
|
-
If you created a **Custom** project (devices linked by QR to the project's asset) just omit `username`/`password`/`countryCode`/`schema`:
|
|
79
|
-
|
|
80
|
-
```json5
|
|
81
|
-
"cloud": {
|
|
82
|
-
"accessId": "your-access-id",
|
|
83
|
-
"accessKey": "your-access-secret",
|
|
84
|
-
"region": "eu"
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### Per-device credentials (optional)
|
|
89
|
-
|
|
90
|
-
Instead of (or in addition to) the platform block, a device can carry its own credentials — handy if different devices live in different Tuya projects:
|
|
91
|
-
|
|
92
|
-
```json5
|
|
93
|
-
{
|
|
94
|
-
"name": "Garden Irrigation",
|
|
95
|
-
"type": "IrrigationSystem",
|
|
96
|
-
"id": "bfae6739xxxxxxxxxxxxxx",
|
|
97
|
-
"cloud": {
|
|
98
|
-
"accessId": "…",
|
|
99
|
-
"accessKey": "…",
|
|
100
|
-
"region": "eu",
|
|
101
|
-
"username": "…",
|
|
102
|
-
"password": "…",
|
|
103
|
-
"countryCode": "48"
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
> No local `key` is needed for cloud devices — the cloud authenticates with your project credentials.
|
|
109
|
-
|
|
110
|
-
---
|
|
111
|
-
|
|
112
|
-
## Data-points are addressed by "code" on the cloud
|
|
113
|
-
|
|
114
|
-
Over the LAN, data-points are numbered (1, 2, …). Over the **cloud** they're named **codes** (e.g. `switch_1`, `battery_percentage`). When a cloud device connects, the plugin **logs the exact codes** it reports, e.g.:
|
|
115
|
-
|
|
116
|
-
```
|
|
117
|
-
Garden Irrigation: Tuya Cloud data-point codes → switch_1=false, switch_2=false, switch_3=false, switch_4=false, countdown_1=0, …, battery_percentage=99
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
The `IrrigationSystem` defaults already match the common 4-zone layout (`switch_1`…`switch_4`, battery `battery_percentage`). If your device differs, use the logged codes:
|
|
121
|
-
|
|
122
|
-
```json5
|
|
123
|
-
"valves": [
|
|
124
|
-
{ "name": "Front Lawn", "dp": "switch_1", "defaultDuration": 900 },
|
|
125
|
-
{ "name": "Back Lawn", "dp": "switch_2", "defaultDuration": 900 }
|
|
126
|
-
],
|
|
127
|
-
"dpBattery": "battery_percentage",
|
|
128
|
-
"noRainSensor": true // or: "dpRain": "rain_sensor_state"
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
See **[Irrigation Systems / Sprinklers](https://github.com/adrianjagielak/homebridge-tuya-plus/blob/main/wiki/Supported-Device-Types.md#irrigation-systems--sprinklers)** for all options (per-zone durations, master switch, etc.).
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
## Realtime updates (MQTT)
|
|
69
|
+
### Security note
|
|
136
70
|
|
|
137
|
-
|
|
71
|
+
Your **Access Secret** and app password are sensitive. Keep them only in your Homebridge `config.json`. If you ever share a config for support, redact them.
|
|
138
72
|
|
|
139
|
-
|
|
140
|
-
sudo npm install -g mqtt
|
|
141
|
-
```
|
|
73
|
+
## Troubleshooting
|
|
142
74
|
|
|
143
|
-
|
|
75
|
+
### A device reads fine over the cloud but won't accept commands (`command or value not support`, code `2008` / `2003`)
|
|
144
76
|
|
|
145
|
-
|
|
77
|
+
The plugin controls devices through Tuya's current **`iot-03`** device API (`POST /v1.0/iot-03/devices/{id}/commands`), the same one tinytuya and the official Tuya Homebridge plugin use. That works for almost everything.
|
|
146
78
|
|
|
147
|
-
|
|
79
|
+
Some **custom data-points** (e.g. a gate/garage controller's open/close/stop) aren't in the device's standard instruction set — `/commands` answers `2003`/`2008` for them — yet the cloud still models them as **thing-model properties** (their status reads fine, and the device acts on the same write over the LAN). For these, **you don't need to configure anything**: when a `/commands` write is rejected with `2008`/`2003`, the plugin automatically retries it through Tuya's thing-model endpoint (`POST /v2.0/cloud/thing/{id}/shadow/properties/issue`) — which is how Tuya's own app drives such a device — and remembers the working endpoint **per data-point**. So a device that mixes ordinary DPs (a switch) with custom ones (a trigger) drives each over the endpoint it accepts; the standard commands API is always tried first.
|
|
148
80
|
|
|
149
|
-
|
|
150
|
-
|---|---|
|
|
151
|
-
| `failed to connect to Tuya Cloud: token request failed … (code 1004)` | Wrong **Access ID/Secret**, or host clock skew — the signature includes a timestamp, so keep the machine **NTP-synced**. |
|
|
152
|
-
| `… (code 1106) permission deny` / `No permissions` | API service not authorized or **trial expired** (step 2), or **wrong region**, or you logged in with the developer account instead of the **app** account. |
|
|
153
|
-
| Device connects but shows nothing / `0` devices | **Region mismatch**, or the device isn't linked to the project (step 3), or the linked account isn't the device's **owner** (shared/guest access hides devices). |
|
|
154
|
-
| `realtime disabled: the optional "mqtt" package is not installed` | Install `mqtt` (above), or ignore if you don't need live external updates. |
|
|
155
|
-
| Realtime never connects (control works, external changes don't) | Outbound **port 8883** blocked by a firewall. |
|
|
156
|
-
| Logs show different codes than expected | Use the codes from the startup log line shown above. |
|
|
157
|
-
|
|
158
|
-
### Security note
|
|
81
|
+
If a write fails on **both** endpoints, the data-point is genuinely **report-only** for that device (its Tuya product defines it that way), which only the manufacturer can change — there's no cloud workaround. Such devices still work normally over the **LAN**; only the cloud fallback can't drive them.
|
|
159
82
|
|
|
160
|
-
|
|
83
|
+
The undocumented `debug.logCloudHttp` switch logs the full (credential-redacted) request/response for every cloud call if you want to see exactly what was sent and how the cloud replied.
|