Full-featured Home Assistant custom component for Eufy robot vacuums. Controls cleaning scenes, individual rooms, dock station, and streams a live floor map — all over MQTT with no cloud polling.
⭐ Help others find this integration! If it's working well for you, please star this repository.
- Requires an MQTT-enabled Eufy vacuum (e.g. RoboVac X10 Pro Omni, C28 Omni, X9 Pro, L70, G50, and others — see supported models below)
- Tested on X10 Pro Omni and C28 Omni; should work on other MQTT-capable models
- Personal project maintained for Home Assistant users. Contributions welcome!
Note
This integration is a fork of martijnpoppen/eufy-clean with significant new features added, including a live floor map camera, error notifications, off-peak charging, and more.
A live floor plan camera entity (camera.<device>_map) streams the robot's map in real time via MQTT. No Tuya developer account or additional credentials needed.
- Room-coloured rendering — rooms colour-coded and labelled with names from the Eufy app
- No-go zones and virtual walls — forbidden zones (red), ban-mop zones (orange), virtual walls (red lines) as overlays
- Live robot position — tracks position in two styles: orange with googly eyes (default) or plain dark dot
- Dock icon — gold house icon marks the dock; robot snaps to it when docked
- Status badges — coloured badge next to robot: lightning bolt (charging, disappears at 100%), water drop (washing), snowflake (drying), dust icon (emptying)
- Cleaning trail — orange line traces the robot's path; clears on new session, survives HA restarts, preserved across brief auto-empty dock visits
- Persistent map — map and room data saved to storage and restored on restart
Map size (256/512/1024/2048 px) and robot marker style configurable via integration options.
- Start / Stop / Pause cleaning operations
- Return to dock command
- Scene Selection — trigger pre-configured cleaning scenes via select entity or service call
- Room-specific cleaning — clean individual rooms or combinations
- Battery monitoring — level and charging status
- Find Robot — locate device by playing a sound
Select entities exposed per device (hidden until supported DPS fields are received):
| Entity | Options |
|---|---|
| Suction Level | Quiet, Standard, Turbo, Max, Boost IQ |
| Cleaning Mode | Vacuum, Mop, Vacuum and mop, Mopping after sweeping |
| Water Level | Low, Medium, High |
| Mop Intensity | Quiet, Automatic, Max (Matter-compatible alias for Water Level) |
| Cleaning Intensity | Normal, Narrow, Quick |
| Voice Language | 17 languages: English, German, French, Spanish, Japanese, and more |
Action buttons for: Wash mop, Dry mop, Stop dry mop, Empty dust bin
| Setting | Options |
|---|---|
| Wash Frequency Mode | ByRoom / ByTime |
| Wash Frequency Value | 15–25 minutes |
| Auto Mop Washing | On / Off |
| Dry Duration | 2h / 3h / 4h |
| Auto Empty | On / Off |
| Auto Empty Mode | Smart, 15 / 30 / 45 / 60 min |
| Off-Peak Charging | On / Off + start/end time |
Sends a notification when the robot reports an error (Wheel Stuck, Sensor Dirty, etc.):
- Desktop notification (toggle) — shows in the HA bell icon, auto-dismissed when the error clears
- Mobile push (dropdown) — pick your phone from discovered Companion App devices or type a service name; leave blank to skip mobile alerts
Note
Error codes are reported by the robot via MQTT. Dock hardware faults (error light on the station) use a separate channel not currently accessible via MQTT and will not trigger notifications.
| Sensor | Notes |
|---|---|
| Battery level | % |
| Charging status | Binary |
| Work status & mode | Retained across docking |
| Cleaning area | Retained until next clean |
| Total cleaning area / time / count | Lifetime stats |
| Dock firmware version | Station FW |
| Error code & description | Real-time |
| Accessory life remaining | Filter, brushes, mop, tray (hours) |
Extended device info: Serial number, MAC address, firmware version in the HA device panel.
Dedicated reset buttons for each consumable (filter, side brush, rolling brush, sensors, mop, cleaning tray).
Note
The Eufy App tracks two types: "Maintenance" (app-calculated, not via MQTT) and "Replacement" (actual firmware usage). This integration tracks Replacement life only.
When rooms are added, removed, or renamed, the integration raises a Repair issue under Settings → System → Repairs. Useful if you use home-assistant-matter-hub.
Room segments with guaranteed unique names (duplicates auto-suffixed, e.g. Kitchen (2)). Mop Intensity uses Matter-compatible option names (Quiet, Automatic, Max).
| Series | Models |
|---|---|
| X-Series | T2261, T2262, T2266, T2276, T2320, T2351 (X8, X8 Pro, X9 Pro, X10 Pro Omni) |
| C-Series | T1250, T2117, T2118, T2120, T2128, T2130, T2132, T2280, T2292 (C20, C28 Omni) |
| L-Series | T2190, T2267, T2268, T2278 (L60, L70) |
| G-Series | T2210–T2278 (G20, G30, G35, G40, G50) |
| S-Series | T2119, T2080 (RoboVac 11S, S1) |
- Click the button above → Open Link → Add in HACS
- Click Download (bottom right) → Download on the version prompt
- Restart Home Assistant
- Add the integration:
- Enter your Eufy account email and password
Note
This integration requires the Pillow image library for live map rendering. Home Assistant installs it automatically from PyPI when the integration first loads — no manual action needed.
| Setting | Default | Notes |
|---|---|---|
| Map image size | 512 px | 256 / 512 / 1024 / 2048 px |
| Robot marker style | Googly Eyes | Googly Eyes / Dot |
| Desktop notification | Off | HA bell icon on robot errors |
| Mobile notification service | (blank) | Select phone or type mobile_app_name; blank = disabled |
Tip
Changes made via HA may not appear in the Eufy mobile app immediately — navigate away and back in the app to refresh the state.
For devices the Eufy API reports as non-MQTT (served over the Tuya Cloud
path and otherwise polled every 30 s) you can opt-in to a direct LAN socket
on the dock instead. Whether a device uses this path is decided per-device at
runtime from the Eufy API's mqtt flag — not by model name — so open
Configure to see which of your devices are eligible. Updates then arrive
within seconds of the device emitting them and continue to work while the
Eufy / Tuya cloud is unreachable.
How to enable it:
- Find the LAN address of your dock — DHCP reservation, your router's
device list, or a quick
nmap -sn 192.168.1.0/24. The local key is auto-supplied by the Tuya Cloud login, you don't need to extract it. - Go to Settings → Devices & Services → Eufy Robovac MQTT → Configure.
- Enter the host (IP or DNS name) for each cloud-discovered vacuum and pick the Tuya protocol version (3.3 fits most vacuums; try 3.4/3.5 if your model is newer and 3.3 fails to connect).
- Save. The integration reloads and switches that device to local push.
If the local socket fails to open (wrong host, firewall, dock offline) the coordinator silently falls back to cloud polling, so the dashboard never goes unavailable just because the LAN address has shifted.
Warning
Security model. The local transport is AES-encrypted with your device's local key — it is not TLS and performs no certificate validation, so it is intended for a trusted LAN only. The local key grants full local control of the dock and is a secret: never share it, and never paste integration debug logs that might contain it into public issues.
Note
Live map and live X/Y position are not available over either Tuya
transport — Eufy delivers them through a separate encrypted P2P channel
(eufy_mega SDK) that no public reverse-engineering has cracked yet.
Everything else — vacuum/mop mode, water level, clean count, spot/zone/room
commands, station status, consumables, lifetime stats, all sensors —
works fine over both transports.
The room list (and the select.robovac_clean_room entity that targets it)
normally comes from the same encrypted P2P channel as the map, so on Tuya
transports the dropdown is empty. If you'd like to drive room cleaning from
HA anyway, you can supply your own room_id: name mapping:
- Settings → Devices & Services → Eufy Robovac MQTT → Configure.
- In the Rooms field for your vacuum, enter one room per line:
1: Lounge 2: Kitchen 3: Playroom - Save. The
Clean Roomselect entity reappears with your names as the options. Selecting one firesroom_cleanwith the matching ID.
Finding the IDs is iterative until someone wires up MQTT-side discovery for
Tuya devices: try 1, 2, 3, ... and watch which room the vacuum starts on
each, then adjust the mapping. The IDs are stable across sessions (they
change only when the dock re-maps the floor plan).
Overrides also work on the MQTT transport — useful if the auto-discovered names from the device aren't friendly enough for your dashboard.
action: vacuum.send_command
data:
command: scene_clean
params:
scene_id: 5
target:
entity_id: vacuum.eufy_omni_c28Default scenes are typically 1–3; custom scenes start at 4+. Find IDs in the Scene/Task select entity.
action: vacuum.send_command
target:
entity_id: vacuum.eufy_omni_c28
data:
command: room_clean
params:
map_id: 4
room_ids: [3, 4]
fan_speed: "Turbo"action: vacuum.send_command
target:
entity_id: vacuum.eufy_omni_c28
data:
command: room_clean
params:
map_id: 4
rooms:
- id: 3 # Kitchen
fan_speed: "Turbo"
clean_mode: "vacuum_mop"
water_level: "High"
- id: 4 # Hallway
fan_speed: "Quiet"
clean_mode: "vacuum"Clean one or more free-form rectangles instead of whole rooms. Each zone is given as
normalized coordinates [x0, y0, x1, y1] — fractions (0–1) of the rendered map
image, with (0, 0) at the top-left and (1, 1) at the bottom-right of the map
camera image. They are converted to the robot's world frame against the current map, so the
map must have been received at least once (run a clean or dock first).
action: vacuum.send_command
target:
entity_id: vacuum.eufy_omni_c28
data:
command: zone_clean
params:
zones:
- [0.05, 0.70, 0.35, 0.95] # bottom-left corner of the map
- [0.40, 0.40, 0.60, 0.60] # a box in the centre
clean_times: 1map_id is taken from the current map automatically; pass it explicitly to override. The
robot uses its current cleaning mode (vacuum / mop) and fan settings for the zone run.
Hand-writing normalized coordinates is fiddly, so the integration bundles a small
Lovelace card that lets you drag the boxes on the live map instead. It ships inside the
integration and is auto-registered on setup — there's no www/ copy and no Lovelace
Resources entry to add. Just drop it on a dashboard:
type: custom:zone-clean-card
vacuum: vacuum.eufy_omni_c28
camera: camera.eufy_omni_c28_map
# title: Zone Clean # optional
# selects: # optional — defaults to auto-discovering the vacuum's selects
# - select.eufy_omni_c28_cleaning_mode
# - select.eufy_omni_c28_clean_speedDraw up to 10 boxes, set suction/mode via the surfaced select entities, and hit Clean
— it fires the zone_clean send_command shown above. The map only renders after the robot
has cleaned once (or you've edited the map in the app).
- Active Map sensor —
sensor.<device>_active_mapshows the current map ID (needed for service calls) - Room IDs — available in the vacuum entity's
rooms/segmentsstate attributes; inspect via Developer Tools → States
Tip
"Unable to identify position" usually means the map_id doesn't match the vacuum's current map. Check the Active Map sensor.
- Robot position not shown on first install — appears after the first cleaning run or docking event. No MQTT command exists to request current position while idle.
- Dock hardware faults — error light on the station itself is not exposed via MQTT and will not trigger notifications.
- Map switching — not supported; switch maps in the Eufy app.
A docker-compose.yml is included for local development:
docker compose upStarts a local HA instance at http://localhost:8123 with the component mounted from custom_components/robovac_mqtt/.
pip install -r requirements_test.txt
pytest
pytest tests/test_parser.py -vpre-commit run --all-files
mypy custom_components/robovac_mqtt/- Issues: GitHub Issues
- Original Integration: @martijnpoppen — created the foundation
- Maintainer: @jeppesens — ongoing maintenance and improvements
- Contributor: @smcneece — live map camera, error notifications, off-peak charging, and additional sensors
- @jeppesens — active maintainer
- @m11tch — codeowner
MIT License. See LICENSE. This integration is not affiliated with or endorsed by Eufy / Anker Innovations. Use at your own risk; no warranty is provided.