mirror of
https://github.com/mitchellrj/eufy_robovac.git
synced 2025-11-25 20:52:41 +00:00
More detail and sync-friendly options
This commit is contained in:
@@ -16,43 +16,53 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from .property import DeviceProperty, StringEnum
|
||||||
from .tuya import TuyaDevice
|
from .tuya import TuyaDevice
|
||||||
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class WorkMode:
|
class WorkMode(StringEnum):
|
||||||
AUTO = 'auto'
|
AUTO = 'auto'
|
||||||
NO_SWEEP = 'Nosweep'
|
NO_SWEEP = 'Nosweep'
|
||||||
SMALL_ROOM = 'SmallRoom'
|
SMALL_ROOM = 'SmallRoom'
|
||||||
EDGE = 'Edge'
|
EDGE = 'Edge'
|
||||||
Spot = 'Spot'
|
SPOT = 'Spot'
|
||||||
|
|
||||||
|
|
||||||
class Direction:
|
class Direction(StringEnum):
|
||||||
LEFT = 'left'
|
LEFT = 'left'
|
||||||
RIGHT = 'right'
|
RIGHT = 'right'
|
||||||
FORWARD = 'forward'
|
FORWARD = 'forward'
|
||||||
BACKWARD = 'backward'
|
BACKWARD = 'backward'
|
||||||
|
|
||||||
|
|
||||||
class WorkStatus:
|
class WorkStatus(StringEnum):
|
||||||
|
RUNNING = 'Running'
|
||||||
CHARGING = 'Charging'
|
CHARGING = 'Charging'
|
||||||
STAND_BY = 'standby'
|
STAND_BY = 'standby'
|
||||||
SLEEPING = 'Sleeping'
|
SLEEPING = 'Sleeping'
|
||||||
RECHARGING = 'Recharge'
|
RECHARGING = 'Recharge'
|
||||||
|
|
||||||
|
|
||||||
class CleanSpeed:
|
class CleanSpeed(StringEnum):
|
||||||
NO_SUCTION = 'No_suction'
|
NO_SUCTION = 'No_suction'
|
||||||
STANDARD = 'Standard'
|
STANDARD = 'Standard'
|
||||||
BOOST_IQ = 'Boost_IQ'
|
BOOST_IQ = 'Boost_IQ'
|
||||||
MAX = 'Max'
|
MAX = 'Max'
|
||||||
|
|
||||||
|
|
||||||
class ErrorCode:
|
class ErrorCode(StringEnum):
|
||||||
pass
|
NO_ERROR = 'no_error'
|
||||||
|
WHEEL_STUCK = 'Wheel_stuck'
|
||||||
|
R_BRUSH_STUCK = 'R_brush_stuck'
|
||||||
|
CRASH_BAR_STUCK = 'Crash_bar_stuck'
|
||||||
|
SENSOR_DIRTY = 'sensor_dirty'
|
||||||
|
NOT_ENOUGH_POWER = 'N_enough_pow'
|
||||||
|
STUCK_5_MIN = 'Stuck_5_min'
|
||||||
|
FAN_STUCK = 'Fan_stuck'
|
||||||
|
S_BRUSH_STUCK = 'S_brush_stuck'
|
||||||
|
|
||||||
|
|
||||||
class Robovac(TuyaDevice):
|
class Robovac(TuyaDevice):
|
||||||
@@ -67,23 +77,34 @@ class Robovac(TuyaDevice):
|
|||||||
FIND_ROBOT = '103'
|
FIND_ROBOT = '103'
|
||||||
BATTERY_LEVEL = '104'
|
BATTERY_LEVEL = '104'
|
||||||
ERROR_CODE = '106'
|
ERROR_CODE = '106'
|
||||||
KEY_NAMES = {
|
|
||||||
PLAY_PAUSE: 'play/pause',
|
|
||||||
DIRECTION: 'direction',
|
|
||||||
WORK_MODE: 'work mode',
|
|
||||||
WORK_STATUS: 'work status',
|
|
||||||
GO_HOME: 'go home',
|
|
||||||
CLEAN_SPEED: 'clean speed',
|
|
||||||
FIND_ROBOT: 'find robot',
|
|
||||||
BATTERY_LEVEL: 'battery level',
|
|
||||||
ERROR_CODE: 'error code'
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
play_pause = DeviceProperty(PLAY_PAUSE)
|
||||||
super().__init__(*args, **kwargs)
|
direction = DeviceProperty(DIRECTION)
|
||||||
|
work_mode = DeviceProperty(WORK_MODE, WorkMode)
|
||||||
|
work_status = DeviceProperty(WORK_STATUS, WorkStatus, True)
|
||||||
|
go_home = DeviceProperty(GO_HOME)
|
||||||
|
clean_speed = DeviceProperty(CLEAN_SPEED, CleanSpeed)
|
||||||
|
find_robot = DeviceProperty(FIND_ROBOT)
|
||||||
|
battery_level = DeviceProperty(BATTERY_LEVEL, read_only=True)
|
||||||
|
error_code = DeviceProperty(ERROR_CODE, ErrorCode, True)
|
||||||
|
|
||||||
|
async def async_play(self, callback=None):
|
||||||
|
await self.async_set({self.PLAY_PAUSE: True}, callback)
|
||||||
|
|
||||||
|
async def async_pause(self, callback=None):
|
||||||
|
await self.async_set({self.PLAY_PAUSE: False}, callback)
|
||||||
|
|
||||||
async def async_start_cleaning(self, callback=None):
|
async def async_start_cleaning(self, callback=None):
|
||||||
await self.async_set({self.WORK_MODE: WorkMode.AUTO}, callback)
|
await self.async_set({self.WORK_MODE: str(WorkMode.AUTO)}, callback)
|
||||||
|
|
||||||
async def async_go_home(self, callback=None):
|
async def async_go_home(self, callback=None):
|
||||||
await self.async_set({self.GO_HOME: True}, callback)
|
await self.async_set({self.GO_HOME: True}, callback)
|
||||||
|
|
||||||
|
async def async_set_work_mode(self, work_mode, callback=None):
|
||||||
|
await self.async_set({self.WORK_MODE: work_mode}, callback)
|
||||||
|
|
||||||
|
async def async_find_robot(self, callback=None):
|
||||||
|
await self.async_set({self.FIND_ROBOT: True}, callback)
|
||||||
|
|
||||||
|
async def async_set_clean_speed(self, clean_speed, callback=None):
|
||||||
|
await self.async_set({self.CLEAN_SPEED: str(clean_speed)}, callback)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ from json.decoder import JSONDecodeError
|
|||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from cryptography.hazmat.backends.openssl import backend as openssl_backend
|
from cryptography.hazmat.backends.openssl import backend as openssl_backend
|
||||||
@@ -156,7 +157,7 @@ class RequestResponseCommandMismatch(TuyaException):
|
|||||||
|
|
||||||
|
|
||||||
class TuyaCipher:
|
class TuyaCipher:
|
||||||
"""The Tuya encryption cipher"""
|
"""Tuya cryptographic helpers."""
|
||||||
|
|
||||||
def __init__(self, key, version):
|
def __init__(self, key, version):
|
||||||
"""Initialize the cipher."""
|
"""Initialize the cipher."""
|
||||||
@@ -218,6 +219,7 @@ class TuyaCipher:
|
|||||||
intermediate = digest.finalize().hex()
|
intermediate = digest.finalize().hex()
|
||||||
return intermediate[8:24]
|
return intermediate[8:24]
|
||||||
|
|
||||||
|
|
||||||
def crc(data):
|
def crc(data):
|
||||||
"""Calculate the Tuya-flavored CRC of some data."""
|
"""Calculate the Tuya-flavored CRC of some data."""
|
||||||
c = 0xFFFFFFFF
|
c = 0xFFFFFFFF
|
||||||
@@ -395,6 +397,22 @@ class Message:
|
|||||||
return cls(command, payload, sequence)
|
return cls(command, payload, sequence)
|
||||||
|
|
||||||
|
|
||||||
|
def _call_async(fn, *args):
|
||||||
|
loop = None
|
||||||
|
if sys.version_info >= (3, 7):
|
||||||
|
try:
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
except RuntimeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
|
def wrapper(fn, *args):
|
||||||
|
asyncio.ensure_future(fn(*args))
|
||||||
|
|
||||||
|
loop.call_soon(wrapper, fn, *args)
|
||||||
|
|
||||||
|
|
||||||
class TuyaDevice:
|
class TuyaDevice:
|
||||||
"""Represents a generic Tuya device."""
|
"""Represents a generic Tuya device."""
|
||||||
|
|
||||||
@@ -438,10 +456,6 @@ class TuyaDevice:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{} ({}:{})".format(self.device_id, self.host, self.port)
|
return "{} ({}:{})".format(self.device_id, self.host, self.port)
|
||||||
|
|
||||||
@property
|
|
||||||
def loop(self):
|
|
||||||
return asyncio.get_running_loop()
|
|
||||||
|
|
||||||
async def async_connect(self, callback=None):
|
async def async_connect(self, callback=None):
|
||||||
sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
|
sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
|
||||||
sock.settimeout(self.timeout)
|
sock.settimeout(self.timeout)
|
||||||
@@ -482,7 +496,10 @@ class TuyaDevice:
|
|||||||
'dps': dps
|
'dps': dps
|
||||||
}
|
}
|
||||||
message = Message(Message.SET_COMMAND, payload, encrypt_for=self)
|
message = Message(Message.SET_COMMAND, payload, encrypt_for=self)
|
||||||
return await message.async_send(self, callback)
|
await message.async_send(self, callback)
|
||||||
|
|
||||||
|
def set(self, dps):
|
||||||
|
_call_async(self.async_set, dps)
|
||||||
|
|
||||||
async def _async_ping(self):
|
async def _async_ping(self):
|
||||||
self.last_ping = time.time()
|
self.last_ping = time.time()
|
||||||
|
|||||||
Reference in New Issue
Block a user