# Dreame Vacuum — Home Assistant Integration The **Dreame Vacuum** integration (`dreame_vacuum`, v1.0.9) is a complete app replacement for Dreame robot vacuums within Home Assistant. It reverse-engineers the official Dreame/Mijia App protocol to expose virtually all device settings, states, and map features. The integration supports both cloud-connected (Mi account) and local-only configurations, automatically discovers supported devices, and exposes a rich set of entities — vacuum, sensor, switch, select, number, button, binary sensor, and camera — that mirror every capability available in the official app. Core functionality includes: fully decoded live and multi-floor map rendering with P-frame partial update support (3-second refresh), per-room customized cleaning parameters, zone/segment/spot cleaning services, map editing (merge, split, rename rooms, set restricted zones), do-not-disturb scheduling, consumable life tracking and reset, persistent Home Assistant notifications, and an event system for automations. The integration communicates locally via the MiIO protocol and via the Xiaomi cloud API, using MQTT for real-time push updates. Requirements: `pillow`, `numpy`, `pybase64`, `requests`, `pycryptodome`, `python-miio`, `mini-racer`, `paho-mqtt`. --- ## Configuration ### Config Flow — Mi Account (With Map) Registers the integration with cloud credentials enabling full map support and room entities. ```python # Handled automatically via UI config flow. # Settings stored in config entry: { "name": "My Vacuum", "host": "192.168.1.100", # Auto-discovered via cloud "token": "<32-char-hex-token>", # Auto-retrieved from cloud "username": "user@example.com", # Mi/Dreame account username "password": "secret", "country": "de", # de | cn | us | ru | tw | sg | in | i2 "account_type": "mi", # "mi" = with map, "local" = without map "mac": "aa:bb:cc:dd:ee:ff", "did": 123456789, "auth_key": None # Cached auth key (populated after first login) } # Options (editable after setup): { "notify": ["cleanup_completed", "consumable", "information", "warning", "error"], "color_scheme": "Dreame Light", # Dreame Light | Dreame Dark | Mijia Light | Mijia Dark | Grayscale "icon_set": "Dreame", # Dreame | Dreame Old | Mijia | Material "hidden_map_objects": [], # e.g. ["path", "no_go", "robot"] "prefer_cloud": False # Force cloud polling even when local is available } ``` ### Config Flow — Local Only (Without Map) ```python # Minimum required fields for local-only setup (no map feature): { "host": "192.168.1.100", "token": "<32-char-hex-token>" } ``` --- ## Vacuum Entity ### Standard Vacuum Actions The core `vacuum.*` entity supports start, pause, stop, return home, locate, fan speed, and send_command. ```yaml # Start cleaning service: vacuum.start target: entity_id: vacuum.my_vacuum # Pause cleaning service: vacuum.pause target: entity_id: vacuum.my_vacuum # Return to dock service: vacuum.return_to_base target: entity_id: vacuum.my_vacuum # Set fan speed (maps to suction level) service: vacuum.set_fan_speed data: fan_speed: "Turbo" # Silent | Standard | Strong | Turbo target: entity_id: vacuum.my_vacuum # Locate the robot service: vacuum.locate target: entity_id: vacuum.my_vacuum ``` ### Vacuum Entity Attributes ```yaml # Key attributes exposed on vacuum.my_vacuum: state: cleaning # cleaning | docked | idle | paused | returning | error status: "Sweeping" cleaning_mode: "Sweeping and Mopping" # Sweeping | Mopping | Sweeping and Mopping suction_level: "Standard" water_tank: true mop_pad: false battery_level: 85 cleaned_area: 42 # m² cleaning_time: 28 # minutes current_segment: 3 # room id currently being cleaned (map feature) customized_cleaning: true cleaning_sequence: [3, 1, 2, 5, 4] rooms: 14: # map_id - id: 1 name: "Living Room" suction_level: 1 water_volume: 2 cleaning_times: 1 order: 2 - id: 2 name: "Kitchen" suction_level: 3 water_volume: 3 cleaning_times: 2 order: 1 selected_map: 14 active_segments: [3, 5] active_areas: [[819, -263, 4424, 2105]] active_points: [[819, -263]] ``` --- ## Cleaning Services ### `dreame_vacuum.vacuum_clean_segment` — Room Cleaning Starts cleaning of one or more rooms by segment ID with optional per-room parameters. ```yaml # Clean rooms 3 and 5 — each room twice, different suction levels service: dreame_vacuum.vacuum_clean_segment data: segments: - 3 - 5 repeats: - 2 # room 3 cleaned 2 times - 1 # room 5 cleaned 1 time suction_level: - "high" # room 3: high suction (0=quiet,1=standard,2=high,3=turbo or name) - "quiet" # room 5: quiet suction water_volume: 2 # applies to all rooms; or list per room target: entity_id: vacuum.my_vacuum # Clean a single room service: dreame_vacuum.vacuum_clean_segment data: segments: 3 target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_clean_zone` — Zone Cleaning Cleans rectangular zones defined by map coordinates `[x1, y1, x2, y2]`. ```yaml # Clean two zones with different repeat counts service: dreame_vacuum.vacuum_clean_zone data: zone: - [819, -263, 4424, 2105] # zone 1 - [2001, -3050, 542, 515] # zone 2 repeats: - 2 # zone 1 twice - 3 # zone 2 three times target: entity_id: vacuum.my_vacuum # Single zone, one pass service: dreame_vacuum.vacuum_clean_zone data: zone: [819, -263, 4424, 2105] target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_clean_spot` — Spot Cleaning Cleans around specific map coordinates. ```yaml # Clean two spots with different repeat counts service: dreame_vacuum.vacuum_clean_spot data: points: - [819, -263] - [2001, -3050] repeats: - 2 - 3 suction_level: "turbo" target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_set_dnd` — Do Not Disturb Sets or disables the do-not-disturb window. ```yaml # Enable DND from 22:00 to 08:00 service: dreame_vacuum.vacuum_set_dnd data: dnd_enabled: true dnd_start: "22:00" dnd_end: "08:00" target: entity_id: vacuum.my_vacuum # Disable DND service: dreame_vacuum.vacuum_set_dnd data: dnd_enabled: false target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_set_custom_cleaning` — Per-Room Cleaning Settings Batch-sets suction, water, and repeat counts for all rooms on the current map. ```yaml # Rooms 1 and 5: different suction/water/repeat settings service: dreame_vacuum.vacuum_set_custom_cleaning data: segment_id: [1, 5] suction_level: [0, 3] # 0=quiet, 1=standard, 2=strong, 3=turbo water_volume: [1, 2] # 1=low, 2=medium, 3=high repeats: [2, 1] target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_set_cleaning_sequence` — Room Cleaning Order Sets the order in which rooms are cleaned. All room IDs on the map must be listed. ```yaml # Clean rooms in order: 3 → 5 → 4 → 2 → 1 service: dreame_vacuum.vacuum_set_cleaning_sequence data: cleaning_sequence: [3, 5, 4, 2, 1] target: entity_id: vacuum.my_vacuum # Disable custom sequence (resets to default order) service: dreame_vacuum.vacuum_set_cleaning_sequence data: cleaning_sequence: [] target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_reset_consumable` — Reset Consumable Life Resets the remaining-life counter for a consumable after replacement. ```yaml # Reset main brush life service: dreame_vacuum.vacuum_reset_consumable data: consumable: "main_brush" # Options: main_brush | side_brush | filter | sensor | mop_pad | silver_ion | detergent target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_remote_control_move_step` — Remote Control Sends a remote movement command (designed for custom Lovelace cards). ```yaml service: dreame_vacuum.vacuum_remote_control_move_step data: rotation: 64 # -128 to 128 velocity: 100 # -300 to 100 target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_install_voice_pack` — Install Voice Pack Installs an official voice pack from a URL. ```yaml service: dreame_vacuum.vacuum_install_voice_pack data: lang_id: "DE" url: "http://awsde0.fds.api.xiaomi.com/dreame-product/dreame.vacuum.p2009/voices/package/deyu.tar.gz" md5: "d25986c1f608c0897475707e77d856f9" size: 4067845 target: entity_id: vacuum.my_vacuum ``` --- ## Map Services ### `dreame_vacuum.vacuum_select_map` — Switch Active Map ```yaml service: dreame_vacuum.vacuum_select_map data: map_id: 27 # Obtain from camera entity attributes target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_delete_map` — Delete a Saved Map ```yaml service: dreame_vacuum.vacuum_delete_map data: map_id: 48 target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_rename_map` — Rename a Map ```yaml service: dreame_vacuum.vacuum_rename_map data: map_id: 14 map_name: "Second Floor" target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_set_restricted_zone` — Virtual Walls and No-Go Zones Sets all virtual walls, no-go zones, and no-mop zones at once (full replacement). ```yaml service: dreame_vacuum.vacuum_set_restricted_zone data: walls: - [819, -263, 4424, 2105] zones: - [819, -263, 4424, 2105] - [-2001, -3050, -542, 515] no_mops: [] target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_merge_segments` — Merge Two Rooms ```yaml # Merge room 4 into room 6 (room 6 is deleted) service: dreame_vacuum.vacuum_merge_segments data: map_id: 63 segments: [4, 6] target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_split_segments` — Split a Room ```yaml # Split room 4 along the given line service: dreame_vacuum.vacuum_split_segments data: map_id: 63 segment: 4 line: [819, -263, 4424, 2105] target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_rename_segment` — Rename a Room ```yaml service: dreame_vacuum.vacuum_rename_segment data: segment_id: 3 segment_name: "Dining Room" target: entity_id: vacuum.my_vacuum ``` ### Temporary Map Management ```yaml # After new map creation — save it service: dreame_vacuum.vacuum_save_temporary_map target: entity_id: vacuum.my_vacuum # Discard the new map service: dreame_vacuum.vacuum_discard_temporary_map target: entity_id: vacuum.my_vacuum # Replace new map with an existing saved map (id 39) service: dreame_vacuum.vacuum_replace_temporary_map data: map_id: 39 target: entity_id: vacuum.my_vacuum ``` ### `dreame_vacuum.vacuum_request_map` — Force Map Upload ```yaml # Trigger device to upload the current map to cloud service: dreame_vacuum.vacuum_request_map target: entity_id: vacuum.my_vacuum ``` --- ## Raw API Command via `vacuum.send_command` Allows sending raw MiIO property/action commands not exposed by the integration. ```yaml # Trigger auto-emptying (siid=15, aiid=1) service: vacuum.send_command data: entity_id: vacuum.my_vacuum command: action params: did: "15.1" siid: 15 aiid: 1 in: [] # Set multiple properties at once (tight mopping ON, carpet boost OFF) service: vacuum.send_command data: entity_id: vacuum.my_vacuum command: set_properties params: - did: "4.29" siid: 4 piid: 29 value: 1 # tight_mopping = on - did: "4.12" siid: 4 piid: 12 value: 0 # carpet_boost = off ``` --- ## Select Navigation Services Input-select-style helpers for cycling through select entity options (useful in Lovelace cards and automations). ```yaml # Advance to next suction level option service: dreame_vacuum.select_select_next data: entity_id: select.my_vacuum_suction_level # Go back to previous option (no wrap-around) service: dreame_vacuum.select_select_previous data: cycle: false entity_id: select.my_vacuum_room_3_suction_level # Jump to first or last option service: dreame_vacuum.select_select_first data: entity_id: select.my_vacuum_cleaning_mode service: dreame_vacuum.select_select_last data: entity_id: select.my_vacuum_cleaning_mode ``` --- ## Entity Reference ### Switch Entities (`switch._*`) | Entity | Description | |---|---| | `resume_cleaning` | Auto-resume after recharge | | `carpet_boost` | Increase suction on carpets | | `carpet_recognition` | Ultrasonic carpet detection | | `obstacle_avoidance` | 3D obstacle avoidance (line-laser models) | | `customized_cleaning` | Per-room settings mode | | `tight_mopping` | Tight mopping pattern | | `dnd` | Do-not-disturb master switch | | `multi_floor_map` | Store multiple floor maps | | `auto_dust_collecting` | Auto-empty after cleaning | | `self_clean` | Auto mop washing | | `auto_drying` | Auto mop drying | | `cleaning_sequence` | Custom room order (dynamic entity) | | `ai_obstacle_detection` | AI obstacle detection | | `carpet_avoidance` | Avoid carpets when mop attached | ### Sensor Entities (`sensor._*`) ```yaml # Automation example: notify when filter needs replacing automation: trigger: platform: numeric_state entity_id: sensor.my_vacuum_filter_left below: 10 action: service: notify.mobile_app data: message: "Vacuum filter below 10% — replace soon!" # Key sensors and their units: # cleaning_time — minutes (current/last job) # cleaned_area — m² (current/last job) # battery_level — % # main_brush_left — % remaining # side_brush_left — % remaining # filter_left — % remaining # sensor_dirty_left — % (line-laser models) # mop_pad_left — % (self-wash base) # error — fault description string # state — sweeping|idle|paused|error|returning|charging|charging_completed|... # total_cleaned_area — m² lifetime # cleaning_count — total cleans # current_room — room name (map feature) ``` ### Select Entities (`select._*`) ```yaml # Global selects: # suction_level — Quiet | Standard | Strong | Turbo # water_volume — Low | Medium | High # mop_pad_humidity — Slightly Dry | Moist | Wet # cleaning_mode — Sweeping | Mopping | Sweeping and Mopping # carpet_sensitivity — Low | Medium | High # map_rotation — 0 | 90 | 180 | 270 # selected_map — map name (multi-floor) # Per-room selects (naming schema: select._room__): # select.my_vacuum_room_3_name — predefined type or custom name # select.my_vacuum_room_3_suction_level — per-room suction # select.my_vacuum_room_3_water_volume — per-room water # select.my_vacuum_room_3_cleaning_times — 1 | 2 | 3 # select.my_vacuum_room_3_order — cleaning sequence position ``` ### Number Entities (`number._*`) ```yaml # volume — speaker volume level # dnd_start_hour — DND window start hour # dnd_start_minute — DND window start minute # dnd_end_hour — DND window end hour # dnd_end_minute — DND window end minute # mop_cleaning_remainder — area before mop wash trigger ``` ### Button Entities (`button._*`) ```yaml # reset_main_brush — reset main brush life # reset_side_brush — reset side brush life # reset_filter — reset filter life # reset_sensor — reset sensor cleaning life # reset_mop_pad — reset mop pad life (self-wash base) # start_auto_empty — trigger auto-empty dock # clear_warning — dismiss device warning # start_fast_mapping — begin fast mapping run # start_mapping — create new map with full clean # start_washing — manually trigger mop washing # start_drying — manually trigger mop drying ``` ### Camera Entities (`camera._*`) ```yaml # map — live map (rendered PNG, updates every ~3 seconds during cleaning) # map_data — Valetudo-compatible JSON map data (disabled by default) # map_1 — saved map at index 1 (current map when multi-floor disabled) # map_2 — saved map at index 2 (multi-floor only) # map_3 — saved map at index 3 (multi-floor only) # Camera entity attributes include: # map_id, map_name, rooms, calibration_points, vacuum_position, charger_position, # walls, no_go_areas, no_mopping_areas, rotation, active_areas, active_points ``` --- ## Events The integration fires Home Assistant events for automations regardless of notification settings. ### `dreame_vacuum_task_status` — Cleaning Started / Completed ```yaml # Automation: send notification when cleaning job completes automation: trigger: platform: event event_type: dreame_vacuum_task_status event_data: completed: true action: service: notify.mobile_app data: message: > Cleaning done! Area: {{ trigger.event.data.cleaned_area }} m², Time: {{ trigger.event.data.cleaning_time }} min. # Event payload fields: # entity_id, cleaning_mode, status, water_tank, mop_pad, completed, # cleaned_area (when completed), cleaning_time (when completed), # active_segments (map feature), active_areas (map feature), active_points (map feature) ``` ### `dreame_vacuum_consumable` — Consumable Depleted ```yaml automation: trigger: platform: event event_type: dreame_vacuum_consumable action: service: notify.mobile_app data: message: "Replace: {{ trigger.event.data.consumable }}" # consumable values: main_brush | side_brush | filter | sensor | mop_pad | silver_ion | detergent ``` ### `dreame_vacuum_error` — Device Error ```yaml automation: trigger: platform: event event_type: dreame_vacuum_error action: service: notify.mobile_app data: message: "Vacuum error {{ trigger.event.data.code }}: {{ trigger.event.data.error }}" ``` ### `dreame_vacuum_warning` — Dismissible Warning ```yaml # Dismissing the HA notification auto-clears the warning on the device automation: trigger: platform: event event_type: dreame_vacuum_warning action: service: notify.persistent_notification data: message: "Warning: {{ trigger.event.data.warning }} (code {{ trigger.event.data.code }})" ``` ### `dreame_vacuum_information` — Informational Events ```yaml # Fired for: dust_collection (not performed due to DnD) | cleaning_paused (low battery) automation: trigger: platform: event event_type: dreame_vacuum_information event_data: information: "cleaning_paused" action: service: notify.mobile_app data: message: "Vacuum paused due to low battery — will resume after charging." ``` ### `dreame_vacuum_2fa_login_` — 2FA Required ```yaml # entity_id, url (2FA login URL to open in browser) automation: trigger: platform: event event_type: dreame_vacuum_2fa_login_ action: service: notify.mobile_app data: message: "2FA required: {{ trigger.event.data.url }}" ``` --- ## Room Entities Lovelace Card Dynamic rooms management card using `config-template-card` and `multiple-entity-row`. ```yaml # Requires: config-template-card, multiple-entity-row (HACS) # Replace "vacuum." with your actual vacuum entity_id type: entities title: Rooms show_header_toggle: false entities: # (Generated dynamically via Jinja2 template — see docs/room_entities.md) # Example for room 3: - type: custom:multiple-entity-row entity: select.my_vacuum_room_3_name show_state: false name: Kitchen entities: - entity: select.my_vacuum_room_3_suction_level name: ' ' tap_action: action: call-service service: dreame_vacuum.select_select_next service_data: entity_id: select.my_vacuum_room_3_suction_level - entity: select.my_vacuum_room_3_water_volume name: ' ' tap_action: action: call-service service: dreame_vacuum.select_select_next service_data: entity_id: select.my_vacuum_room_3_water_volume - entity: select.my_vacuum_room_3_cleaning_times name: ' ' - entity: switch.my_vacuum_customized_cleaning name: Customized Cleaning - entity: switch.my_vacuum_cleaning_sequence name: Cleaning Sequence ``` --- ## Xiaomi Vacuum Map Card Integration Full map-card integration for zone/room/spot cleaning via the UI. ```yaml # Requires: lovelace-xiaomi-vacuum-map-card (HACS) type: custom:xiaomi-vacuum-map-card entity: vacuum.my_vacuum map_source: camera: camera.my_vacuum_map calibration_source: camera: true vacuum_platform: Tasshack/dreame-vacuum # Click "Generate rooms config" in card editor to auto-populate room list ``` --- ## Supported Device Models ```python # Dreame branded (excerpt): DREAME_MODELS = [ "dreame.vacuum.r2228o", # L10s Ultra "dreame.vacuum.r2215o", # L10s Pro "dreame.vacuum.r2205", # D10 Plus "dreame.vacuum.r2235", # X10 Ultra "dreame.vacuum.r2215", # X10 "dreame.vacuum.r2104", # W10 Pro "dreame.vacuum.p2029", # L10 Pro # ... 30+ models total ] # Mijia/Mi branded (excerpt): MIJIA_MODELS = [ "dreame.vacuum.p2041", # 1T "dreame.vacuum.r2209", # X10 (Mijia) "dreame.vacuum.p2114a", # X10+ "dreame.vacuum.p2150a", # Vacuum-Mop 2 Ultra # ... 16+ models total ] ``` --- ## DreameVacuumDevice — Internal Python API The `DreameVacuumDevice` class in `dreame/device.py` is the core device abstraction used by the coordinator. ```python from custom_components.dreame_vacuum.dreame.device import DreameVacuumDevice from custom_components.dreame_vacuum.dreame.types import DreameVacuumProperty # Instantiate device (handled by coordinator in normal HA usage) device = DreameVacuumDevice( name="My Vacuum", host="192.168.1.100", token="abcdef1234567890abcdef1234567890", mac="aa:bb:cc:dd:ee:ff", username="user@example.com", password="secret", country="de", prefer_cloud=False, device_id=123456789, ) # Register a callback for any property change def on_update(): print("Device updated:", device.status.state) device.listen_all(on_update) # Register callback for a specific property device.listen(lambda: print("battery:", device.data.get(DreameVacuumProperty.BATTERY_LEVEL)), DreameVacuumProperty.BATTERY_LEVEL) # Key status properties (via device.status): device.status.state # DreameVacuumState enum device.status.battery_level # int 0-100 device.status.suction_level # DreameVacuumSuctionLevel enum device.status.water_volume # DreameVacuumWaterVolume enum device.status.cleaning_mode # DreameVacuumCleaningMode enum device.status.task_status # DreameVacuumTaskStatus enum device.status.error_code # DreameVacuumErrorCode enum device.status.has_map # bool — map data available device.status.customized_cleaning # bool device.status.map_list # list of saved MapData objects ``` --- The Dreame Vacuum integration's primary use cases are: full smart-home automation of robot vacuum workflows (scheduled room cleaning, zone-specific passes, consumable alerts, error recovery), Lovelace dashboard display of live and saved maps with editing capabilities, and multi-floor household management with per-floor map selection and per-room cleaning profiles. Typical automation patterns include triggering room-specific cleaning when occupancy sensors detect an empty room, notifying users on consumable depletion events, auto-dismissing dismissible warnings, and dynamically adjusting suction or water levels based on floor type detected via room selection entities. Integration with other Home Assistant components is straightforward: camera entities feed into `xiaomi-vacuum-map-card` or `valetudo-map-card` Lovelace cards for visual map interaction; event triggers (`dreame_vacuum_task_status`, `dreame_vacuum_error`, `dreame_vacuum_consumable`) drive notification and logging automations; select and switch entities integrate with voice assistants and dashboards; and the raw `vacuum.send_command` service provides an escape hatch for any device features not yet surfaced by the integration's entity layer.