From 604c1d03c99fa7492115e2526eb003a182ac91fa Mon Sep 17 00:00:00 2001 From: Luis Teixeira Date: Sat, 11 Oct 2025 22:23:50 +0100 Subject: [PATCH 1/2] Enable lte sensors. Slight refactoring of dataclasses to accomodate the proper modelling of categories of attributes that may or may not occur depending on the device --- tplinkrouterc6u/client/mr.py | 5 +- tplinkrouterc6u/client_abstract.py | 2 +- tplinkrouterc6u/common/dataclass.py | 163 +++++++++++++++------------- 3 files changed, 89 insertions(+), 81 deletions(-) diff --git a/tplinkrouterc6u/client/mr.py b/tplinkrouterc6u/client/mr.py index ceef7d5..19336e0 100644 --- a/tplinkrouterc6u/client/mr.py +++ b/tplinkrouterc6u/client/mr.py @@ -212,6 +212,8 @@ def get_status(self) -> Status: status.devices = list(devices.values()) status.clients_total = status.wired_total + status.wifi_clients_total + status.guest_clients_total + status = self.populate_lte_status(status) + return status def get_ipv4_reservations(self) -> [IPv4Reservation]: @@ -682,8 +684,7 @@ def send_ussd(self, command: str) -> str: elif status == '2': raise ClientError('Cannot send USSD!') - def get_lte_status(self) -> LTEStatus: - status = LTEStatus() + def populate_lte_status(self, status) -> Status: acts = [ self.ActItem(self.ActItem.GET, 'WAN_LTE_LINK_CFG', '2,1,0,0,0,0', attrs=['enable', 'connectStatus', 'networkType', 'roamingStatus', 'simStatus']), diff --git a/tplinkrouterc6u/client_abstract.py b/tplinkrouterc6u/client_abstract.py index c920334..ecc6327 100644 --- a/tplinkrouterc6u/client_abstract.py +++ b/tplinkrouterc6u/client_abstract.py @@ -1,7 +1,7 @@ from requests.packages import urllib3 from logging import Logger from tplinkrouterc6u.common.package_enum import Connection -from tplinkrouterc6u.common.dataclass import Firmware, Status, IPv4Status +from tplinkrouterc6u.common.dataclass import Firmware, Status, IPv4Status, LTEStatus from abc import ABC, abstractmethod diff --git a/tplinkrouterc6u/common/dataclass.py b/tplinkrouterc6u/common/dataclass.py index 5df5051..0666795 100644 --- a/tplinkrouterc6u/common/dataclass.py +++ b/tplinkrouterc6u/common/dataclass.py @@ -2,28 +2,32 @@ from ipaddress import IPv4Address from dataclasses import dataclass, field from datetime import datetime +from typing import Optional + from tplinkrouterc6u.common.package_enum import Connection @dataclass class Firmware: - hardware_version: str - model: str - firmware_version: str + def __init__(self, hardware: str, model: str, firmware: str) -> None: + self.hardware_version = hardware + self.model = model + self.firmware_version = firmware @dataclass class Device: - type: Connection - _macaddr: EUI48 - _ipaddr: IPv4Address - hostname: str - packets_sent: int | None = None - packets_received: int | None = None - down_speed: int | None = None - up_speed: int | None = None - signal: int | None = None - active: bool = True + def __init__(self, type: Connection, macaddr: EUI48, ipaddr: IPv4Address, hostname: str) -> None: + self.type = type + self._macaddr = macaddr + self._ipaddr = ipaddr + self.hostname = hostname + self.packets_sent: int | None = None + self.packets_received: int | None = None + self.down_speed: int | None = None + self.up_speed: int | None = None + self.signal: int | None = None + self.active: bool = True @property def macaddr(self): @@ -41,32 +45,31 @@ def ipaddr(self): def ipaddress(self): return self._ipaddr - @dataclass -class Status: - _wan_macaddr: EUI48 | None = None - _lan_macaddr: EUI48 = None - _wan_ipv4_addr: IPv4Address | None = None - _lan_ipv4_addr: IPv4Address | None = None - _wan_ipv4_gateway: IPv4Address | None = None +class RouterStatus: + _wan_macaddr: Optional[EUI48] = None + _lan_macaddr: Optional[EUI48] = None + _wan_ipv4_addr: Optional[IPv4Address] = None + _lan_ipv4_addr: Optional[IPv4Address] = None + _wan_ipv4_gateway: Optional[IPv4Address] = None wired_total: int = 0 wifi_clients_total: int = 0 guest_clients_total: int = 0 - iot_clients_total: int | None = None + iot_clients_total: Optional[int] = None clients_total: int = 0 - guest_2g_enable: bool | None = None - guest_5g_enable: bool | None = None - guest_6g_enable: bool | None = None - iot_2g_enable: bool | None = None - iot_5g_enable: bool | None = None - iot_6g_enable: bool | None = None - wifi_2g_enable: bool | None = None - wifi_5g_enable: bool | None = None - wifi_6g_enable: bool | None = None - wan_ipv4_uptime: int | None = None - mem_usage: float | None = None - cpu_usage: float | None = None - conn_type: str | None = None + guest_2g_enable: bool = False + guest_5g_enable: Optional[bool] = None + guest_6g_enable: Optional[bool] = None + iot_2g_enable: Optional[bool] = None + iot_5g_enable: Optional[bool] = None + iot_6g_enable: Optional[bool] = None + wifi_2g_enable: bool = False + wifi_5g_enable: Optional[bool] = None + wifi_6g_enable: Optional[bool] = None + wan_ipv4_uptime: Optional[int] = None + mem_usage: Optional[float] = None + cpu_usage: Optional[float] = None + conn_type: Optional[str] = None devices: list[Device] = field(default_factory=list) @property @@ -112,10 +115,11 @@ def wan_ipv4_gateway_address(self) -> IPv4Address | None: @dataclass class IPv4Reservation: - _macaddr: EUI48 | None = None - _ipaddr: IPv4Address | None = None - hostname: str | None = None - enabled: bool = True + def __init__(self, macaddr: EUI48, ipaddr: IPv4Address, hostname: str, enabled: bool) -> None: + self._macaddr = macaddr + self._ipaddr = ipaddr + self.hostname = hostname + self.enabled = enabled @property def macaddr(self): @@ -136,10 +140,11 @@ def ipaddress(self): @dataclass class IPv4DHCPLease: - _macaddr: EUI48 - _ipaddr: IPv4Address - hostname: str - lease_time: str + def __init__(self, macaddr: EUI48, ipaddr: IPv4Address, hostname: str, lease_time: str) -> None: + self._macaddr = macaddr + self._ipaddr = ipaddr + self.hostname = hostname + self.lease_time = lease_time @property def macaddr(self): @@ -157,21 +162,20 @@ def ipaddr(self): def ipaddress(self): return self._ipaddr - @dataclass class IPv4Status: - _wan_macaddr: EUI48 | None = None - _wan_ipv4_ipaddr: IPv4Address | None = None - _wan_ipv4_gateway: IPv4Address | None = None - _wan_ipv4_conntype: str = "" - _wan_ipv4_netmask: IPv4Address | None = None - _wan_ipv4_pridns: IPv4Address | None = None - _wan_ipv4_snddns: IPv4Address | None = None - _lan_macaddr: EUI48 | None = None - _lan_ipv4_ipaddr: IPv4Address | None = None - lan_ipv4_dhcp_enable: bool | None = None - _lan_ipv4_netmask: IPv4Address | None = None - remote: bool | None = None + _wan_macaddr: Optional[EUI48] = None + _wan_ipv4_ipaddr: Optional[IPv4Address] = None + _wan_ipv4_gateway: Optional[IPv4Address] = None + _wan_ipv4_conntype: Optional[str] = None + _wan_ipv4_netmask: Optional[IPv4Address] = None + _wan_ipv4_pridns: Optional[IPv4Address] = None + _wan_ipv4_snddns: Optional[IPv4Address] = None + _lan_macaddr: Optional[EUI48] = None + _lan_ipv4_ipaddr: Optional[IPv4Address] = None + lan_ipv4_dhcp_enable: bool = False + _lan_ipv4_netmask: Optional[IPv4Address] = None + remote: Optional[bool] = None @property def wan_macaddr(self): @@ -187,7 +191,7 @@ def wan_ipv4_ipaddr(self): @property def wan_ipv4_conntype(self): - return self._wan_ipv4_conntype + return self._wan_ipv4_conntype if hasattr(self, '_wan_ipv4_conntype') else '' @property def wan_ipv4_ipaddress(self): @@ -252,33 +256,36 @@ def lan_ipv4_netmask_address(self): @dataclass class SMS: - id: int - sender: str - content: str - received_at: datetime - unread: bool - + def __init__(self, index: int, sender: str, content: str, received_at: datetime, unread: bool) -> None: + self.id = index + self.sender = sender + self.content = content + self.received_at = received_at + self.unread = unread @dataclass class LTEStatus: - enable: int | None = None - connect_status: int | None = None - network_type: int | None = None - sim_status: int | None = None - total_statistics: int | None = None - cur_rx_speed: int | None = None - cur_tx_speed: int | None = None - sms_unread_count: int | None = None - sig_level: int | None = None - rsrp: int | None = None - rsrq: int | None = None - snr: int | None = None - isp_name: str | None = None - + enable: int = 0 + connect_status: int = 0 + network_type: int = 0 + sim_status: int = 0 + total_statistics: int = 0 + cur_rx_speed: int = 0 + cur_tx_speed: int = 0 + sms_unread_count: int = 0 + sig_level: int = 0 + rsrp: int = 0 + rsrq: int = 0 + snr: int = 0 + isp_name: str = "" @dataclass class VPNStatus: - openvpn_enable: bool | None = None - pptpvpn_enable: bool | None = None + openvpn_enable: bool = False + pptpvpn_enable: bool = False openvpn_clients_total: int = 0 pptpvpn_clients_total: int = 0 + +@dataclass +class Status(RouterStatus, IPv4Status, LTEStatus, VPNStatus): + pass From da736e9073317962362c7f0731cab4d8ec5e8ab1 Mon Sep 17 00:00:00 2001 From: Luis Teixeira Date: Sat, 11 Oct 2025 22:41:11 +0100 Subject: [PATCH 2/2] Minor cleanup --- tplinkrouterc6u/client/mr.py | 1 - tplinkrouterc6u/client_abstract.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tplinkrouterc6u/client/mr.py b/tplinkrouterc6u/client/mr.py index 19336e0..91392cd 100644 --- a/tplinkrouterc6u/client/mr.py +++ b/tplinkrouterc6u/client/mr.py @@ -18,7 +18,6 @@ IPv4DHCPLease, IPv4Status, SMS, - LTEStatus, VPNStatus, ) from tplinkrouterc6u.common.exception import ClientException, ClientError diff --git a/tplinkrouterc6u/client_abstract.py b/tplinkrouterc6u/client_abstract.py index ecc6327..c920334 100644 --- a/tplinkrouterc6u/client_abstract.py +++ b/tplinkrouterc6u/client_abstract.py @@ -1,7 +1,7 @@ from requests.packages import urllib3 from logging import Logger from tplinkrouterc6u.common.package_enum import Connection -from tplinkrouterc6u.common.dataclass import Firmware, Status, IPv4Status, LTEStatus +from tplinkrouterc6u.common.dataclass import Firmware, Status, IPv4Status from abc import ABC, abstractmethod