Skip to content

Commit 2ab158b

Browse files
authored
Retrieve temperature, modem status and service flows (#16)
* Add retrieval for fun=144 (cmstatus) * Add retrieval for interesting values of fun=136 (temperature)
1 parent 3c5b43a commit 2ab158b

3 files changed

Lines changed: 133 additions & 2 deletions

File tree

connect_box/__init__.py

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@
77
from aiohttp.hdrs import REFERER, USER_AGENT
88
import defusedxml.ElementTree as element_tree
99

10-
from .data import Device, DownstreamChannel, UpstreamChannel
10+
from .data import (
11+
Device,
12+
DownstreamChannel,
13+
UpstreamChannel,
14+
CmStatus,
15+
ServiceFlow,
16+
Temperature,
17+
)
1118
from . import exceptions
1219

1320
_LOGGER = logging.getLogger(__name__)
@@ -19,6 +26,8 @@
1926
CMD_DEVICES = 123
2027
CMD_DOWNSTREAM = 10
2128
CMD_UPSTREAM = 11
29+
CMD_TEMPERATURE = 136
30+
CMD_CMSTATUS = 144
2231

2332

2433
class ConnectBox:
@@ -44,8 +53,12 @@ def __init__(
4453
self.devices: List[Device] = []
4554
self.ds_channels: List[DownstreamChannel] = []
4655
self.us_channels: List[UpstreamChannel] = []
56+
self.cmstatus: Optional[CmStatus] = None
57+
self.upstream_service_flows: List[ServiceFlow] = []
58+
self.downstream_service_flows: List[ServiceFlow] = []
59+
self.temperature: Optional[Temperature] = None
4760

48-
async def async_get_devices(self) -> List[Device]:
61+
async def async_get_devices(self):
4962
"""Scan for new devices and return a list with found device IDs."""
5063
if self.token is None:
5164
await self.async_initialize_token()
@@ -132,6 +145,75 @@ async def async_get_upstream(self):
132145
self.token = None
133146
raise exceptions.ConnectBoxNoDataAvailable() from None
134147

148+
async def async_get_cmstatus_and_service_flows(self):
149+
"""Get various status information."""
150+
if self.token is None:
151+
await self.async_initialize_token()
152+
153+
self.cmstatus = None
154+
self.downstream_service_flows = []
155+
self.upstream_service_flows = []
156+
raw = await self._async_ws_function(CMD_CMSTATUS)
157+
158+
try:
159+
xml_root = element_tree.fromstring(raw)
160+
self.cmstatus = CmStatus(
161+
provisioningStatus=xml_root.find("provisioning_st").text,
162+
cmComment=xml_root.find("cm_comment").text,
163+
cmDocsisMode=xml_root.find("cm_docsis_mode").text,
164+
cmNetworkAccess=xml_root.find("cm_network_access").text,
165+
numberOfCpes=int(xml_root.find("NumberOfCpes").text),
166+
firmwareFilename=xml_root.find("FileName").text,
167+
dMaxCpes=int(xml_root.find("dMaxCpes").text),
168+
bpiEnable=int(xml_root.find("bpiEnable").text),
169+
)
170+
for elmt_service_flow in xml_root.iter("serviceflow"):
171+
service_flow = ServiceFlow(
172+
id=int(elmt_service_flow.find("Sfid").text),
173+
pMaxTrafficRate=int(elmt_service_flow.find("pMaxTrafficRate").text),
174+
pMaxTrafficBurst=int(
175+
elmt_service_flow.find("pMaxTrafficBurst").text
176+
),
177+
pMinReservedRate=int(
178+
elmt_service_flow.find("pMinReservedRate").text
179+
),
180+
pMaxConcatBurst=int(elmt_service_flow.find("pMaxConcatBurst").text),
181+
pSchedulingType=int(elmt_service_flow.find("pSchedulingType").text),
182+
)
183+
direction = int(elmt_service_flow.find("direction").text)
184+
if direction == 1:
185+
self.downstream_service_flows.append(service_flow)
186+
elif direction == 2:
187+
self.upstream_service_flows.append(service_flow)
188+
else:
189+
raise element_tree.ParseError(
190+
"Unknown service flow direction '{}'".format(direction)
191+
)
192+
except (element_tree.ParseError, TypeError):
193+
_LOGGER.warning("Can't read cmstatus from %s", self.host)
194+
self.token = None
195+
raise exceptions.ConnectBoxNoDataAvailable() from None
196+
197+
async def async_get_temperature(self):
198+
"""Get temperature information (in degrees Celsius)."""
199+
if self.token is None:
200+
await self.async_initialize_token()
201+
202+
self.temperature = None
203+
raw = await self._async_ws_function(CMD_TEMPERATURE)
204+
205+
f_to_c = lambda f: (5.0 / 9) * (f - 32)
206+
try:
207+
xml_root = element_tree.fromstring(raw)
208+
self.temperature = Temperature(
209+
tunerTemperature=f_to_c(int(xml_root.find("TunnerTemperature").text)),
210+
temperature=f_to_c(int(xml_root.find("Temperature").text)),
211+
)
212+
except (element_tree.ParseError, TypeError):
213+
_LOGGER.warning("Can't read temperature from %s", self.host)
214+
self.token = None
215+
raise exceptions.ConnectBoxNoDataAvailable() from None
216+
135217
async def async_close_session(self) -> None:
136218
"""Logout and close session."""
137219
if not self.token:

connect_box/data.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,42 @@ class UpstreamChannel:
4646
t4Timeouts: int = attr.ib()
4747
channelType: str = attr.ib()
4848
messageType: int = attr.ib()
49+
50+
51+
@attr.s
52+
class CmStatus:
53+
provisioningStatus: str = attr.ib()
54+
cmComment: str = attr.ib()
55+
cmDocsisMode: str = attr.ib()
56+
cmNetworkAccess: str = attr.ib()
57+
firmwareFilename: str = attr.ib()
58+
59+
# number of IP addresses to assign via DHCP
60+
numberOfCpes: int = attr.ib()
61+
62+
# ???
63+
dMaxCpes: int = attr.ib()
64+
bpiEnable: int = attr.ib()
65+
66+
67+
@attr.s
68+
class ServiceFlow:
69+
id: int = attr.ib()
70+
pMaxTrafficRate: int = attr.ib()
71+
pMaxTrafficBurst: int = attr.ib()
72+
pMinReservedRate: int = attr.ib()
73+
pMaxConcatBurst: int = attr.ib()
74+
75+
# 2 seems to be Best Effort
76+
pSchedulingType: int = attr.ib()
77+
78+
79+
@attr.s
80+
class Temperature:
81+
# temperatures in degrees Celsius
82+
tunerTemperature: float = attr.ib()
83+
temperature: float = attr.ib()
84+
85+
# several other stats remain untapped here:
86+
# wan_ipv4_addr
87+
# wan_ipv6_addr, wan_ipv6_addr_entry

example.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ async def main():
2525
await client.async_get_devices()
2626
pprint(client.devices)
2727

28+
# Print details on general device status
29+
await client.async_get_cmstatus_and_service_flows()
30+
pprint(client.cmstatus)
31+
pprint(client.downstream_service_flows)
32+
pprint(client.upstream_service_flows)
33+
34+
# Print temperature status
35+
await client.async_get_temperature()
36+
pprint(client.temperature)
37+
2838
await client.async_close_session()
2939

3040

0 commit comments

Comments
 (0)