Ecovacs Vacuum Cleaners Binding [3.2.0;4.0.0)

logo

This binding integrates vacuum cleaners made by Ecovacs into openHAB 3.x.

(Note: for openHAB 4.x, it will be part of the addon distribution)

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 either myself or various people using the binding).

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)

Version 20220615

  • Add rule actions for device sound playback
  • Add channel for current cleaning spot (for ā€˜custom areaā€™ and ā€˜spot areaā€™ modes)
  • Add command for custom area cleaning

Version 20220622

  • Fix event updates not working when using more than one MQTT device

Version 20220726

  • Rebuild against OH 3.4.0 snapshot

Version 20220902

  • Change separators of ā€˜spotAreaā€™ and ā€˜customAreaā€™ definition lists to semicolons to allow using spotArea and customArea commands in command options

Version 20220916

  • Added Deebot T10 models to supported device list

Version 20220921

  • Fixed communication error being shown after access token expiry

Version 20221106

  • Fix vacuum thing being set ONLINE too early if initialization fails

Version 20230109

  • Add channel for enabling/disabling ā€˜True Detect 3Dā€™
  • Add channel for enabling/disabling continuous cleaning
  • Add channel for setting default number of cleaning passes
  • Add channel for enabling/disabling/triggering auto dust bin emptying

Version 20230114

  • Fix device metadata for newer devices with auto empty station & True Detect 3D
  • Fix clean info report parsing for Deebot X1 Omni

Version 20230116

  • Fix event update stopping on Deebot X1 Omni when cleaning pads are washed

Version 20230118

  • Ignore MQTT messages with invalid JSON syntax, which previously broke event updates

Version 20230201

  • Fix authentication token expiry not being handled correctly on some (XML-over-MQTT) models

Version 20230314

  • Add some missing models to supported device list

Version 20230424

  • Add Deebot N8 Pro Care to supported device list

Resources

  • Latest release kar file: here
  • Source code: here
11 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.