fix: remove get_wireless_clients/get_ssids/get_radio_status from AccessPointDriver

These three methods were defined with `raise NotImplementedError` in
AccessPointDriver. Because AccessPointDriver appears before the mixin
classes in the MRO of concrete drivers (e.g. OpenWrtDriver), this caused
the abstract body to be called instead of the mixin implementation.

Symptoms:
- get_radio_status() → NotImplementedError, silently caught in poll →
  radio_snapshot never updated after the initial snap
- get_ssids() / get_wireless_clients() → same silent failure

Fix: remove the method bodies from AccessPointDriver entirely. Python then
continues the MRO search and finds the correct mixin implementation.

The comment documents the invariant so it is not accidentally re-introduced.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-25 00:11:34 +02:00
co-authored by Claude Sonnet 4.6
parent 9e5e6a5d95
commit cc8bdc7b5e
+6 -105
View File
@@ -69,111 +69,12 @@ class AccessPointDriver(DeviceTypeDriver):
and not name.startswith(self._EXCLUDED_INTERFACE_PREFIXES)
}
def get_wireless_clients(self) -> List[WirelessClientDict]:
"""
Returns a list of wireless clients currently associated with this
access point.
Each entry contains:
* mac (string) - client MAC address
* ssid (string) - SSID the client is connected to
* radio (string) - radio identifier (e.g. ``"radio0"``, ``"5GHz"``)
* signal (int) - received signal strength in dBm
* noise (int) - noise floor in dBm
* tx_rate (float) - TX bitrate in Mbit/s
* rx_rate (float) - RX bitrate in Mbit/s
* uptime (int) - association duration in seconds
Example::
[
{
"mac": "AA:BB:CC:DD:EE:FF",
"ssid": "MyNetwork",
"radio": "radio1",
"signal": -65,
"noise": -95,
"tx_rate": 300.0,
"rx_rate": 144.0,
"uptime": 3600,
}
]
"""
raise NotImplementedError
def get_ssids(self) -> Dict[str, SSIDDict]:
"""
Returns the configured SSIDs (VAPs) on this access point.
Keys are SSID names. Each value contains:
* enabled (bool) - whether the SSID is currently broadcasting
* radio (string) - radio the SSID is bound to
* bssid (string) - BSSID (MAC) of the VAP
* encryption (string) - e.g. ``"WPA2-PSK"``, ``"WPA3-SAE"``, ``"open"``
* hidden (bool) - whether the SSID is hidden
* clients (int) - number of currently associated clients
Example::
{
"MyNetwork": {
"enabled": True,
"radio": "radio1",
"bssid": "AA:BB:CC:DD:EE:F0",
"encryption": "WPA2-PSK",
"hidden": False,
"clients": 3,
},
"GuestNet": {
"enabled": True,
"radio": "radio0",
"bssid": "AA:BB:CC:DD:EE:F1",
"encryption": "WPA2-PSK",
"hidden": False,
"clients": 1,
},
}
"""
raise NotImplementedError
def get_radio_status(self) -> Dict[str, RadioStatusDict]:
"""
Returns the status of each radio interface.
Keys are radio identifiers (e.g. ``"radio0"``, ``"radio1"``).
Each value contains:
* enabled (bool) - whether the radio is active
* band (string) - frequency band, e.g. ``"2.4GHz"``, ``"5GHz"``, ``"6GHz"``
* channel (int) - operating channel number
* channel_width (int) - channel width in MHz (e.g. 20, 40, 80, 160)
* tx_power (int) - transmit power in dBm
* frequency (float) - center frequency in MHz
Example::
{
"radio0": {
"enabled": True,
"band": "2.4GHz",
"channel": 6,
"channel_width": 20,
"tx_power": 20,
"frequency": 2437.0,
},
"radio1": {
"enabled": True,
"band": "5GHz",
"channel": 36,
"channel_width": 80,
"tx_power": 23,
"frequency": 5180.0,
},
}
"""
raise NotImplementedError
# get_wireless_clients, get_ssids, get_radio_status are intentionally NOT
# defined here. AccessPointDriver sits before mixin classes in the MRO of
# concrete drivers (e.g. OpenWrtDriver(AccessPointDriver, ..., WirelessMixin)).
# Any definition in AccessPointDriver — even `raise NotImplementedError` —
# would shadow the concrete mixin implementation. Leaving them absent forces
# Python to continue the MRO search and find the mixin version.
def get_wireless_config(self) -> WirelessConfigDict:
"""