def __init__(self, hass, config): """Initialize the system based on host parameter.""" self.hass = hass self.area = {} self.async_add_devices = {} self.waiting_devices = {} self.host = config[CONF_HOST] # Configure the dynalite devices self.dynalite_devices = DynaliteDevices( new_device_func=self.add_devices_when_registered, update_device_func=self.update_device, ) self.dynalite_devices.configure(config)
def __init__(self, hass: HomeAssistant, config: dict[str, Any]) -> None: """Initialize the system based on host parameter.""" self.hass = hass self.async_add_devices: dict[str, Callable] = {} self.waiting_devices: dict[str, list[str]] = {} self.host = config[CONF_HOST] # Configure the dynalite devices self.dynalite_devices = DynaliteDevices( new_device_func=self.add_devices_when_registered, update_device_func=self.update_device, notification_func=self.handle_notification, ) self.dynalite_devices.configure(config)
def __init__(self, hass: HomeAssistant, config: Dict[str, Any]) -> None: """Initialize the system based on host parameter.""" self.hass = hass self.area = {} self.async_add_devices = {} self.waiting_devices = {} self.host = config[CONF_HOST] # Configure the dynalite devices self.dynalite_devices = DynaliteDevices( new_device_func=self.add_devices_when_registered, update_device_func=self.update_device, ) self.dynalite_devices.configure(convert_config(config))
def __init__(self, opp: OpenPeerPower, config: dict[str, Any]) -> None: """Initialize the system based on host parameter.""" self.opp = opp self.area = {} self.async_add_devices = {} self.waiting_devices = {} self.host = config[CONF_HOST] # Configure the dynalite devices self.dynalite_devices = DynaliteDevices( new_device_func=self.add_devices_when_registered, update_device_func=self.update_device, notification_func=self.handle_notification, ) self.dynalite_devices.configure(convert_config(config))
def __init__(self, request, message_delay_zero): """Initialize the class.""" request.addfinalizer(self.fin) self.reader = None self.writer = None self.server = None self.in_buffer = bytearray() self.new_dev_func = Mock() self.update_dev_func = Mock() self.exceptions = [] if message_delay_zero: with patch("dynalite_devices_lib.dynalite.MESSAGE_DELAY", 0): self.dyn_dev = DynaliteDevices( new_device_func=self.new_dev_func, update_device_func=self.update_dev_func, ) else: self.dyn_dev = DynaliteDevices( new_device_func=self.new_dev_func, update_device_func=self.update_dev_func, )
class DynaliteBridge: """Manages a single Dynalite bridge.""" def __init__(self, hass: HomeAssistant, config: dict[str, Any]) -> None: """Initialize the system based on host parameter.""" self.hass = hass self.async_add_devices: dict[str, Callable] = {} self.waiting_devices: dict[str, list[str]] = {} self.host = config[CONF_HOST] # Configure the dynalite devices self.dynalite_devices = DynaliteDevices( new_device_func=self.add_devices_when_registered, update_device_func=self.update_device, notification_func=self.handle_notification, ) self.dynalite_devices.configure(config) async def async_setup(self) -> bool: """Set up a Dynalite bridge.""" # Configure the dynalite devices LOGGER.debug("Setting up bridge - host %s", self.host) return await self.dynalite_devices.async_setup() def reload_config(self, config: MappingProxyType[str, Any]) -> None: """Reconfigure a bridge when config changes.""" LOGGER.debug("Reloading bridge - host %s, config %s", self.host, config) self.dynalite_devices.configure(convert_config(config)) def update_signal(self, device: DynaliteBaseDevice | None = None) -> str: """Create signal to use to trigger entity update.""" if device: signal = f"dynalite-update-{self.host}-{device.unique_id}" else: signal = f"dynalite-update-{self.host}" return signal @callback def update_device(self, device: DynaliteBaseDevice | None = None) -> None: """Call when a device or all devices should be updated.""" if not device: # This is used to signal connection or disconnection, so all devices may become available or not. log_string = ("Connected" if self.dynalite_devices.connected else "Disconnected") LOGGER.info("%s to dynalite host", log_string) async_dispatcher_send(self.hass, self.update_signal()) else: async_dispatcher_send(self.hass, self.update_signal(device)) @callback def handle_notification(self, notification: DynaliteNotification) -> None: """Handle a notification from the platform and issue events.""" if notification.notification == NOTIFICATION_PACKET: self.hass.bus.async_fire( "dynalite_packet", { ATTR_HOST: self.host, ATTR_PACKET: notification.data[NOTIFICATION_PACKET], }, ) if notification.notification == NOTIFICATION_PRESET: self.hass.bus.async_fire( "dynalite_preset", { ATTR_HOST: self.host, ATTR_AREA: notification.data[dyn_CONF_AREA], ATTR_PRESET: notification.data[dyn_CONF_PRESET], }, ) @callback def register_add_devices(self, platform: str, async_add_devices: Callable) -> None: """Add an async_add_entities for a category.""" self.async_add_devices[platform] = async_add_devices if platform in self.waiting_devices: self.async_add_devices[platform](self.waiting_devices[platform]) def add_devices_when_registered(self, devices: list[DynaliteBaseDevice]) -> None: """Add the devices to HA if the add devices callback was registered, otherwise queue until it is.""" for platform in PLATFORMS: platform_devices = [ device for device in devices if device.category == platform ] if platform in self.async_add_devices: self.async_add_devices[platform](platform_devices) else: # handle it later when it is registered if platform not in self.waiting_devices: self.waiting_devices[platform] = [] self.waiting_devices[platform].extend(platform_devices)
class DynaliteBridge: """Manages a single Dynalite bridge.""" def __init__(self, hass, config): """Initialize the system based on host parameter.""" self.hass = hass self.area = {} self.async_add_devices = {} self.waiting_devices = {} self.host = config[CONF_HOST] # Configure the dynalite devices self.dynalite_devices = DynaliteDevices( new_device_func=self.add_devices_when_registered, update_device_func=self.update_device, ) self.dynalite_devices.configure(config) async def async_setup(self): """Set up a Dynalite bridge.""" # Configure the dynalite devices LOGGER.debug("Setting up bridge - host %s", self.host) return await self.dynalite_devices.async_setup() def reload_config(self, config): """Reconfigure a bridge when config changes.""" LOGGER.debug("Reloading bridge - host %s, config %s", self.host, config) self.dynalite_devices.configure(config) def update_signal(self, device=None): """Create signal to use to trigger entity update.""" if device: signal = f"dynalite-update-{self.host}-{device.unique_id}" else: signal = f"dynalite-update-{self.host}" return signal @callback def update_device(self, device): """Call when a device or all devices should be updated.""" if device == CONF_ALL: # This is used to signal connection or disconnection, so all devices may become available or not. log_string = ("Connected" if self.dynalite_devices.available else "Disconnected") LOGGER.info("%s to dynalite host", log_string) async_dispatcher_send(self.hass, self.update_signal()) else: async_dispatcher_send(self.hass, self.update_signal(device)) @callback def register_add_devices(self, platform, async_add_devices): """Add an async_add_entities for a category.""" self.async_add_devices[platform] = async_add_devices if platform in self.waiting_devices: self.async_add_devices[platform](self.waiting_devices[platform]) def add_devices_when_registered(self, devices): """Add the devices to HA if the add devices callback was registered, otherwise queue until it is.""" for platform in ENTITY_PLATFORMS: platform_devices = [ device for device in devices if device.category == platform ] if platform in self.async_add_devices: self.async_add_devices[platform](platform_devices) else: # handle it later when it is registered if platform not in self.waiting_devices: self.waiting_devices[platform] = [] self.waiting_devices[platform].extend(platform_devices)
class DynaliteBridge: """Manages a single Dynalite bridge.""" def __init__(self, hass: HomeAssistant, config: Dict[str, Any]) -> None: """Initialize the system based on host parameter.""" self.hass = hass self.area = {} self.async_add_devices = {} self.waiting_devices = {} self.area_reg = None self.device_reg = None self.host = config[CONF_HOST] self.areacreate = config[CONF_AREA_CREATE].lower() # Configure the dynalite devices self.dynalite_devices = DynaliteDevices( new_device_func=self.add_devices_when_registered, update_device_func=self.update_device, ) self.dynalite_devices.configure(config) async def async_setup(self) -> bool: """Set up a Dynalite bridge.""" # Configure the dynalite devices LOGGER.debug("Setting up bridge - host %s", self.host) self.area_reg = await ar.async_get_registry(self.hass) self.device_reg = await dr.async_get_registry(self.hass) return await self.dynalite_devices.async_setup() def reload_config(self, config: Dict[str, Any]) -> None: """Reconfigure a bridge when config changes.""" LOGGER.debug("Reloading bridge - host %s, config %s", self.host, config) self.dynalite_devices.configure(config) def update_signal(self, device: "DynaliteBase" = None) -> str: """Create signal to use to trigger entity update.""" if device: signal = f"dynalite-update-{self.host}-{device.unique_id}" else: signal = f"dynalite-update-{self.host}" return signal @callback def update_device(self, device: "DynaliteBase") -> None: """Call when a device or all devices should be updated.""" if device == CONF_ALL: # This is used to signal connection or disconnection, so all devices may become available or not. log_string = ("Connected" if self.dynalite_devices.connected else "Disconnected") LOGGER.info("%s to dynalite host", log_string) async_dispatcher_send(self.hass, self.update_signal()) else: async_dispatcher_send(self.hass, self.update_signal(device)) @callback def register_add_devices(self, platform: str, async_add_devices: Callable) -> None: """Add an async_add_entities for a category.""" self.async_add_devices[platform] = async_add_devices if platform in self.waiting_devices: self.async_add_devices[platform](self.waiting_devices[platform]) def add_devices_when_registered(self, devices: List["DynaliteBase"]) -> None: """Add the devices to HA if the add devices callback was registered, otherwise queue until it is.""" for platform in ENTITY_PLATFORMS: platform_devices = [ device for device in devices if device.category == platform ] if platform in self.async_add_devices: self.async_add_devices[platform](platform_devices) else: # handle it later when it is registered if platform not in self.waiting_devices: self.waiting_devices[platform] = [] self.waiting_devices[platform].extend(platform_devices) @property def available(self): return self.dynalite_devices.connected async def entity_added_to_ha(self, entity): """Call when an entity is added to HA so we can set its area.""" if self.areacreate == CONF_AREA_CREATE_MANUAL: LOGGER.debug("area assignment set to manual - ignoring") return # only need to update the areas if it is 'assign' or 'create' assert self.areacreate in [ CONF_AREA_CREATE_ASSIGN, CONF_AREA_CREATE_AUTO ] uniqueID = entity.unique_id hassArea = entity.get_hass_area if hassArea != "": LOGGER.debug("assigning hass area %s to entity %s" % (hassArea, uniqueID)) device = self.device_reg.async_get_device({(DOMAIN, uniqueID)}, ()) if not device: LOGGER.error("uniqueID %s has no device ID", uniqueID) return areaEntry = self.area_reg._async_is_registered(hassArea) if not areaEntry: if self.areacreate != CONF_AREA_CREATE_AUTO: LOGGER.debug( "Area %s not registered and " + CONF_AREA_CREATE + ' is not "' + CONF_AREA_CREATE_AUTO + '" - ignoring', hassArea, ) return else: LOGGER.debug("Creating new area %s", hassArea) areaEntry = self.area_reg.async_create(hassArea) LOGGER.debug("assigning deviceid=%s area_id=%s" % (device.id, areaEntry.id)) self.device_reg.async_update_device(device.id, area_id=areaEntry.id)
class MockGateway: """Class to mock a TCP gateway.""" def __init__(self, request, message_delay_zero): """Initialize the class.""" request.addfinalizer(self.fin) self.reader = None self.writer = None self.server = None self.in_buffer = bytearray() self.new_dev_func = Mock() self.update_dev_func = Mock() self.exceptions = [] if message_delay_zero: with patch("dynalite_devices_lib.dynalite.MESSAGE_DELAY", 0): self.dyn_dev = DynaliteDevices( new_device_func=self.new_dev_func, update_device_func=self.update_dev_func, ) else: self.dyn_dev = DynaliteDevices( new_device_func=self.new_dev_func, update_device_func=self.update_dev_func, ) async def run_server(self): """Run the actual server.""" async def handle_connection(reader, writer): """Run a single session. Assumes only one for tests.""" assert not self.reader and not self.writer self.reader = reader self.writer = writer while not reader.at_eof(): data = await reader.read(100) addr = writer.get_extra_info("peername") dyn_const.LOGGER.debug("Received message from %s - %s", addr, [int(byte) for byte in data]) for byte in data: self.in_buffer.append(byte) self.reader = self.writer = None self.server = await asyncio.start_server(handle_connection, "127.0.0.1", 12345) addr = self.server.sockets[0].getsockname() dyn_const.LOGGER.debug("Serving on %s", addr) async with self.server: await self.server.serve_forever() async def async_setup_server(self): """Start the server.""" def exc_handle(loop, context): """Handle exceptions by rethrowing them, which will fail the test.""" self.exceptions.append(context["exception"]) asyncio.get_event_loop().set_exception_handler(exc_handle) asyncio.create_task(self.run_server()) await asyncio.sleep(0.01) async def check_writes(self, packets): """Check that a set of packets was written.""" await asyncio.sleep(0.01) assert len(self.in_buffer) == len(packets) * 8 received = [ self.in_buffer[i * 8:i * 8 + 8] for i in range(0, len(packets)) ] for packet in packets: assert packet.msg in received self.reset() async def check_single_write(self, packet): """Check that there was only a single packet written.""" await self.check_writes([packet]) async def receive_message(self, message): """Fake a received message.""" self.writer.write(message) await self.writer.drain() await asyncio.sleep(0.01) async def receive(self, packet): """Fake a received packet.""" await self.receive_message(packet.msg) def configure_dyn_dev(self, config, num_devices=1): """Configure the DynaliteDevices.""" self.new_dev_func.reset_mock() self.dyn_dev.configure(config) if num_devices == 0: self.new_dev_func.assert_not_called() return None self.new_dev_func.assert_called_once() assert len(self.new_dev_func.mock_calls[0][1][0]) == num_devices return self.new_dev_func.mock_calls[0][1][0] async def async_setup_dyn_dev(self): """Set up the internal DynaliteDevices.""" return await self.dyn_dev.async_setup() def reset(self): """Reset the in buffer.""" self.in_buffer = bytearray() def reset_connection(self): """Reset the current connection.""" if self.writer: self.writer.close() async def shutdown(self): """Shut down the server.""" self.reset_connection() self.server.close() await self.server.wait_closed() async def async_fin(self): """Shut the gateway down.""" await self.shutdown() await self.dyn_dev.async_reset() def fin(self): """Run shutdown async.""" asyncio.get_event_loop().run_until_complete(self.async_fin()) for ex in self.exceptions: raise ex