Xiaomi Robot Vacuum Binding

I’m a big fan of Xiaomi products… Recently I bought the Xiaomi Robot vacuum.
This vacuum can be controlled via openhab using the miio binding.

The miio binding utilises the Mi IO protocol/encryption to communicate with the devices.
This is not using the cloud, it is communicating directly to the devices.

To have a working binding, a little difficult step needs to be done to retrieve the vacuum token.

The easiest way to obtain tokens is to browse through log files of the Mi Home app version 5.4.49 for Android. It seems that version was released with debug messages turned on by mistake. An APK file with the old version can be easily found using one of the popular web search engines. After downgrading use a file browser to navigate to directory SmartHome/logs/plug_DeviceManager , then open the most recent file and search for the token. When finished, use Google Play to get the most recent version back.

3 March 2020: You can also use the experimental version of the binding to get the tokens in an easy way see this post

The binding is is mainly supporting the first version of the rockrobo vacuum, but is also (mostly) usable for newer models as well. Main functionality, like getting the status, switching it on & off etc are working.

Sending custom commands
To send custom commands, enable the cmd channel in paperUI (using the ‘show more’ in the channel list as it is a channel marked as advanced) and link a String item to the channel.

You can than send the command to the created string item. It will send the command to the Xiaomi device and update the channel with the response.

Commands for the vacuum are described here https://github.com/marcelrv/XiaomiRobotVacuumProtocol
Note that the binding takes care of parts of the increasing the id and the 'making a json message, e.g to send {'method': 'set_custom_mode', 'params': [40],'id': 17694} to the device, send set_custom_mode [40] to the cmd channel.

Item files
Example item files and channels for each device are now in the readme file

Note, unfortunately the maps that are displayed in the app are not directly coming from the vacuum, instead they are coming from the Xiaomi cloud. Much more discovery is needed to find out exactly how to connect to the Xiaomi cloud and get this details.
note that direct cleaning map display is possible using dustcloud with hacked firmware
3 march 2020: You can now get the map with the experimental version that has the cloud connectivity. See this post

Known issues

  • Yeelights dimming will not trigger on/off. It purely reports what the device is returning as value.

If you have issues, please include your firmware version (can be seen in mihome app) and the log. Depending on the issue this may be the debug or the trace log.

log:set debug org.openhab.binding.miio
log:display org.openhab.binding.miio

If the binding works for you let us know as well :slight_smile:

New / Unsupported devices
If your device is reported as unsupported, you can experiment with using the definition of similar devices. In that case, (manually) add it as a miio:basic device, try to find similar model and override the modelId with the one from the similar device (see binding readme for all devices).
If you find a file that works well for your device, please share your findings (preferably make a new issue on github with the details of the device and which modelId it works with so it can be added)

Note: for discussion around Air purifiers check topic : Xiaomi Mi Air Purifier (Xiaomi Mi IO)


Some example screens

Sample item text

Group  gVac     "Xiaomi Robot Vacuum"      <fan>
Group  gVacStat "Status Details"           <status> (gVac)
Group  gVacCons "Consumables Usage"        <line-increase> (gVac)
Group  gVacDND  "Do Not Disturb Settings"  <moon> (gVac)
Group  gVacHist "Cleaning History"         <calendar> (gVac)
Group  gVacNetwork "Network Details"       <network> (gVac)

String actionControl  "Vacuum Control"     (gVac)     {channel="miio:generic:034F0E45:actions#control" }
Number actionFan      "Vacuum Fan"         (gVac)   {channel="miio:generic:034F0E45:actions#fan" }
String actionCommand  "Vacuum Command"          {channel="miio:generic:034F0E45:actions#commands" }

Number statusBat    "Battery Level [%1.0f%%]" <battery>   (gVac,gVacStat) {channel="miio:generic:034F0E45:status#battery" }
Number statusArea    "Cleaned Area [%1.0fm²]" <zoom>   (gVac,gVacStat) {channel="miio:generic:034F0E45:status#clean_area" }
Number statusTime    "Cleaning Time [%1.0f']" <clock>   (gVac,gVacStat) {channel="miio:generic:034F0E45:status#clean_time" }
String  statusError    "Error [%s]"  <error>  (gVac,gVacStat) {channel="miio:generic:034F0E45:status#error_code" }
Number statusFanPow    "Fan Power [%1.0f %%]"  <signal>   (gVacStat) {channel="miio:generic:034F0E45:status#fan_power" } 
Number statusClean    "In Cleaning Status [%1.0f]"   <switch>  (gVacStat) {channel="miio:generic:034F0E45:status#in_cleaning" }
Switch statusDND    "DND Activated"    (gVacStat) {channel="miio:generic:034F0E45:status#dnd_enabled" }
String statusStatus    "Status [%s]"  <status>  (gVacStat) {channel="miio:generic:034F0E45:status#state"} 

Number consumableMainT    "Main Brush [%1.0f]"    (gVacCons) {channel="miio:generic:034F0E45:consumables#main_brush_time"}
Number consumableMainP    "Main Brush [%1.0f%%]"    (gVacCons) {channel="miio:generic:034F0E45:consumables#main_brush_percent"}
Number consumableSideT    "Side Brush [%1.0f]"    (gVacCons) {channel="miio:generic:034F0E45:consumables#side_brush_time"}
Number consumableSideP    "Side Brush [%1.0f%%]"    (gVacCons) {channel="miio:generic:034F0E45:consumables#side_brush_percent"}
Number consumableFilterT    "Filter Time[%1.0f]"    (gVacCons) {channel="miio:generic:034F0E45:consumables#filter_time" }
Number consumableFilterP    "Filter Time[%1.0f%%]"    (gVacCons) {channel="miio:generic:034F0E45:consumables#filter_percent" }
Number consumableSensorT    "Sensor [%1.0f]"    (gVacCons) {channel="miio:generic:034F0E45:consumables#sensor_dirt_time"}
Number consumableSensorP    "Sensor [%1.0f%%]"    (gVacCons) {channel="miio:generic:034F0E45:consumables#sensor_dirt_percent"}

Switch dndFunction   "DND Function" <moon>   (gVacDND) {channel="miio:generic:034F0E45:dnd#dnd_function"}
String dndStart   "DND Start Time [%s]" <clock>   (gVacDND) {channel="miio:generic:034F0E45:dnd#dnd_start"}
String dndEnd   "DND End Time [%s]"   <clock-on>  (gVacDND) {channel="miio:generic:034F0E45:dnd#dnd_end"}

Number historyArea    "Total Cleaned Area [%1.0fm²]" <zoom>    (gVacHist) {channel="miio:generic:034F0E45:history#total_clean_area"}
Number historyTime    "Total Clean Time [%1.0f']"   <clock>     (gVacHist) {channel="miio:generic:034F0E45:history#total_clean_time"}
Number historyCount    "Total # Cleanings [%1.0f]"  <office>  (gVacHist) {channel="miio:generic:034F0E45:history#total_clean_count"}

String  miNetSSID    "Network SSID [%s]"  <network>  (gVac,gVacNetwork) {channel="miio:generic:034F0E45:network#ssid" }
String  miNetBSSID    "Network BSSID [%s]"  <network>  (gVac,gVacNetwork) {channel="miio:generic:034F0E45:network#bssid" }
Number  miNetRSSI    "Network RSSI [%1.0f]"  <network>  (gVac,gVacNetwork) {channel="miio:generic:034F0E45:network#rssi" }
Number  miNetLife    "Uptime [%1.0f]"  <clock>  (gVac,gVacNetwork) {channel="miio:generic:034F0E45:network#life" }

in the Sitemap

Group item=gVac {
		Switch item=actionControl mappings=[vacuum="Vacuum", pause="Pause",spot="Spot", dock="Dock"]
 		Switch item=actionFan mappings=[38="Silent", 60="Normal", 77="Power",90="Full", -1="Custom"]
		Default item=statusBat 
		Default item=statusArea 
		Default item=statusTime 
		Group  item=gVacStat
		Group  item=gVacCons
		Group  item=gVacDND
		Group  item=gVacHist
		Group  item=gVacNetwork

Binding is updated today

Differences between previous version

  • Increase timeouts to avoid offline for devices with slow response @sasha_jpr @BOFH90
  • Change consumables logic to remaining instead of used time
  • Reuse port for connectivity
  • Cleanup channels, e.g. message version channel
  • Update Readme wrt iphone token
  • Simplify the channels. Single command channel @kaufsim

NB, as channels changed, in you need to delete your thing and add it again to have all the channels properly available.


Thanks for the binding and the update! Works much better now!
Great work!!

Why is history#total_clean_time a String? Doesn’t it have to ba a Number like status#clean_time?

@oliver it is because I prefer to have it in the hh:mm format rather than total time in minutes, or total time in like 10.5 hours, which is not possible when I define it as a decimal.

In the status#clean_time it is displayed in minutes, hence the string formatting was not needed.

I understand, but it might be better to user a number whenever applicable as you can evaluate it more easily in rules without parsing a string. I don’t think it’s a good idea to derive the datatype from the ui representation.

However, there seems to be a bug as the official Mi app states that my robot 145 minutes, but your binding returns “05:00”.

@marcel_verpaalen, currently my robot is idle, but the battery level decreases constantly. From 90% to 75% in the last 2 hours. Is it possible that the receivement of the status information (every 30 seconds) causes this decrease?

I confirm that is a issue. I’ll fix it with the next release

I would consider that unlikely… robot has a quite significant accu, and the messages send are simple, not data intensive. If so I would consider it more of a firmware bug.
Anyhow, I would encourage you to test it. The refresh interval can be changed in the configuration, it is marked as advanced, so you need to select show more to see it

@marcel_verpaalen quick question, any idea how to get the token with an IOS device?

I don’t have any IOS devices, but this is what I read on one of the other forums

I setup my iOS device with the Mi-Home app.
Created an unencrypted backup of the device on my laptop using itunes.
Installed iBackup Viewer from here: http://www.imactools.com/iphonebackupviewer/
Extracted this file /raw data/com.xiami.mihome/_mihome.sqlite to my computer
Open the file extracted using notepad. You will then see the list of all the device in your account with their token

Binding was updated today and loaded to the market place.

Changed to prior version:

  • Fix wrong total cleaning time, change format total cleaning time to minutes @oliver
  • Allowed control of vacuum fan level

NB, as channels changed. You need to delete your thing and add it again to have all the channels properly available.

Works like a charm. Thanks a lot for this amazing binding!

Do you think it’s possible to integrate the cleaning map in openHAB?

1 Like

Once day maybe…:slight_smile: I would love to have it as well.
It is actually quite complicated as far as I can see. The maps are not coming from the device itself, instead from the Xiaomi cloud. I sniff the network traffic, setting up MITM proxy to workaount the ssl encryption, but even than, there is quite some crypto stuff done. So the data can’t be easy read.
There is some documentation how to logon to the cloud & sdk, but it requires you to sign up and provide copies of my passport, which I’m not willing to do.Besides if I remember well, it was all in Chinese.
Anyway, I guess in the long run we will figure out how, as that would also solve the token retrieval, but don’t count on it anytime soon.

1 Like

@marcel_verpaalen, my log file is full of these messages:

13:45:51.056 [INFO ] [me.event.ThingStatusInfoChangedEvent] - 'xiaomivacuum:vacuum:Hugo' changed from ONLINE to OFFLINE (COMMUNICATION_ERROR): No valid status response
13:46:21.096 [INFO ] [me.event.ThingStatusInfoChangedEvent] - 'xiaomivacuum:vacuum:Hugo' changed from OFFLINE (COMMUNICATION_ERROR): No valid status response to ONLINE
13:46:31.115 [INFO ] [me.event.ThingStatusInfoChangedEvent] - 'xiaomivacuum:vacuum:Hugo' changed from ONLINE to OFFLINE (COMMUNICATION_ERROR): No valid status response
13:47:01.142 [INFO ] [me.event.ThingStatusInfoChangedEvent] - 'xiaomivacuum:vacuum:Hugo' changed from OFFLINE (COMMUNICATION_ERROR): No valid status response to ONLINE
13:47:11.171 [INFO ] [me.event.ThingStatusInfoChangedEvent] - 'xiaomivacuum:vacuum:Hugo' changed from ONLINE to OFFLINE (COMMUNICATION_ERROR): No valid status response
13:48:21.189 [INFO ] [me.event.ThingStatusInfoChangedEvent] - 'xiaomivacuum:vacuum:Hugo' changed from OFFLINE (COMMUNICATION_ERROR): No valid status response to ONLINE
13:48:31.317 [INFO ] [me.event.ThingStatusInfoChangedEvent] - 'xiaomivacuum:vacuum:Hugo' changed from ONLINE to OFFLINE (COMMUNICATION_ERROR): No valid consumables response
13:49:01.328 [INFO ] [me.event.ThingStatusInfoChangedEvent] - 'xiaomivacuum:vacuum:Hugo' changed from OFFLINE (COMMUNICATION_ERROR): No valid consumables response to ONLINE
13:49:11.421 [INFO ] [me.event.ThingStatusInfoChangedEvent] - 'xiaomivacuum:vacuum:Hugo' changed from ONLINE to OFFLINE (COMMUNICATION_ERROR): No valid status response

Maybe I am just bad…but i have no idea to install this…can you quickly help me?!

Hi @Multisaft7

First install the market place binding. See Distributing bindings through the IoT Marketplace for details.
Once that is activated you can go to the addons, and select the Xiaomi Vacuum binding (see screenie).
Once installed, read the first topic on how to get the tolken, as that is the tricky piece.

Hope this helps you getting started.

1 Like

But for this market installation i need a snapshot version of openhab? right?

I think release 2.1 already has the market place binding. Released versions before 2.1 won’t have it indeed.

1 Like

Same here…

Status: OFFLINE - COMMUNICATION_ERROR No valid Network response