44until the API is stable.
55"""
66
7- import enum
87import logging
9- from collections .abc import Callable
10- from functools import cached_property
11-
12- from roborock .containers import (
13- HomeDataDevice ,
14- HomeDataProduct ,
15- ModelStatus ,
16- S7MaxVStatus ,
17- Status ,
18- UserData ,
19- )
8+ from abc import ABC
9+ from collections .abc import Callable , Mapping
10+ from types import MappingProxyType
11+
12+ from roborock .containers import HomeDataDevice
2013from roborock .roborock_message import RoborockMessage
21- from roborock .roborock_typing import RoborockCommand
2214
23- from .v1_channel import V1Channel
15+ from .channel import Channel
16+ from .traits .trait import Trait
2417
2518_LOGGER = logging .getLogger (__name__ )
2619
2720__all__ = [
2821 "RoborockDevice" ,
29- "DeviceVersion" ,
3022]
3123
3224
33- class DeviceVersion (enum .StrEnum ):
34- """Enum for device versions."""
35-
36- V1 = "1.0"
37- A01 = "A01"
38- UNKNOWN = "unknown"
39-
25+ class RoborockDevice (ABC ):
26+ """A generic channel for establishing a connection with a Roborock device.
4027
41- class RoborockDevice :
42- """Unified Roborock device class with automatic connection setup."""
28+ Individual channel implementations have their own methods for speaking to
29+ the device that hide some of the protocol specific complexity, but they
30+ are still specialized for the device type and protocol.
31+ """
4332
4433 def __init__ (
4534 self ,
46- user_data : UserData ,
4735 device_info : HomeDataDevice ,
48- product_info : HomeDataProduct ,
49- v1_channel : V1Channel ,
36+ channel : Channel ,
37+ traits : list [ Trait ] ,
5038 ) -> None :
5139 """Initialize the RoborockDevice.
5240
5341 The device takes ownership of the V1 channel for communication with the device.
5442 Use `connect()` to establish the connection, which will set up the appropriate
5543 protocol channel. Use `close()` to clean up all connections.
5644 """
57- self ._user_data = user_data
58- self ._device_info = device_info
59- self ._product_info = product_info
60- self ._v1_channel = v1_channel
45+ self ._duid = device_info .duid
46+ self ._name = device_info .name
47+ self ._channel = channel
6148 self ._unsub : Callable [[], None ] | None = None
49+ self ._trait_map = {trait .name : trait for trait in traits }
6250
6351 @property
6452 def duid (self ) -> str :
6553 """Return the device unique identifier (DUID)."""
66- return self ._device_info . duid
54+ return self ._duid
6755
6856 @property
6957 def name (self ) -> str :
7058 """Return the device name."""
71- return self ._device_info .name
72-
73- @cached_property
74- def device_version (self ) -> str :
75- """Return the device version.
76-
77- At the moment this is a simple check against the product version (pv) of the device
78- and used as a placeholder for upcoming functionality for devices that will behave
79- differently based on the version and capabilities.
80- """
81- if self ._device_info .pv == DeviceVersion .V1 .value :
82- return DeviceVersion .V1
83- elif self ._device_info .pv == DeviceVersion .A01 .value :
84- return DeviceVersion .A01
85- _LOGGER .warning (
86- "Unknown device version %s for device %s, using default UNKNOWN" ,
87- self ._device_info .pv ,
88- self ._device_info .name ,
89- )
90- return DeviceVersion .UNKNOWN
59+ return self ._name
9160
9261 @property
9362 def is_connected (self ) -> bool :
9463 """Return whether the device is connected."""
95- return self ._v1_channel . is_mqtt_connected or self . _v1_channel . is_local_connected
64+ return self ._channel . is_connected
9665
9766 async def connect (self ) -> None :
9867 """Connect to the device using the appropriate protocol channel."""
9968 if self ._unsub :
10069 raise ValueError ("Already connected to the device" )
101- self ._unsub = await self ._v1_channel .subscribe (self ._on_message )
70+ self ._unsub = await self ._channel .subscribe (self ._on_message )
10271 _LOGGER .info ("Connected to V1 device %s" , self .name )
10372
10473 async def close (self ) -> None :
@@ -111,10 +80,7 @@ def _on_message(self, message: RoborockMessage) -> None:
11180 """Handle incoming messages from the device."""
11281 _LOGGER .debug ("Received message from device: %s" , message )
11382
114- async def get_status (self ) -> Status :
115- """Get the current status of the device.
116-
117- This is a placeholder command and will likely be changed/moved in the future.
118- """
119- status_type : type [Status ] = ModelStatus .get (self ._product_info .model , S7MaxVStatus )
120- return await self ._v1_channel .rpc_channel .send_command (RoborockCommand .GET_STATUS , response_type = status_type )
83+ @property
84+ def traits (self ) -> Mapping [str , Trait ]:
85+ """Return the traits of the device."""
86+ return MappingProxyType (self ._trait_map )
0 commit comments