Skip to content

Commit

Permalink
Merge pull request #34 from FaserF/fix-object-not-found
Browse files Browse the repository at this point in the history
fix object not found
  • Loading branch information
kvj authored Nov 23, 2024
2 parents 78713af + 08dc181 commit f4b61b0
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 53 deletions.
104 changes: 66 additions & 38 deletions custom_components/openwrt/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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):
Expand Down Expand Up @@ -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(
Expand All @@ -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",
Expand All @@ -174,7 +192,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"),
Expand All @@ -184,14 +202,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", "")),
Expand All @@ -203,16 +224,15 @@ 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",
dict(name=name, action=action)
)
_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"),
Expand All @@ -225,7 +245,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:
Expand All @@ -249,7 +278,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] = {
Expand Down Expand Up @@ -307,8 +336,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

Expand Down
36 changes: 21 additions & 15 deletions custom_components/openwrt/ubus.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

DEFAULT_TIMEOUT: int = 15


class Ubus:
def __init__(
self,
Expand All @@ -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",
Expand Down Expand Up @@ -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():
Expand All @@ -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")

0 comments on commit f4b61b0

Please sign in to comment.