Hello everyone! First of all, I’m not sure whether other similar components already exist, but here is my own.
Previous context
While watching this video, I discovered a very interesting Matter feature called bindings: they basically allow smart home devices to communicate directly with each other without a central hub.
I found this pretty interesting, especially for presence-based automations that control critical lights as a fallback for Home Assistant.
My case
One of my critical lights is a Tapo bulb in the bathroom. The manual switch is quite far from the door and tedious to reach, so if Home Assistant fails, manual control isn’t very comfortable. I use an ESP32-C3 with an LD2410C to turn it on based on presence.
So I thought: why not create a custom component to turn the light on and off directly from the ESP32, as a fallback for Home Assistant? And here it is: esp-tapo.
esp-tapo
It’s a custom component that lets the ESP control Tapo devices over their local API (KLAP v2). It currently supports:
- Lights (RGB/CCT bulbs like the L530) as an ESPHome
lightplatform: on/off, brightness, RGB color and color temperature (2500–6500 K). - Plugs/switches (P100/P110/P115…) as an ESPHome
switchplatform: on/off.
Example: turn on an L530 using an LD2410C if Home Assistant is down
substitutions:
device_name: "l530-motion"
friendly_name: "L530 Motion Sensor"
esphome:
name: ${device_name}
friendly_name: ${friendly_name}
esp32:
board: esp32-c3-devkitm-1
framework:
type: esp-idf
logger:
api:
encryption:
key: !secret api_key
ota:
- platform: esphome
password: !secret ota_password
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "${device_name} fallback"
password: !secret ap_password
captive_portal:
# ---------------------------------------------------------------------
# External `tapo` component (this repository)
# ---------------------------------------------------------------------
external_components:
- source: github://Alejandro12120/esp-tapo
components: [tapo]
# Tapo hub: ONE hub = ONE device (IP + app credentials).
tapo:
id: l530_hub
host: !secret tapo_l530_host
username: !secret tapo_username
password: !secret tapo_password
update_interval: 30s # poll get_device_info to mirror the real device state
# ---------------------------------------------------------------------
# mmWave LD2410 radar (UART)
# ---------------------------------------------------------------------
uart:
id: ld2410_uart
tx_pin: GPIO5
rx_pin: GPIO4
baud_rate: 115200
parity: NONE
stop_bits: 1
ld2410:
id: ld2410_radar
uart_id: ld2410_uart
binary_sensor:
- platform: ld2410
ld2410_id: ld2410_radar
has_target:
name: "Presence"
on_press:
# Fallback: only turn the bulb on if NO API client is connected
# (e.g. Home Assistant down or unreachable).
- if:
condition:
lambda: 'return !api::global_api_server->is_connected();'
then:
- light.turn_on:
id: tapo_light
brightness: 100%
on_release:
# Symmetric off: only when there is no API client either.
- if:
condition:
lambda: 'return !api::global_api_server->is_connected();'
then:
- delay: 30s
- light.turn_off: tapo_light
# ---------------------------------------------------------------------
# Light: Tapo L530 bulb (on/off + brightness + RGB + color temperature)
# ---------------------------------------------------------------------
light:
- platform: tapo
id: tapo_light
name: "L530 Bulb"
tapo_id: l530_hub
# Supported modes: RGB (hue/saturation) and COLOR_TEMPERATURE (2500-6500 K).
# Brightness/color control from HA or automations is translated to
# set_device_info automatically.
# internal: true hides the entity from the API client (Home Assistant) but
# it still works in ESPHome automations/lambdas. Remove this line to also
# expose it to HA.
internal: true
# restore_mode controls the state written on ESP boot.
# RESTORE_DEFAULT_OFF: turns the bulb off when the ESP powers on.
# ALWAYS_ON / RESTORE_DEFAULT_ON: tries to keep the bulb on.
restore_mode: RESTORE_DEFAULT_OFF
Thanks
- python-kasa — reference implementation of the KLAP v2 protocol (handshake, encryption, session handling).
- omegahiro/tapo-esp32 — ESP32 implementation (Arduino), tested against real devices, the basis for the crypto port.
- mihai-dinculescu/tapo — Rust client that documents the KLAP request flow and device commands.
- TP-Link community — reports on local API behavior across firmware versions and the “Third-Party Compatibility” requirement.
- ESPHome — the platform this component is built on (docs, external component system, light/switch APIs).