Skip to content

Commit b2f2f15

Browse files
fix: local_api should receive ip for each device
1 parent a010304 commit b2f2f15

File tree

5 files changed

+76
-16
lines changed

5 files changed

+76
-16
lines changed

roborock/api.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
RoborockDeviceProp,
4343
RoborockCommand,
4444
RoborockDockSummary,
45+
RoborockDeviceInfo,
4546
)
4647

4748
_LOGGER = logging.getLogger(__name__)
@@ -92,8 +93,8 @@ async def request(
9293

9394
class RoborockClient:
9495

95-
def __init__(self, endpoint: str, device_localkey: dict[str, str]) -> None:
96-
self.device_localkey = device_localkey
96+
def __init__(self, endpoint: str, devices_info: dict[str, RoborockDeviceInfo]) -> None:
97+
self.devices_info = devices_info
9798
self._seq = 1
9899
self._random = 4711
99100
self._id_counter = 10000
@@ -146,7 +147,7 @@ def _decode_msg(self, msg: bytes, local_key: str) -> dict[str, Any]:
146147
}
147148

148149
def _encode_msg(self, device_id, request_id, protocol, timestamp, payload, prefix=None) -> bytes:
149-
local_key = self.device_localkey[device_id]
150+
local_key = self.devices_info[device_id].device.local_key
150151
aes_key = md5bin(encode_timestamp(timestamp) + local_key + self._salt)
151152
cipher = AES.new(aes_key, AES.MODE_ECB)
152153
encrypted = cipher.encrypt(pad(payload, AES.block_size))
@@ -172,7 +173,7 @@ def _encode_msg(self, device_id, request_id, protocol, timestamp, payload, prefi
172173

173174
async def on_message(self, device_id, msg) -> bool:
174175
try:
175-
data = self._decode_msg(msg, self.device_localkey[device_id])
176+
data = self._decode_msg(msg, self.devices_info[device_id].device.local_key)
176177
protocol = data.get("protocol")
177178
if protocol == 102 or protocol == 4:
178179
payload = json.loads(data.get("payload").decode())

roborock/containers.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,14 @@ class WashTowelField(str, Enum):
229229
Wash_MODE = "wash_mode"
230230

231231

232+
class NetworkInfoField(str, Enum):
233+
SSID = "ssid"
234+
IP = "ip"
235+
MAC = "mac"
236+
BSSID = "bssid"
237+
RSSI = "rssi"
238+
239+
232240
class RoborockBase(dict):
233241
def __init__(self, data: dict[str, any]) -> None:
234242
super().__init__()
@@ -1044,3 +1052,23 @@ def smart_wash(self) -> int:
10441052
@property
10451053
def wash_interval(self) -> int:
10461054
return self.get(SmartWashField.WASH_INTERVAL)
1055+
1056+
class NetworkInfo(RoborockBase):
1057+
def __init__(self, data: dict[str, any]) -> None:
1058+
super().__init__(data)
1059+
1060+
@property
1061+
def ssid(self) -> str:
1062+
return self.get(NetworkInfoField.SSID)
1063+
@property
1064+
def ip(self) -> str:
1065+
return self.get(NetworkInfoField.IP)
1066+
@property
1067+
def mac(self) -> str:
1068+
return self.get(NetworkInfoField.MAC)
1069+
@property
1070+
def bssid(self) -> str:
1071+
return self.get(NetworkInfoField.BSSID)
1072+
@property
1073+
def rssi(self) -> int:
1074+
return self.get(NetworkInfoField.RSSI)

roborock/local_api.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
import asyncio
44
import logging
55
import socket
6-
from asyncio import Lock
6+
from asyncio import Lock, Future
77
from typing import Callable, Coroutine, Any
88

99
import async_timeout
1010

1111
from roborock.api import RoborockClient, SPECIAL_COMMANDS
1212
from roborock.exceptions import RoborockTimeout, CommandVacuumError
13-
from roborock.typing import RoborockCommand
13+
from roborock.typing import RoborockCommand, RoborockDeviceInfo
1414
from roborock.util import get_running_loop_or_create_one
1515

1616
secured_prefix = 199
@@ -21,13 +21,26 @@
2121
_LOGGER = logging.getLogger(__name__)
2222

2323

24+
class RoborockProtocol(asyncio.DatagramProtocol):
25+
26+
def __init__(self, fut: Future):
27+
self.fut = fut
28+
29+
def datagram_received(self, data, addr):
30+
self.fut.set_result((data, addr))
31+
32+
def error_received(self, exc):
33+
self.fut.set_exception(exc)
34+
35+
2436
class RoborockLocalClient(RoborockClient):
2537

26-
def __init__(self, ip: str, device_localkey: dict[str, str]):
27-
super().__init__("abc", device_localkey)
38+
def __init__(self, devices_info: dict[str, RoborockDeviceInfo]):
39+
super().__init__("abc", devices_info)
40+
self.loop = get_running_loop_or_create_one()
2841
self.device_listener: dict[str, RoborockSocketListener] = {
29-
device_id: RoborockSocketListener(ip, device_id, self.on_message)
30-
for device_id in device_localkey
42+
device_id: RoborockSocketListener(device_info.network_info.ip, device_id, self.on_message)
43+
for device_id, device_info in devices_info.items()
3144
}
3245
self._mutex = Lock()
3346

roborock/offline/offline.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,30 @@
11
import asyncio
22
import logging
33

4+
from roborock.containers import HomeDataDevice, HomeDataDeviceField, HomeDataProduct, HomeDataProductField, NetworkInfo, \
5+
NetworkInfoField
46
from roborock.local_api import RoborockLocalClient
7+
from roborock.typing import RoborockDeviceInfo
58

6-
local_ip = "<local_ip>"
7-
local_key = "<local_key>"
9+
local_ip = "192.168.1.232"
10+
local_key = "nXTBj42ej5WxQopO"
11+
device_id = "1r9W0cAmDZ2COuVekgRhKA"
812

913

1014
async def main():
1115
logging_config = {
1216
"level": logging.DEBUG
1317
}
1418
logging.basicConfig(**logging_config)
15-
device_id = "1r9W0cAmDZ2COuVekgRhKA"
16-
client = RoborockLocalClient(local_ip, {
17-
"1r9W0cAmDZ2COuVekgRhKA": local_key
19+
client = RoborockLocalClient({
20+
device_id: RoborockDeviceInfo(HomeDataDevice({
21+
HomeDataDeviceField.DUID: device_id,
22+
HomeDataDeviceField.LOCAL_KEY: local_key
23+
}), HomeDataProduct({
24+
HomeDataProductField.MODEL: "test"
25+
}), NetworkInfo({
26+
NetworkInfoField.IP: local_ip
27+
}))
1828
})
1929
await client.async_connect()
2030
props = await client.get_prop(device_id)

roborock/typing.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
from __future__ import annotations
2+
13
from enum import Enum
24

35
from .code_mappings import RoborockDockDustCollectionType, RoborockDockWashingModeType
46
from .containers import Status, CleanSummary, Consumable, \
5-
DNDTimer, CleanRecord, SmartWashParameters
7+
DNDTimer, CleanRecord, SmartWashParameters, HomeDataDevice, HomeDataProduct, NetworkInfo
68

79

810
class RoborockDevicePropField(str, Enum):
@@ -84,7 +86,13 @@ class RoborockCommand(str, Enum):
8486
SET_SERVER_TIMER = "set_server_timer"
8587
APP_GET_INIT_STATUS = "get_init_status"
8688
SET_APP_TIMEZONE = "set_app_timezone"
89+
GET_NETWORK_INFO = "get_network_info"
8790

91+
class RoborockDeviceInfo:
92+
def __init__(self, device: HomeDataDevice, product: HomeDataProduct, network_info: NetworkInfo = None):
93+
self.device = device
94+
self.product = product
95+
self.network_info: NetworkInfo | None = network_info
8896

8997
class RoborockDockSummary:
9098
def __init__(self, dust_collection_mode: RoborockDockDustCollectionType,

0 commit comments

Comments
 (0)