Skip to content
 
 

Repository files navigation

Eufy Clean — Home Assistant Integration

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.

hacs_badge GitHub release (latest by date) GitHub commit activity GitHub Maintainer Validate with hassfest HACS Validation

Help others find this integration! If it's working well for you, please star this repository.

GitHub stars GitHub forks


FAQ

  • 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.


Features

Live Floor Map Camera

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.

Live floor map showing room colours, cleaning trail, and dock icon

  • 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.

Vacuum Control

  • 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

Cleaning Parameters

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

Dock Tasks

Action buttons for: Wash mop, Dry mop, Stop dry mop, Empty dust bin

Dock Configuration

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

Error Notifications

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.

Sensors

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.

Accessory Reset Buttons

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.

Segment Change Detection

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.

Matter Hub Support

Room segments with guaranteed unique names (duplicates auto-suffixed, e.g. Kitchen (2)). Mop Intensity uses Matter-compatible option names (Quiet, Automatic, Max).


Supported Devices

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)

Installation

Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.

  1. Click the button above → Open LinkAdd in HACS
  2. Click Download (bottom right) → Download on the version prompt
  3. Restart Home Assistant
  4. Add the integration:

Open your Home Assistant instance and start setting up a new integration.

  1. 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.


Options (gear icon)

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.


Usage

Optional: Local Tuya transport (push, no 30 s polling)

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:

  1. 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.
  2. Go to Settings → Devices & Services → Eufy Robovac MQTTConfigure.
  3. 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).
  4. 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.

Optional: Manual room name overrides

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:

  1. Settings → Devices & Services → Eufy Robovac MQTTConfigure.
  2. In the Rooms field for your vacuum, enter one room per line:
    1: Lounge
    2: Kitchen
    3: Playroom
    
  3. Save. The Clean Room select entity reappears with your names as the options. Selecting one fires room_clean with 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.

Cleaning Scenes

action: vacuum.send_command
data:
  command: scene_clean
  params:
    scene_id: 5
target:
  entity_id: vacuum.eufy_omni_c28

Default scenes are typically 1–3; custom scenes start at 4+. Find IDs in the Scene/Task select entity.

Room Cleaning

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"

Multi-Room Custom Settings

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"

Zone Cleaning

Clean one or more free-form rectangles instead of whole rooms. Each zone is given as normalized coordinates [x0, y0, x1, y1] — fractions (01) 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: 1

map_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.

Drawing zones — bundled card

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_speed

Draw 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).

Map and Room IDs

  • Active Map sensorsensor.<device>_active_map shows the current map ID (needed for service calls)
  • Room IDs — available in the vacuum entity's rooms / segments state 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.


Known Limitations

  • 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.

Development

Local Testing

A docker-compose.yml is included for local development:

docker compose up

Starts a local HA instance at http://localhost:8123 with the component mounted from custom_components/robovac_mqtt/.

Running Tests

pip install -r requirements_test.txt
pytest
pytest tests/test_parser.py -v

Lint

pre-commit run --all-files
mypy custom_components/robovac_mqtt/

Support


Credits & Attribution

  • 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

Codeowners


License

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.


About

Eufy Clean Home Assistant Custom Component

Topics

Resources

Stars

202 stars

Watchers

11 watching

Forks

Releases

Contributors

Languages