Xiaomi Robot Vacuum Binding

Hallo Doug,

To clarify few things…

  1. the steps described in the link works, but the same method works with openhab as well. So you can reset your device and connect to it’s wifi with your openhab. Than execute a discovery. It will find the device and the token.
    The big BUT… with the latest firmware the token is changing when you connect it to the new network. Hence this discovery method is no longer very useful.

  2. The device ID between the 2 applications is the same, but the writing mode is different. In OH I use a so called hexidecimal representation, homebridge is using the regular decimal notation. You can convert these numbers easy e.g. type in google “[your homebridge id] to hex” and you will get the number as found by openhab.
    In any case, you should not need to type this device id, if you enter the ip, the binding will find the id.

  3. I think it is recommended first to let OH discover the binding, Once everything is working fine, you can transfer the values to a text config if that is what your prefered config method is.

  4. telnet to the port does not help you, as the device expect a very specific sequence of header & encrypted content.

If you don’t get response from your vacuum, and you are sure the io is right, it generally means the token is wrong.
With wrong tokens, the device only responds to the ping, but no other commands.
In OH you can see this if after the binding is started, or after you made a change to the thing config, it will go to online, and after approx 1 minute changes to offline - configuration error.

The only known way with current firmware is to extract the token from your phone. Maybe you have a phone that can be rooted (e.g. an older phone you don’t use, or download an android emulator) than you can find the miio2.db file and read the token from that.

Thank you Marcel,

It sounds like I have simply got the wrong token then. It sounds like my next best step to to play with the Android Emulators as you suggest.

Thanks again,

Doug

Hallo Marcel!

You did a really great Job with this binding! :+1:t3:

Since 2 days I got an error after updating the MiHome-App and the robot’s firmware to Version 3.3.9_003077:

2017-11-03 17:53:18.727 [hingStatusInfoChangedEvent] - ‘miio:vacuum:03D4A566’ changed from ONLINE to OFFLINE (CONFIGURATION_ERROR)

I reinstalled the binding and added the correct token… the status switched to “Online” and after pressing the action-button it changes to the displayed error.

Any suggestions?

Thanks,
peter

In the latest firmware version the token is changing when certain parameters are updated.

Suggest to extract your token once more from the mihome Android app

1 Like

As you wrote 2 answers above…
Next time i’ll have a better look… :face_with_monocle:

Works perfect! Great Job!

on my iPad it shows only Gateway token plus all id’s of all zigbee devices connected to gateway.
I have xiaomi wifi plugs, lights and cameras - No one listed on that screen.

dang, you’re right…was to quick :frowning_face:

Finally found my tokens using this Xiaomi Robot Vacuum Binding

@marcel_verpaalen After power was restored from a recent power outage, the binding was unable to restore communication with the vacuum (my OH server is on battery and generator backup). I’m assuming that the vacuum is fine because I can control it from the smartphone app.

I tried to stop/start the binding from the karaf console in order to possibly clear the problem. The log messages show the binding stopping; however, it appears a thread is still running after the binding is stopped.

2017-11-08 10:59:08.624 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Communication error for Mi IO device at 192.168.XX.XX: Receive timed out
2017-11-08 10:59:08.625 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Command added to Queue {"id":7,"method":"get_clean_summary","params":[]} -> 192.168.XX.XX (Device: 03D9D158 token: XXXX Queue: 3)
2017-11-08 10:59:10.390 [DEBUG] [org.openhab.binding.miio            ] - BundleEvent STOPPING - org.openhab.binding.miio
2017-11-08 10:59:10.399 [DEBUG] [org.openhab.binding.miio            ] - ServiceEvent UNREGISTERING - {org.eclipse.smarthome.io.transport.mdns.discovery.MDNSDiscoveryParticipant}={component.name=org.openhab.binding.miio.internal.discovery, component.id=235, service.id=443, service.bundleid=11, service.scope=bundle} - org.openhab.binding.miio
2017-11-08 10:59:10.418 [DEBUG] [org.openhab.binding.miio            ] - ServiceEvent UNREGISTERING - {org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory}={component.name=org.openhab.binding.miio.internal.MiIoHandlerFactory, component.id=236, service.id=445, service.bundleid=11, service.scope=bundle} - org.openhab.binding.miio
2017-11-08 10:59:10.419 [DEBUG] [ing.miio.handler.MiIoAbstractHandler] - Disposing Xiaomi Mi IO handler 'miio:generic:03D9D158'
2017-11-08 10:59:15.425 [WARN ] [ome.core.thing.internal.ThingManager] - Disposing handler for thing 'miio:generic:03D9D158' takes more than 5000ms.
2017-11-08 10:59:18.636 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Communication error for Mi IO device at 192.168.XX.XX: Receive timed out
2017-11-08 10:59:20.432 [ERROR] [ome.core.thing.internal.ThingManager] - Exception occurred while calling thing handler factory 'org.openhab.binding.miio.internal.MiIoHandlerFactory@5bfb16ac'
java.util.concurrent.TimeoutException: null
        at java.util.concurrent.FutureTask.get(FutureTask.java:205) [?:?]
        at org.eclipse.smarthome.core.common.SafeMethodCaller.callAsynchronous(SafeMethodCaller.java:194) [102:org.eclipse.smarthome.core:0.9.0.201710240931]
        at org.eclipse.smarthome.core.common.SafeMethodCaller.call(SafeMethodCaller.java:83) [102:org.eclipse.smarthome.core:0.9.0.201710240931]
        at org.eclipse.smarthome.core.common.SafeMethodCaller.call(SafeMethodCaller.java:67) [102:org.eclipse.smarthome.core:0.9.0.201710240931]
        at org.eclipse.smarthome.core.thing.internal.ThingManager.doUnregisterHandler(ThingManager.java:690) [109:org.eclipse.smarthome.core.thing:0.9.0.201710240931]
        at org.eclipse.smarthome.core.thing.internal.ThingManager.unregisterHandler(ThingManager.java:680) [109:org.eclipse.smarthome.core.thing:0.9.0.201710240931]
        at org.eclipse.smarthome.core.thing.internal.ThingManager.unregisterAndDisposeHandler(ThingManager.java:763) [109:org.eclipse.smarthome.core.thing:0.9.0.201710240931]
        at org.eclipse.smarthome.core.thing.internal.ThingManager.removeThingHandlerFactory(ThingManager.java:989) [109:org.eclipse.smarthome.core.thing:0.9.0.201710240931]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[?:?]
        at org.apache.felix.scr.impl.inject.BaseMethod.invokeMethod(BaseMethod.java:229) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.inject.BaseMethod.access$500(BaseMethod.java:39) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.inject.BaseMethod$Resolved.invoke(BaseMethod.java:650) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.inject.BaseMethod.invoke(BaseMethod.java:506) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.inject.BindMethod.invoke(BindMethod.java:658) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.DependencyManager.invokeUnbindMethod(DependencyManager.java:1837) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.SingleComponentManager.invokeUnbindMethod(SingleComponentManager.java:395) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.DependencyManager$MultipleDynamicCustomizer.removedService(DependencyManager.java:375) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.DependencyManager$MultipleDynamicCustomizer.removedService(DependencyManager.java:291) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.ServiceTracker$Tracked.customizerRemoved(ServiceTracker.java:1241) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.ServiceTracker$Tracked.customizerRemoved(ServiceTracker.java:1136) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.ServiceTracker$AbstractTracked.untrack(ServiceTracker.java:996) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.ServiceTracker$Tracked.serviceChanged(ServiceTracker.java:1175) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.BundleComponentActivator$ListenerInfo.serviceChanged(BundleComponentActivator.java:127) [42:org.apache.felix.scr:2.0.12]
        at org.eclipse.osgi.internal.serviceregistry.FilteredServiceListener.serviceChanged(FilteredServiceListener.java:109) [?:?]
        at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:915) [?:?]
        at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230) [?:?]
        at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148) [?:?]
        at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEventPrivileged(ServiceRegistry.java:862) [?:?]
        at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.publishServiceEvent(ServiceRegistry.java:801) [?:?]
        at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.unregister(ServiceRegistrationImpl.java:222) [?:?]
        at org.apache.felix.scr.impl.manager.AbstractComponentManager$3.unregister(AbstractComponentManager.java:909) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.AbstractComponentManager$3.unregister(AbstractComponentManager.java:874) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.RegistrationManager.changeRegistration(RegistrationManager.java:139) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.AbstractComponentManager.unregisterService(AbstractComponentManager.java:951) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.AbstractComponentManager.doDeactivate(AbstractComponentManager.java:806) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.AbstractComponentManager.deactivateInternal(AbstractComponentManager.java:788) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.AbstractComponentManager.dispose(AbstractComponentManager.java:580) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.manager.ConfigurableComponentHolder.disposeComponents(ConfigurableComponentHolder.java:706) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.BundleComponentActivator.dispose(BundleComponentActivator.java:523) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.Activator.disposeComponents(Activator.java:439) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.Activator.access$300(Activator.java:54) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.scr.impl.Activator$ScrExtension.destroy(Activator.java:293) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.utils.extender.AbstractExtender$2.run(AbstractExtender.java:285) [42:org.apache.felix.scr:2.0.12]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:?]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:?]
        at org.apache.felix.utils.extender.AbstractExtender.destroyExtension(AbstractExtender.java:307) [42:org.apache.felix.scr:2.0.12]
        at org.apache.felix.utils.extender.AbstractExtender.bundleChanged(AbstractExtender.java:181) [42:org.apache.felix.scr:2.0.12]
        at org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:903) [?:?]
        at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230) [?:?]
        at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148) [?:?]
        at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEventPrivileged(EquinoxEventPublisher.java:213) [?:?]
        at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:120) [?:?]
        at org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:112) [?:?]
        at org.eclipse.osgi.internal.framework.EquinoxContainerAdaptor.publishModuleEvent(EquinoxContainerAdaptor.java:156) [?:?]
        at org.eclipse.osgi.container.Module.publishEvent(Module.java:476) [?:?]
        at org.eclipse.osgi.container.Module.doStop(Module.java:634) [?:?]
        at org.eclipse.osgi.container.Module.stop(Module.java:498) [?:?]
        at org.eclipse.osgi.internal.framework.EquinoxBundle.stop(EquinoxBundle.java:410) [?:?]
        at org.apache.karaf.bundle.command.Stop.executeOnBundle(Stop.java:38) [48:org.apache.karaf.bundle.core:4.1.2]
        at org.apache.karaf.bundle.command.BundlesCommand.doExecute(BundlesCommand.java:62) [48:org.apache.karaf.bundle.core:4.1.2]
        at org.apache.karaf.bundle.command.BundlesCommand.execute(BundlesCommand.java:52) [48:org.apache.karaf.bundle.core:4.1.2]
        at org.apache.karaf.shell.impl.action.command.ActionCommand.execute(ActionCommand.java:84) [15:org.apache.karaf.shell.core:4.1.2]
        at org.apache.karaf.shell.impl.console.osgi.secured.SecuredCommand.execute(SecuredCommand.java:68) [15:org.apache.karaf.shell.core:4.1.2]
        at org.apache.karaf.shell.impl.console.osgi.secured.SecuredCommand.execute(SecuredCommand.java:86) [15:org.apache.karaf.shell.core:4.1.2]
        at org.apache.felix.gogo.runtime.Closure.executeCmd(Closure.java:571) [15:org.apache.karaf.shell.core:4.1.2]
        at org.apache.felix.gogo.runtime.Closure.executeStatement(Closure.java:497) [15:org.apache.karaf.shell.core:4.1.2]
        at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:386) [15:org.apache.karaf.shell.core:4.1.2]
        at org.apache.felix.gogo.runtime.Pipe.doCall(Pipe.java:417) [15:org.apache.karaf.shell.core:4.1.2]
        at org.apache.felix.gogo.runtime.Pipe.call(Pipe.java:229) [15:org.apache.karaf.shell.core:4.1.2]
        at org.apache.felix.gogo.runtime.Pipe.call(Pipe.java:59) [15:org.apache.karaf.shell.core:4.1.2]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:?]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:?]
        at java.lang.Thread.run(Thread.java:748) [?:?]
2017-11-08 10:59:20.463 [DEBUG] [org.openhab.binding.miio            ] - ServiceEvent UNREGISTERING - {org.eclipse.smarthome.config.discovery.DiscoveryService}={component.name=org.openhab.binding.miio.internal.discovery.MiIoDiscovery, component.id=237, service.id=446, service.bundleid=11, service.scope=bundle} - org.openhab.binding.miio
2017-11-08 10:59:20.467 [DEBUG] [iio.internal.discovery.MiIoDiscovery] - Stop Xiaomi  Mi IO background discovery
2017-11-08 10:59:20.467 [DEBUG] [iio.internal.discovery.MiIoDiscovery] - Receiver thread ended
2017-11-08 10:59:20.496 [DEBUG] [org.openhab.binding.miio            ] - BundleEvent STOPPED - org.openhab.binding.miio
2017-11-08 10:59:28.648 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Communication error for Mi IO device at 192.168.XX.XX: Receive timed out
2017-11-08 10:59:38.657 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Communication error for Mi IO device at 192.168.XX.XX: Receive timed out

2017-11-08 10:59:48.669 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Communication error for Mi IO device at 192.168.XX.XX: Receive timed out

2017-11-08 10:59:58.681 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Communication error for Mi IO device at 192.168.XX.XX: Receive timed out
2017-11-08 11:00:08.693 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Communication error for Mi IO device at 192.168.XX.XX: Receive timed out
2017-11-08 11:00:08.694 [DEBUG] [ing.miio.handler.MiIoAbstractHandler] - Ping Mi IO device 03D9D158 at 192.168.XX.XX
2017-11-08 11:00:08.697 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Starting Mi IO MessageSenderThread
2017-11-08 11:00:18.707 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Communication error for Mi IO device at 192.168.XX.XX: Receive timed out
2017-11-08 11:00:28.719 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Communication error for Mi IO device at 192.168.XX.XX: Receive timed out
2017-11-08 11:00:38.729 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Communication error for Mi IO device at 192.168.XX.XX: Receive timed out
2017-11-08 11:00:38.730 [DEBUG] [ing.miio.handler.MiIoAbstractHandler] - Ping response from device 03D9D158 at 192.168.XX.XX FAILED
2017-11-08 11:00:38.732 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Command added to Queue {"id":10,"method":"get_consumable","params":[]} -> 192.168.XX.XX (Device: 03D9D158 token: XXXX Queue: 1)
2017-11-08 11:00:48.744 [DEBUG] [nal.transport.MiIoAsyncCommunication] - Communication error for Mi IO device at 192.168.XX.XX: Receive timed out

Yes, seems something is blocking the disposing of the thing.
I’ll take a look @ the code see if I can see anything that blocks this. (e.g. is the disposing disrupted if there is no communication)

2017-11-08 10:59:15.425 [WARN ] [ome.core.thing.internal.ThingManager] - Disposing handler for thing 'miio:generic:03D9D158' takes more than 5000ms.

Note: the most logic reason for the error wrt to the communication is that after the power is restored your’re vacuum has a different ip. My assumption is that the next discovery would fix that, but if you manually added your thing, you’ll need to manually update the ip in the config.

Good point. It did pick up a new IP, and it does appear that the thing config has now been updated with the new IP. :thumbsup:

To avoid this in the future, I’ll give the device a fixed IP in my DHCP config.

I own Mi vacuum and Mi air purifier 2.
I would like to add both units to OpenHAB as they are great. Both have fixed IP,

My progress:

  1. I got two tokens from Mi ToolKit after activating developer options on Android and USB Debug (which was not mentioned in the first post). zhimi.airpurifier.m2 and rockrobo.vacuum.v1
  2. Paper UI/Configuration/Thing/+/Xiaomi Mi IO Binding
    Nothing was found…
    Manually add thing.
    Xiaomi Robo Vacuum.
    Token/IP/Location/
    And I’m getting "OFFLINE - COMMUNICATION_ERROR No Response from device"
    Any idea what can be the problem? I did try both tokens just to be sure…

It means somehow your device is not reachable by openhab. The binding uses 2 different methods to discover your devices and both don’t seem to work.

Do you use a complex network setup? e.g. your devices are in some different vlan than your OH?
In the mihome app, is it connected as ‘remote’, is the ip you see there matching the ip in OH

Can you ping the devices from the command line?

Thank you for the fast answer!
I’m running simple network. Router 192.168.0.1. OpenHAB 192.168.0.4. Vacuum 192.168.0.11. AIR 192.168.0.17.
I’m not sure what you mean by remote connected item in mihome app. I’m the only user of mihome app and I did add both units to the network. So far did not have a problem with them and I can use them from all over the world.
Yes. IP in the mihome app is correct and matching the one that I used during manual adding thing.

I’m using network binding to find my wifi cellphones. It’s working great. I have to check if this binding can find Mi devices. If not. It will be difficult to explain why.

Today I did change router and now binding found two things. After adding token they are “ONLINE”.

Cool, good it is working for you.
Thanks for letting me know

One more time. Thank you for your support.
Where can I find items and sitemap code that will let me incorporate all the buttons and informations as you shown in 10July2017 post?
Sorry, I found them below pictures…

Hello. I integrated your work in my openhab item and sitemap. I’m connected to the vacuum cleaner and can see all the statistics which are walid.

It is strange that when I hit “VACUUM” button it is ON/red for 1s and becomes OFF/grey. “DOCK” is becoming ON/red again. Vacuum is starting and is working normally. Other buttons have the same problem.
I’m adding Xiaomi Air purifier in the same time and there buttons operate in correct way.

Please add “Find my robot vacuum”. It is useful to test communication and in real life.

Got my vacuum Friday and within 10 mins I was up and running thanks so much.

Bonus points - Is there a way to turn off the LED when charging? I’d love to have that off during DND time.

That would very odd indeed. What kind of item / sitemap you have, as it is more likely to come from that