Skip to content

Commit eb6b716

Browse files
authored
Merge pull request #74 from MarkGodwin/fix_clients_6.2
Fix clients API for Omada 6.2.0.x
2 parents 23f133d + 4ff0b9e commit eb6b716

File tree

6 files changed

+51
-14
lines changed

6 files changed

+51
-14
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Only a subset of the controller's features are supported:
2525
* Lan port configuration for Access Points
2626
* Gateway port status and WAN port Connect/Disconnect control
2727

28-
Tested with OC200 on Omada Controller Version 5.5.7 - 5.12.x. Other versions may not be fully compatible.
28+
Tested with OC200 on Omada Controller Version 5.5.7 - 6.2.x. Other versions may not be fully compatible.
2929
Version 5.0.x is definitely not compatible.
3030

3131
## CLI

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "tplink_omada_client"
7-
version = "1.5.5"
7+
version = "1.5.6"
88
authors = [
99
{ name="Mark Godwin", email="10632972+MarkGodwin@users.noreply.github.com" },
1010
]

src/tplink_omada_client/clients.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ class OmadaWiredClient(OmadaConnectedClient):
213213
@property
214214
def dot1x_vlan(self) -> int:
215215
"""Network name corresponding to the VLAN obtained by 802.1x D-VLAN"""
216-
return self._data["dot1xVlan"]
216+
return self._data.get("dot1xVlan", 0)
217217

218218
@property
219219
def gateway_mac(self) -> str | None:
@@ -233,7 +233,7 @@ def network_name(self) -> str:
233233
@property
234234
def port(self) -> int:
235235
"""Switch port client is connected to"""
236-
return self._data["port"]
236+
return self._data.get("port", -1)
237237

238238
@property
239239
def switch_mac(self) -> str | None:

src/tplink_omada_client/omadaapiconnection.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,16 +137,16 @@ def format_url(self, end_point: str, site: str | None = None) -> str:
137137

138138
return urljoin(self._url, f"/{self._controller_id}/api/v2/{end_point}")
139139

140-
def format_openapi_url(self, end_point: str, site: str | None = None) -> str:
140+
def format_openapi_url(self, end_point: str, version: str = "v1", site: str | None = None) -> str:
141141
"""Get a REST url for the controller action"""
142142

143143
if site:
144144
end_point = f"/sites/{site}/{end_point}"
145145

146-
return urljoin(self._url, f"/openapi/v1/{self._controller_id}{end_point}")
146+
return urljoin(self._url, f"/openapi/{version}/{self._controller_id}{end_point}")
147147

148148
async def iterate_pages(self, url: str, params: dict[str, Any] | None = None) -> AsyncIterable[dict[str, Any]]:
149-
"""Iterates all the entries of a paged endpoint"""
149+
"""Iterates all the entries of a paged endpoint using GET with query parameters (old API)"""
150150
request_params = {}
151151
if params is not None:
152152
request_params.update(params)
@@ -169,6 +169,30 @@ async def iterate_pages(self, url: str, params: dict[str, Any] | None = None) ->
169169
for item in data:
170170
yield item
171171

172+
async def iterate_pages_openapi(self, url: str, body: dict[str, Any] | None = None) -> AsyncIterable[dict[str, Any]]:
173+
"""Iterates all the entries of a paged endpoint using POST with JSON body (OpenAPI v2)"""
174+
request_body = {}
175+
if body is not None:
176+
request_body.update(body)
177+
actual_page_size = _PAGE_SIZE
178+
179+
current_page = 1
180+
has_next = True
181+
while has_next:
182+
request_body["pageSize"] = actual_page_size
183+
request_body["page"] = current_page
184+
response = await self.request("post", url, json=request_body)
185+
186+
# Setup next page request
187+
actual_page_size = int(response["currentSize"])
188+
total_rows = int(response["totalRows"])
189+
has_next = total_rows > current_page * actual_page_size
190+
current_page += 1
191+
192+
data: list[dict[str, Any]] = response["data"]
193+
for item in data:
194+
yield item
195+
172196
async def request(self, method: str, url: str, params=None, json=None, data: Payload | None = None) -> Any:
173197
"""Perform a request specific to the controlller, with authentication"""
174198

src/tplink_omada_client/omadasiteclient.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,12 +218,25 @@ async def update_client(self, mac_or_client: str | OmadaNetworkClient, settings:
218218

219219
async def get_connected_clients(self) -> AsyncIterable[OmadaConnectedClient]:
220220
"""Get the clients connected to the site network."""
221-
async for client in self._api.iterate_pages(self._api.format_url("clients", self._site_id), {"filters.active": "false"}):
222-
is_wireless = client.get("wireless")
223-
if is_wireless:
224-
yield OmadaWirelessClient(client)
225-
elif is_wireless is False:
226-
yield OmadaWiredClient(client)
221+
if (await self._api.get_controller_version()) >= AwesomeVersion("6.2.0.0"):
222+
request_url = self._api.format_openapi_url("clients", version="v2", site=self._site_id)
223+
async for client in self._api.iterate_pages_openapi(
224+
request_url,
225+
body={"filters": {"active": True}, "sorts": {}, "hideHealthUnsupported": True, "scope": 1},
226+
):
227+
is_wireless = client.get("wireless")
228+
if is_wireless:
229+
yield OmadaWirelessClient(client)
230+
elif is_wireless is False:
231+
yield OmadaWiredClient(client)
232+
else:
233+
request_url = self._api.format_url("clients", self._site_id)
234+
async for client in self._api.iterate_pages(request_url, {"filters.active": "false"}):
235+
is_wireless = client.get("wireless")
236+
if is_wireless:
237+
yield OmadaWirelessClient(client)
238+
elif is_wireless is False:
239+
yield OmadaWiredClient(client)
227240

228241
async def get_known_clients(self) -> AsyncIterable[OmadaNetworkClient]:
229242
"""Get the clients connected to the site network."""

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)