mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 23:27:37 +00:00
Enable strict typing to emulated_hue (#72676)
* Add typing to emulated_hue part 2 * cleanups * adjust targets in test
This commit is contained in:
parent
6e355e1074
commit
1c334605b6
@ -83,6 +83,7 @@ homeassistant.components.dunehd.*
|
|||||||
homeassistant.components.efergy.*
|
homeassistant.components.efergy.*
|
||||||
homeassistant.components.elgato.*
|
homeassistant.components.elgato.*
|
||||||
homeassistant.components.elkm1.*
|
homeassistant.components.elkm1.*
|
||||||
|
homeassistant.components.emulated_hue.*
|
||||||
homeassistant.components.esphome.*
|
homeassistant.components.esphome.*
|
||||||
homeassistant.components.energy.*
|
homeassistant.components.energy.*
|
||||||
homeassistant.components.evil_genius_labs.*
|
homeassistant.components.evil_genius_labs.*
|
||||||
|
@ -13,7 +13,7 @@ from homeassistant.const import (
|
|||||||
EVENT_HOMEASSISTANT_START,
|
EVENT_HOMEASSISTANT_START,
|
||||||
EVENT_HOMEASSISTANT_STOP,
|
EVENT_HOMEASSISTANT_STOP,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import Event, HomeAssistant
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
@ -48,11 +48,7 @@ from .hue_api import (
|
|||||||
HueUnauthorizedUser,
|
HueUnauthorizedUser,
|
||||||
HueUsernameView,
|
HueUsernameView,
|
||||||
)
|
)
|
||||||
from .upnp import (
|
from .upnp import DescriptionXmlView, async_create_upnp_datagram_endpoint
|
||||||
DescriptionXmlView,
|
|
||||||
UPNPResponderProtocol,
|
|
||||||
create_upnp_datagram_endpoint,
|
|
||||||
)
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -93,6 +89,40 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def start_emulated_hue_bridge(
|
||||||
|
hass: HomeAssistant, config: Config, app: web.Application
|
||||||
|
) -> None:
|
||||||
|
"""Start the emulated hue bridge."""
|
||||||
|
protocol = await async_create_upnp_datagram_endpoint(
|
||||||
|
config.host_ip_addr,
|
||||||
|
config.upnp_bind_multicast,
|
||||||
|
config.advertise_ip,
|
||||||
|
config.advertise_port or config.listen_port,
|
||||||
|
)
|
||||||
|
|
||||||
|
runner = web.AppRunner(app)
|
||||||
|
await runner.setup()
|
||||||
|
|
||||||
|
site = web.TCPSite(runner, config.host_ip_addr, config.listen_port)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await site.start()
|
||||||
|
except OSError as error:
|
||||||
|
_LOGGER.error(
|
||||||
|
"Failed to create HTTP server at port %d: %s", config.listen_port, error
|
||||||
|
)
|
||||||
|
protocol.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
async def stop_emulated_hue_bridge(event: Event) -> None:
|
||||||
|
"""Stop the emulated hue bridge."""
|
||||||
|
protocol.close()
|
||||||
|
await site.stop()
|
||||||
|
await runner.cleanup()
|
||||||
|
|
||||||
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_emulated_hue_bridge)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, yaml_config: ConfigType) -> bool:
|
async def async_setup(hass: HomeAssistant, yaml_config: ConfigType) -> bool:
|
||||||
"""Activate the emulated_hue component."""
|
"""Activate the emulated_hue component."""
|
||||||
local_ip = await async_get_source_ip(hass)
|
local_ip = await async_get_source_ip(hass)
|
||||||
@ -108,9 +138,6 @@ async def async_setup(hass: HomeAssistant, yaml_config: ConfigType) -> bool:
|
|||||||
app._on_startup.freeze()
|
app._on_startup.freeze()
|
||||||
await app.startup()
|
await app.startup()
|
||||||
|
|
||||||
runner = None
|
|
||||||
site = None
|
|
||||||
|
|
||||||
DescriptionXmlView(config).register(app, app.router)
|
DescriptionXmlView(config).register(app, app.router)
|
||||||
HueUsernameView().register(app, app.router)
|
HueUsernameView().register(app, app.router)
|
||||||
HueConfigView(config).register(app, app.router)
|
HueConfigView(config).register(app, app.router)
|
||||||
@ -122,54 +149,10 @@ async def async_setup(hass: HomeAssistant, yaml_config: ConfigType) -> bool:
|
|||||||
HueGroupView(config).register(app, app.router)
|
HueGroupView(config).register(app, app.router)
|
||||||
HueFullStateView(config).register(app, app.router)
|
HueFullStateView(config).register(app, app.router)
|
||||||
|
|
||||||
listen = create_upnp_datagram_endpoint(
|
async def _start(event: Event) -> None:
|
||||||
config.host_ip_addr,
|
"""Start the bridge."""
|
||||||
config.upnp_bind_multicast,
|
await start_emulated_hue_bridge(hass, config, app)
|
||||||
config.advertise_ip,
|
|
||||||
config.advertise_port or config.listen_port,
|
|
||||||
)
|
|
||||||
protocol: UPNPResponderProtocol | None = None
|
|
||||||
|
|
||||||
async def stop_emulated_hue_bridge(event):
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, _start)
|
||||||
"""Stop the emulated hue bridge."""
|
|
||||||
nonlocal protocol
|
|
||||||
nonlocal site
|
|
||||||
nonlocal runner
|
|
||||||
|
|
||||||
if protocol:
|
|
||||||
protocol.close()
|
|
||||||
if site:
|
|
||||||
await site.stop()
|
|
||||||
if runner:
|
|
||||||
await runner.cleanup()
|
|
||||||
|
|
||||||
async def start_emulated_hue_bridge(event):
|
|
||||||
"""Start the emulated hue bridge."""
|
|
||||||
nonlocal protocol
|
|
||||||
nonlocal site
|
|
||||||
nonlocal runner
|
|
||||||
|
|
||||||
transport_protocol = await listen
|
|
||||||
protocol = transport_protocol[1]
|
|
||||||
|
|
||||||
runner = web.AppRunner(app)
|
|
||||||
await runner.setup()
|
|
||||||
|
|
||||||
site = web.TCPSite(runner, config.host_ip_addr, config.listen_port)
|
|
||||||
|
|
||||||
try:
|
|
||||||
await site.start()
|
|
||||||
except OSError as error:
|
|
||||||
_LOGGER.error(
|
|
||||||
"Failed to create HTTP server at port %d: %s", config.listen_port, error
|
|
||||||
)
|
|
||||||
if protocol:
|
|
||||||
protocol.close()
|
|
||||||
else:
|
|
||||||
hass.bus.async_listen_once(
|
|
||||||
EVENT_HOMEASSISTANT_STOP, stop_emulated_hue_bridge
|
|
||||||
)
|
|
||||||
|
|
||||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, start_emulated_hue_bridge)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -55,9 +55,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
class Config:
|
class Config:
|
||||||
"""Hold configuration variables for the emulated hue bridge."""
|
"""Hold configuration variables for the emulated hue bridge."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, hass: HomeAssistant, conf: ConfigType, local_ip: str) -> None:
|
||||||
self, hass: HomeAssistant, conf: ConfigType, local_ip: str | None
|
|
||||||
) -> None:
|
|
||||||
"""Initialize the instance."""
|
"""Initialize the instance."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self.type = conf.get(CONF_TYPE)
|
self.type = conf.get(CONF_TYPE)
|
||||||
@ -73,17 +71,10 @@ class Config:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Get the IP address that will be passed to the Echo during discovery
|
# Get the IP address that will be passed to the Echo during discovery
|
||||||
self.host_ip_addr = conf.get(CONF_HOST_IP)
|
self.host_ip_addr: str = conf.get(CONF_HOST_IP) or local_ip
|
||||||
if self.host_ip_addr is None:
|
|
||||||
self.host_ip_addr = local_ip
|
|
||||||
|
|
||||||
# Get the port that the Hue bridge will listen on
|
# Get the port that the Hue bridge will listen on
|
||||||
self.listen_port = conf.get(CONF_LISTEN_PORT)
|
self.listen_port: int = conf.get(CONF_LISTEN_PORT) or DEFAULT_LISTEN_PORT
|
||||||
if not isinstance(self.listen_port, int):
|
|
||||||
self.listen_port = DEFAULT_LISTEN_PORT
|
|
||||||
_LOGGER.info(
|
|
||||||
"Listen port not specified, defaulting to %s", self.listen_port
|
|
||||||
)
|
|
||||||
|
|
||||||
# Get whether or not UPNP binds to multicast address (239.255.255.250)
|
# Get whether or not UPNP binds to multicast address (239.255.255.250)
|
||||||
# or to the unicast address (host_ip_addr)
|
# or to the unicast address (host_ip_addr)
|
||||||
@ -113,11 +104,11 @@ class Config:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Calculated effective advertised IP and port for network isolation
|
# Calculated effective advertised IP and port for network isolation
|
||||||
self.advertise_ip = conf.get(CONF_ADVERTISE_IP) or self.host_ip_addr
|
self.advertise_ip: str = conf.get(CONF_ADVERTISE_IP) or self.host_ip_addr
|
||||||
|
|
||||||
self.advertise_port = conf.get(CONF_ADVERTISE_PORT) or self.listen_port
|
self.advertise_port: int = conf.get(CONF_ADVERTISE_PORT) or self.listen_port
|
||||||
|
|
||||||
self.entities = conf.get(CONF_ENTITIES, {})
|
self.entities: dict[str, dict[str, str]] = conf.get(CONF_ENTITIES, {})
|
||||||
|
|
||||||
self._entities_with_hidden_attr_in_config = {}
|
self._entities_with_hidden_attr_in_config = {}
|
||||||
for entity_id in self.entities:
|
for entity_id in self.entities:
|
||||||
|
@ -858,7 +858,7 @@ async def wait_for_state_change_or_timeout(
|
|||||||
ev = asyncio.Event()
|
ev = asyncio.Event()
|
||||||
|
|
||||||
@core.callback
|
@core.callback
|
||||||
def _async_event_changed(_):
|
def _async_event_changed(event: core.Event) -> None:
|
||||||
ev.set()
|
ev.set()
|
||||||
|
|
||||||
unsub = async_track_state_change_event(hass, [entity_id], _async_event_changed)
|
unsub = async_track_state_change_event(hass, [entity_id], _async_event_changed)
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
"""Support UPNP discovery method that mimics Hue hubs."""
|
"""Support UPNP discovery method that mimics Hue hubs."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
|
||||||
from homeassistant import core
|
from homeassistant import core
|
||||||
from homeassistant.components.http import HomeAssistantView
|
from homeassistant.components.http import HomeAssistantView
|
||||||
|
|
||||||
|
from .config import Config
|
||||||
from .const import HUE_SERIAL_NUMBER, HUE_UUID
|
from .const import HUE_SERIAL_NUMBER, HUE_UUID
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@ -23,12 +27,12 @@ class DescriptionXmlView(HomeAssistantView):
|
|||||||
name = "description:xml"
|
name = "description:xml"
|
||||||
requires_auth = False
|
requires_auth = False
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config: Config) -> None:
|
||||||
"""Initialize the instance of the view."""
|
"""Initialize the instance of the view."""
|
||||||
self.config = config
|
self.config = config
|
||||||
|
|
||||||
@core.callback
|
@core.callback
|
||||||
def get(self, request):
|
def get(self, request: web.Request) -> web.Response:
|
||||||
"""Handle a GET request."""
|
"""Handle a GET request."""
|
||||||
resp_text = f"""<?xml version="1.0" encoding="UTF-8" ?>
|
resp_text = f"""<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<root xmlns="urn:schemas-upnp-org:device-1-0">
|
<root xmlns="urn:schemas-upnp-org:device-1-0">
|
||||||
@ -55,13 +59,91 @@ class DescriptionXmlView(HomeAssistantView):
|
|||||||
return web.Response(text=resp_text, content_type="text/xml")
|
return web.Response(text=resp_text, content_type="text/xml")
|
||||||
|
|
||||||
|
|
||||||
@core.callback
|
class UPNPResponderProtocol(asyncio.Protocol):
|
||||||
def create_upnp_datagram_endpoint(
|
"""Handle responding to UPNP/SSDP discovery requests."""
|
||||||
host_ip_addr,
|
|
||||||
upnp_bind_multicast,
|
def __init__(
|
||||||
advertise_ip,
|
self,
|
||||||
advertise_port,
|
loop: asyncio.AbstractEventLoop,
|
||||||
):
|
ssdp_socket: socket.socket,
|
||||||
|
advertise_ip: str,
|
||||||
|
advertise_port: int,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the class."""
|
||||||
|
self.transport: asyncio.DatagramTransport | None = None
|
||||||
|
self._loop = loop
|
||||||
|
self._sock = ssdp_socket
|
||||||
|
self.advertise_ip = advertise_ip
|
||||||
|
self.advertise_port = advertise_port
|
||||||
|
self._upnp_root_response = self._prepare_response(
|
||||||
|
"upnp:rootdevice", f"uuid:{HUE_UUID}::upnp:rootdevice"
|
||||||
|
)
|
||||||
|
self._upnp_device_response = self._prepare_response(
|
||||||
|
"urn:schemas-upnp-org:device:basic:1", f"uuid:{HUE_UUID}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def connection_made(self, transport: asyncio.BaseTransport) -> None:
|
||||||
|
"""Set the transport."""
|
||||||
|
self.transport = cast(asyncio.DatagramTransport, transport)
|
||||||
|
|
||||||
|
def connection_lost(self, exc: Exception | None) -> None:
|
||||||
|
"""Handle connection lost."""
|
||||||
|
|
||||||
|
def datagram_received(self, data: bytes, addr: tuple[str, int]) -> None:
|
||||||
|
"""Respond to msearch packets."""
|
||||||
|
decoded_data = data.decode("utf-8", errors="ignore")
|
||||||
|
|
||||||
|
if "M-SEARCH" not in decoded_data:
|
||||||
|
return
|
||||||
|
|
||||||
|
_LOGGER.debug("UPNP Responder M-SEARCH method received: %s", data)
|
||||||
|
# SSDP M-SEARCH method received, respond to it with our info
|
||||||
|
response = self._handle_request(decoded_data)
|
||||||
|
_LOGGER.debug("UPNP Responder responding with: %s", response)
|
||||||
|
assert self.transport is not None
|
||||||
|
self.transport.sendto(response, addr)
|
||||||
|
|
||||||
|
def error_received(self, exc: Exception) -> None:
|
||||||
|
"""Log UPNP errors."""
|
||||||
|
_LOGGER.error("UPNP Error received: %s", exc)
|
||||||
|
|
||||||
|
def close(self) -> None:
|
||||||
|
"""Stop the server."""
|
||||||
|
_LOGGER.info("UPNP responder shutting down")
|
||||||
|
if self.transport:
|
||||||
|
self.transport.close()
|
||||||
|
self._loop.remove_writer(self._sock.fileno())
|
||||||
|
self._loop.remove_reader(self._sock.fileno())
|
||||||
|
self._sock.close()
|
||||||
|
|
||||||
|
def _handle_request(self, decoded_data: str) -> bytes:
|
||||||
|
if "upnp:rootdevice" in decoded_data:
|
||||||
|
return self._upnp_root_response
|
||||||
|
|
||||||
|
return self._upnp_device_response
|
||||||
|
|
||||||
|
def _prepare_response(self, search_target: str, unique_service_name: str) -> bytes:
|
||||||
|
# Note that the double newline at the end of
|
||||||
|
# this string is required per the SSDP spec
|
||||||
|
response = f"""HTTP/1.1 200 OK
|
||||||
|
CACHE-CONTROL: max-age=60
|
||||||
|
EXT:
|
||||||
|
LOCATION: http://{self.advertise_ip}:{self.advertise_port}/description.xml
|
||||||
|
SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.16.0
|
||||||
|
hue-bridgeid: {HUE_SERIAL_NUMBER}
|
||||||
|
ST: {search_target}
|
||||||
|
USN: {unique_service_name}
|
||||||
|
|
||||||
|
"""
|
||||||
|
return response.replace("\n", "\r\n").encode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
async def async_create_upnp_datagram_endpoint(
|
||||||
|
host_ip_addr: str,
|
||||||
|
upnp_bind_multicast: bool,
|
||||||
|
advertise_ip: str,
|
||||||
|
advertise_port: int,
|
||||||
|
) -> UPNPResponderProtocol:
|
||||||
"""Create the UPNP socket and protocol."""
|
"""Create the UPNP socket and protocol."""
|
||||||
# Listen for UDP port 1900 packets sent to SSDP multicast address
|
# Listen for UDP port 1900 packets sent to SSDP multicast address
|
||||||
ssdp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
ssdp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
@ -84,79 +166,8 @@ def create_upnp_datagram_endpoint(
|
|||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
return loop.create_datagram_endpoint(
|
transport_protocol = await loop.create_datagram_endpoint(
|
||||||
lambda: UPNPResponderProtocol(loop, ssdp_socket, advertise_ip, advertise_port),
|
lambda: UPNPResponderProtocol(loop, ssdp_socket, advertise_ip, advertise_port),
|
||||||
sock=ssdp_socket,
|
sock=ssdp_socket,
|
||||||
)
|
)
|
||||||
|
return transport_protocol[1]
|
||||||
|
|
||||||
class UPNPResponderProtocol:
|
|
||||||
"""Handle responding to UPNP/SSDP discovery requests."""
|
|
||||||
|
|
||||||
def __init__(self, loop, ssdp_socket, advertise_ip, advertise_port):
|
|
||||||
"""Initialize the class."""
|
|
||||||
self.transport = None
|
|
||||||
self._loop = loop
|
|
||||||
self._sock = ssdp_socket
|
|
||||||
self.advertise_ip = advertise_ip
|
|
||||||
self.advertise_port = advertise_port
|
|
||||||
self._upnp_root_response = self._prepare_response(
|
|
||||||
"upnp:rootdevice", f"uuid:{HUE_UUID}::upnp:rootdevice"
|
|
||||||
)
|
|
||||||
self._upnp_device_response = self._prepare_response(
|
|
||||||
"urn:schemas-upnp-org:device:basic:1", f"uuid:{HUE_UUID}"
|
|
||||||
)
|
|
||||||
|
|
||||||
def connection_made(self, transport):
|
|
||||||
"""Set the transport."""
|
|
||||||
self.transport = transport
|
|
||||||
|
|
||||||
def connection_lost(self, exc):
|
|
||||||
"""Handle connection lost."""
|
|
||||||
|
|
||||||
def datagram_received(self, data, addr):
|
|
||||||
"""Respond to msearch packets."""
|
|
||||||
decoded_data = data.decode("utf-8", errors="ignore")
|
|
||||||
|
|
||||||
if "M-SEARCH" not in decoded_data:
|
|
||||||
return
|
|
||||||
|
|
||||||
_LOGGER.debug("UPNP Responder M-SEARCH method received: %s", data)
|
|
||||||
# SSDP M-SEARCH method received, respond to it with our info
|
|
||||||
response = self._handle_request(decoded_data)
|
|
||||||
_LOGGER.debug("UPNP Responder responding with: %s", response)
|
|
||||||
self.transport.sendto(response, addr)
|
|
||||||
|
|
||||||
def error_received(self, exc):
|
|
||||||
"""Log UPNP errors."""
|
|
||||||
_LOGGER.error("UPNP Error received: %s", exc)
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
"""Stop the server."""
|
|
||||||
_LOGGER.info("UPNP responder shutting down")
|
|
||||||
if self.transport:
|
|
||||||
self.transport.close()
|
|
||||||
self._loop.remove_writer(self._sock.fileno())
|
|
||||||
self._loop.remove_reader(self._sock.fileno())
|
|
||||||
self._sock.close()
|
|
||||||
|
|
||||||
def _handle_request(self, decoded_data):
|
|
||||||
if "upnp:rootdevice" in decoded_data:
|
|
||||||
return self._upnp_root_response
|
|
||||||
|
|
||||||
return self._upnp_device_response
|
|
||||||
|
|
||||||
def _prepare_response(self, search_target, unique_service_name):
|
|
||||||
# Note that the double newline at the end of
|
|
||||||
# this string is required per the SSDP spec
|
|
||||||
response = f"""HTTP/1.1 200 OK
|
|
||||||
CACHE-CONTROL: max-age=60
|
|
||||||
EXT:
|
|
||||||
LOCATION: http://{self.advertise_ip}:{self.advertise_port}/description.xml
|
|
||||||
SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.16.0
|
|
||||||
hue-bridgeid: {HUE_SERIAL_NUMBER}
|
|
||||||
ST: {search_target}
|
|
||||||
USN: {unique_service_name}
|
|
||||||
|
|
||||||
"""
|
|
||||||
return response.replace("\n", "\r\n").encode("utf-8")
|
|
||||||
|
11
mypy.ini
11
mypy.ini
@ -676,6 +676,17 @@ no_implicit_optional = true
|
|||||||
warn_return_any = true
|
warn_return_any = true
|
||||||
warn_unreachable = true
|
warn_unreachable = true
|
||||||
|
|
||||||
|
[mypy-homeassistant.components.emulated_hue.*]
|
||||||
|
check_untyped_defs = true
|
||||||
|
disallow_incomplete_defs = true
|
||||||
|
disallow_subclassing_any = true
|
||||||
|
disallow_untyped_calls = true
|
||||||
|
disallow_untyped_decorators = true
|
||||||
|
disallow_untyped_defs = true
|
||||||
|
no_implicit_optional = true
|
||||||
|
warn_return_any = true
|
||||||
|
warn_unreachable = true
|
||||||
|
|
||||||
[mypy-homeassistant.components.esphome.*]
|
[mypy-homeassistant.components.esphome.*]
|
||||||
check_untyped_defs = true
|
check_untyped_defs = true
|
||||||
disallow_incomplete_defs = true
|
disallow_incomplete_defs = true
|
||||||
|
@ -108,7 +108,9 @@ def hass_hue(loop, hass):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
with patch("homeassistant.components.emulated_hue.create_upnp_datagram_endpoint"):
|
with patch(
|
||||||
|
"homeassistant.components.emulated_hue.async_create_upnp_datagram_endpoint"
|
||||||
|
):
|
||||||
loop.run_until_complete(
|
loop.run_until_complete(
|
||||||
setup.async_setup_component(
|
setup.async_setup_component(
|
||||||
hass,
|
hass,
|
||||||
@ -314,7 +316,9 @@ async def test_lights_all_dimmable(hass, hass_client_no_auth):
|
|||||||
emulated_hue.CONF_EXPOSE_BY_DEFAULT: True,
|
emulated_hue.CONF_EXPOSE_BY_DEFAULT: True,
|
||||||
emulated_hue.CONF_LIGHTS_ALL_DIMMABLE: True,
|
emulated_hue.CONF_LIGHTS_ALL_DIMMABLE: True,
|
||||||
}
|
}
|
||||||
with patch("homeassistant.components.emulated_hue.create_upnp_datagram_endpoint"):
|
with patch(
|
||||||
|
"homeassistant.components.emulated_hue.async_create_upnp_datagram_endpoint"
|
||||||
|
):
|
||||||
await setup.async_setup_component(
|
await setup.async_setup_component(
|
||||||
hass,
|
hass,
|
||||||
emulated_hue.DOMAIN,
|
emulated_hue.DOMAIN,
|
||||||
|
@ -122,13 +122,13 @@ async def test_setup_works(hass):
|
|||||||
"""Test setup works."""
|
"""Test setup works."""
|
||||||
hass.config.components.add("network")
|
hass.config.components.add("network")
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.emulated_hue.create_upnp_datagram_endpoint",
|
"homeassistant.components.emulated_hue.async_create_upnp_datagram_endpoint",
|
||||||
AsyncMock(),
|
AsyncMock(),
|
||||||
) as mock_create_upnp_datagram_endpoint, patch(
|
) as mock_create_upnp_datagram_endpoint, patch(
|
||||||
"homeassistant.components.emulated_hue.async_get_source_ip"
|
"homeassistant.components.emulated_hue.async_get_source_ip"
|
||||||
):
|
):
|
||||||
assert await async_setup_component(hass, "emulated_hue", {})
|
assert await async_setup_component(hass, "emulated_hue", {})
|
||||||
|
|
||||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(mock_create_upnp_datagram_endpoint.mock_calls) == 2
|
|
||||||
|
assert len(mock_create_upnp_datagram_endpoint.mock_calls) == 1
|
||||||
|
@ -53,7 +53,9 @@ def hue_client(aiohttp_client):
|
|||||||
|
|
||||||
async def setup_hue(hass):
|
async def setup_hue(hass):
|
||||||
"""Set up the emulated_hue integration."""
|
"""Set up the emulated_hue integration."""
|
||||||
with patch("homeassistant.components.emulated_hue.create_upnp_datagram_endpoint"):
|
with patch(
|
||||||
|
"homeassistant.components.emulated_hue.async_create_upnp_datagram_endpoint"
|
||||||
|
):
|
||||||
assert await setup.async_setup_component(
|
assert await setup.async_setup_component(
|
||||||
hass,
|
hass,
|
||||||
emulated_hue.DOMAIN,
|
emulated_hue.DOMAIN,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user