--- created: 2026-05-26 modified: 2026-10-20 type: area status: active tags: - homeassistant - tuya-local - zha - zigbee - networking - hardware aliases: - Tuya Local Notes --- # Tuya Local Integration Notes > **Strategic position (2026-10-20):** Wi-Fi Tuya lighting is a fragile stack — it depends on a stable DHCP lease, a non-rotating local key, a live cloud account *and* an AP that stays up. Zigbee has none of those dependencies. The Dining Room and Finn's room have already moved to Zigbee and work reliably. **Preferred path for any new or replacement light: Zigbee, not Wi-Fi Tuya.** --- ## 1. General Operating Principles ### Static DHCP reservations are mandatory Tuya Wi-Fi bulbs publish no mDNS/NetBIOS hostname. `tuya_local` addresses them by **fixed IPv4 on TCP 6668**. - Any lease change silently breaks the entry. - Confirmed in practice: the Harry Overhead bulb drifted `.41 → .34` and stopped working. - Reserve every bulb MAC on the primary router `192.168.20.1` → DHCP Server → Static IP. ### Single TCP connection per device Tuya MCUs accept **one** connection on port 6668. - An open Tuya/Smart Life/Genio app on a phone holds it. - Force-close the phone app before configuring in Home Assistant. ### `tuya-local` vs `localtuya` - **`tuya-local`** (`make-all`) — current choice. Supports protocol 3.4/3.5, uses TinyTuya, device profiles. - **`xZetsubou/hass-localtuya`** — legacy fork. Bundles an old pytuya without 3.4/3.5; fails "session key negotiation failed on step 1". Avoid. ### TRAP: `setup_retry` does not reset when you edit the device Editing a device's IP/key in the UI **saves correctly but does not restart the retry timer**. The entry stays in `setup_retry` with exponential backoff (up to ~15 min), and the UI reports success with no visible change. This looks exactly like "the change didn't work". **Always reload after any edit:** - UI: Settings → Devices & Services → Tuya Local → device → **⋮ → Reload** - API: `POST /api/config/config_entries/entry//reload` --- ## 2. Device Inventory ### Wi-Fi Tuya bulbs (require DHCP reservation) | Device | MAC | Current IP | Device ID | Local Key | | :--- | :--- | :--- | :--- | :--- | | **Sams Bed Lamp** | `70:89:76:07:8b:bc` | `192.168.20.29` | `bf58284019c309e738m9ri` | *unverified* | | **Harry Overhead Light** | `70:89:76:07:83:e1` | `192.168.20.34` | `bf10d9430854f401e7vw2w` | `!6E$CV@BAJNQ:mj*` ✅ verified with tinytuya | | **Harry Genio Lamp** | `c4:82:e1:0f:b6:ed` | `192.168.20.33` | *unverified* (`bfce09bd…` or `bf40c2aa…`) | *unverified* | | **Finn Main Light** | `f8:17:2d:c5:76:79` | `192.168.20.17` | `bfc8b022833308dd52ivfh` | `xZN4VwUPbAS?8~q` | | **Finn Genio A60** | *unknown* | *unknown* | `bfa6dbca41b5ae3000cply` | *unverified* | **Orphan:** the old Dining Room Wi-Fi bulb `1c:69:20:a2:ce:38` (`bfc8b2ffde5654946dhint`, key `R_>@>f&u@=?$=Jd^`) is still powered somewhere at `192.168.20.10` but refuses port 6668. Its `tuya_local` entry was deleted 2026-10-20. **Physically find and remove it** — it holds a lease and generates error spam. ### Zigbee (ZHA) — preferred | Device | IEEE | Model | Area | | :--- | :--- | :--- | :--- | | **Dining Room Light** | `a4:c1:38:7b:5d:d7:80:6a` | TS0505B (Tuya) | `dining_room` | Entity is `light.dining_room_main_light_local` (friendly name "Overhead Light" — rename pending). **Coordinator:** SMLIGHT SLZB-07, **USB-serial** (`/dev/serial/by-id/usb-SMLIGHT_…-if00-port0`, 115200 baud), EZSP/bellows 1.0.1, firmware 7.3.0.0 build 131. Not network-attached — ZHA does not depend on TCP to reach it. **Network:** PAN `1A62`, **channel 22** (~2460 MHz), tx_power 8. 26 nodes known — 21 available. --- ## 3. Failure Mode: all bulbs drop out simultaneously **Symptom:** every Wi-Fi Tuya bulb becomes `unavailable` at once. Log shows: ``` ERROR [custom_components.tuya_local.device] Failed to refresh device state for . Device reported error 901: Network Error: Unable to Connect ``` **Simultaneous failure of all devices means one shared dependency broke** — not N dead bulbs. Check in this order: 1. **Is the AP radio actually on?** (This was the actual root cause on 2026-10-20 — see §4.) 2. Did the router hand out new leases? (IP churn → all entries point at wrong addresses) 3. Did the bulbs' stored SSID/security change? (Tuya bulbs retry forever, never fall back) 4. Only then: keys, device IDs, cloud account. **Not the cause, don't waste time here:** the IoT Core developer subscription. It is valid to **2027-04-06** and was `In service` throughout. Australia maps to the **Central Europe** data centre — do not try to switch data centres. --- ## 4. Failure Mode: AP radio disabled (2026-10-20) The secondary NetComm AP (`192.168.20.254`, AP mode, DHCP off, SSID `NetComm Wireless`, WPA2-PSK/AES) had **`Enable Wireless` unchecked**. Radio off ⇒ the SSID the bulbs had stored no longer existed ⇒ they sat dark, retrying forever, invisible to ARP and DHCP. **Why it fooled everything:** Tuya cloud still reported the bulbs `is_online: true` (stale), and the phone app still listed them. Only the LAN told the truth. **Diagnosis:** hunt the bulbs' MAC OUIs in the ARP table. Absent entirely = not associated to anything, not an IP or key problem. **Fix:** tick `Enable Wireless`, keep SSID/security identical, then **do not re-pair** — the bulbs rejoin on their own within minutes and the entries clear their `setup_retry` state after a reload. **Settings that can block Tuya association on a NetComm AP:** - `Clients Isolation` — must be **off**, or bulbs associate but no LAN host can reach them - `Max Clients` — 16 on the secondary (firmware-locked); fine for ~5 bulbs, watch headroom - Verified **non**-issues: `54g Rate 1 Mbps` and `XPress Technology Enable` did not prevent association **Unknown:** why the radio disabled itself. If it recurs, check the AP's system log — likely a firmware reset or config-restore event. --- ## 5. Zigbee (ZHA) recovery ### A bulb that was removed from ZHA does not come back on an off/on A single power cycle just reboots it; it keeps retrying its old (now unknown) network and stays silent. **Five-cycle reset into pairing mode:** 1. Switch **ON** 2. Then 5×: **OFF, wait 5 s, ON, wait 5 s** 3. Finish **ON** and leave it **Then open the network:** - UI: Settings → Devices & Services → ZHA → **Add device** - API: `zha/devices/permit` with `duration: 254` (**254 s is the maximum**; requesting more returns `success: false`) The bulb rejoins within ~60 s. It comes back with a **new IEEE but the same `entity_id`**, and ZHA restores the area automatically. ### Gotcha: dining-room automations are AREA-scoped, not entity-scoped `Switch Button Dining On` / `Off` (Zigbee remote `a4:c1:38:37:57:e9:2f:1e`) call `light.turn_on` / `light.turn_off` against **`area_id: dining_room`**. If no light is assigned to that area, the physical button silently does nothing. **Deleting a light entity from an area looks exactly like "the Zigbee button broke".** Always check area assignment before diagnosing the remote. --- ## 6. Diagnostics — what to actually query Home Assistant REST API (long-lived token from Profile → Security): | Purpose | Endpoint | | :--- | :--- | | Integration health per entry | `GET /api/config/config_entries/entry` | | **Logs (works on HA OS)** | `GET /api/hassio/core/logs` | | ~~Logs~~ | `GET /api/error_log` → **404 on HA OS**, don't use | | Entity states | `GET /api/states` | | History incl. deleted entities | `GET /api/history/period/?filter_entity_id=` | | Force a retry after an edit | `POST /api/config/config_entries/entry//reload` | `config_entries` state values: `loaded` = working · `setup_retry` = backoff, needs reload · `setup_error` = failed outright. WebSocket (`ws:///api/websocket`) for registry detail: `zha/devices`, `config/device_registry/list`, `config/entity_registry/list`, `config/area_registry/list`, `zha/devices/permit`. **Verify a bulb independently of HA** — this proves whether a key/ID is correct while HA still fails: ```python import tinytuya d = tinytuya.BulbDevice(dev_id='bf10d9430854f401e7vw2w', address='192.168.20.34', local_key='!6E$CV@BAJNQ:mj*', version=3.3) print(d.status()) ``` Note: a wrong `dev_id` against a live Tuya host returns `Unexpected Payload from Device`; an unreachable host returns `Network Error: Device Unreachable`. **Reading port 6668 results:** `111` (RST) = host up, not listening — usually a *different* device holding that IP, not a "socket lockup". A **timeout** is the anomaly worth chasing (implies silent filtering). --- ## 7. Tuya Cloud API — local key retrieval - **Portal:** - **Data centre:** Central Europe (`openapi.tuyaeu.com`) — correct for Australia, do not change - **Access ID:** `pwwd8y3v7kj8j9c3nnj5` - **IoT Core status:** `In service`, expires **2027-04-06** **To get a local key:** 1. **Cloud → API Explorer** 2. Left panel → **Device Management** (not Device Control) → **Get Device Details** 3. Enter the Device ID → Submit 4. Copy `"local_key"` from the response **Pitfalls:** - `GET /v2.0/cloud/thing//model` returns the **datapoint model**, not the key - The key is **not** shown in the web device table, the Debug Device page, or the logs — API Explorer is the only place - Device ID after a re-pair is the **virtual ID from the phone app** (Device Information), and the key **rotates** — always re-fetch - `code: 28841002` means the *resource pack* expired, not that the project is broken; `40001900 "No space permission"` means the app account isn't linked to the project space --- ## 8. Outstanding items - [ ] **DHCP reservations** for the four Wi-Fi MACs (§2) — do this to prevent recurrence - [ ] Physically remove the orphan Wi-Fi bulb at `192.168.20.10` - [ ] Rename `light.dining_room_main_light_local` ("Overhead Light") → "Dining Room Light" - [ ] **5 stale Zigbee entries** — see §9. These are *not* a mesh fault; three have been offline for 6–11 months - [ ] **2.4 GHz interference:** ZHA is on **channel 22 (2460 MHz)**. Wi-Fi **ch 6** (2427–2447) does *not* collide — the secondary AP is correctly placed. Wi-Fi **ch 11** (2442–2462) **does** overlap: check what channel the primary router `Aussie Broadband 8729` is on and move it to ch 1 or 6 if it is on 11 - [ ] Find out why the AP radio disabled itself --- ## 9. Stale Zigbee entries (2026-10-20) Five nodes show `unavailable`, but the `last_seen` dates show this is **bookkeeping, not a mesh problem**. Do not chase interference for these. | Node | Type | Model | Area | Last seen | Read | | :--- | :--- | :--- | :--- | :--- | :--- | | Zigbee Router 1 | Router | esp32c6 | — | **2025-12-01** | retired/decommissioned | | Harry Radar | Router | esp32c6 | bedroom_harry | **2025-11-28** | retired/decommissioned | | Finn Room | EndDevice | esp32h2 | bedroom_finn | **2026-04-27** | retired/decommissioned | | Zbeacon TS0505B | Router | TS0505B | — | 2026-10-06 | spare bulb, not installed | | Hallway Bathroom Lights | EndDevice | esp32c6 | hallway | 2026-09-29 | recent — possibly still deployed | **Action:** if the physical device is gone, delete the ZHA entry (Settings → Devices & Services → ZHA → device → Delete). If it still exists, power it on. Leaving them causes recurring "unavailable" noise. Healthy baseline for comparison — everything else is fine: | Node | Type | LQI | RSSI | | :--- | :--- | :--- | :--- | | Dining Room Light | Router | 140 | -65 | | Router 2 Hallway | Router | 100 | -75 | | Switch Button Dining Room | EndDevice | 128 | -68 | | Bathroom light / Toilet light | Router | 72 | -82 | LQI 72–180 across 15 routers is a normal, well-populated mesh. No orphaned routes, no single point of failure.