Skip to content

Commit a1c0975

Browse files
sharttepvizeli
authored andcommitted
Added ability to read downstream and upstream channels (#1)
* Added ability to read downstream and upstream channels. * Fix code formatting and code style issues.
1 parent 037f917 commit a1c0975

File tree

2 files changed

+111
-2
lines changed

2 files changed

+111
-2
lines changed

connect_box/__init__.py

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
CMD_LOGIN = 15
1919
CMD_LOGOUT = 16
2020
CMD_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+
3268
class 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."""

example.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Get the data from an UPC Connect Box."""
22
import asyncio
3+
from pprint import pprint
34

45
import aiohttp
56

@@ -11,9 +12,17 @@ async def main():
1112
async with aiohttp.ClientSession() as session:
1213
client = ConnectBox(session, "password")
1314

15+
# Print details about the downstream channel connectivity
16+
await client.async_get_downstream()
17+
pprint(client.ds_channels)
18+
19+
# Print details about the upstream channel connectivity
20+
await client.async_get_upstream()
21+
pprint(client.us_channels)
22+
1423
# Print details about the connected devices
1524
await client.async_get_devices()
16-
print(client.devices)
25+
pprint(client.devices)
1726

1827
await client.async_close_session()
1928

0 commit comments

Comments
 (0)