mirror of
https://github.com/home-assistant/core.git
synced 2025-08-30 18:01:31 +02:00
Add multiple NICs in govee_light_local (#128123)
This commit is contained in:
@@ -9,6 +9,7 @@ import logging
|
||||
|
||||
from govee_local_api.controller import LISTENING_PORT
|
||||
|
||||
from homeassistant.components import network
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
@@ -23,12 +24,24 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: GoveeLocalConfigEntry) -> bool:
|
||||
"""Set up Govee light local from a config entry."""
|
||||
coordinator = GoveeLocalApiCoordinator(hass, entry)
|
||||
|
||||
# Get source IPs for all enabled adapters
|
||||
source_ips = await network.async_get_enabled_source_ips(hass)
|
||||
_LOGGER.debug("Enabled source IPs: %s", source_ips)
|
||||
|
||||
coordinator: GoveeLocalApiCoordinator = GoveeLocalApiCoordinator(
|
||||
hass=hass, config_entry=entry, source_ips=source_ips
|
||||
)
|
||||
|
||||
async def await_cleanup():
|
||||
cleanup_complete: asyncio.Event = coordinator.cleanup()
|
||||
cleanup_complete_events: [asyncio.Event] = coordinator.cleanup()
|
||||
with suppress(TimeoutError):
|
||||
await asyncio.wait_for(cleanup_complete.wait(), 1)
|
||||
await asyncio.gather(
|
||||
*[
|
||||
asyncio.wait_for(cleanup_complete_event.wait(), 1)
|
||||
for cleanup_complete_event in cleanup_complete_events
|
||||
]
|
||||
)
|
||||
|
||||
entry.async_on_unload(await_cleanup)
|
||||
|
||||
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from contextlib import suppress
|
||||
from ipaddress import IPv4Address, IPv6Address
|
||||
import logging
|
||||
|
||||
from govee_local_api import GoveeController
|
||||
@@ -23,15 +24,13 @@ from .const import (
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def _async_has_devices(hass: HomeAssistant) -> bool:
|
||||
"""Return if there are devices that can be discovered."""
|
||||
|
||||
adapter = await network.async_get_source_ip(hass, network.PUBLIC_TARGET_IP)
|
||||
|
||||
async def _async_discover(
|
||||
hass: HomeAssistant, adapter_ip: IPv4Address | IPv6Address
|
||||
) -> bool:
|
||||
controller: GoveeController = GoveeController(
|
||||
loop=hass.loop,
|
||||
logger=_LOGGER,
|
||||
listening_address=adapter,
|
||||
listening_address=str(adapter_ip),
|
||||
broadcast_address=CONF_MULTICAST_ADDRESS_DEFAULT,
|
||||
broadcast_port=CONF_TARGET_PORT_DEFAULT,
|
||||
listening_port=CONF_LISTENING_PORT_DEFAULT,
|
||||
@@ -41,9 +40,10 @@ async def _async_has_devices(hass: HomeAssistant) -> bool:
|
||||
)
|
||||
|
||||
try:
|
||||
_LOGGER.debug("Starting discovery with IP %s", adapter_ip)
|
||||
await controller.start()
|
||||
except OSError as ex:
|
||||
_LOGGER.error("Start failed, errno: %d", ex.errno)
|
||||
_LOGGER.error("Start failed on IP %s, errno: %d", adapter_ip, ex.errno)
|
||||
return False
|
||||
|
||||
try:
|
||||
@@ -51,16 +51,34 @@ async def _async_has_devices(hass: HomeAssistant) -> bool:
|
||||
while not controller.devices:
|
||||
await asyncio.sleep(delay=1)
|
||||
except TimeoutError:
|
||||
_LOGGER.debug("No devices found")
|
||||
_LOGGER.debug("No devices found with IP %s", adapter_ip)
|
||||
|
||||
devices_count = len(controller.devices)
|
||||
cleanup_complete: asyncio.Event = controller.cleanup()
|
||||
cleanup_complete_events: list[asyncio.Event] = []
|
||||
with suppress(TimeoutError):
|
||||
await asyncio.wait_for(cleanup_complete.wait(), 1)
|
||||
await asyncio.gather(
|
||||
*[
|
||||
asyncio.wait_for(cleanup_complete_event.wait(), 1)
|
||||
for cleanup_complete_event in cleanup_complete_events
|
||||
]
|
||||
)
|
||||
|
||||
return devices_count > 0
|
||||
|
||||
|
||||
async def _async_has_devices(hass: HomeAssistant) -> bool:
|
||||
"""Return if there are devices that can be discovered."""
|
||||
|
||||
# Get source IPs for all enabled adapters
|
||||
source_ips = await network.async_get_enabled_source_ips(hass)
|
||||
_LOGGER.debug("Enabled source IPs: %s", source_ips)
|
||||
|
||||
# Run discovery on every IPv4 address and gather results
|
||||
results = await asyncio.gather(*[_async_discover(hass, ip) for ip in source_ips])
|
||||
|
||||
return any(results)
|
||||
|
||||
|
||||
config_entry_flow.register_discovery_flow(
|
||||
DOMAIN, "Govee light local", _async_has_devices
|
||||
)
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Callable
|
||||
from ipaddress import IPv4Address, IPv6Address
|
||||
import logging
|
||||
|
||||
from govee_local_api import GoveeController, GoveeDevice
|
||||
@@ -11,7 +12,6 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
from .const import (
|
||||
CONF_DISCOVERY_INTERVAL_DEFAULT,
|
||||
CONF_LISTENING_PORT_DEFAULT,
|
||||
CONF_MULTICAST_ADDRESS_DEFAULT,
|
||||
CONF_TARGET_PORT_DEFAULT,
|
||||
@@ -26,10 +26,11 @@ type GoveeLocalConfigEntry = ConfigEntry[GoveeLocalApiCoordinator]
|
||||
class GoveeLocalApiCoordinator(DataUpdateCoordinator[list[GoveeDevice]]):
|
||||
"""Govee light local coordinator."""
|
||||
|
||||
config_entry: GoveeLocalConfigEntry
|
||||
|
||||
def __init__(
|
||||
self, hass: HomeAssistant, config_entry: GoveeLocalConfigEntry
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
config_entry: GoveeLocalConfigEntry,
|
||||
source_ips: list[IPv4Address | IPv6Address],
|
||||
) -> None:
|
||||
"""Initialize my coordinator."""
|
||||
super().__init__(
|
||||
@@ -40,32 +41,40 @@ class GoveeLocalApiCoordinator(DataUpdateCoordinator[list[GoveeDevice]]):
|
||||
update_interval=SCAN_INTERVAL,
|
||||
)
|
||||
|
||||
self._controller = GoveeController(
|
||||
self._controllers: list[GoveeController] = [
|
||||
GoveeController(
|
||||
loop=hass.loop,
|
||||
logger=_LOGGER,
|
||||
listening_address=str(source_ip),
|
||||
broadcast_address=CONF_MULTICAST_ADDRESS_DEFAULT,
|
||||
broadcast_port=CONF_TARGET_PORT_DEFAULT,
|
||||
listening_port=CONF_LISTENING_PORT_DEFAULT,
|
||||
discovery_enabled=True,
|
||||
discovery_interval=CONF_DISCOVERY_INTERVAL_DEFAULT,
|
||||
discovered_callback=None,
|
||||
discovery_interval=1,
|
||||
update_enabled=False,
|
||||
)
|
||||
for source_ip in source_ips
|
||||
]
|
||||
|
||||
async def start(self) -> None:
|
||||
"""Start the Govee coordinator."""
|
||||
await self._controller.start()
|
||||
self._controller.send_update_message()
|
||||
|
||||
for controller in self._controllers:
|
||||
await controller.start()
|
||||
controller.send_update_message()
|
||||
|
||||
async def set_discovery_callback(
|
||||
self, callback: Callable[[GoveeDevice, bool], bool]
|
||||
) -> None:
|
||||
"""Set discovery callback for automatic Govee light discovery."""
|
||||
self._controller.set_device_discovered_callback(callback)
|
||||
|
||||
def cleanup(self) -> asyncio.Event:
|
||||
"""Stop and cleanup the cooridinator."""
|
||||
return self._controller.cleanup()
|
||||
for controller in self._controllers:
|
||||
controller.set_device_discovered_callback(callback)
|
||||
|
||||
def cleanup(self) -> list[asyncio.Event]:
|
||||
"""Stop and cleanup the coordinator."""
|
||||
|
||||
return [controller.cleanup() for controller in self._controllers]
|
||||
|
||||
async def turn_on(self, device: GoveeDevice) -> None:
|
||||
"""Turn on the light."""
|
||||
@@ -96,8 +105,14 @@ class GoveeLocalApiCoordinator(DataUpdateCoordinator[list[GoveeDevice]]):
|
||||
@property
|
||||
def devices(self) -> list[GoveeDevice]:
|
||||
"""Return a list of discovered Govee devices."""
|
||||
return self._controller.devices
|
||||
|
||||
devices: list[GoveeDevice] = []
|
||||
for controller in self._controllers:
|
||||
devices = devices + controller.devices
|
||||
return devices
|
||||
|
||||
async def _async_update_data(self) -> list[GoveeDevice]:
|
||||
self._controller.send_update_message()
|
||||
return self._controller.devices
|
||||
for controller in self._controllers:
|
||||
controller.send_update_message()
|
||||
|
||||
return self.devices
|
||||
|
Reference in New Issue
Block a user