Skip to content

Commit ff10349

Browse files
committed
Combine branches (#268)
* weeee * disable watchdog * async update * bubble exception * default * parameterize * parameterize * unused * remove duplicate tests * restructure models and clean up * remove duplicate model * convert to folder modules * add model modules * missed one * restructure * restructure * restructure * typing * mypy and tests * fix test flakiness
1 parent 0c0ffaa commit ff10349

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+3244
-1784
lines changed

tests/conftest.py

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import reprlib
99
import threading
1010
from types import TracebackType
11+
from typing import Self
1112
from unittest.mock import AsyncMock, MagicMock, patch
1213

1314
import aiohttp.test_utils
@@ -214,6 +215,7 @@ async def zigpy_app_controller_fixture():
214215
zigpy.config.CONF_DATABASE: None,
215216
zigpy.config.CONF_DEVICE: {zigpy.config.CONF_DEVICE_PATH: "/dev/null"},
216217
zigpy.config.CONF_STARTUP_ENERGY_SCAN: False,
218+
zigpy.config.CONF_WATCHDOG_ENABLED: False,
217219
zigpy.config.CONF_NWK_BACKUP_ENABLED: False,
218220
zigpy.config.CONF_TOPO_SCAN_ENABLED: False,
219221
zigpy.config.CONF_OTA: {
@@ -328,6 +330,81 @@ async def __aexit__(
328330
await asyncio.sleep(0)
329331

330332

333+
class CombinedWebsocketGateways:
334+
"""Combine multiple gateways into a single one."""
335+
336+
def __init__(
337+
self,
338+
client_gateway: WebSocketClientGateway,
339+
server_gateway: WebSocketServerGateway,
340+
):
341+
"""Initialize the CombinedWebsocketGateways class."""
342+
self.client_gateway = client_gateway
343+
self.server_gateway = server_gateway
344+
self.application_controller = server_gateway.application_controller
345+
346+
async def async_block_till_done(self) -> None:
347+
"""Block until all gateways are done."""
348+
await self.server_gateway.async_block_till_done()
349+
350+
async def async_device_initialized(self, device: zigpy.device.Device) -> None:
351+
"""Handle device joined and basic information discovered (async)."""
352+
await self.server_gateway.async_device_initialized(device)
353+
354+
def get_device(self, ieee: zigpy.types.EUI64):
355+
"""Return Device for given ieee."""
356+
return self.client_gateway.get_device(ieee)
357+
358+
async def shutdown(self) -> None:
359+
"""Stop ZHA Controller Application."""
360+
await self.server_gateway.stop_server()
361+
await self.server_gateway.wait_closed()
362+
363+
364+
class CombinedGateways:
365+
"""Combine multiple gateways into a single one."""
366+
367+
def __init__(self, zha_data: ZHAData):
368+
"""Initialize the CombinedGateways class."""
369+
self.zha_data = zha_data
370+
self.zha_gateway: Gateway
371+
self.ws_gateway: CombinedWebsocketGateways
372+
373+
async def __aenter__(self) -> Self:
374+
"""Start the ZHA gateway."""
375+
self.zha_gateway = await Gateway.async_from_config(self.zha_data)
376+
await self.zha_gateway.async_initialize()
377+
await self.zha_gateway.async_block_till_done()
378+
await self.zha_gateway.async_initialize_devices_and_entities()
379+
INSTANCES.append(self.zha_gateway)
380+
381+
ws_gateway = await WebSocketServerGateway.async_from_config(self.zha_data)
382+
await ws_gateway.start_server()
383+
await ws_gateway.async_initialize()
384+
await ws_gateway.async_block_till_done()
385+
await ws_gateway.async_initialize_devices_and_entities()
386+
387+
client_gateway = WebSocketClientGateway(self.zha_data)
388+
await client_gateway.connect()
389+
await client_gateway.clients.listen()
390+
self.ws_gateway = CombinedWebsocketGateways(client_gateway, ws_gateway)
391+
INSTANCES.append(self.ws_gateway)
392+
return self
393+
394+
async def __aexit__(
395+
self, exc_type: Exception, exc_value: str, traceback: TracebackType
396+
) -> None:
397+
"""Shutdown the ZHA gateway."""
398+
INSTANCES.remove(self.zha_gateway)
399+
await self.zha_gateway.shutdown()
400+
await asyncio.sleep(0)
401+
402+
INSTANCES.remove(self.ws_gateway)
403+
await self.ws_gateway.client_gateway.disconnect()
404+
await self.ws_gateway.shutdown()
405+
await asyncio.sleep(0)
406+
407+
331408
@pytest.fixture
332409
async def connected_client_and_server(
333410
zha_data: ZHAData,
@@ -363,7 +440,7 @@ async def zha_gateway(
363440
zha_data: ZHAData,
364441
zigpy_app_controller,
365442
caplog, # pylint: disable=unused-argument
366-
):
443+
) -> AsyncGenerator[Gateway, None]:
367444
"""Set up ZHA component."""
368445

369446
with (
@@ -380,6 +457,27 @@ async def zha_gateway(
380457
yield gateway
381458

382459

460+
@pytest.fixture
461+
async def zha_gateways(
462+
zha_data: ZHAData,
463+
zigpy_app_controller,
464+
caplog, # pylint: disable=unused-argument
465+
):
466+
"""Set up ZHA component with connected client and server and the regular gateway."""
467+
with (
468+
patch(
469+
"bellows.zigbee.application.ControllerApplication.new",
470+
return_value=zigpy_app_controller,
471+
),
472+
patch(
473+
"bellows.zigbee.application.ControllerApplication",
474+
return_value=zigpy_app_controller,
475+
),
476+
):
477+
async with CombinedGateways(zha_data) as gateway:
478+
yield gateway
479+
480+
383481
@pytest.fixture(scope="session", autouse=True)
384482
def disable_request_retry_delay():
385483
"""Disable ZHA request retrying delay to speed up failures."""
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"ieee":"00:0d:6f:00:0f:3a:e3:69","nwk":"0x970A","manufacturer":"CentraLite","model":"3320-L","name":"CentraLite 3320-L","quirk_applied":true,"quirk_class":"zhaquirks.centralite.ias.CentraLiteIASSensor","quirk_id":null,"manufacturer_code":49887,"power_source":"Battery or Unknown","lqi":null,"rssi":null,"available":true,"device_type":"EndDevice","signature":{"node_descriptor":{"logical_type":2,"complex_descriptor_available":0,"user_descriptor_available":0,"reserved":0,"aps_flags":0,"frequency_band":8,"mac_capability_flags":128,"manufacturer_code":49887,"maximum_buffer_size":82,"maximum_incoming_transfer_size":82,"server_mask":0,"maximum_outgoing_transfer_size":82,"descriptor_capability_field":0},"endpoints":{"1":{"profile_id":"0x0104","device_type":"0x0402","input_clusters":["0x0000","0x0001","0x0003","0x0020","0x0402","0x0500","0x0b05"],"output_clusters":["0x0019"]},"2":{"profile_id":"0xc2df","device_type":"0x000c","input_clusters":["0x0000","0x0003","0x0b05","0xfc0f"],"output_clusters":["0x0003"]}},"manufacturer":"CentraLite","model":"3320-L"},"active_coordinator":false,"entities":{"binary_sensor,00:0d:6f:00:0f:3a:e3:69-1-1280":{"platform":"binary_sensor","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-1280","class_name":"IASZone","translation_key":null,"device_class":"opening","state_class":null,"entity_category":null,"entity_registry_enabled_default":true,"enabled":true,"fallback_name":null,"state":{"class_name":"IASZone","state":false,"available":true},"cluster_handlers":[{"class_name":"IASZoneClusterHandler","generic_id":"cluster_handler_0x0500","endpoint_id":1,"cluster":{"id":1280,"name":"IAS Zone","type":"server","endpoint_id":1,"endpoint_attribute":"ias_zone"},"id":"1:0x0500","unique_id":"00:0d:6f:00:0f:3a:e3:69:1:0x0500","status":"initialized","value_attribute":null}],"device_ieee":"00:0d:6f:00:0f:3a:e3:69","endpoint_id":1,"available":true,"group_id":null,"attribute_name":"zone_status"},"button,00:0d:6f:00:0f:3a:e3:69-1-3":{"platform":"button","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-3","class_name":"IdentifyButton","translation_key":null,"device_class":"identify","state_class":null,"entity_category":"diagnostic","entity_registry_enabled_default":true,"enabled":true,"fallback_name":null,"state":{"class_name":"IdentifyButton","available":true,"state":null},"cluster_handlers":[{"class_name":"IdentifyClusterHandler","generic_id":"cluster_handler_0x0003","endpoint_id":1,"cluster":{"id":3,"name":"Identify","type":"server","endpoint_id":1,"endpoint_attribute":"identify"},"id":"1:0x0003","unique_id":"00:0d:6f:00:0f:3a:e3:69:1:0x0003","status":"initialized","value_attribute":null}],"device_ieee":"00:0d:6f:00:0f:3a:e3:69","endpoint_id":1,"available":true,"group_id":null,"command":"identify","attribute_name":null,"attribute_value":null,"args":[5],"kwargs":{}},"sensor,00:0d:6f:00:0f:3a:e3:69-1-1":{"platform":"sensor","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-1","class_name":"Battery","translation_key":null,"device_class":"battery","state_class":"measurement","entity_category":"diagnostic","entity_registry_enabled_default":true,"enabled":true,"fallback_name":null,"state":{"class_name":"Battery","state":100,"battery_size":"Other","battery_quantity":1,"battery_voltage":2.8,"available":true},"cluster_handlers":[{"class_name":"PowerConfigurationClusterHandler","generic_id":"cluster_handler_0x0001","endpoint_id":1,"cluster":{"id":1,"name":"Power Configuration","type":"server","endpoint_id":1,"endpoint_attribute":"power"},"id":"1:0x0001","unique_id":"00:0d:6f:00:0f:3a:e3:69:1:0x0001","status":"initialized","value_attribute":"battery_voltage"}],"device_ieee":"00:0d:6f:00:0f:3a:e3:69","endpoint_id":1,"available":true,"group_id":null,"attribute":"battery_percentage_remaining","decimals":1,"divisor":1,"multiplier":1,"unit":"%"},"sensor,00:0d:6f:00:0f:3a:e3:69-1-1026":{"platform":"sensor","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-1026","class_name":"Temperature","translation_key":null,"device_class":"temperature","state_class":"measurement","entity_category":null,"entity_registry_enabled_default":true,"enabled":true,"fallback_name":null,"state":{"class_name":"Temperature","available":true,"state":20.2},"cluster_handlers":[{"class_name":"TemperatureMeasurementClusterHandler","generic_id":"cluster_handler_0x0402","endpoint_id":1,"cluster":{"id":1026,"name":"Temperature Measurement","type":"server","endpoint_id":1,"endpoint_attribute":"temperature"},"id":"1:0x0402","unique_id":"00:0d:6f:00:0f:3a:e3:69:1:0x0402","status":"initialized","value_attribute":"measured_value"}],"device_ieee":"00:0d:6f:00:0f:3a:e3:69","endpoint_id":1,"available":true,"group_id":null,"attribute":"measured_value","decimals":1,"divisor":100,"multiplier":1,"unit":"°C"},"sensor,00:0d:6f:00:0f:3a:e3:69-1-0-rssi":{"platform":"sensor","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-0-rssi","class_name":"RSSISensor","translation_key":"rssi","device_class":"signal_strength","state_class":"measurement","entity_category":"diagnostic","entity_registry_enabled_default":false,"enabled":true,"fallback_name":null,"state":{"class_name":"RSSISensor","available":true,"state":null},"cluster_handlers":[{"class_name":"BasicClusterHandler","generic_id":"cluster_handler_0x0000","endpoint_id":1,"cluster":{"id":0,"name":"Basic","type":"server","endpoint_id":1,"endpoint_attribute":"basic"},"id":"1:0x0000","unique_id":"00:0d:6f:00:0f:3a:e3:69:1:0x0000","status":"initialized","value_attribute":null}],"device_ieee":"00:0d:6f:00:0f:3a:e3:69","endpoint_id":1,"available":true,"group_id":null,"attribute":null,"decimals":1,"divisor":1,"multiplier":1,"unit":"dBm"},"sensor,00:0d:6f:00:0f:3a:e3:69-1-0-lqi":{"platform":"sensor","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-0-lqi","class_name":"LQISensor","translation_key":"lqi","device_class":null,"state_class":"measurement","entity_category":"diagnostic","entity_registry_enabled_default":false,"enabled":true,"fallback_name":null,"state":{"class_name":"LQISensor","available":true,"state":null},"cluster_handlers":[{"class_name":"BasicClusterHandler","generic_id":"cluster_handler_0x0000","endpoint_id":1,"cluster":{"id":0,"name":"Basic","type":"server","endpoint_id":1,"endpoint_attribute":"basic"},"id":"1:0x0000","unique_id":"00:0d:6f:00:0f:3a:e3:69:1:0x0000","status":"initialized","value_attribute":null}],"device_ieee":"00:0d:6f:00:0f:3a:e3:69","endpoint_id":1,"available":true,"group_id":null,"attribute":null,"decimals":1,"divisor":1,"multiplier":1,"unit":null},"update,00:0d:6f:00:0f:3a:e3:69-1-25-firmware_update":{"platform":"update","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-25-firmware_update","class_name":"FirmwareUpdateEntity","translation_key":null,"device_class":"firmware","state_class":null,"entity_category":"config","entity_registry_enabled_default":true,"enabled":true,"fallback_name":null,"state":{"class_name":"FirmwareUpdateEntity","available":true,"installed_version":null,"in_progress":false,"progress":0,"latest_version":null,"release_summary":null,"release_notes":null,"release_url":null},"cluster_handlers":[{"class_name":"OtaClientClusterHandler","generic_id":"cluster_handler_0x0019","endpoint_id":1,"cluster":{"id":25,"name":"Ota","type":"client","endpoint_id":1,"endpoint_attribute":"ota"},"id":"1:0x0019","unique_id":"00:0d:6f:00:0f:3a:e3:69:1:0x0019","status":"initialized","value_attribute":null}],"device_ieee":"00:0d:6f:00:0f:3a:e3:69","endpoint_id":1,"available":true,"group_id":null,"supported_features":7}},"neighbors":[],"routes":[],"endpoint_names":[{"name":"IAS_ZONE"},{"name":"unknown 12 device_type of 0xc2df profile id"}],"device_automation_triggers":{"device_offline,device_offline":{"device_event_type":"device_offline"}}}
1+
{"ieee":"00:0d:6f:00:0f:3a:e3:69","nwk":"0x970A","manufacturer":"CentraLite","model":"3320-L","name":"CentraLite 3320-L","quirk_applied":true,"quirk_class":"zhaquirks.centralite.ias.CentraLiteIASSensor","quirk_id":null,"manufacturer_code":49887,"power_source":"Battery or Unknown","lqi":null,"rssi":null,"available":true,"device_type":"EndDevice","signature":{"node_descriptor":{"logical_type":2,"complex_descriptor_available":0,"user_descriptor_available":0,"reserved":0,"aps_flags":0,"frequency_band":8,"mac_capability_flags":128,"manufacturer_code":49887,"maximum_buffer_size":82,"maximum_incoming_transfer_size":82,"server_mask":0,"maximum_outgoing_transfer_size":82,"descriptor_capability_field":0},"endpoints":{"1":{"profile_id":"0x0104","device_type":"0x0402","input_clusters":["0x0000","0x0001","0x0003","0x0020","0x0402","0x0500","0x0b05"],"output_clusters":["0x0019"]},"2":{"profile_id":"0xc2df","device_type":"0x000c","input_clusters":["0x0000","0x0003","0x0b05","0xfc0f"],"output_clusters":["0x0003"]}},"manufacturer":"CentraLite","model":"3320-L"},"active_coordinator":false,"entities":{"binary_sensor,00:0d:6f:00:0f:3a:e3:69-1-1280":{"platform":"binary_sensor","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-1280","class_name":"IASZone","translation_key":null,"device_class":"opening","state_class":null,"entity_category":null,"entity_registry_enabled_default":true,"enabled":true,"fallback_name":null,"state":{"class_name":"IASZone","state":false,"available":true},"cluster_handlers":[{"class_name":"IASZoneClusterHandler","generic_id":"cluster_handler_0x0500","endpoint_id":1,"cluster":{"id":1280,"name":"IAS Zone","type":"server","endpoint_id":1,"endpoint_attribute":"ias_zone"},"id":"1:0x0500","unique_id":"00:0d:6f:00:0f:3a:e3:69:1:0x0500","status":"initialized","value_attribute":null}],"device_ieee":"00:0d:6f:00:0f:3a:e3:69","endpoint_id":1,"available":true,"group_id":null,"attribute_name":"zone_status"},"button,00:0d:6f:00:0f:3a:e3:69-1-3":{"platform":"button","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-3","class_name":"IdentifyButton","translation_key":null,"device_class":"identify","state_class":null,"entity_category":"diagnostic","entity_registry_enabled_default":true,"enabled":true,"fallback_name":null,"state":{"class_name":"IdentifyButton","available":true,"state":null},"cluster_handlers":[{"class_name":"IdentifyClusterHandler","generic_id":"cluster_handler_0x0003","endpoint_id":1,"cluster":{"id":3,"name":"Identify","type":"server","endpoint_id":1,"endpoint_attribute":"identify"},"id":"1:0x0003","unique_id":"00:0d:6f:00:0f:3a:e3:69:1:0x0003","status":"initialized","value_attribute":null}],"device_ieee":"00:0d:6f:00:0f:3a:e3:69","endpoint_id":1,"available":true,"group_id":null,"command":"identify","attribute_name":null,"attribute_value":null,"args":[5],"kwargs":{}},"sensor,00:0d:6f:00:0f:3a:e3:69-1-1":{"platform":"sensor","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-1","class_name":"Battery","translation_key":null,"device_class":"battery","state_class":"measurement","entity_category":"diagnostic","entity_registry_enabled_default":true,"enabled":true,"fallback_name":null,"state":{"class_name":"Battery","state":100,"battery_size":"Other","battery_quantity":1,"battery_voltage":2.8,"available":true},"cluster_handlers":[],"device_ieee":null,"endpoint_id":null,"available":null,"group_id":null,"attribute":"battery_percentage_remaining","decimals":1,"divisor":1,"multiplier":1,"unit":"%"},"sensor,00:0d:6f:00:0f:3a:e3:69-1-1026":{"platform":"sensor","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-1026","class_name":"Temperature","translation_key":null,"device_class":"temperature","state_class":"measurement","entity_category":null,"entity_registry_enabled_default":true,"enabled":true,"fallback_name":null,"state":{"class_name":"Temperature","available":true,"state":20.2},"cluster_handlers":[{"class_name":"TemperatureMeasurementClusterHandler","generic_id":"cluster_handler_0x0402","endpoint_id":1,"cluster":{"id":1026,"name":"Temperature Measurement","type":"server","endpoint_id":1,"endpoint_attribute":"temperature"},"id":"1:0x0402","unique_id":"00:0d:6f:00:0f:3a:e3:69:1:0x0402","status":"initialized","value_attribute":"measured_value"}],"device_ieee":"00:0d:6f:00:0f:3a:e3:69","endpoint_id":1,"available":true,"group_id":null,"attribute":"measured_value","decimals":1,"divisor":100,"multiplier":1,"unit":"°C"},"sensor,00:0d:6f:00:0f:3a:e3:69-1-0-rssi":{"platform":"sensor","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-0-rssi","class_name":"RSSISensor","translation_key":"rssi","device_class":"signal_strength","state_class":"measurement","entity_category":"diagnostic","entity_registry_enabled_default":false,"enabled":true,"fallback_name":null,"state":{"class_name":"RSSISensor","available":true,"state":null},"cluster_handlers":[{"class_name":"BasicClusterHandler","generic_id":"cluster_handler_0x0000","endpoint_id":1,"cluster":{"id":0,"name":"Basic","type":"server","endpoint_id":1,"endpoint_attribute":"basic"},"id":"1:0x0000","unique_id":"00:0d:6f:00:0f:3a:e3:69:1:0x0000","status":"initialized","value_attribute":null}],"device_ieee":"00:0d:6f:00:0f:3a:e3:69","endpoint_id":1,"available":true,"group_id":null,"attribute":null,"decimals":1,"divisor":1,"multiplier":1,"unit":"dBm"},"sensor,00:0d:6f:00:0f:3a:e3:69-1-0-lqi":{"platform":"sensor","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-0-lqi","class_name":"LQISensor","translation_key":"lqi","device_class":null,"state_class":"measurement","entity_category":"diagnostic","entity_registry_enabled_default":false,"enabled":true,"fallback_name":null,"state":{"class_name":"LQISensor","available":true,"state":null},"cluster_handlers":[{"class_name":"BasicClusterHandler","generic_id":"cluster_handler_0x0000","endpoint_id":1,"cluster":{"id":0,"name":"Basic","type":"server","endpoint_id":1,"endpoint_attribute":"basic"},"id":"1:0x0000","unique_id":"00:0d:6f:00:0f:3a:e3:69:1:0x0000","status":"initialized","value_attribute":null}],"device_ieee":"00:0d:6f:00:0f:3a:e3:69","endpoint_id":1,"available":true,"group_id":null,"attribute":null,"decimals":1,"divisor":1,"multiplier":1,"unit":null},"update,00:0d:6f:00:0f:3a:e3:69-1-25-firmware_update":{"platform":"update","unique_id":"00:0d:6f:00:0f:3a:e3:69-1-25-firmware_update","class_name":"FirmwareUpdateEntity","translation_key":null,"device_class":"firmware","state_class":null,"entity_category":"config","entity_registry_enabled_default":true,"enabled":true,"fallback_name":null,"state":{"class_name":"FirmwareUpdateEntity","available":true,"installed_version":null,"in_progress":false,"progress":0,"latest_version":null,"release_summary":null,"release_notes":null,"release_url":null},"cluster_handlers":[{"class_name":"OtaClientClusterHandler","generic_id":"cluster_handler_0x0019","endpoint_id":1,"cluster":{"id":25,"name":"Ota","type":"client","endpoint_id":1,"endpoint_attribute":"ota"},"id":"1:0x0019","unique_id":"00:0d:6f:00:0f:3a:e3:69:1:0x0019","status":"initialized","value_attribute":null}],"device_ieee":"00:0d:6f:00:0f:3a:e3:69","endpoint_id":1,"available":true,"group_id":null,"supported_features":7}},"neighbors":[],"routes":[],"endpoint_names":[{"name":"IAS_ZONE"},{"name":"unknown 12 device_type of 0xc2df profile id"}],"device_automation_triggers":{"device_offline,device_offline":{"device_event_type":"device_offline"}}}

0 commit comments

Comments
 (0)