Skip to content

Commit

Permalink
Create client after init failure / Reduce CCU calls (#239)
Browse files Browse the repository at this point in the history
* Try create client after init failure

* Reduce CCU calls

* Cleanup device.py

* Update Example und test
  • Loading branch information
SukramJ authored Jan 27, 2022
1 parent 2f58fc0 commit e939ae6
Show file tree
Hide file tree
Showing 10 changed files with 291 additions and 184 deletions.
4 changes: 4 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Version 0.28.0 (2022-01-27)
- Try create client after init failure
- Reduce CCU calls

Version 0.27.2 (2022-01-25)
- Optimize data_load

Expand Down
13 changes: 5 additions & 8 deletions example.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,10 @@ def systemcallback(self, src, *args):
self.got_devices = True
print("Number of new device descriptions: %i" % len(args[0]))
return
elif src == const.HH_EVENT_DEVICES_CREATED:
if len(self.central.hm_devices) > 1:
self.got_devices = True
print("New devices:")
print(len(args[0]))
print("New entities:")
print(len(args[1]))
elif src == const.HH_EVENT_DEVICES_CREATED and args and args[0] and len(args[0]) > 0:
self.got_devices = True
print("New devices:")
print(len(args[0]))
return
for arg in args:
print("argument: %s" % arg)
Expand Down Expand Up @@ -102,7 +99,7 @@ async def example_run(self):
await self.central.create_clients(client_configs)
# Once the central_1 is running we subscribe to receive messages.
await self.central.init_clients()

self.central.start_connection_checker()
while not self.got_devices and self.SLEEPCOUNTER < 20:
print("Waiting for devices")
self.SLEEPCOUNTER += 1
Expand Down
81 changes: 55 additions & 26 deletions hahomematic/central_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ def __init__(self, central_config: CentralConfig):
hm_data.INSTANCES[self.instance_name] = self
self._connection_checker = ConnectionChecker(self)
self.hub: HmHub | HmDummyHub | None = None
self._saved_client_configs: set[hm_client.ClientConfig] | None = None

@property
def domain(self) -> str:
Expand Down Expand Up @@ -225,14 +226,14 @@ async def load_caches(self) -> None:
_LOGGER.warning("load_caches: Failed to load caches.")
await self.clear_all()

def _create_devices(self) -> None:
async def _create_devices(self) -> None:
"""Create the devices."""
if not self._clients:
raise Exception(
"_create_devices: No clients initialized. Not starting central_unit."
)
try:
create_devices(self)
await create_devices(self)
except Exception as err:
_LOGGER.error(
"_create_devices: Exception (%s) Failed to create entities", err.args
Expand Down Expand Up @@ -325,7 +326,7 @@ async def add_new_devices(
await self.paramset_descriptions.save()
await client.fetch_names()
await self.names.save()
create_devices(self)
await create_devices(self)

async def stop(self) -> None:
"""
Expand All @@ -334,14 +335,8 @@ async def stop(self) -> None:
"""
_LOGGER.info("stop: Stop connection checker.")
self._stop_connection_checker()
for name, client in self._clients.items():
if await client.proxy_de_init():
_LOGGER.info("stop: Proxy de-initialized: %s", name)
client.stop()

_LOGGER.info("stop: Clearing existing clients. Please recreate them!")
self._clients.clear()
self._clients_by_init_url.clear()
await self._de_init_client()

# un-register this instance from XMLRPCServer
self._xml_rpc_server.un_register_central(central=self)
Expand All @@ -351,11 +346,37 @@ async def stop(self) -> None:
_LOGGER.info("stop: Removing instance")
del hm_data.INSTANCES[self.instance_name]

async def create_clients(self, client_configs: set[hm_client.ClientConfig]) -> None:
async def _de_init_client(self) -> None:
"""De-init clients"""
for name, client in self._clients.items():
if await client.proxy_de_init():
_LOGGER.info("stop: Proxy de-initialized: %s", name)
client.stop()

_LOGGER.info("stop: Clearing existing clients.")
self._clients.clear()
self._clients_by_init_url.clear()

async def create_clients(
self, client_configs: set[hm_client.ClientConfig] | None = None
) -> bool:
"""Create clients for the central unit. Start connection checker afterwards"""
if client_configs is None:
client_configs = self._saved_client_configs
_LOGGER.warning(
"create_clients: Trying to create interfaces to central %s. Using saved client configs)",
self.instance_name,
)

for client_config in client_configs:
try:
if client_configs is None:
_LOGGER.warning(
"create_clients: Failed to create interfaces to central %s. Missing client configs)",
self.instance_name,
)
return False

try:
for client_config in client_configs:
if client := await client_config.get_client():
_LOGGER.debug(
"create_clients: Adding client %s to central.",
Expand All @@ -366,22 +387,25 @@ async def create_clients(self, client_configs: set[hm_client.ClientConfig]) -> N
if client.init_url not in self._clients_by_init_url:
self._clients_by_init_url[client.init_url] = []
self._clients_by_init_url[client.init_url].append(client)
await self.rooms.load()
self._create_devices()
except BaseHomematicException as ex:
_LOGGER.debug(
"create_clients: Failed to create interface %s to central. (%s)",
client_config.name,
ex.args,
)
await self.rooms.load()
await self._create_devices()
return True
except BaseHomematicException as ex:
await self._de_init_client()
_LOGGER.warning(
"create_clients: Failed to create interfaces for central %s. (%s)",
self.clients,
ex.args,
)
# Save client config for later use
self._saved_client_configs = client_configs
return False

async def init_clients(self) -> None:
"""Init clients of control unit, and start connection checker."""
for client in self._clients.values():
await client.proxy_init()

self._start_connection_checker()

def create_task(self, target: Awaitable) -> None:
"""Add task to the executor pool."""
try:
Expand Down Expand Up @@ -421,7 +445,7 @@ async def async_add_executor_job(
)
raise HaHomematicException from cer

def _start_connection_checker(self) -> None:
def start_connection_checker(self) -> None:
"""Start the connection checker."""
if self.model is not BACKEND_PYDEVCCU:
self._connection_checker.start()
Expand Down Expand Up @@ -555,8 +579,6 @@ async def get_paramset(
interface_id: str,
channel_address: str,
paramset_key: str,
value: Any,
rx_mode: str | None = None,
) -> Any:
"""Set paramsets manually."""

Expand Down Expand Up @@ -679,6 +701,13 @@ async def _check_connection(self) -> None:
)
await asyncio.sleep(connection_checker_interval)
await self._central.reconnect()
elif len(self._central.clients) == 0:
_LOGGER.error(
"check_connection: No clients exist. Trying to create clients for server %s",
self._central.instance_name,
)
await self._central.create_clients()
await self._central.init_clients()
await asyncio.sleep(connection_checker_interval)
except NoConnection as nex:
_LOGGER.error("check_connection: no connection: %s", nex.args)
Expand Down
18 changes: 9 additions & 9 deletions hahomematic/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ async def fetch_paramset_description(
"""
Fetch a specific paramset and add it to the known ones.
"""
_LOGGER.debug("fetch_paramset: %s for %s", paramset, channel_address)
_LOGGER.debug("fetch_paramset_description: %s for %s", paramset, channel_address)

try:
parameter_data = await self._proxy.getParamsetDescription(
Expand All @@ -338,7 +338,7 @@ async def fetch_paramset_description(
)
except BaseHomematicException as hhe:
_LOGGER.warning(
"fetch_paramset: %s (%s) Unable to get paramset %s for channel_address %s",
"fetch_paramset_description: %s (%s) Unable to get paramset %s for channel_address %s",
hhe.name,
hhe.args,
paramset,
Expand All @@ -356,7 +356,7 @@ async def fetch_paramset_descriptions(
device_description=device_description, relevant_paramsets=RELEVANT_PARAMSETS
)
for address, paramsets in data.items():
_LOGGER.debug("fetch_paramsets for %s", address)
_LOGGER.debug("fetch_paramset_descriptions for %s", address)
for paramset, paramset_description in paramsets.items():
self._central.paramset_descriptions.add(
interface_id=self.interface_id,
Expand All @@ -376,7 +376,7 @@ async def get_paramset_descriptions(
paramsets: dict[str, dict[str, Any]] = {}
address = device_description[ATTR_HM_ADDRESS]
paramsets[address] = {}
_LOGGER.debug("get_paramsets for %s", address)
_LOGGER.debug("get_paramset_descriptions for %s", address)
for paramset in device_description.get(ATTR_HM_PARAMSETS, []):
if relevant_paramsets and paramset not in relevant_paramsets:
continue
Expand All @@ -394,10 +394,10 @@ async def get_paramset_descriptions(
)
return paramsets

async def get_all_paramsets(
async def get_all_paramset_descriptions(
self, device_descriptions: list[dict[str, Any]]
) -> dict[str, dict[str, Any]]:
"""Get all paramsets for provided device descriptions."""
"""Get all paramset descriptions for provided device descriptions."""
all_paramsets: dict[str, dict[str, Any]] = {}
for device_description in device_descriptions:
all_paramsets.update(
Expand All @@ -409,19 +409,19 @@ async def get_all_paramsets(

async def update_paramset_descriptions(self, device_address: str) -> None:
"""
Update paramsets for provided device_address.
Update paramsets descriptionsfor provided device_address.
"""
if not self._central.raw_devices.get_interface(interface_id=self.interface_id):
_LOGGER.warning(
"update_paramsets: Interface ID missing in central_unit.raw_devices.devices_raw_dict. Not updating paramsets for %s.",
"update_paramset_descriptions: Interface ID missing in central_unit.raw_devices.devices_raw_dict. Not updating paramsets for %s.",
device_address,
)
return
if not self._central.raw_devices.get_device(
interface_id=self.interface_id, device_address=device_address
):
_LOGGER.warning(
"update_paramsets: Channel missing in central_unit.raw_devices.devices_raw_dict[_interface_id]. Not updating paramsets for %s.",
"update_paramset_descriptions: Channel missing in central_unit.raw_devices.devices_raw_dict[_interface_id]. Not updating paramsets for %s.",
device_address,
)
return
Expand Down
4 changes: 3 additions & 1 deletion hahomematic/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
# However, usually multiple of these events are fired, so we should only
# act on the last one. This also only seems to fire on channel 0.
EVENT_CONFIG_PENDING = "CONFIG_PENDING"
EVENT_UPDATE_PENDING = "UPDATE_PENDING"
EVENT_ERROR = "ERROR"

# Only available on CCU
Expand Down Expand Up @@ -72,6 +73,7 @@
EVENT_ERROR,
EVENT_STICKY_UN_REACH,
EVENT_UN_REACH,
EVENT_UPDATE_PENDING,
]

BUTTON_ACTIONS = ["RESET_MOTION", "RESET_PRESENCE"]
Expand Down Expand Up @@ -125,7 +127,6 @@
"TEMPERATURE_LIMITER",
"TEMPERATURE_OUT_OF_RANGE",
"TIME_OF_OPERATION",
"UPDATE_PENDING",
"WOCHENPROGRAMM",
]

Expand Down Expand Up @@ -266,6 +267,7 @@ class HmEntityUsage(Enum):
CE_SECONDARY = "ce_secondary"
CE_SENSOR = "ce_sensor"
ENTITY_NO_CREATE = "entity_no_create"
ENTITY_NO_PARAMSET_DATA = "entity_no_paramset_data"
ENTITY = "ENTITY"
EVENT = "event"

Expand Down
Loading

0 comments on commit e939ae6

Please sign in to comment.