Sharing my ESPHome configurations for the Eufy RoboVac 30C and Tzumi Ionvac SmartClean 2000, which are based on the Tuya wifi module. There may be room for improvement. Guessing several generic vacuums will have similar configuration files.
Eufy Robovac 30C
ESP8266EX
TYWE1S Module
esphome:
name: esphome-eufy-robovac-30c
friendly_name: ESPHome RoboVac 30C
min_version: 2025.11.0
name_add_mac_suffix: false
on_boot:
priority: 800
then:
- delay: 5s
- logger.log: "MCU Waiting for heartbeat..."
esp8266:
board: esp01_1m
# Enable Home Assistant API
api:
# Allow Over-The-Air updates
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: Eufy-Robovac Fallback Hotspot
password: Redacted
captive_portal:
web_server:
# Tuya supports sending time to the application processor and the vacuum does use it (not sure for why though) so let's configure a time reference
time:
- platform: homeassistant
id: time_source
# UART will be used to talk to the application processor, so we need to disable any logging over it
logger:
baud_rate: 0
# UART to talk to the application processor
uart:
id: vacuum_uart
rx_pin: GPIO13
tx_pin: GPIO15
baud_rate: 115200
debug: null
# the TuyaMCU object
tuya:
id: vacuum_tuya
uart_id: vacuum_uart
time_id: time_source
sensor:
- platform: tuya
name: Battery
sensor_datapoint: 104
unit_of_measurement: "%"
icon: mdi:battery
device_class: battery
state_class: measurement
entity_category: diagnostic
button:
- platform: template
name: Start cleaning
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_enum_datapoint_value(5, 0);
- platform: template
name: Start spot cleaning
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_enum_datapoint_value(5, 2);
- platform: template
name: Pause
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_boolean_datapoint_value(2, false);
- platform: template
name: Resume
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_boolean_datapoint_value(2, true);
- platform: template
name: Return to dock
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_boolean_datapoint_value(101, true);
- platform: template
name: Nav Forward
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_enum_datapoint_value(3, 0);
- platform: template
name: Nav Back
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_enum_datapoint_value(3, 1);
- platform: template
name: Nav Right
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_enum_datapoint_value(3, 2);
- platform: template
name: Nav Left
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_enum_datapoint_value(3, 3);
select:
- platform: tuya
id: nav_dp
enum_datapoint: 3
options:
0: "Forward"
1: "Back"
2: "Right"
3: "Left"
- platform: tuya
name: "Cleaning Mode"
enum_datapoint: 5
options:
0: Auto
1: Edge
2: Spot
3: Small Room
entity_category: config
- platform: tuya
id: status_dp
enum_datapoint: 15
options:
0: Running
1: Idle
2: Sleeping
3: Charging
4: Charged
5: Docking
on_value: &publish_state_sensor
then:
- text_sensor.template.publish:
id: state_sensor
state: !lambda 'return (id(pause_dp).state == "Paused" && id(status_dp).state == "Idle") ? "Paused" : id(status_dp).state;'
- platform: tuya
name: Fan speed
enum_datapoint: 102
entity_category: config
options:
0: Standard
1: BoostIQ
2: Max
- platform: tuya
id: pause_dp
enum_datapoint: 2
options:
0: Paused
1: Resume
on_value: *publish_state_sensor
text_sensor:
- platform: template
name: State
entity_category: diagnostic
id: state_sensor
- platform: tuya
name: "Error Code"
sensor_datapoint: 106
entity_category: diagnostic
icon: mdi:alert-circle
switch:
- platform: tuya
name: Locate
icon: mdi:map-marker
entity_category: config
switch_datapoint: 103
- platform: tuya
name: Power
switch_datapoint: 2
icon: mdi:power
Tzumi Ionvac SmartClean 2000
RTL8710BN
WR3 Module
I had to use the framework 1.9.2 to overcome a LibreTiny bug in the RX communication from the MCU. It may be fixed in more recent versions of ESPHome.
esphome:
name: esphome-smartclean-2000
friendly_name: ESPHome SmartClean 2000
rtl87xx:
board: wr3
framework:
version: 1.9.2
# Enable Home Assistant API
api:
# Allow Over-The-Air updates
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: Esphome-Smartclean Fallback
password: "Redacted"
captive_portal:
web_server:
# Tuya supports sending time to the application processor and the vacuum does use it (not sure for why though) so let's configure a time reference
time:
- platform: homeassistant
id: time_source
# UART will be used to talk to the application processor, so we need to disable any logging over it
logger:
baud_rate: 0
# UART to talk to the application processor
uart:
id: vacuum_uart
tx_pin: PA23
rx_pin: PA18
baud_rate: 115200
debug: null
# the TuyaMCU object
tuya:
id: vacuum_tuya
uart_id: vacuum_uart
time_id: time_source
sensor:
- platform: tuya
name: Battery
sensor_datapoint: 6
unit_of_measurement: "%"
icon: mdi:battery
device_class: battery
state_class: measurement
entity_category: diagnostic
- platform: tuya
name: Clean Time Last
sensor_datapoint: 17
unit_of_measurement: minutes
icon: mdi:timer-sync
device_class: duration
state_class: total_increasing
entity_category: diagnostic
- platform: tuya
name: Clean Time Total
sensor_datapoint: 108
unit_of_measurement: minutes
icon: mdi:timer-sync
device_class: duration
state_class: total_increasing
entity_category: diagnostic
- platform: tuya
name: Use Side Brush
sensor_datapoint: 7
unit_of_measurement: "%"
icon: mdi:broom
device_class: battery
state_class: measurement
entity_category: diagnostic
- platform: tuya
name: Use Main Brush
sensor_datapoint: 8
unit_of_measurement: "%"
icon: mdi:broom
device_class: battery
state_class: measurement
entity_category: diagnostic
- platform: tuya
name: Use Filter
sensor_datapoint: 9
unit_of_measurement: "%"
icon: mdi:air-filter
device_class: battery
state_class: measurement
entity_category: diagnostic
button:
# Not working
- platform: template
name: Reset side brush
icon: mdi:broom
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_boolean_datapoint_value(10, true);
# Not working
- platform: template
name: Reset main brush
icon: mdi:broom
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_boolean_datapoint_value(11, true);
# Not working
- platform: template
name: Reset filter
icon: mdi:air-filter
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_boolean_datapoint_value(12, true);
- platform: template
name: Start cleaning
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_enum_datapoint_value(3, 1);
- platform: template
name: Start spot cleaning
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_enum_datapoint_value(3, 3);
- platform: template
name: Pause
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_boolean_datapoint_value(2, 0);
- platform: template
name: Resume
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_boolean_datapoint_value(2, 1);
- platform: template
name: Return to dock
entity_category: config
on_press:
- lambda: id(vacuum_tuya).force_set_boolean_datapoint_value(3, 5);
select:
- platform: tuya
name: "Mode"
enum_datapoint: 3
options:
0: Standby
1: Auto
2: Edge
3: Spot
4: PartialBow
5: Dock
entity_category: config
- platform: tuya
name: "Direction"
enum_datapoint: 4
options:
0: "Forward"
1: "180"
2: "Left"
3: "Right"
4: "Stop"
- platform: tuya
id: status_dp
enum_datapoint: 5
options:
0: Idle
1: Charging
2: Running
3: Docking
4: Fault
9: Docked
on_value: &publish_state_sensor
then:
- text_sensor.template.publish:
id: state_sensor
state: !lambda 'return (id(pause_dp).state == "Paused" && id(status_dp).state == "Idle") ? "Paused" : id(status_dp).state;'
- platform: tuya
id: pause_dp
enum_datapoint: 2
options:
1: Paused
2: Resume
on_value: *publish_state_sensor
- platform: tuya
name: Fan speed
enum_datapoint: 14
entity_category: config
options:
1: Normal
2: Strong
text_sensor:
- platform: template
name: State
entity_category: diagnostic
id: state_sensor
switch:
- platform: tuya
name: Power
switch_datapoint: 2
icon: mdi:power
- platform: tuya
name: Locate
icon: mdi:map-marker
entity_category: config
switch_datapoint: 13
Thanks to Rjevski for his config esphome-eufy-robovac-g10-hybrid.