diff --git a/300 areas/310 Home Assistant/Tuya Local Integration Notes.md b/300 areas/310 Home Assistant/Tuya Local Integration Notes.md index 3a8d53d..8fd2d94 100644 --- a/300 areas/310 Home Assistant/Tuya Local Integration Notes.md +++ b/300 areas/310 Home Assistant/Tuya Local Integration Notes.md @@ -1,11 +1,13 @@ --- created: 2026-05-26 -modified: 2026-10-02 +modified: 2026-10-20 type: area status: active tags: - homeassistant - tuya-local + - zha + - zigbee - networking - hardware aliases: @@ -13,93 +15,210 @@ aliases: --- # Tuya Local Integration Notes -## 1. General Operating & Setup Principles - -### Core Network Requirement: Static DHCP Reservations -Tuya Wi-Fi smart bulbs do **not** publish mDNS/NetBIOS hostnames to local DNS. Home Assistant communicates directly via local IPv4 addresses on TCP port 6668. -- **The Problem**: Whenever a router reboots or a light is turned off at the wall switch, DHCP assigns a new IP address. Home Assistant loses connection and enters a "Reloading / Initializing / Failed" loop. -- **The Solution**: Every Tuya device **must have a permanent static DHCP reservation** set in the main router (`192.168.20.1`). - -### The Single-TCP-Connection Constraint -Tuya bulb microcontrollers only accept **one active TCP connection at a time** on port 6668. -- If the Tuya/Smart Life/Genio app is open on a mobile phone, it holds the TCP connection open. -- Any attempt by Home Assistant to connect or submit configuration will fail with `Connection refused` (Errno 111) or `Unable to connect`. -- **Rule**: Always force-close / swipe away phone apps before configuring devices in Home Assistant. - -### Tuya Local (`make-all/tuya-local`) vs Legacy `LocalTuya` -- **`tuya-local` (by make-all)**: Modern component that supports Tuya protocol 3.4/3.5, auto-discovers devices using linked Tuya Cloud accounts, and maps device features via standard device profiles. -- **`xZetsubou/hass-localtuya`**: Legacy fork. Requires manual datapoint (DP) mapping for every entity. +> **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.** --- -## 2. Household Tuya Device Inventory & Router Reservations +## 1. General Operating Principles -Configure these static assignments under **Router Settings (`192.168.20.1`) → DHCP Server → Static IP / Reservation**: +### 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. -| Device Name | MAC Address | Reserved IP | Device ID | Local Key | Protocol | +### 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 | | :--- | :--- | :--- | :--- | :--- | :--- | -| **Dining Room Main Light** | `1c:69:20:a2:ce:38` | `192.168.20.10` | `bfc8b2ffde5654946dhint` | `R_>@>f&u@=?$=Jd^` | 3.3 / Auto | -| **Harry Overhead Light** | `70:89:76:07:83:e1` | `192.168.20.41` (or `.33`) | `bf10d9430854f401e7vw2w` | `!6E$CV@BAJNQ:mj*` | 3.3 / Auto | -| **Harry Genio Lamp (Par38)** | `c4:82:e1:0f:b6:ed` | `192.168.20.33` | `bf40c2aa1ded88033bpvm1` | `}Hl^^S=8}MgMVVj<` | Auto | -| **Sam's Bed Lamp** | `70:89:76:07:8b:bc` | `192.168.20.29` | — | — | Auto | -| **Finn Main Light** | `f8:17:2d:c5:76:79` | `192.168.20.17` | `bfc8b022833308dd52ivfh` | `xZN4VwUPbAS?8~q` | Auto | -| **Secondary Lamp / Plug** | `88:13:bf:69:a3:fc` | `192.168.20.14` | — | — | Auto | +| 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. -## 3. Light Bulb Status Diagnostics & Recovery +Healthy baseline for comparison — everything else is fine: -### Bulb Physical Light Modes -- **Rapid Flashing Red / Color (2x per sec)**: Device was reset (e.g., wall switch toggled 3-5 times). It is in **EZ-Mode pairing** and disconnected from Wi-Fi. -- **Slow / Regular Blinking White (1x every 2 sec)**: Device is in **AP-Mode pairing**. It is broadcasting an internal setup hotspot (`SmartLife-XXXX`) and offline from local Wi-Fi. -- **Solid White / Color**: Device is connected to Wi-Fi. -- **Pingable but Port 6668 Refuses Connection**: Device micro-controller socket lockup, or phone app is holding the connection, or HA is currently connected. +| 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 | -### HA "Reloading / Initializing / Failed" Loop -If Home Assistant cycles endlessly on a device entry: -1. Verify the bulb's MAC address is actually on its assigned IP (run `ip neigh show` on local host). -2. If the IP shifted, update the IP in HA or reboot the router to enforce the DHCP reservation. -3. Power cycle the wall switch **once** (off 10s, on 1s) to clear frozen TCP sockets on the bulb. - ---- - -## 4. Dining Room Light Hardware Status & Replacement Plan - -### Diagnostic Status -- **Current MAC**: `1c:69:20:a2:ce:38` -- **Status**: The physical bulb micro-controller was repeatedly power-cycled and exhibited rapid red/white reset states. While ICMP ping responds at `192.168.20.10`, local TCP port 6668 connection remains blocked/refused. -- **Conclusion**: If power cycling off/on once and assigning static IP `192.168.20.10` fails to restore local control, the bulb's internal Wi-Fi/MCU board has suffered hardware failure or persistent firmware corruption. - -### Replacement Specifications -If replacing the Dining Room globe: -- **Bulb Form Factor**: Standard A60 (or ST64/Globe depending on fitting) Smart LED Bulb. -- **Base Fitting**: E27 (Edison Screw) or B22 (Bayonet) – check physical socket. -- **Channels / Color**: 5-Channel RGB+CCT (RGBCW: Red, Green, Blue + Warm White + Cool White). -- **Protocol**: Wi-Fi 2.4 GHz (Tuya / Smart Life ecosystem compatible). -- **Wattage**: 9W – 12W (800 – 1100 Lumens). - -### Recommended Replacement Models -1. **Mirabella Genio Smart Wi-Fi LED Bulb A60 RGB+CCT** (Available locally at Kmart / Target / Bunnings). -2. **Grid Connect / Arlec Smart RGB+CCT Wi-Fi LED Bulb** (Bunnings). -3. **Standard Tuya / Smart Life Wi-Fi 5-Channel RGB+CCT A60 E27/B22 Bulb** (AliExpress / Amazon). - -### New Bulb Onboarding Procedure -1. Install new globe and power on. -2. Open **Tuya Smart** app on phone (connected to 2.4 GHz Wi-Fi) and add the bulb. -3. Reserve the new bulb's MAC address in router settings (`192.168.20.1`). -4. Log into [Tuya IoT Portal](https://iot.tuya.com/) → **Cloud → API Explorer → Device Management → Get Device Details** using the Device ID to retrieve the **Local Key**. -5. In HA: **Settings → Devices & Services → Tuya Local → Add Device**, enter IP, Device ID, and Local Key. - ---- - -## 5. Tuya Cloud API & Key Retrieval Reference - -### Tuya IoT Portal Settings -- **URL**: [https://iot.tuya.com/](https://iot.tuya.com/) -- **Data Center**: Central Europe Data Center (`https://openapi.tuyaeu.com`) -- **Access ID**: `pwwd8y3v7kj8j9c3nnj5` - -### Retrieval Steps -1. Go to **Cloud → API Explorer → Device Management → Get Device Details** (or *Query Devices*). -2. Input Device ID and execute. -3. Copy `"local_key"` into Home Assistant Tuya Local setup form. +LQI 72–180 across 15 routers is a normal, well-populated mesh. No orphaned routes, no single point of failure.