Skip to content

Latest commit

 

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Tuya ESP32 HomeKit Bridge logo

Tuya ESP32 HomeKit Bridge

Turn a Tuya / Smart Life Wi-Fi plug into a local Apple HomeKit Outlet without reflashing or opening the plug.

Tuya ESP32 HomeKit Bridge concept

This project uses:

  • Python + TinyTuya to discover and verify local Tuya control first
  • ESP32 + HomeSpan to expose the plug to Apple HomeKit
  • local LAN control for switching on/off

The original Tuya / Smart Life firmware stays on the plug.

In plain language: the ESP32 behaves like a small translator. Apple Home talks to the ESP32 using HomeKit, and the ESP32 talks to the Tuya plug using the plug's local Tuya protocol.

Start Here

If you already know Python, Arduino IDE, ESP32 flashing, and HomeKit pairing, follow the phases in this README.

If you are new to those tools, use the beginner walkthrough first:

Beginner Guide

The beginner guide explains each step in smaller pieces, including what to install, what values to copy, what should happen after every step, and when to stop instead of guessing.

For maintainers preparing a GitHub release, use:

Release Checklist

Current Status

Current development branch: v2.1 Smart Setup & Diagnostics.

  • tested with one Tesla Smart Plug / Tuya protocol 3.4
  • local Python control works through TinyTuya
  • ESP32 local Tuya POC works for status, on, and off
  • HomeSpan sketch exposes one Tuya relay as a HomeKit Outlet, Light, or Switch
  • HomeSpan sketch has a step-based setup web wizard, so users no longer need to edit source code for normal setup
  • admin dashboard shows HomeKit, Tuya, network and diagnostics status after the ESP32 joins Wi-Fi
  • experimental LAN scan and read-only DPS inspector are available from the web UI

This is still experimental. Treat the project as a working reference build for one known device, not as a universal Tuya bridge.

Compatibility

Device Brand Protocol Relay DPS Status Notes
Tesla Smart Plug Tesla 3.4 1 Working Verified by author with local Tuya LAN control

Please open an issue if you verify another device. Do not include local keys, Wi-Fi passwords, Tuya Access Secret values, or unredacted API responses.

Web Setup and Dashboard

The recommended firmware is:

esp32/homespan_tuya_outlet/homespan_tuya_outlet.ino

On first boot, the ESP32 starts a setup access point:

TuyaHomeKit-Setup

Open:

http://192.168.4.1/

The v2.1 wizard is step-based:

  1. Wi-Fi setup
  2. Find Tuya device
  3. Enter Tuya credentials
  4. Test connection
  5. HomeKit settings
  6. Save and reboot

The wizard still supports manual entry for Wi-Fi SSID/password, Tuya IP, device ID, local key, protocol version, relay DPS, HomeKit name/type/pairing code, and polling interval.

After normal boot, Serial Monitor prints a local admin URL, for example:

Admin URL: http://192.168.1.50:8080

The dashboard shows:

  • HomeKit accessory name, type, relay state and polling interval
  • Tuya IP, protocol version, relay DPS, last status, latency and failed poll count
  • Wi-Fi SSID, ESP32 IP address, RSSI, uptime and free heap
  • recent in-memory diagnostics events

Available dashboard actions:

  • Test Tuya connection
  • Scan DPS
  • Restart ESP32
  • Reset configuration
  • Reset HomeKit pairing

Experimental LAN Scan

The Find Tuya devices button scans the ESP32's local subnet for candidates with common Tuya LAN ports open, especially 6668 and 6669.

Results are intentionally labelled as possible Tuya device or likely Tuya device. An open port is not proof that the device is Tuya. If a candidate looks right, use Use this IP and then run Test Tuya connection with the correct device ID and local key.

LAN scan limitations:

  • ESP32 and plug must be on the same subnet/VLAN
  • some routers or IoT networks block local client-to-client traffic
  • scan timeouts are short, so slow devices may be missed
  • this does not discover the local key

Experimental DPS Inspector

The Scan DPS button queries the Tuya status payload and displays returned datapoints.

This v2.1 inspector is read-only. It does not toggle unknown datapoints. Boolean values are labelled as possible relay/switch candidates, and numeric values are labelled as possible sensor/energy/power values.

Use Use as relay DPS only when the boolean datapoint clearly represents the relay state.

Security Note

  • The setup and admin pages currently have no authentication.
  • Use them only on a trusted LAN, guest network, or IoT network.
  • Do not expose the ESP32 dashboard to the internet.
  • Wi-Fi password and Tuya local key are stored in ESP32 flash memory.
  • The web UI does not show saved Wi-Fi passwords or local keys back in the form; leave those fields blank to keep saved values when editing.

Visual Overview

Local smart home control diagram

The intended flow is local: HomeKit talks to the ESP32, and the ESP32 talks to the Tuya plug on your Wi-Fi network.

What This Is

This is an experimental local bridge for existing Tuya Wi-Fi plugs. The ESP32 joins your Wi-Fi network, talks directly to the Tuya plug over the LAN, and exposes a HomeKit Outlet accessory via HomeSpan.

The proven test setup was:

Other Tuya devices may work, but they must be verified first. Do not assume protocol version, datapoints, or local-key behavior.

What This Is Not

  • It does not flash the Tuya plug.
  • It does not require opening the plug.
  • It does not use Tuya cloud for HomeKit on/off commands.
  • It is not a universal Tuya device bridge yet.
  • It is not intended for critical loads or safety-critical switching.

Hardware

  • ESP32 development board
  • Existing Tuya / Smart Life Wi-Fi plug
  • 2.4 GHz Wi-Fi network
  • A safe test load, such as a small lamp

Optional but strongly recommended:

  • DHCP reservation for the Tuya plug
  • DHCP reservation for the ESP32

DHCP reservation means telling your router to always give the same IP address to the same device. This prevents the bridge from breaking when the router changes the plug's IP address.

Project Structure

.
├── .env.example
├── requirements.txt
├── docs/
│   ├── beginner-guide.md
│   └── release-checklist.md
├── scripts/
│   ├── scan_devices.py
│   ├── test_plug.py
│   └── export_esp32_secrets.py
└── esp32/
    ├── tuya_local_poc/
    └── homespan_tuya_outlet/

Safety

Tuya plugs switch mains voltage. Test with a small non-critical load first.

Do not use this project for:

  • heaters without independent thermal protection
  • medical equipment
  • pumps or appliances where unexpected switching can cause damage
  • any load that would be dangerous after a reboot, Wi-Fi outage, or software bug

Secret Handling

Never commit:

  • .env
  • tinytuya.json
  • devices.json
  • tuya-raw.json
  • snapshot.json
  • esp32/**/secrets.h

These files are ignored by .gitignore because they can contain device IDs, cloud credentials, Wi-Fi passwords, or Tuya local keys.

If you pasted a Tuya Access Secret somewhere public, rotate it in the Tuya IoT Platform.

Phase 1: Verify Local Tuya Control

Do this before flashing the ESP32. If local TinyTuya control does not work, HomeKit will not work reliably either.

macOS / Linux Setup

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

Scan LAN for Tuya Devices

If you already know the plug IP, pass it as --target-ip.

Run:

python scripts/scan_devices.py --target-ip 192.168.1.123

Look for:

  • plug IP address
  • Device ID
  • Tuya protocol version
  • product information

Confirm the IP address in your router/DHCP lease table. TinyTuya may not always report the MAC address.

Get local_key

You need the plug's local_key.

This is a 16-character device secret used by the local Tuya protocol. Without it, the ESP32 cannot decrypt or send local commands.

Common route:

  1. Open Tuya IoT Platform.
  2. Create a Tuya IoT account if you do not already have one.
  3. Create a Tuya IoT cloud project if you do not already have one.
  4. Link your Smart Life / Tuya app account.
  5. Add the device to the project.
  6. Use TinyTuya wizard or Tuya IoT Platform API Explorer to retrieve local_key.

You need both a Tuya IoT account and a cloud project. The Smart Life mobile-app account alone is not enough to access the API Explorer.

TinyTuya wizard:

python -m tinytuya wizard

Tuya IoT Platform API Explorer:

  1. Open Tuya IoT Platform.
  2. Open your cloud project.
  3. Select the correct data center, for example Central Europe Data Center.
  4. Go to API Explorer.
  5. Select IoT Core.
  6. Open Device Management.
  7. Choose Query Device Details.
  8. Enter the device ID found by TinyTuya scan.
  9. Click Submit Request.
  10. In the JSON response, copy the result.local_key value into your local .env.

The API Explorer page can also show a generated curl command. Treat both the curl command and the JSON response as secrets because they may contain:

  • local_key
  • client_id
  • request signature
  • access token
  • location and device metadata

Do not paste the API Explorer response, request URL, or generated curl command into issues, README files, screenshots, or commits unless all secrets are redacted.

Tuya sometimes requires an active IoT Core / Cloud Development plan to retrieve device details. The cloud is used only to get local_key; switching is local after that.

Configure .env

cp .env.example .env

Fill:

DEVICE_ID=your_device_id
DEVICE_IP=your_plug_lan_ip
LOCAL_KEY=your_16_byte_local_key
DEVICE_VERSION=3.4

Use the version discovered by scan. Do not guess.

Test Status and Switching

Read status first:

python scripts/test_plug.py status

Then test switching:

python scripts/test_plug.py on
python scripts/test_plug.py off

For the tested plug, the relay datapoint was:

dps["1"] = true / false

If your device uses a different datapoint, update the ESP32 configuration before flashing.

Phase 2: ESP32 Local Tuya POC

Use this sketch before HomeSpan:

esp32/tuya_local_poc/tuya_local_poc.ino

Generate local ESP32 secrets:

python scripts/export_esp32_secrets.py

Edit:

nano esp32/tuya_local_poc/secrets.h

Fill Wi-Fi:

#define WIFI_SSID "..."
#define WIFI_PASSWORD "..."

Flash the sketch, open Serial Monitor at 115200, and test:

status
on
off

Only continue when this works reliably.

This step deliberately avoids HomeKit. It proves that the ESP32 can control the plug locally before adding another layer.

Phase 3: HomeKit Outlet with HomeSpan Setup Wizard

Use:

esp32/homespan_tuya_outlet/homespan_tuya_outlet.ino

Install in Arduino IDE:

  • ESP32 board support
  • HomeSpan library

Recommended Arduino IDE settings for a common 4 MB ESP32 board:

  • Board: ESP32 Dev Module
  • Partition Scheme: No OTA (2MB APP/2MB SPIFFS) or larger
  • Upload Speed: any stable value for your board

The default ESP32 partition is usually too small for HomeSpan plus the setup web wizard.

Flash the sketch, open Serial Monitor at 115200, and wait for setup mode.

On first boot, or when no saved config exists, the ESP32 starts its own setup Wi-Fi access point:

TuyaHomeKit-Setup

The setup Wi-Fi password is randomly generated for each setup session and printed in Serial Monitor. Connect to that Wi-Fi network from a phone or computer and open:

http://192.168.4.1/

Fill:

  • Wi-Fi SSID
  • Wi-Fi password
  • Tuya plug IP address
  • Tuya device ID
  • Tuya local key
  • Tuya protocol version, default 3.4
  • relay DPS, default 1
  • HomeKit accessory name
  • HomeKit type, default Outlet
  • optional HomeKit pairing code
  • polling interval in seconds, default 30

The setup page uses plain HTTP on the temporary ESP32 setup network. Configure it near the ESP32 and do not leave setup mode running longer than needed. Saved Wi-Fi passwords and Tuya local keys are stored in ESP32 Preferences in plaintext, but they are not shown back in the form; leave those fields blank to keep existing saved values when reconfiguring. Use an IoT or guest Wi-Fi network if possible.

Use Test Tuya connection before saving if you want a quick check from the setup page.

Click Save and restart. On the next boot, the ESP32 loads the saved config from flash, connects to Wi-Fi, starts HomeSpan, and exposes the plug to HomeKit.

After normal boot, Serial Monitor prints an admin URL with the ESP32's LAN IP address, for example:

Admin URL: http://192.168.1.50:8080

Open that URL from the same Wi-Fi network to edit the saved Tuya/HomeKit settings, test the Tuya connection, clear bridge configuration, or clear HomeKit pairing on the ESP32. The admin page is plain local HTTP without login, so use it only on a trusted LAN or IoT network.

If Wi-Fi connection fails repeatedly during boot, the ESP32 falls back to setup mode and periodically retries the saved Wi-Fi. If the network comes back, the ESP32 restarts into normal HomeSpan mode.

Reset options:

  • Edit settings: open the admin URL and save new values.
  • Clear saved config: use the admin/setup page button. This removes Wi-Fi and Tuya settings, restarts, and opens setup mode. It does not clear HomeKit pairing.
  • Clear HomeKit pairing: use the admin page button, then remove the accessory in Apple Home too.
  • Restart: press EN. This is the ESP32 hardware reset button.
  • Factory reset: while the ESP32 is running, hold BOOT / GPIO0 for about 8 seconds. This clears bridge configuration, HomeKit pairing data, and the HomeKit device ID, then restarts into setup mode.

Holding GPIO0 / BOOT while the ESP32 starts still forces setup mode by clearing bridge configuration. On some dev boards, holding BOOT before reset enters the bootloader; if that happens, release BOOT and reset again.

Status LED:

  • setup mode: fast blink
  • after Wi-Fi connects successfully: 10 slow blinks, then off
  • normal running, paired with HomeKit, no current error: steady dim light around 1% brightness
  • Wi-Fi disconnected or Tuya plug not responding: dim SOS blink pattern

The default status LED pin is GPIO2, which matches many ESP32 Dev Module boards. If your board uses another LED pin, change STATUS_LED_PIN in the sketch. If the built-in LED is wired differently, adjust STATUS_LED_ON.

The HomeSpan sketch no longer requires esp32/homespan_tuya_outlet/secrets.h. Secrets are stored in ESP32 flash memory through the setup wizard and must still never be committed or shared.

HomeKit Pairing Code

The HomeKit pairing code is the 8-digit code Apple Home asks for when adding the accessory. It is not the Wi-Fi password and it is not the temporary setup AP password.

The setup/admin page has an optional HomeKit pairing code field:

  • enter your own 8-digit code before pairing and write it down
  • type it without hyphens, for example 11223344
  • Apple Home displays it with hyphens, for example 112-23-344
  • if left blank and never changed, HomeSpan uses its default code 466-37-726
  • if forgotten, enter a new code in the admin page and save/restart

HomeSpan stores a hashed pairing code internally. The real code cannot be read back from the ESP32 later.

Equivalent arduino-cli compile check:

arduino-cli compile --fqbn esp32:esp32:esp32:PartitionScheme=no_ota esp32/homespan_tuya_outlet

Set HomeKit Pairing Code from Serial

For security, do not hardcode the HomeKit pairing code in the sketch.

As an alternative to the web field, open Serial Monitor at 115200 and use the HomeSpan CLI command:

S 11223344

Rules:

  • the code must be exactly 8 digits
  • type it without hyphens in Serial Monitor
  • write it down before pairing
  • use your own code, not 11223344

When Apple Home asks for the setup code, enter it in the usual HomeKit format. For example:

112-23-344

for the Serial command S 11223344.

HomeKit Type and Re-Pairing

The setup/admin page can expose the same Tuya relay as a HomeKit Outlet, Light, or generic Switch.

Use:

  • Outlet for a physical smart plug
  • Light only when the plug controls a lamp
  • Switch for a generic on/off device

If you change HomeKit type or the accessory appears stale in Apple Home, remove the accessory in Apple Home, click Clear HomeKit pairing in the ESP32 admin page, restart, and add it again with the pairing code.

How It Maps to HomeKit

The HomeSpan sketch exposes:

  • HomeKit service: configured as Outlet, Light, or Switch
  • HomeKit On: Tuya relay DPS 1
  • HomeKit OutletInUse: same value as relay state when type is Outlet

OutletInUse is currently not real power detection. It only means the relay is on.

The sketch polls local Tuya status at the configured interval, default 30 seconds, so HomeKit can notice changes made from Smart Life or the physical button.

Stability Notes

For long-term use:

  • reserve a fixed LAN IP for the plug
  • reserve a fixed LAN IP for the ESP32
  • keep the ESP32 close enough to the Wi-Fi access point
  • use a stable USB power supply
  • test for several days before relying on it

The biggest unknown is Tuya firmware behavior. A future plug firmware update could change local protocol behavior.

Troubleshooting

Problem Possible cause Fix
Device found but connection test fails Wrong local key Verify local_key with TinyTuya or Tuya IoT Platform
No Tuya device found Device on another VLAN/subnet Put ESP32 and plug on the same LAN, or enter the IP manually
Port is open but test still fails Wrong protocol version or local key Keep protocol 3.4 for the verified plug and re-check credentials
Relay DPS not found Plug uses a different datapoint Use Scan DPS and choose the correct boolean DPS
HomeKit state updates slowly Polling interval is high Lower polling interval if your network and plug tolerate it
Admin page is unreachable ESP32 IP changed Check Serial Monitor or reserve the ESP32 IP in your router

TinyTuya finds the device but status fails

Check:

  • LOCAL_KEY
  • DEVICE_VERSION
  • plug IP address
  • same LAN / VLAN
  • Smart Life app is not holding a conflicting local session

HomeKit controls the ESP32 but the plug does not switch

Go back to the ESP32 local POC and verify status/on/off over Serial Monitor.

If the POC works, restart the HomeSpan sketch into setup mode by holding GPIO0 / BOOT while the sketch starts. On some dev boards, pressing BOOT too early enters the bootloader. Re-enter the Tuya IP, device ID, local key, protocol version, and relay DPS, then use Test Tuya connection.

ESP32 always starts setup mode

Check Serial Monitor. The sketch prints the setup reason, such as missing config, invalid saved local key, or repeated Wi-Fi connection failure.

HomeKit shows stale state

The sketch polls at the configured interval. Wait for one poll cycle.

If state never updates, check Serial Monitor for Tuya status/decrypt errors.

Pairing fails

If the ESP32 was paired before, clear HomeSpan pairing data using the HomeSpan Serial CLI, then pair again.

References

Contact

For questions, bug reports, or compatible-device reports, open a GitHub issue:

github.com/Lisejnik/tuya-esp32-homekit-bridge/issues

When opening an issue, include:

  • device model
  • Tuya protocol version
  • relay datapoint if known
  • ESP32 board type
  • sanitized Serial Monitor logs

Do not include local_key, Wi-Fi passwords, Tuya Access Secret, generated curl commands, or unredacted API Explorer responses.

Publishing Your Fork

Before pushing to GitHub, verify that local secrets are ignored:

git status --ignored --short

These files must not appear as tracked files:

.env
tinytuya.json
devices.json
tuya-raw.json
snapshot.json
esp32/**/secrets.h

If you accidentally committed a secret, remove it from git history and rotate the affected key.

Status

Working prototype:

  • local TinyTuya control verified
  • ESP32 Tuya 3.4 local POC verified
  • HomeSpan HomeKit Outlet verified

Still experimental:

  • broader Tuya device support
  • automatic datapoint discovery
  • robust recovery for every network edge case

About

Local ESP32 HomeKit bridge for Tuya Smart Life plugs using HomeSpan

Topics

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages