1818CMD_LOGIN = 15
1919CMD_LOGOUT = 16
2020CMD_DEVICES = 123
21+ CMD_DOWNSTREAM = 10
22+ CMD_UPSTREAM = 11
2123
2224
2325@attr .s
@@ -29,6 +31,40 @@ class Device:
2931 ip : Union [IPv4Address , IPv6Address ] = attr .ib (cmp = False , convert = convert_ip )
3032
3133
34+ @attr .s
35+ class DownstreamChannel :
36+ """A locked downstream channel."""
37+
38+ frequency : int = attr .ib ()
39+ powerLevel : int = attr .ib ()
40+ modulation : str = attr .ib ()
41+ id : str = attr .ib ()
42+ snr : float = attr .ib ()
43+ preRs : int = attr .ib ()
44+ postRs : int = attr .ib ()
45+ qamLocked : bool = attr .ib ()
46+ fecLocked : bool = attr .ib ()
47+ mpegLocked : bool = attr .ib ()
48+
49+
50+ @attr .s
51+ class UpstreamChannel :
52+ """A locked upstream channel."""
53+
54+ frequency : int = attr .ib ()
55+ powerLevel : int = attr .ib ()
56+ symbolRate : str = attr .ib ()
57+ id : str = attr .ib ()
58+ modulation : str = attr .ib ()
59+ type : str = attr .ib ()
60+ t1Timeouts : int = attr .ib ()
61+ t2Timeouts : int = attr .ib ()
62+ t3Timeouts : int = attr .ib ()
63+ t4Timeouts : int = attr .ib ()
64+ channelType : str = attr .ib ()
65+ messageType : int = attr .ib ()
66+
67+
3268class ConnectBox :
3369 """A class for handling the data retrieval from an UPC Connect Box ."""
3470
@@ -50,6 +86,8 @@ def __init__(
5086 ),
5187 }
5288 self .devices : List [Device ] = []
89+ self .ds_channels : List [DownstreamChannel ] = []
90+ self .us_channels : List [UpstreamChannel ] = []
5391
5492 async def async_get_devices (self ) -> List [Device ]:
5593 """Scan for new devices and return a list with found device IDs."""
@@ -75,7 +113,69 @@ async def async_get_devices(self) -> List[Device]:
75113 self .token = None
76114 raise exceptions .ConnectBoxNoDataAvailable () from None
77115
78- return self .devices
116+ async def async_get_downstream (self ):
117+ """Get the current downstream cable modem state."""
118+
119+ if self .token is None :
120+ await self .async_initialize_token ()
121+
122+ raw = await self ._async_ws_function (CMD_DOWNSTREAM )
123+
124+ try :
125+ xml_root = element_tree .fromstring (raw )
126+ self .ds_channels .clear ()
127+ for downstream in xml_root .iter ("downstream" ):
128+ self .ds_channels .append (
129+ DownstreamChannel (
130+ int (downstream .find ("freq" ).text ),
131+ int (downstream .find ("pow" ).text ),
132+ downstream .find ("mod" ).text ,
133+ downstream .find ("chid" ).text ,
134+ float (downstream .find ("RxMER" ).text ),
135+ int (downstream .find ("PreRs" ).text ),
136+ int (downstream .find ("PostRs" ).text ),
137+ downstream .find ("IsQamLocked" ).text == "1" ,
138+ downstream .find ("IsFECLocked" ).text == "1" ,
139+ downstream .find ("IsMpegLocked" ).text == "1" ,
140+ )
141+ )
142+ except (element_tree .ParseError , TypeError ):
143+ _LOGGER .warning ("Can't read downstream channels from %s" , self .host )
144+ self .token = None
145+ raise exceptions .ConnectBoxNoDataAvailable () from None
146+
147+ async def async_get_upstream (self ):
148+ """Get the current upstream cable modem state."""
149+
150+ if self .token is None :
151+ await self .async_initialize_token ()
152+
153+ raw = await self ._async_ws_function (CMD_UPSTREAM )
154+
155+ try :
156+ xml_root = element_tree .fromstring (raw )
157+ self .us_channels .clear ()
158+ for upstream in xml_root .iter ("upstream" ):
159+ self .us_channels .append (
160+ UpstreamChannel (
161+ int (upstream .find ("freq" ).text ),
162+ int (upstream .find ("power" ).text ),
163+ upstream .find ("srate" ).text ,
164+ upstream .find ("usid" ).text ,
165+ upstream .find ("mod" ).text ,
166+ upstream .find ("ustype" ).text ,
167+ int (upstream .find ("t1Timeouts" ).text ),
168+ int (upstream .find ("t2Timeouts" ).text ),
169+ int (upstream .find ("t3Timeouts" ).text ),
170+ int (upstream .find ("t4Timeouts" ).text ),
171+ upstream .find ("channeltype" ).text ,
172+ int (upstream .find ("messageType" ).text ),
173+ )
174+ )
175+ except (element_tree .ParseError , TypeError ):
176+ _LOGGER .warning ("Can't read upstream channels from %s" , self .host )
177+ self .token = None
178+ raise exceptions .ConnectBoxNoDataAvailable () from None
79179
80180 async def async_close_session (self ) -> None :
81181 """Logout and close session."""
0 commit comments