Ecovacs Vacuum Cleaners Binding

logo

This binding integrates vacuum cleaners made by Ecovacs into openHAB.

Supported devices

Most devices made in the last 3 years should work with it, namely:

  • Deebot 600/601/605
  • Deebot OZMO 610
  • Deebot 710/711/711s
  • Deebot 900/901
  • Deebot OZMO 900/905
  • Deebot OZMO 920 *
  • Deebot OZMO 930 *
  • Deebot OZMO 950 *
  • Deebot Slim 2
  • Deebot OZMO Slim 10/11 *
  • Deebot OZMO T5
  • Deebot (OZMO) T8 series
  • Deebot T9 series
  • Deebot N3 MAX
  • Deebot N7
  • Deebot N8 series
  • Deebot U2 series
  • Deebot X1 Omni

Devices marked with an asterisk were successfully tested so far (by myself and with the help of @Hamlet and @Elrusso).

Supported features

Supported are

  • reading device state
  • sending commands to start and stop cleaning
  • reading last cleaning log entry
  • tracking current cleaning area/duration changes
  • changing suction power level and amount of water used for mopping (on OZMO devices)
  • tracking brush and filter life times

Please see the README file for details on the supported channels.

Changelog

Version 20220207

  • Initial release

Version 20220212

  • Improve last cleaning map image download (retry on failure)
  • Correctly handle unconfigured country

Version 20220213

  • Handle server-side MQTT disconnections (reconnect in that case)

Version 20220222

  • Split state channel: state now only contains basic operational state (cleaning, pause, stop, returning, charging, idle), while the currently used cleaning mode (if device is active) is now provided in the current-cleaning-mode channel. For details see README file.

Version 20220224

  • Fix deadlock on server-side MQTT disconnection

Version 20220226

  • Fix API server selection for users in UK and China

Version 20220228

  • (Hopefully) fix login for UK users

Version 20220304

  • Correctly handle expired login token

Version 20220309

  • Handle expired login token
  • Correctly handle reconnections
  • Fix Deebot 610 device definition

Version 20220513

  • Fix device metadata for Deebot OZMO 900/905 (add missing mapping capability)
  • Add some more Deebot N8 and Deebot X1 models to supported device list

Version 20220520

  • Remove ‘last clean map’ and ‘last clean mode’ channels for XML devices (clean log doesn’t contain those fields for those models)

Resources

  • Latest release kar file: here
  • Source code: here
9 Likes

Hey, i tried to Install your Addon.

It does not seem to take the continent out of the configuration
I got this error:

COMMUNICATION_ERROR
java.util.concurrent.ExecutionException: java.net.UnknownHostException: gl--api.ecovacs.com: Name or service not known

Solution:
OpenHab’s settings regarding language were not set for me.

Oh, I wasn’t aware language and/or country could be unset. I can add a fallback … I’m just not sure what value to use there. Maybe I’ll just set the bridge to OFFLINE if country is unset with a meaningful error message.

Installed and works like a charme. Even the progress image. Just the channels for “Current cleaning time” and “Current cleaned area” are NULL, no matter if deebot is currently cleaning or not.

Many thanks for this binding!

What model do you use? In any case, you can enable trace logging (log:set TRACE org.openhab.binding.ecovacs in Karaf console), start the bot and let it run for 2 minutes or something, then let it return, and send me the log (via PM if you want). I’ll see what’s up there.

Thanks for your offer, @maniac103!

Here’s the log of my T8:

16:29:34.931 [DEBUG] [internal.handler.EcovacsVacuumHandler] - [SERIAL]: Polling data
16:29:34.945 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Sending IOT command getTotalStats with payload {"header":{"pri":1,"ts":1644679774944,"tzm":480,"ver":"0.0.50"}}
16:29:35.071 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Got response payload {"header":{"pri":1,"tzm":480,"ts":"1644679774663","ver":"0.0.1","fwVer":"1.7.1","hwVer":"0.1.1"},"body":{"code":0,"msg":"ok","data":{"area":9555,"time":763964,"count":339}}}
16:29:35.079 [INFO ] [openhab.event.ItemStateChangedEvent  ] - Item 'DEEBOTOZMOT8TotalStatsTotalCleaningTime' changed from 763949 s to 763964 s
16:29:35.084 [INFO ] [openhab.event.ItemStateChangedEvent  ] - Item 'DEEBOTOZMOT8TotalStatsTotalCleanRuns' changed from 338 to 339
16:29:35.514 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Fetching cleaning logs yields 20 records
16:29:35.521 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Sending IOT command getSpeed with payload {"header":{"pri":1,"ts":1644679775521,"tzm":480,"ver":"0.0.50"}}
16:29:35.679 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Got response payload {"header":{"pri":1,"tzm":480,"ts":"1644679775275","ver":"0.0.1","fwVer":"1.7.1","hwVer":"0.1.1"},"body":{"code":0,"msg":"ok","data":{"speed":0}}}
16:29:35.683 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Sending IOT command getWaterInfo with payload {"header":{"pri":1,"ts":1644679775683,"tzm":480,"ver":"0.0.50"}}
16:29:35.894 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Got response payload {"header":{"pri":1,"tzm":480,"ts":"1644679775479","ver":"0.0.1","fwVer":"1.7.1","hwVer":"0.1.1"},"body":{"code":0,"msg":"ok","data":{"enable":0,"amount":2,"type":0,"sweepType":2}}}
16:29:35.898 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Sending IOT command getNetInfo with payload {"header":{"pri":1,"ts":1644679775898,"tzm":480,"ver":"0.0.50"}}
16:29:35.988 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Got response payload {"header":{"pri":1,"tzm":480,"ts":"1644679775581","ver":"0.0.1","fwVer":"1.7.1","hwVer":"0.1.1"},"body":{"code":0,"msg":"ok","data":{"ip":"[...]","ssid":"[...]]","rssi":"-44","wkVer":"0.1.2","mac":"[...]"}}}
16:29:35.992 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Sending IOT command getLifeSpan with payload {"header":{"pri":1,"ts":1644679775992,"tzm":480,"ver":"0.0.50"},"body":{"data":["sideBrush"]}}
16:29:35.999 [INFO ] [openhab.event.ItemStateChangedEvent  ] - Item 'DEEBOTOZMOT8StatusWifiRssi' changed from -54 dBm to -44 dBm
16:29:36.100 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Got response payload {"header":{"pri":1,"tzm":480,"ts":"1644679775685","ver":"0.0.1","fwVer":"1.7.1","hwVer":"0.1.1"},"body":{"code":0,"msg":"ok","data":[{"type":"sideBrush","left":8181,"total":9000}]}}
16:29:36.105 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Sending IOT command getLifeSpan with payload {"header":{"pri":1,"ts":1644679776105,"tzm":480,"ver":"0.0.50"},"body":{"data":["heap"]}}
16:29:36.210 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Got response payload {"header":{"pri":1,"tzm":480,"ts":"1644679775786","ver":"0.0.1","fwVer":"1.7.1","hwVer":"0.1.1"},"body":{"code":0,"msg":"ok","data":[{"type":"heap","left":6431,"total":7200}]}}
16:29:36.215 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Sending IOT command getLifeSpan with payload {"header":{"pri":1,"ts":1644679776215,"tzm":480,"ver":"0.0.50"},"body":{"data":["brush"]}}
16:29:37.321 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Got response payload {"header":{"pri":1,"tzm":480,"ts":"1644679775895","ver":"0.0.1","fwVer":"1.7.1","hwVer":"0.1.1"},"body":{"code":0,"msg":"ok","data":[{"type":"brush","left":5913,"total":18000}]}}
16:29:37.325 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Sending IOT command getVolume with payload {"header":{"pri":1,"ts":1644679777325,"tzm":480,"ver":"0.0.50"}}
16:29:37.389 [TRACE] [vacs.internal.api.impl.EcovacsApiImpl] - [SERIAL]: Got response payload {"header":{"pri":1,"tzm":480,"ts":"1644679776982","ver":"0.0.1","fwVer":"1.7.1","hwVer":"0.1.1"},"body":{"code":0,"msg":"ok","data":{"total":10,"volume":7}}}
16:29:37.393 [DEBUG] [internal.handler.EcovacsVacuumHandler] - [SERIAL]: Scheduling next poll in 300s, refresh interval 5min
16:29:37.396 [DEBUG] [internal.handler.EcovacsVacuumHandler] - [SERIAL]: Data polling completed

Today, it doesn’t reflect its actual state: It’s currently vacuuming selected areas, but the thing state is still “charging”.

That isn’t the full log though, I guess? It’s one data polling result, but cleaning state and current cleaning time/area are sent via (unsolicited) events, so appear outside of polling cycles.

Unfortunately, there were no events. Maybe this is why the state hasn’t been updated today. (Yesterday, this was working).

Beside the part above, I just received several discovery logs before and after the poll log:

[DEBUG] [scovery.EcovacsDeviceDiscoveryService] - Ecovacs discovery found 2 devices

I’ll check this on my device (only used command channel myself so far). I’ll also double check Ecovacs’ app, maybe one needs to refresh the MQTT connection every now and then.

Edit: It looks like I completely forgot to add handling for a disconnection of the MQTT connection … I guess that’s what happened for you. I’ll fix this to both reconnect and add a log line in that scenario.

Today, without any (manual) openhab or binding restart since then, events are again working and the state is correctly reflected. (And MQTT events are shown in the log)

This time, even current cleaning time and current cleaned area are shown and updated regularily. :man_shrugging:

Edit: Just noticed that you’ve published an update that got installed. Seems to work so far. Thank you very much! :slight_smile:

I just published another update that should fully fix the issue: I now register a listener to the connection which recognizes a disconnection and triggers a reconnection.

Hi @maniac103 , very excited to find your Addon. I’ve installed it and configured my bridge in a .things file as per the readme file.

I get this error:

COMMUNICATION_ERROR
java.util.concurrent.ExecutionException: java.net.UnknownHostException: gl-gb-api.ecovacs.com: Name or service not known

My OpenHAB regional settings are :
Language : English
Country/Region : United Kingdom

Any suggestions?

It looks like the Java country code for the UK is ‘GB’, while the server is named ‘uk’. Nothing you can do about it; I’ll have a look into it and let you know when I have a fix for that.

1 Like

Brilliant. Thanks for such a quick reply :slight_smile:

I just published an update, it should hopefully work fine in the UK now :wink:

Thanks @maniac103
It looks like it’s using the right server now but I’m getting a login failure.
Here is the DEBUG log

2022-02-27 12:53:31.070 [DEBUG] [s.internal.handler.EcovacsApiHandler] - Initializing Ecovacs account 'ecovacsapi'
2022-02-27 12:53:31.355 [DEBUG] [s.internal.handler.EcovacsApiHandler] - Ecovacs API login failed
org.openhab.binding.ecovacs.internal.api.EcovacsApiException: Login failed
	at org.openhab.binding.ecovacs.internal.api.impl.EcovacsApiImpl.portalLogin(EcovacsApiImpl.java:170) ~[?:?]
	at org.openhab.binding.ecovacs.internal.api.impl.EcovacsApiImpl.loginAndGetAccessToken(EcovacsApiImpl.java:105) ~[?:?]
	at org.openhab.binding.ecovacs.internal.handler.EcovacsApiHandler.lambda$0(EcovacsApiHandler.java:122) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) [?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
	at java.lang.Thread.run(Thread.java:834) [?:?]

I have the Ecovacs App installed on my phone and I can connect to that with my username and password. I’ve tried changing the password and I can still connect using the App but not through OpenHAB.

Can I confirm that I should be using the same credentials as when I connect using the App?
Is there anything I can change here that will help diagnose the issue? If you have the API call to log in, I can try it here in Postman - if that helps?

Please try again with today’s update. From the source code of sucks it looks like the API wants the country code in upper case letters, while in my last changes I used ‘uk’ (lower case). For all other countries it worked ‘by accident’ because the Java API outputs country codes in upper case.

Yes, that’s definitely the case.

Hi @maniac103 - definitely making progress! The bridge is connecting successfully now. I see this in the logs :

2022-03-01 07:41:32.087 [DEBUG] [s.internal.handler.EcovacsApiHandler] - Initializing Ecovacs account 'ecovacsapi'
2022-03-01 07:41:57.654 [DEBUG] [s.internal.handler.EcovacsApiHandler] - Ecovacs API initialized
2022-03-01 07:41:57.655 [DEBUG] [covery.EcovacsDeviceDiscoveryService] - Starting Ecovacs discovery scan
2022-03-01 07:41:58.018 [DEBUG] [covery.EcovacsDeviceDiscoveryService] - Ecovacs discovery found 1 devices

When I add the new device though (adding it from the Inbox in the UI), I see this :

2022-03-01 07:45:06.115 [DEBUG] [nternal.handler.EcovacsVacuumHandler] - E0001099017609490009: Initializing handler
2022-03-01 07:45:06.181 [TRACE] [.internal.api.impl.EcovacsXmppDevice] - E0001099017609490009: Connecting to XMPP
2022-03-01 07:45:11.872 [DEBUG] [nternal.handler.EcovacsVacuumHandler] - E0001099017609490009: Failed communicating to device, reconnecting
org.openhab.binding.ecovacs.internal.api.EcovacsApiException: org.jivesoftware.smack.SmackException: No supported and enabled SASL Mechanism provided by server. Server announced mechanisms: [PLAIN]. Registered SASL mechanisms with Smack: [SASL Mech: SCRAM-SHA-1-PLUS, Prio: 100, SASL Mech: SCRAM-SHA-1, Prio: 110, SASL Mech: X-OAUTH2, Prio: 410, SASL Mech: ANONYMOUS, Prio: 500]. Enabled SASL mechanisms for this connection: null. Blacklisted SASL mechanisms: [SCRAM-SHA-1-PLUS].
	at org.openhab.binding.ecovacs.internal.api.impl.EcovacsXmppDevice.connect(EcovacsXmppDevice.java:231) ~[?:?]
	at org.openhab.binding.ecovacs.internal.handler.EcovacsVacuumHandler.lambda$5(EcovacsVacuumHandler.java:480) ~[?:?]
	at org.openhab.binding.ecovacs.internal.handler.EcovacsVacuumHandler.doWithDevice(EcovacsVacuumHandler.java:671) ~[?:?]
	at org.openhab.binding.ecovacs.internal.handler.EcovacsVacuumHandler.connectToDevice(EcovacsVacuumHandler.java:479) ~[?:?]
	at org.openhab.binding.ecovacs.internal.handler.EcovacsVacuumHandler.lambda$0(EcovacsVacuumHandler.java:200) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) [?:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
	at java.lang.Thread.run(Thread.java:834) [?:?]
Caused by: org.jivesoftware.smack.SmackException: No supported and enabled SASL Mechanism provided by server. Server announced mechanisms: [PLAIN]. Registered SASL mechanisms with Smack: [SASL Mech: SCRAM-SHA-1-PLUS, Prio: 100, SASL Mech: SCRAM-SHA-1, Prio: 110, SASL Mech: X-OAUTH2, Prio: 410, SASL Mech: ANONYMOUS, Prio: 500]. Enabled SASL mechanisms for this connection: null. Blacklisted SASL mechanisms: [SCRAM-SHA-1-PLUS].
	at org.jivesoftware.smack.SASLAuthentication.selectMechanism(SASLAuthentication.java:361) ~[?:?]
	at org.jivesoftware.smack.SASLAuthentication.authenticate(SASLAuthentication.java:192) ~[?:?]
	at org.jivesoftware.smack.tcp.XMPPTCPConnection.loginInternal(XMPPTCPConnection.java:402) ~[?:?]
	at org.jivesoftware.smack.AbstractXMPPConnection.login(AbstractXMPPConnection.java:528) ~[?:?]
	at org.jivesoftware.smack.AbstractXMPPConnection.login(AbstractXMPPConnection.java:485) ~[?:?]
	at org.openhab.binding.ecovacs.internal.api.impl.EcovacsXmppDevice.connect(EcovacsXmppDevice.java:221) ~[?:?]

I had a quick search this morning and found this - does it help?

No. The problem is simple: you need the smack-sasl-javax bundle. What I do not understand is why OH core/Karaf doesn’t install it automatically on binding install, since it is actually listed as dependency.

Short term solution for you: go to OH console and do bundle:install https://repo1.maven.org/maven2/org/igniterealtime/smack/smack-sasl-javax/4.3.3/smack-sasl-javax-4.3.3.jar and restart OH, the XMPP login should work afterwards.

Hi @maniac103
I’ve installed that bundle and everything is working. Thank you so much for your help. :+1:
If there’s anything I can do to help determine why that dependent bundle didn’t install, please let me know.