Skip to content
Colin Wren
Twitter

Interacting with my Ecovacs Deebot robotic vacuum with Python & Sucks

Python, Technology4 min read

ps4 controller controlling a vaccuum
The end result — I now use my PS4 controller to control my Deebot

After a month of working from home I noticed an increase in the amount of cleaning that my girlfriend and myself had to do to keep the flat in a decent state.

When a friend of mine told me that the Ecovacs Deebot 500 was only £160 on Amazon, came with a set of spares and worked with my Google Home I bought it without even blinking, I could now just let it run on a schedule and pick everything up.

So far I’ve found it to be an amazing little robot and it’s given us a lot of entertainment as it goes about it’s business, especially when it recently knocked a can of Pringles off the shelf and paraded it around the flat.

A nice distraction while being cooped up indoors

There were a few teething problems at the start, the Ecovacs app for instance will not pair with the Deebot unless you enable location access (on iOS at least) but after that’ it’s worked seamlessly — definitely worth the £160.

When I purchased the Deebot I had joked to my friend (who lives down the hallway from me) that we should host a Robot Wars like fight between our machines and a quick search on Github returned a Python library that looked like I might be able to do that.

The library — Sucks

Sucks is a Python library for connecting to your Deebot via API gateway used by the Ecovacs app and sends XMPP messages to the robot in order to start cleaning, stop cleaning, recharge and send it commands to move.

The fact that the Deebot uses XMPP makes me wonder if back in the days when we used Jabber in one my previous employers if we could have had a Deebot as a Jabber bot, that’d be really cool.

In order to set up the library’s CLI you need to create a suck.conf file which contains the following data:

  • email — The email address you use to login to the Ecovacs app
  • password_hash — A md5 hash of the password you use to login to the Ecovacs app
  • device_id — A md5 hash of the timestamp used when logging in
  • country — The two character code for your country
  • continent — The two character code for your continent ( ww also available if you can’t get things to work)

There is a sucks login command that will automatically generate this file for you but there’s currently a bug for UK users where Sucks uses http://ipinfo.io/json to get the country code which returns gb but Ecovacs expects uk so I had to create this myself.

Using the sucks CLI you can:

  • Use sucks clean which will clean similar to the ‘standard mode’ in the Ecovacs app
  • Use sucks edge which will clean similar to the ‘edge mode’ in the Ecovacs app
  • Use sucks charge which will send the robot back to the charger
  • Use sucks stop which will stop the robot at it’s current position

If you want finer control over the Deebot then you’ll need to create a Python script which uses Sucks as a library, as doing so gives access to all the XMPP commands.

Gotchas

I ended up having to use the https://github.com/bmartin5692/sucks fork of sucks to successfully interact with my Deebot 500, the library from PyPi would throw the following error when issuing commands:

1<error type="wait" code="404"><recipient-unavailable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" /></error>

The sucks.conf is only necessary for working with the CLI so if you’re having issues with the CLI but know the information you need to send, it might be easier to just write a Python script and keep the config values there.

Using Sucks to send commands to Deebot

Interacting with your Deebot via the API is pretty straightforward, you log into the Ecovacs API, get a list of devices and then create an VacBot instance for the device you want to control:

1from sucks import *
2
3config = {
4 'device_id': EcoVacsAPI.md5(str(time.time())),
5 'email': '', # Email you use to login to Ecovacs
6 'password_hash': EcoVacsAPI.md5(''), # Password you use to login to Ecovacs
7 'country': '', # Two character country code
8 'continent': '' # Two character continent code, can you ww if have issues
9}
10
11api = EcoVacsAPI(
12 config['device_id'],
13 config['email'],
14 config['password_hash'],
15 config['country'],
16 config['continent']
17)
18
19vacs = api.devices()
20my_vac = vacs[0] # Assuming we want to get the first Deebot
21
22vacbot = VacBot(
23 api.uid,
24 api.REALM,
25 api.resource,
26 api.user_access_token,
27 my_vac,
28 config['continent']
29)
30vacbot.connect_and_wait_until_ready()
Getting an instance of the Deebot you can send commands to

Once you’ve got your VacBot instance you can then use the following methods and properties to get information from the Deebot and send commands to it:

  • refresh_statuses() — Get the statuses for cleaning, charging from the server
  • refresh_components() — Get the components lifespan values from the server
  • charge_status — Returns the charging status of the Deebot (requires refresh_statuses to be called first)
  • battery_status — Returns the battery charge status as a float (0–1 range)
  • components — Returns the lifespan values of the Deebot’s components in days (requires refresh_components to be called first)
  • run() — Tell the Deebot to execute an action such as Clean , Charge , Stop , Move

Actions that can be used with run

The run() method is a wrapper around the XML payloads that get sent via XMPP, the other properties and methods are calling run() with preset arguments but there’s a few that you can send that aren’t in that list.

run() takes an instance of a subclass of VacBotCommand as it’s argument, the following objects are available:

  • Clean — Start cleaning in standard mode
  • Edge — Start cleaning in edge mode
  • Spot — Start cleaning in spot mode
  • Stop — Stop the Deebot in it’s current position
  • Charge — Send the Deebot back to the charger
  • Move — Manually move the Deebot, takes the following options: forward , left , right , turnaround , stop
  • PlaySound — Make the Deebot play a sound
  • GetCleanState — Get the cleaning status
  • GetChargeState — Get the charging status
  • GetBatteryState — Get the battery status
  • GetLifeSpan — Get the lifespan of a component, takes the following options: side_brush , main_brush , filter
  • SetTime — Set the time and timezone of the Deebot, takes a timestamp and timezone

An example script of using run() to start the Deebot cleaning on high in standard mode can be found below:

1from sucks import *
2
3config = {
4 'device_id': EcoVacsAPI.md5(str(time.time())),
5 'email': '', # Email you use to login to Ecovacs
6 'password_hash': EcoVacsAPI.md5(''), # Password you use to login to Ecovacs
7 'country': '', # Two character country code
8 'continent': '' # Two character continent code, can you ww if have issues
9}
10
11api = EcoVacsAPI(
12 config['device_id'],
13 config['email'],
14 config['password_hash'],
15 config['country'],
16 config['continent']
17)
18
19vacs = api.devices()
20my_vac = vacs[0] # Assuming we want to get the first Deebot
21
22vacbot = VacBot(
23 api.uid,
24 api.REALM,
25 api.resource,
26 api.user_access_token,
27 my_vac,
28 config['continent']
29)
30vacbot.connect_and_wait_until_ready()
31vacbot.run(Clean(speed='high'))
The run command takes a Clean action which has a speed kwarg that can be used to set the power the vacuum cleans with

A failed experiment

My girlfriend acting as hand model

Once I had got past all the issues getting Sucks set up and was able to send commands to the Deebot I had an idea — I could use a Playstation 4 controller and the Move commands to essentially turn cleaning into a game.

I set up a simple PyGame script to capture the controller’s D-Pad input and then mapped those buttons to forward , left , right and turnaround but unfortunately it looks like my Deebot 500 doesn’t support the Move command.

This meant that the premise of holding a Deebot Robot Wars was no longer viable so I instead refactored the script to map the X button to start cleaning, Circle to stop cleaning. Square to play a sound and Triangle to send the Deebot back to charging.

1import pygame
2
3# Standard set up for the sucks API with VacBot instance set to vacbot variable
4
5pygame.init()
6controller = pygame.joystick.Joystick(0)
7controller.init()
8
9# buttons x =1, square = 0, triangle = 3, circle = 2
10# d-pad up = (0, 1), down (0, 1), right = (1, 0), left = (-1, 0)
11
12while True:
13 for event in pygame.event.get():
14 if event.type == pygame.JOYBUTTONUP:
15 if event.button == 0:
16 vacbot.run(PlaySound())
17 if event.button == 1:
18 vacbot.run(Clean())
19 if event.button == 2:
20 vacbot.run(Stop())
21 if event.button == 3:
22 vacbot.run(Charge())
Sucks setup not included for brevity, there’s not much needed to get this experiment working

Summary

While my Deebot model only supports the basic commands it was really fun to lose an hour or so hooking up a PS4 controller to send commands to the Deebot.

I’m not sure of how compatible all the models of Deebot are so I can’t say which models support the Move commands but having that amount of control would open a whole range of cleaning options as you could create routes in code and execute them as a set of scripts.

If I ever get my Linux machine up and running again I’ll most likely also look to create some form of Conky script to display the stats on my desktop as this information would be cool to see.