From 7b0fd666c2b7e0632671b49a2a465ee6db295d1d Mon Sep 17 00:00:00 2001 From: SukramJ Date: Tue, 18 Jan 2022 16:15:49 +0100 Subject: [PATCH] Generic schema for entities is name(str):channel(int), (#211) * Improve logging * Generic schema for entities is name(str):channel(int), everthing else is custom. --- changelog.txt | 5 +- hahomematic/central_unit.py | 24 +++++----- hahomematic/client.py | 81 ++++++++++++++++++--------------- hahomematic/device.py | 10 ++-- hahomematic/entity.py | 16 ++++--- hahomematic/helpers.py | 26 +++++++++-- hahomematic/hub.py | 2 +- hahomematic/json_rpc_client.py | 29 ++++++++---- hahomematic/platforms/number.py | 4 +- hahomematic/xml_rpc_server.py | 2 +- setup.py | 2 +- 11 files changed, 122 insertions(+), 79 deletions(-) diff --git a/changelog.txt b/changelog.txt index 28b470bf..c61e1acf 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,7 @@ -Version 0.24.3 (2022-01-18) +Version 0.24.4 (2022-01-18) +- Improve logging +- Generic schema for entities is name(str):channel(int), everthing else is custom. + - Fix sysvar unique_id - Slugify sysvar name - Kill executor on shutdown diff --git a/hahomematic/central_unit.py b/hahomematic/central_unit.py index 707963ca..141d2a2d 100644 --- a/hahomematic/central_unit.py +++ b/hahomematic/central_unit.py @@ -232,7 +232,9 @@ def _create_devices(self) -> None: try: create_devices(self) except Exception as err: - _LOGGER.error("_create_devices: Failed to create entities") + _LOGGER.error( + "_create_devices: Exception (%s) Failed to create entities", err.args + ) raise HaHomematicException("entity-creation-error") from err async def delete_device(self, interface_id: str, device_address: str) -> None: @@ -282,7 +284,7 @@ async def delete_devices(self, interface_id: str, addresses: list[str]) -> None: hm_device.remove_from_collections() del self.hm_devices[address] except KeyError: - _LOGGER.error("delete_devices: Failed to delete: %s", address) + _LOGGER.warning("delete_devices: Failed to delete: %s", address) await self.paramsets.save() await self.names.save() @@ -298,7 +300,7 @@ async def add_new_devices( ) if interface_id not in self._clients: - _LOGGER.error( + _LOGGER.warning( "add_new_devices: Missing client for interface_id %s.", interface_id, ) @@ -315,8 +317,8 @@ async def add_new_devices( if dev_desc[ATTR_HM_ADDRESS] not in known_addresses: self.raw_devices.add_device_description(interface_id, dev_desc) await client.fetch_paramsets(dev_desc) - except Exception: - _LOGGER.error("add_new_devices: Exception") + except Exception as err: + _LOGGER.error("add_new_devices: Exception (%s)", err.args) await self.raw_devices.save() await self.paramsets.save() await client.fetch_names() @@ -344,7 +346,7 @@ async def stop(self) -> None: # un-register and stop XMLRPCServer, if possible xml_rpc.un_register_xml_rpc_server() - _LOGGER.debug("stop: Removing instance") + _LOGGER.info("stop: Removing instance") del hm_data.INSTANCES[self.instance_name] async def create_clients(self, client_configs: set[hm_client.ClientConfig]) -> None: @@ -430,7 +432,7 @@ async def is_connected(self) -> bool: """Check connection to ccu.""" for client in self._clients.values(): if not await client.is_connected(): - _LOGGER.warning( + _LOGGER.error( "is_connected: No connection to %s.", client.interface_id, ) @@ -640,7 +642,7 @@ async def _check_connection(self) -> None: ) try: if not await self._central.is_connected(): - _LOGGER.warning( + _LOGGER.error( "check_connection: No connection to server %s", self._central.instance_name, ) @@ -651,8 +653,8 @@ async def _check_connection(self) -> None: _LOGGER.error("check_connection: no connection: %s", nex.args) await asyncio.sleep(connection_checker_interval) continue - except Exception: - _LOGGER.error("check_connection: Exception") + except Exception as err: + _LOGGER.error("check_connection: Exception (%s)", err.args) class CentralConfig: @@ -896,7 +898,7 @@ async def cleanup(self, interface_id: str, deleted_addresses: list[str]) -> None if self._dev_descriptions.get(interface_id, {}).get(address, {}): del self._dev_descriptions[interface_id][address] except KeyError: - _LOGGER.error("cleanup: Failed to delete: %s", address) + _LOGGER.warning("cleanup: Failed to delete: %s", address) await self.save() def get_addresses(self, interface_id: str) -> dict[str, list[str]]: diff --git a/hahomematic/client.py b/hahomematic/client.py index cbcfd3b1..dc80d643 100644 --- a/hahomematic/client.py +++ b/hahomematic/client.py @@ -94,9 +94,11 @@ async def proxy_init(self) -> int: ) await self._proxy.init(self._init_url, self.interface_id) _LOGGER.info("proxy_init: Proxy for %s initialized", self.interface_id) - except BaseHomematicException: + except BaseHomematicException as hhe: _LOGGER.error( - "proxy_init: Failed to initialize proxy for %s", + "proxy_init: %s (%s) Failed to initialize proxy for %s", + hhe.name, + hhe.args, self.interface_id, ) self.last_updated = INIT_DATETIME @@ -121,9 +123,10 @@ async def proxy_de_init(self) -> int: await self._proxy.init(self._init_url) except BaseHomematicException as hhe: _LOGGER.error( - "proxy_de_init: Failed to de-initialize proxy for %s (%s)", - self.name, + "proxy_de_init: %s (%s) Failed to de-initialize proxy for %s", hhe.name, + hhe.args, + self.name, ) return PROXY_DE_INIT_FAILED @@ -200,7 +203,7 @@ async def get_service_messages(self) -> Any: try: return await self._proxy.getServiceMessages() except BaseHomematicException as hhe: - _LOGGER.error("get_service_messages: %s", hhe.name) + _LOGGER.warning("get_service_messages: %s (%s)", hhe.name, hhe.args) return None # pylint: disable=invalid-name @@ -223,14 +226,14 @@ async def set_install_mode( await self._proxy.setInstallMode(*args) except BaseHomematicException as hhe: - _LOGGER.error("set_install_mode: %s", hhe.name) + _LOGGER.warning("set_install_mode: %s (%s)", hhe.name, hhe.args) async def get_install_mode(self) -> Any: """Get remaining time in seconds install mode is active from CCU / Homegear.""" try: return await self._proxy.getInstallMode() except BaseHomematicException as hhe: - _LOGGER.error("get_install_mode: %s", hhe.name) + _LOGGER.warning("get_install_mode: %s (%s)", hhe.name, hhe.args) return 0 async def get_value(self, channel_address: str, parameter: str) -> Any: @@ -287,9 +290,10 @@ async def put_paramset( await self._proxy.putParamset(channel_address, paramset, value) _LOGGER.debug("put_paramset: %s, %s, %s", channel_address, paramset, value) except BaseHomematicException as hhe: - _LOGGER.error( - "put_paramset failed: %s: %s, %s, %s", + _LOGGER.warning( + "put_paramset failed: %s (%s) %s, %s, %s", hhe.name, + hhe.args, channel_address, paramset, value, @@ -312,11 +316,12 @@ async def fetch_paramset(self, channel_address: str, paramset: str) -> None: paramset_description=parameter_data, ) except BaseHomematicException as hhe: - _LOGGER.error( - "fetch_paramset: Unable to get paramset %s for channel_address %s (%s).", + _LOGGER.warning( + "fetch_paramset: %s (%s) Unable to get paramset %s for channel_address %s", + hhe.name, + hhe.args, paramset, channel_address, - hhe.name, ) await self._central.paramsets.save() @@ -365,7 +370,6 @@ async def get_paramsets( hhe.args, paramset, address, - ) return paramsets @@ -430,7 +434,7 @@ async def fetch_names(self) -> None: "Device.listAllDetail", ) if response[ATTR_ERROR] is None and response[ATTR_RESULT]: - _LOGGER.debug("fetch_names_json: Resolving devicenames") + _LOGGER.debug("fetch_names_json: Resolving device names") for device in response[ATTR_RESULT]: self._central.names.add(device[ATTR_ADDRESS], device[ATTR_NAME]) for channel in device.get(ATTR_CHANNELS, []): @@ -438,7 +442,7 @@ async def fetch_names(self) -> None: channel[ATTR_ADDRESS], channel[ATTR_NAME] ) except BaseHomematicException as hhe: - _LOGGER.error("fetch_names_json: %s, %s", hhe.name, hhe.args) + _LOGGER.warning("fetch_names_json: %s, %s", hhe.name, hhe.args) async def _check_connection(self) -> bool: """Check if _proxy is still initialized.""" @@ -448,7 +452,7 @@ async def _check_connection(self) -> bool: self.last_updated = datetime.now() return True except BaseHomematicException as hhe: - _LOGGER.error("ping: failed for %s", hhe.name) + _LOGGER.error("ping: failed for %s (%s)", hhe.name, hhe.args) self.last_updated = INIT_DATETIME return False @@ -482,8 +486,8 @@ async def set_system_variable(self, name: str, value: Any) -> None: "set_system_variable: Error while setting variable: %s", str(response[ATTR_ERROR]), ) - except BaseHomematicException: - _LOGGER.error("set_system_variable: Exception") + except BaseHomematicException as hhe: + _LOGGER.warning("set_system_variable: %s (%s)", hhe.name, hhe.args) async def delete_system_variable(self, name: str) -> None: """Delete a system variable from CCU / Homegear.""" @@ -503,8 +507,8 @@ async def delete_system_variable(self, name: str) -> None: if response[ATTR_ERROR] is None and response[ATTR_RESULT]: deleted = response[ATTR_RESULT] _LOGGER.info("delete_system_variable: Deleted: %s", str(deleted)) - except BaseHomematicException: - _LOGGER.error("delete_system_variable: Exception") + except BaseHomematicException as hhe: + _LOGGER.warning("delete_system_variable: %s (%s)", hhe.name, hhe.args) async def get_system_variable(self, name: str) -> Any: """Get single system variable from CCU / Homegear.""" @@ -528,8 +532,8 @@ async def get_system_variable(self, name: str) -> Any: var = float(response[ATTR_RESULT]) except Exception: var = response[ATTR_RESULT] == "true" - except BaseHomematicException: - _LOGGER.error("get_system_variable: Exception") + except BaseHomematicException as hhe: + _LOGGER.warning("get_system_variable: %s (%s)", hhe.name, hhe.args) return var @@ -553,8 +557,8 @@ async def get_all_system_variables(self) -> dict[str, Any]: for var in response[ATTR_RESULT]: key, value = parse_ccu_sys_var(var) variables[key] = value - except BaseHomematicException: - _LOGGER.error("get_all_system_variables: Exception") + except BaseHomematicException as hhe: + _LOGGER.warning("get_all_system_variables: %s (%s)", hhe.name, hhe.args) return variables @@ -587,8 +591,10 @@ async def _get_all_channel_ids_room(self) -> dict[str, str]: channel_ids_room[room["id"]] = room["name"] for channel_id in room["channelIds"]: channel_ids_room[channel_id] = room["name"] - except BaseHomematicException: - _LOGGER.error("_get_all_channel_ids_per_room: Exception") + except BaseHomematicException as hhe: + _LOGGER.warning( + "_get_all_channel_ids_per_room: %s (%s)", hhe.name, hhe.args + ) return channel_ids_room @@ -613,8 +619,8 @@ async def _get_device_channel_ids(self) -> dict[str, str]: device_channel_ids[device["address"]] = device["id"] for channel in device["channels"]: device_channel_ids[channel["address"]] = channel["id"] - except BaseHomematicException: - _LOGGER.error("_get_device_channel_ids: Exception") + except BaseHomematicException as hhe: + _LOGGER.warning("_get_device_channel_ids: %s (%s)", hhe.name, hhe.args) return device_channel_ids @@ -658,10 +664,11 @@ async def fetch_names(self) -> None: await self._proxy.getMetadata(address, ATTR_HM_NAME), ) except BaseHomematicException as hhe: - _LOGGER.error( - "Failed to fetch name for device %s (%s).", - address, + _LOGGER.warning( + "%s (%s) Failed to fetch name for device %s", hhe.name, + hhe.args, + address, ) async def _check_connection(self) -> bool: @@ -671,8 +678,8 @@ async def _check_connection(self) -> bool: self.last_updated = datetime.now() return True except BaseHomematicException as hhe: - _LOGGER.error("ping: %s", hhe.name) - _LOGGER.warning( + _LOGGER.error("ping: %s (%s)", hhe.name, hhe.args) + _LOGGER.debug( "_check_connection: Setting initialized to 0 for %s", self.interface_id, ) @@ -684,28 +691,28 @@ async def set_system_variable(self, name: str, value: Any) -> None: try: await self._proxy.setSystemVariable(name, value) except BaseHomematicException as hhe: - _LOGGER.error("set_system_variable: %s", hhe.name) + _LOGGER.warning("set_system_variable: %s (%s)", hhe.name, hhe.args) async def delete_system_variable(self, name: str) -> None: """Delete a system variable from CCU / Homegear.""" try: await self._proxy.deleteSystemVariable(name) except BaseHomematicException as hhe: - _LOGGER.error("delete_system_variable: %s", hhe.name) + _LOGGER.warning("delete_system_variable: %s (%s)", hhe.name, hhe.args) async def get_system_variable(self, name: str) -> Any: """Get single system variable from CCU / Homegear.""" try: return await self._proxy.getSystemVariable(name) except BaseHomematicException as hhe: - _LOGGER.error("get_system_variable: %s", hhe.name) + _LOGGER.warning("get_system_variable: %s (%s)", hhe.name, hhe.args) async def get_all_system_variables(self) -> Any: """Get all system variables from CCU / Homegear.""" try: return await self._proxy.getAllSystemVariables() except BaseHomematicException as hhe: - _LOGGER.error("get_all_system_variables: %s", hhe.name) + _LOGGER.warning("get_all_system_variables: %s (%s)", hhe.name, hhe.args) return None async def get_all_rooms(self) -> dict[str, str]: diff --git a/hahomematic/device.py b/hahomematic/device.py index e1225f02..ede337b4 100644 --- a/hahomematic/device.py +++ b/hahomematic/device.py @@ -666,18 +666,20 @@ def create_devices(central: hm_central.CentralUnit) -> None: ) new_devices.add(device_address) central.hm_devices[device_address] = device - except Exception: + except Exception as err: _LOGGER.error( - "create_devices: Failed to create device: %s, %s", + "create_devices: Exception (%s) Failed to create device: %s, %s", + err.args, interface_id, device_address, ) try: if device: new_entities.extend(device.create_entities()) - except Exception: + except Exception as err: _LOGGER.error( - "create_devices: Failed to create entities: %s, %s", + "create_devices: Exception (%s) Failed to create entities: %s, %s", + err.args, interface_id, device_address, ) diff --git a/hahomematic/entity.py b/hahomematic/entity.py index 4e506ff5..5b51b683 100644 --- a/hahomematic/entity.py +++ b/hahomematic/entity.py @@ -338,9 +338,11 @@ async def send_value(self, value: Any) -> None: parameter=self.parameter, value=self._convert_value(value), ) - except BaseHomematicException: - _LOGGER.error( - "generic_entity: Failed to set state for: %s, %s, %s, %s", + except BaseHomematicException as hhe: + _LOGGER.warning( + "generic_entity: %s (%s) Failed to set state for: %s, %s, %s, %s", + hhe.name, + hhe.args, self._device.device_type, self.channel_address, self.parameter, @@ -769,9 +771,11 @@ async def send_value(self, value: Any) -> None: parameter=self.parameter, value=value, ) - except BaseHomematicException: - _LOGGER.error( - "action_event: Failed to send value for: %s, %s, %s", + except BaseHomematicException as hhe: + _LOGGER.warning( + "action_event: %s (%s) Failed to send value for: %s, %s, %s", + hhe.name, + hhe.args, self.channel_address, self.parameter, value, diff --git a/hahomematic/helpers.py b/hahomematic/helpers.py index a6ba2df0..ba2b5386 100644 --- a/hahomematic/helpers.py +++ b/hahomematic/helpers.py @@ -135,7 +135,7 @@ def get_entity_name( channel_address=channel_address, device_type=device_type, ): - if entity_name.count(":") == 1: + if _check_channel_name_with_channel_no(name=entity_name): d_name = entity_name.split(":")[0] p_name = parameter.title().replace("_", " ") c_name = "" @@ -173,7 +173,7 @@ def get_event_name( channel_address=channel_address, device_type=device_type, ): - if event_name.count(":") == 1: + if _check_channel_name_with_channel_no(name=event_name): d_name = event_name.split(":")[0] p_name = parameter.title().replace("_", " ") c_no = event_name.split(":")[1] @@ -209,10 +209,14 @@ def get_custom_entity_name( channel_address=f"{device_address}:{channel_no}", device_type=device_type, ): - if is_only_primary_channel and ":" in custom_entity_name: + if is_only_primary_channel and _check_channel_name_with_channel_no( + name=custom_entity_name + ): return custom_entity_name.split(":")[0] - marker = " ch" if usage == HmEntityUsage.CE_PRIMARY else " vch" - return custom_entity_name.replace(":", marker) + if _check_channel_name_with_channel_no(name=custom_entity_name): + marker = " ch" if usage == HmEntityUsage.CE_PRIMARY else " vch" + return custom_entity_name.replace(":", marker) + return custom_entity_name _LOGGER.debug( "Helper.get_custom_entity_name: Using unique_id for %s %s %s", @@ -223,6 +227,18 @@ def get_custom_entity_name( return unique_id +def _check_channel_name_with_channel_no(name: str) -> bool: + """check if name contains channel and this is an int.""" + if name.count(":") == 1: + channel_part = name.split(":")[1] + try: + int(channel_part) + return True + except ValueError: + return False + return False + + def get_device_name( central: hm_central.CentralUnit, device_address: str, device_type: str ) -> str: diff --git a/hahomematic/hub.py b/hahomematic/hub.py index 268972e2..36fef1d7 100644 --- a/hahomematic/hub.py +++ b/hahomematic/hub.py @@ -274,7 +274,7 @@ def _create_system_variable(self, name: str, value: Any) -> None: async def set_system_variable(self, name: str, value: Any) -> None: """Set variable value on CCU/Homegear.""" if name not in self.hub_entities: - _LOGGER.error("Variable %s not found on %s", name, self.name) + _LOGGER.warning("Variable %s not found on %s", name, self.name) return await self._central.set_system_variable(name, value) diff --git a/hahomematic/json_rpc_client.py b/hahomematic/json_rpc_client.py index 68bcd9c0..bb6af436 100644 --- a/hahomematic/json_rpc_client.py +++ b/hahomematic/json_rpc_client.py @@ -76,8 +76,10 @@ async def _renew_login(self, session_id: str) -> str | None: if response[ATTR_ERROR] is None and response[ATTR_RESULT]: return str(response[ATTR_RESULT]) return await self._login() - except ClientError: - _LOGGER.error("renew: Exception while renewing JSON-RPC session.") + except ClientError as cer: + _LOGGER.error( + "renew: ClientError (%s) while renewing JSON-RPC session", cer.args + ) return None async def _login(self) -> str | None: @@ -110,8 +112,10 @@ async def _login(self) -> str | None: ) return None return session_id - except BaseHomematicException: - _LOGGER.error("login: Exception while logging in via JSON-RPC") + except BaseHomematicException as hhe: + _LOGGER.error( + "login: %s (%s) while logging in via JSON-RPC", hhe.name, hhe.args + ) return None async def post( @@ -129,7 +133,7 @@ async def post( session_id = await self._login() if not session_id: - _LOGGER.error("post: Exception while logging in via JSON-RPC.") + _LOGGER.warning("post: Error while logging in via JSON-RPC.") return {"error": "Unable to open session.", "result": {}} result = await self._post( @@ -189,14 +193,17 @@ async def _post( if resp.status == 200: try: return await resp.json(encoding="utf-8") - except ValueError: - _LOGGER.error("_post: Failed to parse JSON. Trying workaround.") + except ValueError as ver: + _LOGGER.error( + "_post: ValueError (%s) Failed to parse JSON. Trying workaround", + ver.args, + ) # Workaround for bug in CCU return json.loads( (await resp.json(encoding="utf-8")).replace("\\", "") ) else: - _LOGGER.error("_post: Status: %i", resp.status) + _LOGGER.warning("_post: Status: %i", resp.status) return {"error": resp.status, "result": {}} except ClientConnectorError as err: _LOGGER.error("_post: ClientConnectorError") @@ -231,8 +238,10 @@ async def _logout(self, session_id: str | None) -> None: ) if response[ATTR_ERROR]: _LOGGER.warning("logout: Logout error: %s", response[ATTR_RESULT]) - except ClientError: - _LOGGER.error("logout: Exception while logging in via JSON-RPC") + except ClientError as cer: + _LOGGER.error( + "logout: ClientError (%s) while logging in via JSON-RPC", cer.args + ) return diff --git a/hahomematic/platforms/number.py b/hahomematic/platforms/number.py index bc9e5506..f540e852 100644 --- a/hahomematic/platforms/number.py +++ b/hahomematic/platforms/number.py @@ -52,7 +52,7 @@ async def send_value(self, value: float) -> None: if [sv for sv in self._special.values() if value == sv[ATTR_HM_VALUE]]: await super().send_value(value) else: - _LOGGER.error( + _LOGGER.warning( "number.float: Invalid value: %s (min: %s, max: %s, special: %s)", value, self._min, @@ -75,7 +75,7 @@ async def send_value(self, value: int) -> None: if [sv for sv in self._special.values() if value == sv[ATTR_HM_VALUE]]: await super().send_value(value) else: - _LOGGER.error( + _LOGGER.warning( "number.int: Invalid value: %s (min: %s, max: %s, special: %s)", value, self._min, diff --git a/hahomematic/xml_rpc_server.py b/hahomematic/xml_rpc_server.py index ab7e79c7..632d5773 100644 --- a/hahomematic/xml_rpc_server.py +++ b/hahomematic/xml_rpc_server.py @@ -86,7 +86,7 @@ def error(self, interface_id: str, error_code: str, msg: str) -> None: """ When some error occurs the CCU / Homegear will send its error message here. """ - _LOGGER.error( + _LOGGER.warning( "error: interface_id = %s, error_code = %i, message = %s", interface_id, int(error_code), diff --git a/setup.py b/setup.py index 4ecf8afa..aef5ac75 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ def readme(): }, PACKAGE_NAME = "hahomematic" HERE = os.path.abspath(os.path.dirname(__file__)) -VERSION = "0.24.3" +VERSION = "0.24.4" PACKAGES = find_packages(exclude=["tests", "tests.*", "dist", "build"])