11"""TP-Link api."""
22
33import logging
4- from typing import Final , Tuple
4+ from typing import Tuple
55
66from .classes import (
77 PoeClass ,
1414 PortState ,
1515 TpLinkSystemInfo ,
1616)
17+ from .const import (
18+ FEATURE_POE ,
19+ URL_DEVICE_INFO ,
20+ URL_POE_PORT_SETTINGS_SET ,
21+ URL_POE_SETTINGS_GET ,
22+ URL_POE_SETTINGS_SET ,
23+ URL_PORT_SETTINGS_SET ,
24+ URL_PORTS_SETTINGS_GET ,
25+ )
1726from .coreapi import TpLinkWebApi , VariableType
27+ from .utils import TpLinkFeaturesDetector
1828
1929_LOGGER = logging .getLogger (__name__ )
2030
21- _URL_DEVICE_INFO : Final = "SystemInfoRpm.htm"
22- _URL_PORTS_SETTINGS_GET : Final = "PortSettingRpm.htm"
23- _URL_POE_SETTINGS_GET : Final = "PoeConfigRpm.htm"
24-
25- _URL_PORT_SETTINGS_SET : Final = "port_setting.cgi"
26- _URL_POE_SETTINGS_SET : Final = "poe_global_config.cgi"
27- _URL_POE_PORT_SETTINGS_SET : Final = "poe_port_config.cgi"
28-
2931_POE_PRIORITIES_SET_MAP : dict [PoePriority , int ] = {
3032 PoePriority .HIGH : 1 ,
3133 PoePriority .MIDDLE : 2 ,
@@ -74,8 +76,22 @@ def __init__(
7476 ) -> None :
7577 """Initialize."""
7678 self ._core_api = TpLinkWebApi (host , port , use_ssl , user , password , verify_ssl )
79+ self ._is_features_updated = False
80+ self ._features = TpLinkFeaturesDetector (self ._core_api )
7781 _LOGGER .debug ("New instance of TpLinkApi created" )
7882
83+ async def _ensure_features_updated (self ):
84+ if not self ._is_features_updated :
85+ _LOGGER .debug ("Updating available features" )
86+ await self ._features .update ()
87+ self ._is_features_updated = True
88+ _LOGGER .debug ("Available features updated" )
89+
90+ async def is_feature_available (self , feature : str ) -> bool :
91+ """Return true if specified feature is known and available."""
92+ await self ._ensure_features_updated ()
93+ return self ._features .is_available (feature )
94+
7995 async def authenticate (self ) -> None :
8096 """Perform authentication."""
8197 await self ._core_api .authenticate ()
@@ -92,7 +108,7 @@ def device_url(self) -> str:
92108 async def get_device_info (self ) -> TpLinkSystemInfo :
93109 """Return the device information."""
94110 data = await self ._core_api .get_variable (
95- _URL_DEVICE_INFO , "info_ds" , VariableType .Dict
111+ URL_DEVICE_INFO , "info_ds" , VariableType .Dict
96112 )
97113
98114 def get_value (key : str ) -> str | None :
@@ -116,7 +132,7 @@ def get_value(key: str) -> str | None:
116132 async def get_port_states (self ) -> list [PortState ]:
117133 """Return the port states."""
118134 data = await self ._core_api .get_variables (
119- _URL_PORTS_SETTINGS_GET ,
135+ URL_PORTS_SETTINGS_GET ,
120136 [
121137 ("all_info" , VariableType .Dict ),
122138 ("max_port_num" , VariableType .Int ),
@@ -154,8 +170,11 @@ async def get_port_states(self) -> list[PortState]:
154170
155171 async def get_port_poe_states (self ) -> list [PortPoeState ]:
156172 """Return the port states."""
173+ if not await self .is_feature_available (FEATURE_POE ):
174+ return []
175+
157176 data = await self ._core_api .get_variables (
158- _URL_POE_SETTINGS_GET ,
177+ URL_POE_SETTINGS_GET ,
159178 [
160179 ("portConfig" , VariableType .Dict ),
161180 ("poe_port_num" , VariableType .Int ),
@@ -202,11 +221,13 @@ async def get_port_poe_states(self) -> list[PortPoeState]:
202221
203222 async def get_poe_state (self ) -> PoeState | None :
204223 """Return the port states."""
224+ if not await self .is_feature_available (FEATURE_POE ):
225+ return None
205226
206227 _LOGGER .debug ("Begin fetching POE states" )
207228
208229 poe_config = await self ._core_api .get_variable (
209- _URL_POE_SETTINGS_GET , "globalConfig" , VariableType .Dict
230+ URL_POE_SETTINGS_GET , "globalConfig" , VariableType .Dict
210231 )
211232 if not poe_config :
212233 _LOGGER .debug ("No globalConfig found, returning" )
@@ -235,10 +256,13 @@ async def set_port_state(
235256 f"flowcontrol={ 1 if flow_control_config else 0 } &"
236257 f"apply=Apply"
237258 )
238- await self ._core_api .get (_URL_PORT_SETTINGS_SET , query = query )
259+ await self ._core_api .get (URL_PORT_SETTINGS_SET , query = query )
239260
240261 async def set_poe_limit (self , limit : float ) -> None :
241262 """Change poe limit."""
263+ if not await self .is_feature_available (FEATURE_POE ):
264+ raise ActionError ("POE feature is not supported by device" )
265+
242266 current_state = await self .get_poe_state ()
243267 if not current_state :
244268 raise ActionError ("Can not get actual PoE state" )
@@ -258,7 +282,7 @@ async def set_poe_limit(self, limit: float) -> None:
258282 "name_powerremain" : current_state .power_remain ,
259283 "applay" : "Apply" ,
260284 }
261- result = await self ._core_api .post (_URL_POE_SETTINGS_SET , data )
285+ result = await self ._core_api .post (URL_POE_SETTINGS_SET , data )
262286 _LOGGER .debug ("POE_SET_RESULT: %s" , result )
263287
264288 async def set_port_poe_settings (
@@ -268,12 +292,14 @@ async def set_port_poe_settings(
268292 priority : PoePriority ,
269293 power_limit : PoePowerLimit | float ,
270294 ) -> None :
295+ if not await self .is_feature_available (FEATURE_POE ):
296+ raise ActionError ("POE feature is not supported by device" )
271297 """Change port poe settings."""
272298 if port_number < 1 :
273299 raise ActionError ("Port number should be greater than or equals to 1" )
274300
275301 poe_ports_count = await self ._core_api .get_variable (
276- _URL_POE_SETTINGS_GET , "poe_port_num" , VariableType .Int
302+ URL_POE_SETTINGS_GET , "poe_port_num" , VariableType .Int
277303 )
278304 if not poe_ports_count :
279305 raise ActionError ("Can not get PoE ports count" )
@@ -310,5 +336,5 @@ async def set_port_poe_settings(
310336 f"sel_{ port_number } " : 1 ,
311337 "applay" : "Apply" ,
312338 }
313- result = await self ._core_api .post (_URL_POE_PORT_SETTINGS_SET , data )
339+ result = await self ._core_api .post (URL_POE_PORT_SETTINGS_SET , data )
314340 _LOGGER .debug ("POE_PORT_SETTINGS_SET_RESULT: %s" , result )
0 commit comments