mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 00:37:53 +00:00
Add Wilight integration with SSDP (#36694)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
fefa1a7259
commit
a47f73244c
@ -474,6 +474,7 @@ homeassistant/components/weather/* @fabaff
|
||||
homeassistant/components/webostv/* @bendavid
|
||||
homeassistant/components/websocket_api/* @home-assistant/core
|
||||
homeassistant/components/wiffi/* @mampfes
|
||||
homeassistant/components/wilight/* @leofig-rj
|
||||
homeassistant/components/withings/* @vangorra
|
||||
homeassistant/components/wled/* @frenck
|
||||
homeassistant/components/wolflink/* @adamkrol93
|
||||
|
125
homeassistant/components/wilight/__init__.py
Normal file
125
homeassistant/components/wilight/__init__.py
Normal file
@ -0,0 +1,125 @@
|
||||
"""The WiLight integration."""
|
||||
import asyncio
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from .const import DOMAIN
|
||||
from .parent_device import WiLightParent
|
||||
|
||||
# List the platforms that you want to support.
|
||||
PLATFORMS = ["light"]
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: dict):
|
||||
"""Set up the WiLight with Config Flow component."""
|
||||
|
||||
hass.data[DOMAIN] = {}
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
"""Set up a wilight config entry."""
|
||||
|
||||
parent = WiLightParent(hass, entry)
|
||||
|
||||
if not await parent.async_setup():
|
||||
raise ConfigEntryNotReady
|
||||
|
||||
hass.data[DOMAIN][entry.entry_id] = parent
|
||||
|
||||
# Set up all platforms for this device/entry.
|
||||
for component in PLATFORMS:
|
||||
hass.async_create_task(
|
||||
hass.config_entries.async_forward_entry_setup(entry, component)
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||
"""Unload WiLight config entry."""
|
||||
|
||||
# Unload entities for this entry/device.
|
||||
await asyncio.gather(
|
||||
*(
|
||||
hass.config_entries.async_forward_entry_unload(entry, component)
|
||||
for component in PLATFORMS
|
||||
)
|
||||
)
|
||||
|
||||
# Cleanup
|
||||
parent = hass.data[DOMAIN][entry.entry_id]
|
||||
await parent.async_reset()
|
||||
del hass.data[DOMAIN][entry.entry_id]
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class WiLightDevice(Entity):
|
||||
"""Representation of a WiLight device.
|
||||
|
||||
Contains the common logic for WiLight entities.
|
||||
"""
|
||||
|
||||
def __init__(self, api_device, index, item_name):
|
||||
"""Initialize the device."""
|
||||
# WiLight specific attributes for every component type
|
||||
self._device_id = api_device.device_id
|
||||
self._sw_version = api_device.swversion
|
||||
self._client = api_device.client
|
||||
self._model = api_device.model
|
||||
self._name = item_name
|
||||
self._index = index
|
||||
self._unique_id = f"{self._device_id}_{self._index}"
|
||||
self._status = {}
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""No polling needed."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return a name for this WiLight item."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the unique ID for this WiLight item."""
|
||||
return self._unique_id
|
||||
|
||||
@property
|
||||
def device_info(self):
|
||||
"""Return the device info."""
|
||||
return {
|
||||
"name": self._name,
|
||||
"identifiers": {(DOMAIN, self._unique_id)},
|
||||
"model": self._model,
|
||||
"manufacturer": "WiLight",
|
||||
"sw_version": self._sw_version,
|
||||
"via_device": (DOMAIN, self._device_id),
|
||||
}
|
||||
|
||||
@property
|
||||
def available(self):
|
||||
"""Return True if entity is available."""
|
||||
return bool(self._client.is_connected)
|
||||
|
||||
@callback
|
||||
def handle_event_callback(self, states):
|
||||
"""Propagate changes through ha."""
|
||||
self._status = states
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_update(self):
|
||||
"""Synchronize state with api_device."""
|
||||
await self._client.status(self._index)
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register update callback."""
|
||||
self._client.register_status_callback(self.handle_event_callback, self._index)
|
||||
await self._client.status(self._index)
|
106
homeassistant/components/wilight/config_flow.py
Normal file
106
homeassistant/components/wilight/config_flow.py
Normal file
@ -0,0 +1,106 @@
|
||||
"""Config flow to configure WiLight."""
|
||||
import logging
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import pywilight
|
||||
|
||||
from homeassistant.components import ssdp
|
||||
from homeassistant.config_entries import CONN_CLASS_LOCAL_PUSH, ConfigFlow
|
||||
from homeassistant.const import CONF_HOST
|
||||
|
||||
from .const import DOMAIN # pylint: disable=unused-import
|
||||
|
||||
CONF_SERIAL_NUMBER = "serial_number"
|
||||
CONF_MODEL_NAME = "model_name"
|
||||
|
||||
WILIGHT_MANUFACTURER = "All Automacao Ltda"
|
||||
|
||||
# List the components supported by this integration.
|
||||
ALLOWED_WILIGHT_COMPONENTS = ["light"]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WiLightFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a WiLight config flow."""
|
||||
|
||||
VERSION = 1
|
||||
CONNECTION_CLASS = CONN_CLASS_LOCAL_PUSH
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the WiLight flow."""
|
||||
self._host = None
|
||||
self._serial_number = None
|
||||
self._title = None
|
||||
self._model_name = None
|
||||
self._wilight_components = []
|
||||
self._components_text = ""
|
||||
|
||||
def _wilight_update(self, host, serial_number, model_name):
|
||||
self._host = host
|
||||
self._serial_number = serial_number
|
||||
self._title = f"WL{serial_number}"
|
||||
self._model_name = model_name
|
||||
self._wilight_components = pywilight.get_components_from_model(model_name)
|
||||
self._components_text = ", ".join(self._wilight_components)
|
||||
return self._components_text != ""
|
||||
|
||||
def _get_entry(self):
|
||||
data = {
|
||||
CONF_HOST: self._host,
|
||||
CONF_SERIAL_NUMBER: self._serial_number,
|
||||
CONF_MODEL_NAME: self._model_name,
|
||||
}
|
||||
return self.async_create_entry(title=self._title, data=data)
|
||||
|
||||
async def async_step_ssdp(self, discovery_info):
|
||||
"""Handle a discovered WiLight."""
|
||||
# Filter out basic information
|
||||
if (
|
||||
ssdp.ATTR_SSDP_LOCATION not in discovery_info
|
||||
or ssdp.ATTR_UPNP_MANUFACTURER not in discovery_info
|
||||
or ssdp.ATTR_UPNP_SERIAL not in discovery_info
|
||||
or ssdp.ATTR_UPNP_MODEL_NAME not in discovery_info
|
||||
or ssdp.ATTR_UPNP_MODEL_NUMBER not in discovery_info
|
||||
):
|
||||
return self.async_abort(reason="not_wilight_device")
|
||||
# Filter out non-WiLight devices
|
||||
if discovery_info[ssdp.ATTR_UPNP_MANUFACTURER] != WILIGHT_MANUFACTURER:
|
||||
return self.async_abort(reason="not_wilight_device")
|
||||
|
||||
host = urlparse(discovery_info[ssdp.ATTR_SSDP_LOCATION]).hostname
|
||||
serial_number = discovery_info[ssdp.ATTR_UPNP_SERIAL]
|
||||
model_name = discovery_info[ssdp.ATTR_UPNP_MODEL_NAME]
|
||||
|
||||
if not self._wilight_update(host, serial_number, model_name):
|
||||
return self.async_abort(reason="not_wilight_device")
|
||||
|
||||
# Check if all components of this WiLight are allowed in this version of the HA integration
|
||||
component_ok = all(
|
||||
wilight_component in ALLOWED_WILIGHT_COMPONENTS
|
||||
for wilight_component in self._wilight_components
|
||||
)
|
||||
|
||||
if not component_ok:
|
||||
return self.async_abort(reason="not_supported_device")
|
||||
|
||||
await self.async_set_unique_id(self._serial_number)
|
||||
self._abort_if_unique_id_configured(updates={CONF_HOST: self._host})
|
||||
|
||||
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
|
||||
self.context["title_placeholders"] = {"name": self._title}
|
||||
return await self.async_step_confirm()
|
||||
|
||||
async def async_step_confirm(self, user_input=None):
|
||||
"""Handle user-confirmation of discovered WiLight."""
|
||||
if user_input is not None:
|
||||
return self._get_entry()
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="confirm",
|
||||
description_placeholders={
|
||||
"name": self._title,
|
||||
"components": self._components_text,
|
||||
},
|
||||
errors={},
|
||||
)
|
14
homeassistant/components/wilight/const.py
Normal file
14
homeassistant/components/wilight/const.py
Normal file
@ -0,0 +1,14 @@
|
||||
"""Constants for the WiLight integration."""
|
||||
|
||||
DOMAIN = "wilight"
|
||||
|
||||
# Item types
|
||||
ITEM_LIGHT = "light"
|
||||
|
||||
# Light types
|
||||
LIGHT_ON_OFF = "light_on_off"
|
||||
LIGHT_DIMMER = "light_dimmer"
|
||||
LIGHT_COLOR = "light_rgb"
|
||||
|
||||
# Light service support
|
||||
SUPPORT_NONE = 0
|
179
homeassistant/components/wilight/light.py
Normal file
179
homeassistant/components/wilight/light.py
Normal file
@ -0,0 +1,179 @@
|
||||
"""Support for WiLight lights."""
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_HS_COLOR,
|
||||
SUPPORT_BRIGHTNESS,
|
||||
SUPPORT_COLOR,
|
||||
LightEntity,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import WiLightDevice
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
ITEM_LIGHT,
|
||||
LIGHT_COLOR,
|
||||
LIGHT_DIMMER,
|
||||
LIGHT_ON_OFF,
|
||||
SUPPORT_NONE,
|
||||
)
|
||||
|
||||
|
||||
def entities_from_discovered_wilight(hass, api_device):
|
||||
"""Parse configuration and add WiLight light entities."""
|
||||
entities = []
|
||||
for item in api_device.items:
|
||||
if item["type"] != ITEM_LIGHT:
|
||||
continue
|
||||
index = item["index"]
|
||||
item_name = item["name"]
|
||||
if item["sub_type"] == LIGHT_ON_OFF:
|
||||
entity = WiLightLightOnOff(api_device, index, item_name)
|
||||
elif item["sub_type"] == LIGHT_DIMMER:
|
||||
entity = WiLightLightDimmer(api_device, index, item_name)
|
||||
elif item["sub_type"] == LIGHT_COLOR:
|
||||
entity = WiLightLightColor(api_device, index, item_name)
|
||||
else:
|
||||
continue
|
||||
entities.append(entity)
|
||||
|
||||
return entities
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities
|
||||
):
|
||||
"""Set up WiLight lights from a config entry."""
|
||||
parent = hass.data[DOMAIN][entry.entry_id]
|
||||
|
||||
# Handle a discovered WiLight device.
|
||||
entities = entities_from_discovered_wilight(hass, parent.api)
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class WiLightLightOnOff(WiLightDevice, LightEntity):
|
||||
"""Representation of a WiLights light on-off."""
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Flag supported features."""
|
||||
return SUPPORT_NONE
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if device is on."""
|
||||
return self._status.get("on")
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
"""Turn the device on."""
|
||||
await self._client.turn_on(self._index)
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
"""Turn the device off."""
|
||||
await self._client.turn_off(self._index)
|
||||
|
||||
|
||||
class WiLightLightDimmer(WiLightDevice, LightEntity):
|
||||
"""Representation of a WiLights light dimmer."""
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Flag supported features."""
|
||||
return SUPPORT_BRIGHTNESS
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""Return the brightness of this light between 0..255."""
|
||||
return int(self._status.get("brightness", 0))
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if device is on."""
|
||||
return self._status.get("on")
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
"""Turn the device on,set brightness if needed."""
|
||||
# Dimmer switches use a range of [0, 255] to control
|
||||
# brightness. Level 255 might mean to set it to previous value
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
brightness = kwargs[ATTR_BRIGHTNESS]
|
||||
await self._client.set_brightness(self._index, brightness)
|
||||
else:
|
||||
await self._client.turn_on(self._index)
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
"""Turn the device off."""
|
||||
await self._client.turn_off(self._index)
|
||||
|
||||
|
||||
def wilight_to_hass_hue(value):
|
||||
"""Convert wilight hue 1..255 to hass 0..360 scale."""
|
||||
return min(360, round((value * 360) / 255, 3))
|
||||
|
||||
|
||||
def hass_to_wilight_hue(value):
|
||||
"""Convert hass hue 0..360 to wilight 1..255 scale."""
|
||||
return min(255, round((value * 255) / 360))
|
||||
|
||||
|
||||
def wilight_to_hass_saturation(value):
|
||||
"""Convert wilight saturation 1..255 to hass 0..100 scale."""
|
||||
return min(100, round((value * 100) / 255, 3))
|
||||
|
||||
|
||||
def hass_to_wilight_saturation(value):
|
||||
"""Convert hass saturation 0..100 to wilight 1..255 scale."""
|
||||
return min(255, round((value * 255) / 100))
|
||||
|
||||
|
||||
class WiLightLightColor(WiLightDevice, LightEntity):
|
||||
"""Representation of a WiLights light rgb."""
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Flag supported features."""
|
||||
return SUPPORT_BRIGHTNESS | SUPPORT_COLOR
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""Return the brightness of this light between 0..255."""
|
||||
return int(self._status.get("brightness", 0))
|
||||
|
||||
@property
|
||||
def hs_color(self):
|
||||
"""Return the hue and saturation color value [float, float]."""
|
||||
return [
|
||||
wilight_to_hass_hue(int(self._status.get("hue", 0))),
|
||||
wilight_to_hass_saturation(int(self._status.get("saturation", 0))),
|
||||
]
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if device is on."""
|
||||
return self._status.get("on")
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
"""Turn the device on,set brightness if needed."""
|
||||
# Brightness use a range of [0, 255] to control
|
||||
# Hue use a range of [0, 360] to control
|
||||
# Saturation use a range of [0, 100] to control
|
||||
if ATTR_BRIGHTNESS in kwargs and ATTR_HS_COLOR in kwargs:
|
||||
brightness = kwargs[ATTR_BRIGHTNESS]
|
||||
hue = hass_to_wilight_hue(kwargs[ATTR_HS_COLOR][0])
|
||||
saturation = hass_to_wilight_saturation(kwargs[ATTR_HS_COLOR][1])
|
||||
await self._client.set_hsb_color(self._index, hue, saturation, brightness)
|
||||
elif ATTR_BRIGHTNESS in kwargs and ATTR_HS_COLOR not in kwargs:
|
||||
brightness = kwargs[ATTR_BRIGHTNESS]
|
||||
await self._client.set_brightness(self._index, brightness)
|
||||
elif ATTR_BRIGHTNESS not in kwargs and ATTR_HS_COLOR in kwargs:
|
||||
hue = hass_to_wilight_hue(kwargs[ATTR_HS_COLOR][0])
|
||||
saturation = hass_to_wilight_saturation(kwargs[ATTR_HS_COLOR][1])
|
||||
await self._client.set_hs_color(self._index, hue, saturation)
|
||||
else:
|
||||
await self._client.turn_on(self._index)
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
"""Turn the device off."""
|
||||
await self._client.turn_off(self._index)
|
14
homeassistant/components/wilight/manifest.json
Normal file
14
homeassistant/components/wilight/manifest.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"domain": "wilight",
|
||||
"name": "WiLight",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/wilight",
|
||||
"requirements": ["pywilight==0.0.65"],
|
||||
"ssdp": [
|
||||
{
|
||||
"manufacturer": "All Automacao Ltda"
|
||||
}
|
||||
],
|
||||
"codeowners": ["@leofig-rj"],
|
||||
"quality_scale": "silver"
|
||||
}
|
102
homeassistant/components/wilight/parent_device.py
Normal file
102
homeassistant/components/wilight/parent_device.py
Normal file
@ -0,0 +1,102 @@
|
||||
"""The WiLight Device integration."""
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
import pywilight
|
||||
import requests
|
||||
|
||||
from homeassistant.const import CONF_HOST, EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WiLightParent:
|
||||
"""Manages a single WiLight Parent Device."""
|
||||
|
||||
def __init__(self, hass, config_entry):
|
||||
"""Initialize the system."""
|
||||
self._host = config_entry.data[CONF_HOST]
|
||||
self._hass = hass
|
||||
self._api = None
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
"""Return the host of this parent."""
|
||||
return self._host
|
||||
|
||||
@property
|
||||
def api(self):
|
||||
"""Return the api of this parent."""
|
||||
return self._api
|
||||
|
||||
async def async_setup(self):
|
||||
"""Set up a WiLight Parent Device based on host parameter."""
|
||||
host = self._host
|
||||
hass = self._hass
|
||||
|
||||
api_device = await hass.async_add_executor_job(create_api_device, host)
|
||||
|
||||
if api_device is None:
|
||||
return False
|
||||
|
||||
@callback
|
||||
def disconnected():
|
||||
# Schedule reconnect after connection has been lost.
|
||||
_LOGGER.warning("WiLight %s disconnected", api_device.device_id)
|
||||
async_dispatcher_send(
|
||||
hass, f"wilight_device_available_{api_device.device_id}", False
|
||||
)
|
||||
|
||||
@callback
|
||||
def reconnected():
|
||||
# Schedule reconnect after connection has been lost.
|
||||
_LOGGER.warning("WiLight %s reconnect", api_device.device_id)
|
||||
async_dispatcher_send(
|
||||
hass, f"wilight_device_available_{api_device.device_id}", True
|
||||
)
|
||||
|
||||
async def connect(api_device):
|
||||
# Set up connection and hook it into HA for reconnect/shutdown.
|
||||
_LOGGER.debug("Initiating connection to %s", api_device.device_id)
|
||||
|
||||
client = await api_device.config_client(
|
||||
disconnect_callback=disconnected,
|
||||
reconnect_callback=reconnected,
|
||||
loop=asyncio.get_running_loop(),
|
||||
logger=_LOGGER,
|
||||
)
|
||||
|
||||
# handle shutdown of WiLight asyncio transport
|
||||
hass.bus.async_listen_once(
|
||||
EVENT_HOMEASSISTANT_STOP, lambda x: client.stop()
|
||||
)
|
||||
|
||||
_LOGGER.info("Connected to WiLight device: %s", api_device.device_id)
|
||||
|
||||
await connect(api_device)
|
||||
|
||||
self._api = api_device
|
||||
|
||||
return True
|
||||
|
||||
async def async_reset(self):
|
||||
"""Reset api."""
|
||||
|
||||
# If the initialization was wrong.
|
||||
if self._api is None:
|
||||
return True
|
||||
|
||||
self._api.client.stop()
|
||||
|
||||
|
||||
def create_api_device(host):
|
||||
"""Create an API Device."""
|
||||
try:
|
||||
device = pywilight.device_from_host(host)
|
||||
except (requests.exceptions.ConnectionError, requests.exceptions.Timeout,) as err:
|
||||
_LOGGER.error("Unable to access WiLight at %s (%s)", host, err)
|
||||
return None
|
||||
|
||||
return device
|
16
homeassistant/components/wilight/strings.json
Normal file
16
homeassistant/components/wilight/strings.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"config": {
|
||||
"flow_title": "WiLight: {name}",
|
||||
"step": {
|
||||
"confirm": {
|
||||
"title": "WiLight",
|
||||
"description": "Do you want to set up WiLight {name}?\n\n It supports: {components}"
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||
"not_supported_device": "This WiLight is currently not supported",
|
||||
"not_wilight_device": "This Device is not WiLight"
|
||||
}
|
||||
}
|
||||
}
|
16
homeassistant/components/wilight/translations/en.json
Normal file
16
homeassistant/components/wilight/translations/en.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured_device": "This WiLight is already configured",
|
||||
"not_supported_device": "This WiLight is currently not supported",
|
||||
"not_wilight_device": "This Device is not WiLight"
|
||||
},
|
||||
"flow_title": "WiLight: {name}",
|
||||
"step": {
|
||||
"confirm": {
|
||||
"title": "WiLight",
|
||||
"description": "Do you want to set up WiLight {name}?\n\n It supports: {components}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -199,6 +199,7 @@ FLOWS = [
|
||||
"volumio",
|
||||
"wemo",
|
||||
"wiffi",
|
||||
"wilight",
|
||||
"withings",
|
||||
"wled",
|
||||
"wolflink",
|
||||
|
@ -172,5 +172,10 @@ SSDP = {
|
||||
{
|
||||
"manufacturer": "Belkin International Inc."
|
||||
}
|
||||
],
|
||||
"wilight": [
|
||||
{
|
||||
"manufacturer": "All Automacao Ltda"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1852,6 +1852,9 @@ pywebpush==1.9.2
|
||||
# homeassistant.components.wemo
|
||||
pywemo==0.4.46
|
||||
|
||||
# homeassistant.components.wilight
|
||||
pywilight==0.0.65
|
||||
|
||||
# homeassistant.components.xeoma
|
||||
pyxeoma==1.4.1
|
||||
|
||||
|
@ -857,6 +857,9 @@ pyvolumio==0.1.1
|
||||
# homeassistant.components.html5
|
||||
pywebpush==1.9.2
|
||||
|
||||
# homeassistant.components.wilight
|
||||
pywilight==0.0.65
|
||||
|
||||
# homeassistant.components.zerproc
|
||||
pyzerproc==0.2.5
|
||||
|
||||
|
83
tests/components/wilight/__init__.py
Normal file
83
tests/components/wilight/__init__.py
Normal file
@ -0,0 +1,83 @@
|
||||
"""Tests for the WiLight component."""
|
||||
from homeassistant.components.ssdp import (
|
||||
ATTR_SSDP_LOCATION,
|
||||
ATTR_UPNP_MANUFACTURER,
|
||||
ATTR_UPNP_MODEL_NAME,
|
||||
ATTR_UPNP_MODEL_NUMBER,
|
||||
ATTR_UPNP_SERIAL,
|
||||
)
|
||||
from homeassistant.components.wilight.config_flow import (
|
||||
CONF_MODEL_NAME,
|
||||
CONF_SERIAL_NUMBER,
|
||||
)
|
||||
from homeassistant.components.wilight.const import DOMAIN
|
||||
from homeassistant.const import CONF_HOST
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
HOST = "127.0.0.1"
|
||||
WILIGHT_ID = "000000000099"
|
||||
SSDP_LOCATION = "http://127.0.0.1/"
|
||||
UPNP_MANUFACTURER = "All Automacao Ltda"
|
||||
UPNP_MODEL_NAME_P_B = "WiLight 0102001800010009-10010010"
|
||||
UPNP_MODEL_NAME_DIMMER = "WiLight 0100001700020009-10010010"
|
||||
UPNP_MODEL_NAME_COLOR = "WiLight 0107001800020009-11010"
|
||||
UPNP_MODEL_NAME_LIGHT_FAN = "WiLight 0104001800010009-10"
|
||||
UPNP_MODEL_NUMBER = "123456789012345678901234567890123456"
|
||||
UPNP_SERIAL = "000000000099"
|
||||
UPNP_MAC_ADDRESS = "5C:CF:7F:8B:CA:56"
|
||||
UPNP_MANUFACTURER_NOT_WILIGHT = "Test"
|
||||
CONF_COMPONENTS = "components"
|
||||
|
||||
MOCK_SSDP_DISCOVERY_INFO_P_B = {
|
||||
ATTR_SSDP_LOCATION: SSDP_LOCATION,
|
||||
ATTR_UPNP_MANUFACTURER: UPNP_MANUFACTURER,
|
||||
ATTR_UPNP_MODEL_NAME: UPNP_MODEL_NAME_P_B,
|
||||
ATTR_UPNP_MODEL_NUMBER: UPNP_MODEL_NUMBER,
|
||||
ATTR_UPNP_SERIAL: UPNP_SERIAL,
|
||||
}
|
||||
|
||||
MOCK_SSDP_DISCOVERY_INFO_WRONG_MANUFACTORER = {
|
||||
ATTR_SSDP_LOCATION: SSDP_LOCATION,
|
||||
ATTR_UPNP_MANUFACTURER: UPNP_MANUFACTURER_NOT_WILIGHT,
|
||||
ATTR_UPNP_MODEL_NAME: UPNP_MODEL_NAME_P_B,
|
||||
ATTR_UPNP_MODEL_NUMBER: UPNP_MODEL_NUMBER,
|
||||
ATTR_UPNP_SERIAL: ATTR_UPNP_SERIAL,
|
||||
}
|
||||
|
||||
MOCK_SSDP_DISCOVERY_INFO_MISSING_MANUFACTORER = {
|
||||
ATTR_SSDP_LOCATION: SSDP_LOCATION,
|
||||
ATTR_UPNP_MODEL_NAME: UPNP_MODEL_NAME_P_B,
|
||||
ATTR_UPNP_MODEL_NUMBER: UPNP_MODEL_NUMBER,
|
||||
ATTR_UPNP_SERIAL: ATTR_UPNP_SERIAL,
|
||||
}
|
||||
|
||||
MOCK_SSDP_DISCOVERY_INFO_LIGHT_FAN = {
|
||||
ATTR_SSDP_LOCATION: SSDP_LOCATION,
|
||||
ATTR_UPNP_MANUFACTURER: UPNP_MANUFACTURER,
|
||||
ATTR_UPNP_MODEL_NAME: UPNP_MODEL_NAME_LIGHT_FAN,
|
||||
ATTR_UPNP_MODEL_NUMBER: UPNP_MODEL_NUMBER,
|
||||
ATTR_UPNP_SERIAL: ATTR_UPNP_SERIAL,
|
||||
}
|
||||
|
||||
|
||||
async def setup_integration(hass: HomeAssistantType,) -> MockConfigEntry:
|
||||
"""Mock ConfigEntry in Home Assistant."""
|
||||
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id=WILIGHT_ID,
|
||||
data={
|
||||
CONF_HOST: HOST,
|
||||
CONF_SERIAL_NUMBER: UPNP_SERIAL,
|
||||
CONF_MODEL_NAME: UPNP_MODEL_NAME_P_B,
|
||||
},
|
||||
)
|
||||
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
return entry
|
157
tests/components/wilight/test_config_flow.py
Normal file
157
tests/components/wilight/test_config_flow.py
Normal file
@ -0,0 +1,157 @@
|
||||
"""Test the WiLight config flow."""
|
||||
from asynctest import patch
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.wilight.config_flow import (
|
||||
CONF_MODEL_NAME,
|
||||
CONF_SERIAL_NUMBER,
|
||||
)
|
||||
from homeassistant.components.wilight.const import DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_SSDP
|
||||
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_SOURCE
|
||||
from homeassistant.data_entry_flow import (
|
||||
RESULT_TYPE_ABORT,
|
||||
RESULT_TYPE_CREATE_ENTRY,
|
||||
RESULT_TYPE_FORM,
|
||||
)
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.wilight import (
|
||||
CONF_COMPONENTS,
|
||||
HOST,
|
||||
MOCK_SSDP_DISCOVERY_INFO_LIGHT_FAN,
|
||||
MOCK_SSDP_DISCOVERY_INFO_MISSING_MANUFACTORER,
|
||||
MOCK_SSDP_DISCOVERY_INFO_P_B,
|
||||
MOCK_SSDP_DISCOVERY_INFO_WRONG_MANUFACTORER,
|
||||
UPNP_MODEL_NAME_P_B,
|
||||
UPNP_SERIAL,
|
||||
WILIGHT_ID,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="dummy_get_components_from_model_clear")
|
||||
def mock_dummy_get_components_from_model():
|
||||
"""Mock a clear components list."""
|
||||
components = []
|
||||
with patch(
|
||||
"pywilight.get_components_from_model", return_value=components,
|
||||
):
|
||||
yield components
|
||||
|
||||
|
||||
async def test_show_ssdp_form(hass: HomeAssistantType) -> None:
|
||||
"""Test that the ssdp confirmation form is served."""
|
||||
|
||||
discovery_info = MOCK_SSDP_DISCOVERY_INFO_P_B.copy()
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=discovery_info
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "confirm"
|
||||
assert result["description_placeholders"] == {
|
||||
CONF_NAME: f"WL{WILIGHT_ID}",
|
||||
CONF_COMPONENTS: "light",
|
||||
}
|
||||
|
||||
|
||||
async def test_ssdp_not_wilight_abort_1(hass: HomeAssistantType) -> None:
|
||||
"""Test that the ssdp aborts not_wilight."""
|
||||
|
||||
discovery_info = MOCK_SSDP_DISCOVERY_INFO_WRONG_MANUFACTORER.copy()
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=discovery_info
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "not_wilight_device"
|
||||
|
||||
|
||||
async def test_ssdp_not_wilight_abort_2(hass: HomeAssistantType) -> None:
|
||||
"""Test that the ssdp aborts not_wilight."""
|
||||
|
||||
discovery_info = MOCK_SSDP_DISCOVERY_INFO_MISSING_MANUFACTORER.copy()
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=discovery_info
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "not_wilight_device"
|
||||
|
||||
|
||||
async def test_ssdp_not_wilight_abort_3(
|
||||
hass: HomeAssistantType, dummy_get_components_from_model_clear
|
||||
) -> None:
|
||||
"""Test that the ssdp aborts not_wilight."""
|
||||
|
||||
discovery_info = MOCK_SSDP_DISCOVERY_INFO_P_B.copy()
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=discovery_info
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "not_wilight_device"
|
||||
|
||||
|
||||
async def test_ssdp_not_supported_abort(hass: HomeAssistantType) -> None:
|
||||
"""Test that the ssdp aborts not_supported."""
|
||||
|
||||
discovery_info = MOCK_SSDP_DISCOVERY_INFO_LIGHT_FAN.copy()
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=discovery_info
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "not_supported_device"
|
||||
|
||||
|
||||
async def test_ssdp_device_exists_abort(hass: HomeAssistantType) -> None:
|
||||
"""Test abort SSDP flow if WiLight already configured."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id=WILIGHT_ID,
|
||||
data={
|
||||
CONF_HOST: HOST,
|
||||
CONF_SERIAL_NUMBER: UPNP_SERIAL,
|
||||
CONF_MODEL_NAME: UPNP_MODEL_NAME_P_B,
|
||||
},
|
||||
)
|
||||
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
discovery_info = MOCK_SSDP_DISCOVERY_INFO_P_B.copy()
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=discovery_info,
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_full_ssdp_flow_implementation(hass: HomeAssistantType) -> None:
|
||||
"""Test the full SSDP flow from start to finish."""
|
||||
|
||||
discovery_info = MOCK_SSDP_DISCOVERY_INFO_P_B.copy()
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=discovery_info
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "confirm"
|
||||
assert result["description_placeholders"] == {
|
||||
CONF_NAME: f"WL{WILIGHT_ID}",
|
||||
"components": "light",
|
||||
}
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={}
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == f"WL{WILIGHT_ID}"
|
||||
|
||||
assert result["data"]
|
||||
assert result["data"][CONF_HOST] == HOST
|
||||
assert result["data"][CONF_SERIAL_NUMBER] == UPNP_SERIAL
|
||||
assert result["data"][CONF_MODEL_NAME] == UPNP_MODEL_NAME_P_B
|
65
tests/components/wilight/test_init.py
Normal file
65
tests/components/wilight/test_init.py
Normal file
@ -0,0 +1,65 @@
|
||||
"""Tests for the WiLight integration."""
|
||||
from asynctest import patch
|
||||
import pytest
|
||||
import pywilight
|
||||
|
||||
from homeassistant.components.wilight.const import DOMAIN
|
||||
from homeassistant.config_entries import (
|
||||
ENTRY_STATE_LOADED,
|
||||
ENTRY_STATE_NOT_LOADED,
|
||||
ENTRY_STATE_SETUP_RETRY,
|
||||
)
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from tests.components.wilight import (
|
||||
HOST,
|
||||
UPNP_MAC_ADDRESS,
|
||||
UPNP_MODEL_NAME_P_B,
|
||||
UPNP_MODEL_NUMBER,
|
||||
UPNP_SERIAL,
|
||||
setup_integration,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="dummy_device_from_host")
|
||||
def mock_dummy_device_from_host():
|
||||
"""Mock a valid api_devce."""
|
||||
|
||||
device = pywilight.wilight_from_discovery(
|
||||
f"http://{HOST}:45995/wilight.xml",
|
||||
UPNP_MAC_ADDRESS,
|
||||
UPNP_MODEL_NAME_P_B,
|
||||
UPNP_SERIAL,
|
||||
UPNP_MODEL_NUMBER,
|
||||
)
|
||||
|
||||
device.set_dummy(True)
|
||||
|
||||
with patch(
|
||||
"pywilight.device_from_host", return_value=device,
|
||||
):
|
||||
yield device
|
||||
|
||||
|
||||
async def test_config_entry_not_ready(hass: HomeAssistantType) -> None:
|
||||
"""Test the WiLight configuration entry not ready."""
|
||||
entry = await setup_integration(hass)
|
||||
|
||||
assert entry.state == ENTRY_STATE_SETUP_RETRY
|
||||
|
||||
|
||||
async def test_unload_config_entry(
|
||||
hass: HomeAssistantType, dummy_device_from_host
|
||||
) -> None:
|
||||
"""Test the WiLight configuration entry unloading."""
|
||||
entry = await setup_integration(hass)
|
||||
|
||||
assert entry.entry_id in hass.data[DOMAIN]
|
||||
assert entry.state == ENTRY_STATE_LOADED
|
||||
|
||||
await hass.config_entries.async_unload(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
if DOMAIN in hass.data:
|
||||
assert entry.entry_id not in hass.data[DOMAIN]
|
||||
assert entry.state == ENTRY_STATE_NOT_LOADED
|
369
tests/components/wilight/test_light.py
Normal file
369
tests/components/wilight/test_light.py
Normal file
@ -0,0 +1,369 @@
|
||||
"""Tests for the WiLight integration."""
|
||||
from asynctest import patch
|
||||
import pytest
|
||||
import pywilight
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_HS_COLOR,
|
||||
DOMAIN as LIGHT_DOMAIN,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
)
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from tests.components.wilight import (
|
||||
HOST,
|
||||
UPNP_MAC_ADDRESS,
|
||||
UPNP_MODEL_NAME_COLOR,
|
||||
UPNP_MODEL_NAME_DIMMER,
|
||||
UPNP_MODEL_NAME_LIGHT_FAN,
|
||||
UPNP_MODEL_NAME_P_B,
|
||||
UPNP_MODEL_NUMBER,
|
||||
UPNP_SERIAL,
|
||||
WILIGHT_ID,
|
||||
setup_integration,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="dummy_get_components_from_model_light")
|
||||
def mock_dummy_get_components_from_model_light():
|
||||
"""Mock a components list with light."""
|
||||
components = ["light"]
|
||||
with patch(
|
||||
"pywilight.get_components_from_model", return_value=components,
|
||||
):
|
||||
yield components
|
||||
|
||||
|
||||
@pytest.fixture(name="dummy_device_from_host_light_fan")
|
||||
def mock_dummy_device_from_host_light_fan():
|
||||
"""Mock a valid api_devce."""
|
||||
|
||||
device = pywilight.wilight_from_discovery(
|
||||
f"http://{HOST}:45995/wilight.xml",
|
||||
UPNP_MAC_ADDRESS,
|
||||
UPNP_MODEL_NAME_LIGHT_FAN,
|
||||
UPNP_SERIAL,
|
||||
UPNP_MODEL_NUMBER,
|
||||
)
|
||||
|
||||
device.set_dummy(True)
|
||||
|
||||
with patch(
|
||||
"pywilight.device_from_host", return_value=device,
|
||||
):
|
||||
yield device
|
||||
|
||||
|
||||
@pytest.fixture(name="dummy_device_from_host_pb")
|
||||
def mock_dummy_device_from_host_pb():
|
||||
"""Mock a valid api_devce."""
|
||||
|
||||
device = pywilight.wilight_from_discovery(
|
||||
f"http://{HOST}:45995/wilight.xml",
|
||||
UPNP_MAC_ADDRESS,
|
||||
UPNP_MODEL_NAME_P_B,
|
||||
UPNP_SERIAL,
|
||||
UPNP_MODEL_NUMBER,
|
||||
)
|
||||
|
||||
device.set_dummy(True)
|
||||
|
||||
with patch(
|
||||
"pywilight.device_from_host", return_value=device,
|
||||
):
|
||||
yield device
|
||||
|
||||
|
||||
@pytest.fixture(name="dummy_device_from_host_dimmer")
|
||||
def mock_dummy_device_from_host_dimmer():
|
||||
"""Mock a valid api_devce."""
|
||||
|
||||
device = pywilight.wilight_from_discovery(
|
||||
f"http://{HOST}:45995/wilight.xml",
|
||||
UPNP_MAC_ADDRESS,
|
||||
UPNP_MODEL_NAME_DIMMER,
|
||||
UPNP_SERIAL,
|
||||
UPNP_MODEL_NUMBER,
|
||||
)
|
||||
|
||||
device.set_dummy(True)
|
||||
|
||||
with patch(
|
||||
"pywilight.device_from_host", return_value=device,
|
||||
):
|
||||
yield device
|
||||
|
||||
|
||||
@pytest.fixture(name="dummy_device_from_host_color")
|
||||
def mock_dummy_device_from_host_color():
|
||||
"""Mock a valid api_devce."""
|
||||
|
||||
device = pywilight.wilight_from_discovery(
|
||||
f"http://{HOST}:45995/wilight.xml",
|
||||
UPNP_MAC_ADDRESS,
|
||||
UPNP_MODEL_NAME_COLOR,
|
||||
UPNP_SERIAL,
|
||||
UPNP_MODEL_NUMBER,
|
||||
)
|
||||
|
||||
device.set_dummy(True)
|
||||
|
||||
with patch(
|
||||
"pywilight.device_from_host", return_value=device,
|
||||
):
|
||||
yield device
|
||||
|
||||
|
||||
async def test_loading_light(
|
||||
hass: HomeAssistantType,
|
||||
dummy_device_from_host_light_fan,
|
||||
dummy_get_components_from_model_light,
|
||||
) -> None:
|
||||
"""Test the WiLight configuration entry loading."""
|
||||
|
||||
# Using light_fan and removind fan from get_components_from_model
|
||||
# to test light.py line 28
|
||||
entry = await setup_integration(hass)
|
||||
assert entry
|
||||
assert entry.unique_id == WILIGHT_ID
|
||||
|
||||
entity_registry = await hass.helpers.entity_registry.async_get_registry()
|
||||
|
||||
# First segment of the strip
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
entry = entity_registry.async_get("light.wl000000000099_1")
|
||||
assert entry
|
||||
assert entry.unique_id == "WL000000000099_0"
|
||||
|
||||
|
||||
async def test_on_off_light_state(
|
||||
hass: HomeAssistantType, dummy_device_from_host_pb
|
||||
) -> None:
|
||||
"""Test the change of state of the light switches."""
|
||||
await setup_integration(hass)
|
||||
|
||||
# Turn on
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "light.wl000000000099_1"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_ON
|
||||
|
||||
# Turn off
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: "light.wl000000000099_1"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
|
||||
async def test_dimmer_light_state(
|
||||
hass: HomeAssistantType, dummy_device_from_host_dimmer
|
||||
) -> None:
|
||||
"""Test the change of state of the light switches."""
|
||||
await setup_integration(hass)
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_BRIGHTNESS: 42, ATTR_ENTITY_ID: "light.wl000000000099_1"},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes.get(ATTR_BRIGHTNESS) == 42
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_BRIGHTNESS: 0, ATTR_ENTITY_ID: "light.wl000000000099_1"},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_BRIGHTNESS: 100, ATTR_ENTITY_ID: "light.wl000000000099_1"},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes.get(ATTR_BRIGHTNESS) == 100
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: "light.wl000000000099_1"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
# Turn on
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "light.wl000000000099_1"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_ON
|
||||
|
||||
|
||||
async def test_color_light_state(
|
||||
hass: HomeAssistantType, dummy_device_from_host_color
|
||||
) -> None:
|
||||
"""Test the change of state of the light switches."""
|
||||
await setup_integration(hass)
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_BRIGHTNESS: 42,
|
||||
ATTR_HS_COLOR: [0, 100],
|
||||
ATTR_ENTITY_ID: "light.wl000000000099_1",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes.get(ATTR_BRIGHTNESS) == 42
|
||||
state_color = [
|
||||
round(state.attributes.get(ATTR_HS_COLOR)[0]),
|
||||
round(state.attributes.get(ATTR_HS_COLOR)[1]),
|
||||
]
|
||||
assert state_color == [0, 100]
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_BRIGHTNESS: 0, ATTR_ENTITY_ID: "light.wl000000000099_1"},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_BRIGHTNESS: 100,
|
||||
ATTR_HS_COLOR: [270, 50],
|
||||
ATTR_ENTITY_ID: "light.wl000000000099_1",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes.get(ATTR_BRIGHTNESS) == 100
|
||||
state_color = [
|
||||
round(state.attributes.get(ATTR_HS_COLOR)[0]),
|
||||
round(state.attributes.get(ATTR_HS_COLOR)[1]),
|
||||
]
|
||||
assert state_color == [270, 50]
|
||||
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: "light.wl000000000099_1"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
# Turn on
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "light.wl000000000099_1"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_ON
|
||||
|
||||
# Hue = 0, Saturation = 100
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_HS_COLOR: [0, 100], ATTR_ENTITY_ID: "light.wl000000000099_1"},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_ON
|
||||
state_color = [
|
||||
round(state.attributes.get(ATTR_HS_COLOR)[0]),
|
||||
round(state.attributes.get(ATTR_HS_COLOR)[1]),
|
||||
]
|
||||
assert state_color == [0, 100]
|
||||
|
||||
# Brightness = 60
|
||||
await hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_BRIGHTNESS: 60, ATTR_ENTITY_ID: "light.wl000000000099_1"},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("light.wl000000000099_1")
|
||||
assert state
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes.get(ATTR_BRIGHTNESS) == 60
|
Loading…
x
Reference in New Issue
Block a user