Files
obsidian-vault/300 areas/310 Home Assistant/Tuya Local Integration Notes.md

12 KiB
Raw Blame History

created, modified, type, status, tags, aliases
created modified type status tags aliases
2026-05-26 2026-10-20 area active
homeassistant
tuya-local
zha
zigbee
networking
hardware
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/<entry_id>/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 <name>.
  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/<iso>?filter_entity_id=<id>
Force a retry after an edit POST /api/config/config_entries/entry/<id>/reload

config_entries state values: loaded = working · setup_retry = backoff, needs reload · setup_error = failed outright.

WebSocket (ws://<ha>/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:

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: https://iot.tuya.com/
  • 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/<id>/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.