Initial commit

This commit is contained in:
Maurizio Porrato 2019-02-11 08:06:06 +00:00
commit 80d22843cc
3 changed files with 286 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*~
*%
*.py[co]

168
eufy.py Executable file
View File

@ -0,0 +1,168 @@
#!/usr/bin/env python3
import click
from datetime import datetime
class EufyRawIR:
""" Low level IR signal modulation """
_IR_PREAMBLE = (3000, 3000)
_IR_0 = (400, 600)
_IR_1 = (400, 1600)
_IR_TRAILER = (400, 20000)
def _modulate(self, message):
signal = list(self._IR_PREAMBLE)
for b in message:
for i in range(8):
if (b << i) & 0x80:
signal.extend(list(self._IR_1))
else:
signal.extend(list(self._IR_0))
signal.extend(list(self._IR_TRAILER))
return 3*signal
def sendRaw(self, message):
print(self._modulate(message))
class EufyIR(EufyRawIR):
""" High level Eufy commands """
_HEADER = 0x68
CLEAN_AUTO = 0x5d
CLEAN_SPOT = 0x8c
CLEAN_EDGE = 0x9c
CLEAN_ROOM = 0xad
STOP = 0x4f
POWER_MAX = 0x1c
POWER_BOOSTIQ = 0x1d
POWER_STANDARD = 0x1e
MOVE_FORWARD = 0x2f
MOVE_BACKWARD = 0x7f
MOVE_CCW = 0x3f
MOVE_CW = 0x6f
SET_TIME = 0xbf
SET_SCHEDULE = 0xcf
CANCEL_SCHEDULE = 0xdf
RETURN_BASE = 0xef
def __init__(self):
self._schedule = 0xff
def _message(self, code):
now = datetime.now()
msg = [self._HEADER, code, now.hour, now.minute, self._schedule]
checksum = sum(msg) & 0xff
msg.append(checksum)
return msg
def send(self, code):
self.sendRaw(self._message(code))
def cleanAuto(self):
self.send(self.CLEAN_AUTO)
def cleanSpot(self):
self.send(self.CLEAN_SPOT)
def cleanEdge(self):
self.send(self.CLEAN_EDGE)
def cleanRoom(self):
self.send(self.CLEAN_ROOM)
def start(self):
self.cleanAuto()
def stop(self):
self.send(self.STOP)
def powerMax(self):
self.send(self.POWER_MAX)
def powerBoostIQ(self):
self.send(self.POWER_BOOSTIQ)
def powerStandard(self):
self.send(self.POWER_STANDARD)
def moveForward(self):
self.send(self.MOVE_FORWARD)
def moveBackward(self):
self.send(self.MOVE_BACKWARD)
def moveCCW(self):
self.send(self.MOVE_CCW)
def moveLeft(self):
self.moveCCW()
def moveCW(self):
self.send(self.MOVE_CW)
def moveRight(self):
self.moveCW()
def setTime(self):
self.send(self.SET_TIME)
def setSchedule(self, t):
# FIXME: properly store schedule
self.send(self.SET_SCHEDULE, t)
def cancelSchedule(self):
# FIXME: properly store schedule
self.send(self.CANCEL_SCHEDULE)
def returnBase(self):
self.send(self.RETURN_BASE)
@click.group()
def cli():
pass
@cli.command()
@click.argument('mode', required=False,
type=click.Choice(['auto', 'spot', 'edge', 'room']))
def clean(mode):
eufy = EufyIR()
dict(
auto=eufy.cleanAuto,
spot=eufy.cleanSpot,
edge=eufy.cleanEdge,
room=eufy.cleanRoom
).get(mode, eufy.start)()
@cli.command()
@click.argument('mode', required=True,
type=click.Choice(['standard', 'boostiq', 'max']))
def power(mode):
eufy = EufyIR()
{
'standard': eufy.powerStandard,
'boostiq': eufy.powerBoostIQ,
'max': eufy.powerMax
}.get(mode)()
@cli.command()
@click.argument('mode', required=True,
type=click.Choice(['forward', 'backward', 'ccw', 'cw', 'left', 'right']))
def move(mode):
eufy = EufyIR()
dict(
forward=eufy.moveForward,
backward=eufy.moveBackward,
ccw=eufy.moveCCW,
cw=eufy.moveCW,
left=eufy.moveLeft,
right=eufy.moveRight
).get(mode)()
if __name__ == '__main__':
cli()

115
protocol.txt Normal file
View File

@ -0,0 +1,115 @@
AGC: H:3ms L:3ms
0: H:400µs L:600µs
1: H:400µs L:1.6ms
Frame: (AGC+48bits+H:400µs+L:20ms)*3
Format: 68CCHHMMSSKK
CC: command
HH: hour
MM: minute
SS: schedule (in quarters of an hour from midnight, 0xff=off)
KK: checksum (sum of all bytes in the frame modulo 256)
Code | Command
------+---------
1c | Max power
1d | BoostIQ
1e | Standard power
2f | Forward
3f | Turn CCW
4f | Stop cleaning
5d | Auto cleaning
6f | Turn CW
7f | Backward
8c | Spot cleaning
9c | Edge cleaning
ad | Room cleaning
bf | Set time
cf | Set schedule
df | Clear schedule
ef | Return to base
0110 1000 0101 1101 0000 1111 0010 0111 0010 1000 0010 0011 Start
685d0f272823
0110 1000 0100 1111 0000 1111 0010 0111 0010 1000 0001 0101 Stop
684f0f272815
0110 1000 0101 1101 0001 0001 0000 0010 0010 1000 0000 0000 Start
685d11022800
0110 1000 0100 1111 0001 0001 0000 0010 0010 1000 1111 0010 Stop
684f110228f2
0110 1000 1011 1111 0001 0001 0010 0100 0010 1000 1000 0100 Time (5:36pm)
68bf11242884
0110 1000 1011 1111 0001 0001 0010 1011 0010 1000 1000 1011 Time (5:43pm)
68bf112b288b
0110 1000 1011 1111 0001 0001 0010 1011 0010 1000 1000 1011 Time (5:43pm +1.3s)
68bf112b288b
0110 1000 1011 1111 0001 0010 0000 0110 0010 1000 0110 0111 Time (T:6:06pm A:10:00am)
68bf12062867
HHMM
0110 1000 0101 1101 0001 0010 0000 0110 0010 1000 0000 0101 Start
685d12062805
0110 1000 0100 1111 0001 0010 0000 0110 0010 1000 1111 0111 Stop (start+0.9s)
684f120628f7
0110 1000 1100 1111 0001 0011 0010 0000 0010 1000 1001 0010 Schedule 10:00am
68cf13202892
0110 1000 1100 1111 0001 0011 0010 1011 0010 1001 1001 1110 Schedule 10:15am
68cf132b299e
0110 1000 1100 1111 0001 0011 0011 0000 0101 1111 1101 1001 Schedule 11:45pm
68cf13305fd9
0110 1000 1101 1111 0001 0011 0011 0110 1111 1111 1000 1111 Schedule off
68df1336ff8f
0110 1000 0101 1101 0001 0100 0000 0110 1111 1111 1101 1110 Start
685d1406ffde
0110 1000 0100 1111 0001 0100 0001 0010 1111 1111 1101 1100 Auto
684f1412ffdc
0110 1000 0001 1100 0001 0100 0001 1001 1111 1111 1011 0000 Power (BoostIQ->Max)
681c1419ffb0
0110 1000 0001 1110 0001 0100 0001 1110 1111 1111 1011 0111 Power (Max->Standard)
681e141effb7
0110 1000 0001 1101 0001 0100 0001 1110 1111 1111 1011 0110 Power (Standard->BoostIQ)
681d141effb6
0110 1000 0010 1111 0001 0100 0010 1110 1111 1111 1101 1000 Up
682f142effd8
0110 1000 0111 1111 0001 0100 0010 1110 1111 1111 0010 1000 Down
687f142eff28
0110 1000 0011 1111 0001 0100 0010 1110 1111 1111 1110 1000 Left
683f142effe8
0110 1000 0110 1111 0001 0100 0010 1110 1111 1111 0001 1000 Right
686f142eff18
0110 1000 1000 1100 0001 0101 0000 0100 1111 1111 0000 1100 Spot
688c1504ff0c
0110 1000 1001 1100 0001 0101 0000 1000 1111 1111 0010 0000 Edge
689c1508ff20
0110 1000 1010 1101 0001 0101 0000 1100 1111 1111 0011 0101 Room
68ad150cff35
0110 1000 1110 1111 0001 0101 0001 0000 1111 1111 0111 1011 Base
68ef1510ff7b