From 08dc18184e4c4df4c946062cd137cf4698e0b43f Mon Sep 17 00:00:00 2001 From: Fabian Seitz Date: Tue, 27 Aug 2024 17:15:39 +0200 Subject: [PATCH] fix object not found --- custom_components/openwrt/coordinator.py | 106 ++++++++++++++--------- custom_components/openwrt/ubus.py | 36 ++++---- 2 files changed, 88 insertions(+), 54 deletions(-) diff --git a/custom_components/openwrt/coordinator.py b/custom_components/openwrt/coordinator.py index 92cc94c..161d28b 100644 --- a/custom_components/openwrt/coordinator.py +++ b/custom_components/openwrt/coordinator.py @@ -50,6 +50,7 @@ async def discover_wireless(self) -> dict: wifi_devices = self._configured_devices("wifi_devices") try: response = await self._ubus.api_call('network.wireless', 'status', {}) + _LOGGER.debug(f"Wireless status response: {response}") for radio, item in response.items(): if item.get('disabled', False): continue @@ -64,8 +65,7 @@ async def discover_wireless(self) -> dict: conf['mesh_id'] = iface['config']['mesh_id'] result['mesh'].append(conf) except NameError as err: - _LOGGER.warning( - f"Device [{self._id}] doesn't support wireless: {err}") + _LOGGER.warning(f"Device [{self._id}] doesn't support wireless: {err}") return result def find_mesh_peers(self, mesh_id: str): @@ -113,37 +113,56 @@ async def update_mesh(self, configs) -> dict: noise=assoc.get("noise", 0) ) except ConnectionError: + _LOGGER.warning(f"Failed to get assoclist for {mac} on device {conf['ifname']}") pass except ConnectionError as err: - _LOGGER.warning( - f"Device [{self._id}] doesn't support iwinfo: {err}") + _LOGGER.warning(f"Device [{self._id}] doesn't support iwinfo: {err}") return result async def update_hostapd_clients(self, interface_id: str) -> dict: - response = await self._ubus.api_call( - f"hostapd.{interface_id}", - 'get_clients', - dict() - ) - macs = dict() - for key, value in response['clients'].items(): - macs[key] = dict(signal=value.get("signal")) - result = dict( - clients=len(macs), - macs=macs, - ) try: + _LOGGER.debug(f"Updating hostapd clients for interface: {interface_id}") + response = await self._ubus.api_call( + f"hostapd.{interface_id}", + 'get_clients', + dict() + ) + _LOGGER.debug(f"Hostapd clients response for {interface_id}: {response}") + + if 'clients' in response: + clients = response['clients'] + else: + _LOGGER.warning(f"'clients' key not found in response for interface {interface_id}. Response: {response}") + clients = {} + + macs = dict() + for key, value in clients.items(): + macs[key] = dict(signal=value.get("signal")) + + result = dict( + clients=len(macs), + macs=macs, + ) + if self._wps: - response = await self._ubus.api_call( - f"hostapd.{interface_id}", - 'wps_status', - dict() - ) - result["wps"] = response["pbc_status"] == "Active" - except ConnectionError as err: - _LOGGER.warning( - f"Interface [{interface_id}] doesn't support WPS: {err}") - return result + try: + response = await self._ubus.api_call( + f"hostapd.{interface_id}", + 'wps_status', + dict() + ) + result["wps"] = response.get("pbc_status") == "Active" + except ConnectionError: + _LOGGER.warning(f"Interface [{interface_id}] doesn't support WPS: {err}") + + return result + + except NameError as e: + _LOGGER.warning(f"Could not find object for interface {interface_id}: {e}") + return {} + except Exception as e: + _LOGGER.error(f"Error while updating hostapd clients for {interface_id}: {e}") + return {} async def set_wps(self, interface_id: str, enable: bool): await self._ubus.api_call( @@ -162,8 +181,7 @@ async def do_reboot(self): ) async def do_file_exec(self, command: str, params, env: dict, extra: dict): - _LOGGER.debug( - f"Executing command: {self._id}: {command} with {params} env={env}") + _LOGGER.debug(f"Executing command: {self._id}: {command} with {params} env={env}") result = await self._ubus.api_call( "file", "exec", @@ -171,7 +189,7 @@ async def do_file_exec(self, command: str, params, env: dict, extra: dict): ) _LOGGER.debug(f"Execute result: {self._id}: {result}") self._coordinator.hass.bus.async_fire( - "openwrt_exec_result", + "openwrt_exec_result", { "address": self._config.get("address"), "id": self._config.get("id"), @@ -181,14 +199,17 @@ async def do_file_exec(self, command: str, params, env: dict, extra: dict): **extra, }, ) + def process_output(data: str): try: json = json_loads(data) - if type(json) is list or type(json) is dict: + if isinstance(json, (list, dict)): return json - except: + except Exception as e: + _LOGGER.debug(f"Failed to parse JSON output: {e}") pass return data.strip().split("\n") + return { "code": result.get("code", 1), "stdout": process_output(result.get("stdout", "")), @@ -200,8 +221,7 @@ async def do_ubus_call(self, subsystem: str, method: str, params: dict): return await self._ubus.api_call(subsystem, method, params) async def do_rc_init(self, name: str, action: str): - _LOGGER.debug( - f"Executing name: {self._id}: {name} with {action}") + _LOGGER.debug(f"Executing name: {self._id}: {name} with {action}") result = await self._ubus.api_call( "rc", "init", @@ -209,7 +229,7 @@ async def do_rc_init(self, name: str, action: str): ) _LOGGER.debug(f"Execute result: {self._id}: {result}") self._coordinator.hass.bus.async_fire( - "openwrt_init_result", + "openwrt_init_result", { "address": self._config.get("address"), "id": self._config.get("id"), @@ -222,7 +242,16 @@ async def do_rc_init(self, name: str, action: str): async def update_ap(self, configs) -> dict: result = dict() for item in configs: - result[item['ifname']] = await self.update_hostapd_clients(item['ifname']) + if 'ifname' in item: + ifname = item['ifname'] + try: + _LOGGER.debug(f"Updating AP for interface: {ifname}") + result[ifname] = await self.update_hostapd_clients(ifname) + except Exception as e: + _LOGGER.error(f"Error updating AP for {ifname}: {e}") + continue # Continue with the next item + else: + _LOGGER.warning(f"Missing 'ifname' in AP config: {item}") return result async def update_info(self) -> dict: @@ -246,7 +275,7 @@ async def discover_mwan3(self): "status", dict(section="interfaces") ) - for key, iface in response["interfaces"].items(): + for key, iface in response.get("interfaces", {}).items(): if not iface.get("enabled", False): continue result[key] = { @@ -304,8 +333,7 @@ async def async_update_data(): except PermissionError as err: raise ConfigEntryAuthFailed from err except Exception as err: - _LOGGER.exception( - f"Device [{self._id}] async_update_data error: {err}") + _LOGGER.exception(f"Device [{self._id}] async_update_data error: {err}") raise UpdateFailed(f"OpenWrt communication error: {err}") return async_update_data @@ -326,4 +354,4 @@ def new_coordinator(hass, config: dict, all_devices: dict) -> DeviceCoordinator: _LOGGER.debug(f"new_coordinator: {config}, {all_devices}") connection = new_ubus_client(hass, config) device = DeviceCoordinator(hass, config, connection, all_devices) - return device \ No newline at end of file + return device diff --git a/custom_components/openwrt/ubus.py b/custom_components/openwrt/ubus.py index b52e3d1..e4a5c41 100644 --- a/custom_components/openwrt/ubus.py +++ b/custom_components/openwrt/ubus.py @@ -9,7 +9,6 @@ DEFAULT_TIMEOUT: int = 15 - class Ubus: def __init__( self, @@ -36,15 +35,21 @@ async def api_call( params: dict, rpc_method: str = "call" ) -> dict: + _LOGGER.debug(f"Starting api_call with subsystem: {subsystem}, method: {method}, params: {params}") try: - if self.session_id != "": + if self.session_id: return await self._api_call(rpc_method, subsystem, method, params) except PermissionError as err: - pass + _LOGGER.error(f"PermissionError during api_call: {err}") + except NameError as err: + _LOGGER.error(f"NameError during api_call: {err}") + return {} # Return an empty dict if the object is not found + await self._login() return await self._api_call(rpc_method, subsystem, method, params) async def _login(self): + _LOGGER.debug("Logging in to Ubus...") result = await self._api_call( "call", "session", @@ -77,7 +82,7 @@ async def _api_call( "params": _params, } ) - _LOGGER.debug('New call [%s] %s', self.url, data) + _LOGGER.debug(f'New API call to [{self.url}] with data: {data}') self.rpc_id += 1 try: def post(): @@ -89,36 +94,37 @@ def post(): ) response = await self.executor_job(post) except Exception as err: - _LOGGER.error("api_call exception: %s", err) + _LOGGER.error(f"api_call exception: {err}") raise ConnectionError from err if response.status_code != 200: - _LOGGER.error("api_call http error: %d", response.status_code) - raise ConnectionError(f"Http error: {response.status_code}") + _LOGGER.error(f"api_call http error: {response.status_code}") + raise ConnectionError(f"HTTP error: {response.status_code}") json_response = response.json() - _LOGGER.debug('Raw json: [%s] %s', self.url, json_response) + _LOGGER.debug(f'Raw JSON response from [{self.url}]: {json_response}') if "error" in json_response: code = json_response['error'].get('code') message = json_response['error'].get('message') - _LOGGER.error("api_call rpc error: %s", json_response["error"]) + _LOGGER.error(f"api_call RPC error: {json_response['error']}") if code == -32002: raise PermissionError(message) if code == -32000: raise NameError(message) - raise ConnectionError(f"rpc error: {message}") + raise ConnectionError(f"RPC error: {message}") + result = json_response['result'] if rpc_method == "list": return result result_code = result[0] if result_code == 8: - raise ConnectionError(f"rpc error: not allowed") + raise ConnectionError(f"RPC error: not allowed") if result_code == 6: - raise PermissionError(f"rpc error: insufficient permissions") + raise PermissionError(f"RPC error: insufficient permissions") if result_code == 0: return json_response['result'][1] if len(result) > 1 else {} - raise ConnectionError(f"rpc error: {result[0]}") - + raise ConnectionError(f"RPC error: {result[0]}") + async def api_list(self): - return await self.api_call("*", None, None, "list") + return await self.api_call("*", None, None, "list") \ No newline at end of file