Protocol documentation updated

This commit is contained in:
Torbjörn Axelsson
2017-12-07 21:10:23 -08:00
parent 3479d4a116
commit cc6c3bde19
+121 -68
View File
@@ -1,20 +1,28 @@
There are two protocols involved here. There are a series of HTTPS requests
# Ecovacs Protocol
There are two protocols involved in the communication between the client and Ecovacs systems. There are a series of HTTPS requests
used to log in and find devices. Once logged in, you get a token that is
used to connect to an XMPP server, which mediates communication with the
vacuum. That's right, your robot housecleaner, like an errant teen, spends
all its free time hanging out in an internet chat room.
This is all taken from MITMing the Android app. The protocol is quirky
enough that I wouldn't be shocked if the iPhone app does it differently.
This is all taken from MITMing the Android app. The iOS app appears to
follow the same protocol conventions.
## Location
It appears that Ecovacs have broken up their API servers by location. Some
are designated by country, others by continent. All appear to use the
two-letter ISO codes, but at this time it doesn't look like all codes
map to valid servers. If you're in, say, Australia and are trying to
get this to work, I'd love a packet capture of DNS requests to see what
the app does there.
map to valid servers.
The HTTPS and XMPP servers do not appear to be following the same convention.
For example, a Canadian user must authenticate on country-specific HTTPS
server, but XMPP commands work both on the worldwide server
msg-ww.ecouser.net) and the North America server (msg-na.ecouser.net)
## HTTPS
@@ -53,76 +61,121 @@ vacuum via XMPP
## XMPP
The Android app establishes a connection to an XMPP server and logs in using
a secret that comes from the earlier HTTPS calls. It then sends XMPP IQ commands.
It describes
them as queries, but they all contain "ctl" elements that appear to be commands. Here are a couple of full
examples with the private information removed:
The app establishes a connection to an XMPP server and logs in using
a secret that comes from the earlier HTTPS calls. It then sends XMPP IQ
commands. It describes them as queries, but they all contain "ctl"
elements that appear to be commands.
A clean command:
```
<iq id="TXID" to="ROBOTID@MODELID.ecorobot.net/atom" from="USERID@ecouser.net/RESOURCEID" type="set"><query xmlns="com:ctl"><ctl td="Clean"><clean type="auto" speed="standard"/></ctl></query></iq>
### Cleaning
**Command**
- `<ctl td="Clean"><clean type="auto" speed="standard"/></ctl>`
**State**
- **Request** `<ctl td="GetCleanState" />`
- **Response** `<ctl td="CleanReport"><clean type="stop" speed="standard" /></ctl>`
- type `auto` automatic cleaning program
- type `border` edge cleaning program
- type `singleroom` cleaning a single room
- type `stop` bot at full stop
- speed `standard` regular fan speed (suction)
- speed `strong` high fan speed (suction)
### Charging
**Command**
- `<query xmlns="com:ctl"><ctl td="Charge"><charge type="go"/></ctl>`
- `go` order bot to return to charger
- *Request* `<query xmlns="com:ctl"><ctl td="GetChargeState" />`
- *Response* `<ctl td="ChargeState"><charge type="SlotCharging" /></ctl>`
- `Idle` not trying to charge
- `Going` trying to return to charger
- `SlotCharging` currently charging in dock
- `WireCharging` currently charging by cable
*Note: It appears the bot can be in an active CleanState (i.e. auto) as well as in an active ChargeState (i.e. SlotCharging). The assumption is that in this case, the cleaning task will resume after the bot is sufficiently charged. More testing is needed.*
### Battery State
Battery charge level. 080 = 80% charged.
- *Request* `<ctl td="GetBatteryInfo" />`
- *Response* `<ctl td="BatteryInfo"><battery power="080" /></ctl>`
### Component lifespan
The remaining lifespan of components. Based on an internal counters
that can be reset with command ResetLifeSpan (untested).
It's presumed that the timers need to be reset manually.
- *Request* `<ctl td="GetLifeSpan" type="Brush" />`
- *Response* `<ctl td="LifeSpan" type="Brush" val="095" total="365" />`
- Brush
- SideBrush
- DustCaseHeap
### Manually moving around
To stop the current action, issue the stop action.
**Command**
- `<ctl td="Move"><move action="forward"/></ctl>`
- `<ctl td="Move"><move action="SpinLeft"/></ctl>`
- `<ctl td="Move"><move action="SpinRight"/></ctl>`
- `<ctl td="Move"><move action="stop"/></ctl>`
- `<ctl td="Move"><move action="TurnAround"/></ctl>`
### Errors
The bot broadcasts error codes for a number of cases.
`<ctl td="error" error="BatteryLow" errno="101"></ctl>`
The latest error can be requested like so:
- **Request** `<ctl td="GetError" />`
- **Response** `<ctl ret="ok" errs="100"/>`
However in some cases the robot sends to code 100 shortly
after an error has occurred, meaning that we cannot trust
the GetError request to contain the last error.
For example, if the robot gets stuck it broadcasts 102
HostHang, thenproceeds to stop and broadcasts 100 NoError.
**Known error codes**
- 100 NoError (back to normal)
- 101 BatteryLow
- 102 HostHang (bot is stuck)
- 103 WheelAbnormal
- 104 DownSensorAbnormal
### Untested commands
```
<ctl td="GetOnOff" />
<ctl id="102461185" ret="ok" on="0"/>
A charge command:
```
<iq id="TXID" to="ROBOTID@MODELID.ecorobot.net/atom" from="USERID@ecouser.net/RESOURCEID" type="set"><query xmlns="com:ctl"><ctl td="Charge"><charge type="go"/></ctl></query></iq>
```
Focusing on the core ctl elements, this is a sampling of commands seen on the wire after punching all the app buttons:
```
<ctl id="12351409" td="PlaySound" sid="0"/>
<ctl id="13259797" td="SetTime"><time t="1509622697" tz="-7"/></ctl>
<ctl id="30800321" td="GetSched"/>
<ctl td="Charge"><charge type="go"/></ctl>
<ctl td="Clean"><clean type="auto" speed="standard"/></ctl>
<ctl td="Clean"><clean type="border" speed="strong"/></ctl>
<ctl td="Clean"><clean type="singleRoom" speed="standard"/></ctl>
<ctl td="Clean"><clean type="spot" speed="strong"/></ctl>
<ctl td="Clean"><clean type="stop" speed="standard"/></ctl>
<ctl td="GetBatteryInfo"/>
<ctl td="GetChargeState"/>
<ctl td="GetCleanState"/>
<ctl td="GetLifeSpan" type="Brush"/>
<ctl td="GetLifeSpan" type="DustCaseHeap"/>
<ctl td="GetLifeSpan" type="SideBrush"/>
<ctl td="Move"><move action="forward"/></ctl>
<ctl td="Move"><move action="SpinLeft"/></ctl>
<ctl td="Move"><move action="SpinRight"/></ctl>
<ctl td="Move"><move action="stop"/></ctl>
<ctl td="Move"><move action="TurnAround"/></ctl>
```
It appears that it adds an extra id when it cares to receive a specific response. This is a little odd in that
the iq blocks already contain ids, but perhaps one is more a server id and the other is used by the robot itself.
Here are some assorted responses from that session:
```
<ctl td="BatteryInfo"><battery power="095"/></ctl>
<ctl td="ChargeState"><charge type="going"/></ctl>
<ctl td="ChargeState"><charge type="Going"/></ctl>
<ctl td="ChargeState"><charge type="Idle"/></ctl>
<ctl td="ChargeState"><charge type="SlotCharging"/></ctl>
<ctl td="CleanReport"><clean type="auto"/></ctl>
<ctl td="CleanReport"> <clean type="auto" speed="strong"/> </ctl>
<ctl td="CleanReport"><clean type="border"/></ctl>
<ctl td="CleanReport"> <clean type="border" speed="strong"/> </ctl>
<ctl td="CleanReport"><clean type="singleRoom"/></ctl>
<ctl td="CleanReport"> <clean type="singleRoom" speed="strong"/> </ctl>
<ctl td="CleanReport"><clean type="spot"/></ctl>
<ctl td="CleanReport"> <clean type="spot" speed="strong"/> </ctl>
<ctl td="CleanReport"><clean type="stop"/></ctl>
<ctl td="LifeSpan" type="Brush" val="099" total="365"/>
<ctl td="LifeSpan" type="DustCaseHeap" val="098" total="365"/>
<ctl td="LifeSpan" type="SideBrush" val="098" total="365"/>
<ctl td="Sched2"/>
<ctl td="Sched2" id="30800321"/>
```
I don't totally get the relationship between the duplicate-ish items here, like the various clean reports,
or the charge type differences, but I'll try to come back after rummaging through the logs further.
It appears that it adds an extra id when it cares to receive a specific response.
This is a little odd in that the iq blocks already contain ids, but perhaps one
is more a server id and the other is used by the robot itself.