Add switch to wilight (#62873)
* Created switch.py and support * updated support.py * test for wilight switch * Update for Test * Updated test_switch.py * Trigger service with index * Updated support.py and switch.py * Updated support.py * Updated switch.py as PR#63614 * Updated switch.py * add type hints * Updated support.py * Updated switch.py * Updated switch.py and services.yaml * Updated pywilight * Update homeassistant/components/wilight/switch.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/wilight/switch.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/wilight/switch.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/wilight/switch.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update ci.yaml * Update ci.yaml * Updated as pywilight Renamed Device as PyWiLightDevice in pywilight. * Updated as pywilight Renamed Device as PyWiLightDevice in pywilight. * Updated as pywilight Renamed Device as PyWiLightDevice in pywilight. * Updated as pywilight Renamed Device as PyWiLightDevice in pywilight. * Update switch.py * Update homeassistant/components/wilight/support.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update support.py * Update switch.py * Update support.py * Update support.py * Update switch.py * Update switch.py * Update services.yaml * Update switch.py * Update services.yaml * Update switch.py * Update homeassistant/components/wilight/switch.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/wilight/switch.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/wilight/switch.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update switch.py * Update switch.py * Update switch.py * Update test_switch.py * Update test_switch.py * Update test_switch.py * Decrease exception scope * Clean up Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
74cfdc6c1f
commit
34984a8af8
13 changed files with 707 additions and 9 deletions
|
@ -2,7 +2,7 @@
|
|||
|
||||
from typing import Any
|
||||
|
||||
from pywilight.wilight_device import Device as PyWiLightDevice
|
||||
from pywilight.wilight_device import PyWiLightDevice
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
|
@ -15,7 +15,7 @@ from .parent_device import WiLightParent
|
|||
DOMAIN = "wilight"
|
||||
|
||||
# List the platforms that you want to support.
|
||||
PLATFORMS = [Platform.COVER, Platform.FAN, Platform.LIGHT]
|
||||
PLATFORMS = [Platform.COVER, Platform.FAN, Platform.LIGHT, Platform.SWITCH]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
|
|
@ -16,7 +16,7 @@ CONF_MODEL_NAME = "model_name"
|
|||
WILIGHT_MANUFACTURER = "All Automacao Ltda"
|
||||
|
||||
# List the components supported by this integration.
|
||||
ALLOWED_WILIGHT_COMPONENTS = ["cover", "fan", "light"]
|
||||
ALLOWED_WILIGHT_COMPONENTS = ["cover", "fan", "light", "switch"]
|
||||
|
||||
|
||||
class WiLightFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
|
|
|
@ -13,7 +13,7 @@ from pywilight.const import (
|
|||
WL_SPEED_LOW,
|
||||
WL_SPEED_MEDIUM,
|
||||
)
|
||||
from pywilight.wilight_device import Device as PyWiLightDevice
|
||||
from pywilight.wilight_device import PyWiLightDevice
|
||||
|
||||
from homeassistant.components.fan import DIRECTION_FORWARD, FanEntity, FanEntityFeature
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
|
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from pywilight.const import ITEM_LIGHT, LIGHT_COLOR, LIGHT_DIMMER, LIGHT_ON_OFF
|
||||
from pywilight.wilight_device import Device as PyWiLightDevice
|
||||
from pywilight.wilight_device import PyWiLightDevice
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "WiLight",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/wilight",
|
||||
"requirements": ["pywilight==0.0.70"],
|
||||
"requirements": ["pywilight==0.0.74"],
|
||||
"ssdp": [
|
||||
{
|
||||
"manufacturer": "All Automacao Ltda"
|
||||
|
|
|
@ -5,7 +5,7 @@ import asyncio
|
|||
import logging
|
||||
|
||||
import pywilight
|
||||
from pywilight.wilight_device import Device as PyWiLightDevice
|
||||
from pywilight.wilight_device import PyWiLightDevice
|
||||
import requests
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
|
|
24
homeassistant/components/wilight/services.yaml
Normal file
24
homeassistant/components/wilight/services.yaml
Normal file
|
@ -0,0 +1,24 @@
|
|||
set_watering_time:
|
||||
description: Set watering time
|
||||
target:
|
||||
fields:
|
||||
watering_time:
|
||||
description: Duration for this irrigation to be turned on
|
||||
example: 30
|
||||
set_pause_time:
|
||||
description: Set pause time
|
||||
target:
|
||||
fields:
|
||||
pause_time:
|
||||
description: Duration for this irrigation to be paused
|
||||
example: 24
|
||||
set_trigger:
|
||||
description: Set trigger
|
||||
target:
|
||||
fields:
|
||||
trigger_index:
|
||||
description: Index of Trigger from 1 to 4
|
||||
example: "1"
|
||||
trigger:
|
||||
description: Configuration of trigger
|
||||
example: "'12707001'"
|
87
homeassistant/components/wilight/support.py
Normal file
87
homeassistant/components/wilight/support.py
Normal file
|
@ -0,0 +1,87 @@
|
|||
"""Support for config validation using voluptuous and Translate Trigger."""
|
||||
from __future__ import annotations
|
||||
|
||||
import calendar
|
||||
import locale
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
|
||||
def wilight_trigger(value: Any) -> str | None:
|
||||
"""Check rules for WiLight Trigger."""
|
||||
step = 1
|
||||
err_desc = "Value is None"
|
||||
result_128 = False
|
||||
result_24 = False
|
||||
result_60 = False
|
||||
result_2 = False
|
||||
|
||||
if value is not None:
|
||||
step = 2
|
||||
err_desc = "Expected a string"
|
||||
|
||||
if (step == 2) & isinstance(value, str):
|
||||
step = 3
|
||||
err_desc = "String should only contain 8 decimals character"
|
||||
if re.search(r"^([0-9]{8})$", value) is not None:
|
||||
step = 4
|
||||
err_desc = "First 3 character should be less than 128"
|
||||
result_128 = int(value[0:3]) < 128
|
||||
result_24 = int(value[3:5]) < 24
|
||||
result_60 = int(value[5:7]) < 60
|
||||
result_2 = int(value[7:8]) < 2
|
||||
|
||||
if (step == 4) & result_128:
|
||||
step = 5
|
||||
err_desc = "Hour part should be less than 24"
|
||||
|
||||
if (step == 5) & result_24:
|
||||
step = 6
|
||||
err_desc = "Minute part should be less than 60"
|
||||
|
||||
if (step == 6) & result_60:
|
||||
step = 7
|
||||
err_desc = "Active part shoul be less than 2"
|
||||
|
||||
if (step == 7) & result_2:
|
||||
return value
|
||||
|
||||
raise vol.Invalid(err_desc)
|
||||
|
||||
|
||||
def wilight_to_hass_trigger(value: str | None) -> str | None:
|
||||
"""Convert wilight trigger to hass description.
|
||||
|
||||
Ex: "12719001" -> "sun mon tue wed thu fri sat 19:00 On"
|
||||
"00000000" -> "00:00 Off"
|
||||
"""
|
||||
if value is None:
|
||||
return value
|
||||
|
||||
locale.setlocale(locale.LC_ALL, "")
|
||||
week_days = list(calendar.day_abbr)
|
||||
days = bin(int(value[0:3]))[2:].zfill(8)
|
||||
desc = ""
|
||||
if int(days[7:8]) == 1:
|
||||
desc += f"{week_days[6]} "
|
||||
if int(days[6:7]) == 1:
|
||||
desc += f"{week_days[0]} "
|
||||
if int(days[5:6]) == 1:
|
||||
desc += f"{week_days[1]} "
|
||||
if int(days[4:5]) == 1:
|
||||
desc += f"{week_days[2]} "
|
||||
if int(days[3:4]) == 1:
|
||||
desc += f"{week_days[3]} "
|
||||
if int(days[2:3]) == 1:
|
||||
desc += f"{week_days[4]} "
|
||||
if int(days[1:2]) == 1:
|
||||
desc += f"{week_days[5]} "
|
||||
desc += f"{value[3:5]}:{value[5:7]} "
|
||||
if int(value[7:8]) == 1:
|
||||
desc += "On"
|
||||
else:
|
||||
desc += "Off"
|
||||
|
||||
return desc
|
322
homeassistant/components/wilight/switch.py
Normal file
322
homeassistant/components/wilight/switch.py
Normal file
|
@ -0,0 +1,322 @@
|
|||
"""Support for WiLight switches."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from pywilight.const import ITEM_SWITCH, SWITCH_PAUSE_VALVE, SWITCH_VALVE
|
||||
from pywilight.wilight_device import PyWiLightDevice
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_platform
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import DOMAIN, WiLightDevice
|
||||
from .parent_device import WiLightParent
|
||||
from .support import wilight_to_hass_trigger, wilight_trigger as wl_trigger
|
||||
|
||||
# Attr of features supported by the valve switch entities
|
||||
ATTR_WATERING_TIME = "watering_time"
|
||||
ATTR_PAUSE_TIME = "pause_time"
|
||||
ATTR_TRIGGER_1 = "trigger_1"
|
||||
ATTR_TRIGGER_2 = "trigger_2"
|
||||
ATTR_TRIGGER_3 = "trigger_3"
|
||||
ATTR_TRIGGER_4 = "trigger_4"
|
||||
ATTR_TRIGGER_1_DESC = "trigger_1_description"
|
||||
ATTR_TRIGGER_2_DESC = "trigger_2_description"
|
||||
ATTR_TRIGGER_3_DESC = "trigger_3_description"
|
||||
ATTR_TRIGGER_4_DESC = "trigger_4_description"
|
||||
|
||||
# Attr of services data supported by the valve switch entities
|
||||
ATTR_TRIGGER = "trigger"
|
||||
ATTR_TRIGGER_INDEX = "trigger_index"
|
||||
|
||||
# Service of features supported by the valve switch entities
|
||||
SERVICE_SET_WATERING_TIME = "set_watering_time"
|
||||
SERVICE_SET_PAUSE_TIME = "set_pause_time"
|
||||
SERVICE_SET_TRIGGER = "set_trigger"
|
||||
|
||||
# Range of features supported by the valve switch entities
|
||||
RANGE_WATERING_TIME = 1800
|
||||
RANGE_PAUSE_TIME = 24
|
||||
RANGE_TRIGGER_INDEX = 4
|
||||
|
||||
# Service call validation schemas
|
||||
VALID_WATERING_TIME = vol.All(
|
||||
vol.Coerce(int), vol.Range(min=1, max=RANGE_WATERING_TIME)
|
||||
)
|
||||
VALID_PAUSE_TIME = vol.All(vol.Coerce(int), vol.Range(min=1, max=RANGE_PAUSE_TIME))
|
||||
VALID_TRIGGER_INDEX = vol.All(
|
||||
vol.Coerce(int), vol.Range(min=1, max=RANGE_TRIGGER_INDEX)
|
||||
)
|
||||
|
||||
# Descriptions of the valve switch entities
|
||||
DESC_WATERING = "watering"
|
||||
DESC_PAUSE = "pause"
|
||||
|
||||
# Icons of the valve switch entities
|
||||
ICON_WATERING = "mdi:water"
|
||||
ICON_PAUSE = "mdi:pause-circle-outline"
|
||||
|
||||
|
||||
def entities_from_discovered_wilight(api_device: PyWiLightDevice) -> tuple[Any]:
|
||||
"""Parse configuration and add WiLight switch entities."""
|
||||
entities: Any = []
|
||||
for item in api_device.items:
|
||||
if item["type"] == ITEM_SWITCH:
|
||||
index = item["index"]
|
||||
item_name = item["name"]
|
||||
if item["sub_type"] == SWITCH_VALVE:
|
||||
entities.append(WiLightValveSwitch(api_device, index, item_name))
|
||||
elif item["sub_type"] == SWITCH_PAUSE_VALVE:
|
||||
entities.append(WiLightValvePauseSwitch(api_device, index, item_name))
|
||||
|
||||
return entities
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Set up WiLight switches from a config entry."""
|
||||
parent: WiLightParent = hass.data[DOMAIN][entry.entry_id]
|
||||
|
||||
# Handle a discovered WiLight device.
|
||||
assert parent.api
|
||||
entities = entities_from_discovered_wilight(parent.api)
|
||||
async_add_entities(entities)
|
||||
|
||||
# Handle services for a discovered WiLight device.
|
||||
async def set_watering_time(entity, service: Any) -> None:
|
||||
if not isinstance(entity, WiLightValveSwitch):
|
||||
raise ValueError("Entity is not a WiLight valve switch")
|
||||
watering_time = service.data[ATTR_WATERING_TIME]
|
||||
await entity.async_set_watering_time(watering_time=watering_time)
|
||||
|
||||
async def set_trigger(entity, service: Any) -> None:
|
||||
if not isinstance(entity, WiLightValveSwitch):
|
||||
raise ValueError("Entity is not a WiLight valve switch")
|
||||
trigger_index = service.data[ATTR_TRIGGER_INDEX]
|
||||
trigger = service.data[ATTR_TRIGGER]
|
||||
await entity.async_set_trigger(trigger_index=trigger_index, trigger=trigger)
|
||||
|
||||
async def set_pause_time(entity, service: Any) -> None:
|
||||
if not isinstance(entity, WiLightValvePauseSwitch):
|
||||
raise ValueError("Entity is not a WiLight valve pause switch")
|
||||
pause_time = service.data[ATTR_PAUSE_TIME]
|
||||
await entity.async_set_pause_time(pause_time=pause_time)
|
||||
|
||||
platform = entity_platform.async_get_current_platform()
|
||||
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_WATERING_TIME,
|
||||
{
|
||||
vol.Required(ATTR_WATERING_TIME): VALID_WATERING_TIME,
|
||||
},
|
||||
set_watering_time,
|
||||
)
|
||||
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_TRIGGER,
|
||||
{
|
||||
vol.Required(ATTR_TRIGGER_INDEX): VALID_TRIGGER_INDEX,
|
||||
vol.Required(ATTR_TRIGGER): wl_trigger,
|
||||
},
|
||||
set_trigger,
|
||||
)
|
||||
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_SET_PAUSE_TIME,
|
||||
{
|
||||
vol.Required(ATTR_PAUSE_TIME): VALID_PAUSE_TIME,
|
||||
},
|
||||
set_pause_time,
|
||||
)
|
||||
|
||||
|
||||
def wilight_to_hass_pause_time(value: int) -> int:
|
||||
"""Convert wilight pause_time seconds to hass hour."""
|
||||
return round(value / 3600)
|
||||
|
||||
|
||||
def hass_to_wilight_pause_time(value: int) -> int:
|
||||
"""Convert hass pause_time hours to wilight seconds."""
|
||||
return round(value * 3600)
|
||||
|
||||
|
||||
class WiLightValveSwitch(WiLightDevice, SwitchEntity):
|
||||
"""Representation of a WiLights Valve switch."""
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the switch."""
|
||||
return f"{self._attr_name} {DESC_WATERING}"
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return true if device is on."""
|
||||
return self._status.get("on", False)
|
||||
|
||||
@property
|
||||
def watering_time(self) -> int | None:
|
||||
"""Return watering time of valve switch.
|
||||
|
||||
None is unknown, 1 is minimum, 1800 is maximum.
|
||||
"""
|
||||
return self._status.get("timer_target")
|
||||
|
||||
@property
|
||||
def trigger_1(self) -> str | None:
|
||||
"""Return trigger_1 of valve switch."""
|
||||
return self._status.get("trigger_1")
|
||||
|
||||
@property
|
||||
def trigger_2(self) -> str | None:
|
||||
"""Return trigger_2 of valve switch."""
|
||||
return self._status.get("trigger_2")
|
||||
|
||||
@property
|
||||
def trigger_3(self) -> str | None:
|
||||
"""Return trigger_3 of valve switch."""
|
||||
return self._status.get("trigger_3")
|
||||
|
||||
@property
|
||||
def trigger_4(self) -> str | None:
|
||||
"""Return trigger_4 of valve switch."""
|
||||
return self._status.get("trigger_4")
|
||||
|
||||
@property
|
||||
def trigger_1_description(self) -> str | None:
|
||||
"""Return trigger_1_description of valve switch."""
|
||||
return wilight_to_hass_trigger(self._status.get("trigger_1"))
|
||||
|
||||
@property
|
||||
def trigger_2_description(self) -> str | None:
|
||||
"""Return trigger_2_description of valve switch."""
|
||||
return wilight_to_hass_trigger(self._status.get("trigger_2"))
|
||||
|
||||
@property
|
||||
def trigger_3_description(self) -> str | None:
|
||||
"""Return trigger_3_description of valve switch."""
|
||||
return wilight_to_hass_trigger(self._status.get("trigger_3"))
|
||||
|
||||
@property
|
||||
def trigger_4_description(self) -> str | None:
|
||||
"""Return trigger_4_description of valve switch."""
|
||||
return wilight_to_hass_trigger(self._status.get("trigger_4"))
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the state attributes."""
|
||||
attr: dict[str, Any] = {}
|
||||
|
||||
if self.watering_time is not None:
|
||||
attr[ATTR_WATERING_TIME] = self.watering_time
|
||||
|
||||
if self.trigger_1 is not None:
|
||||
attr[ATTR_TRIGGER_1] = self.trigger_1
|
||||
|
||||
if self.trigger_2 is not None:
|
||||
attr[ATTR_TRIGGER_2] = self.trigger_2
|
||||
|
||||
if self.trigger_3 is not None:
|
||||
attr[ATTR_TRIGGER_3] = self.trigger_3
|
||||
|
||||
if self.trigger_4 is not None:
|
||||
attr[ATTR_TRIGGER_4] = self.trigger_4
|
||||
|
||||
if self.trigger_1_description is not None:
|
||||
attr[ATTR_TRIGGER_1_DESC] = self.trigger_1_description
|
||||
|
||||
if self.trigger_2_description is not None:
|
||||
attr[ATTR_TRIGGER_2_DESC] = self.trigger_2_description
|
||||
|
||||
if self.trigger_3_description is not None:
|
||||
attr[ATTR_TRIGGER_3_DESC] = self.trigger_3_description
|
||||
|
||||
if self.trigger_4_description is not None:
|
||||
attr[ATTR_TRIGGER_4_DESC] = self.trigger_4_description
|
||||
|
||||
return attr
|
||||
|
||||
@property
|
||||
def icon(self) -> str:
|
||||
"""Return the icon to use in the frontend."""
|
||||
return ICON_WATERING
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the device on."""
|
||||
await self._client.turn_on(self._index)
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the device off."""
|
||||
await self._client.turn_off(self._index)
|
||||
|
||||
async def async_set_watering_time(self, watering_time: int) -> None:
|
||||
"""Set the watering time."""
|
||||
await self._client.set_switch_time(self._index, watering_time)
|
||||
|
||||
async def async_set_trigger(self, trigger_index: int, trigger: str) -> None:
|
||||
"""Set the trigger according to index."""
|
||||
if trigger_index == 1:
|
||||
await self._client.set_switch_trigger_1(self._index, trigger)
|
||||
if trigger_index == 2:
|
||||
await self._client.set_switch_trigger_2(self._index, trigger)
|
||||
if trigger_index == 3:
|
||||
await self._client.set_switch_trigger_3(self._index, trigger)
|
||||
if trigger_index == 4:
|
||||
await self._client.set_switch_trigger_4(self._index, trigger)
|
||||
|
||||
|
||||
class WiLightValvePauseSwitch(WiLightDevice, SwitchEntity):
|
||||
"""Representation of a WiLights Valve Pause switch."""
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the switch."""
|
||||
return f"{self._attr_name} {DESC_PAUSE}"
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return true if device is on."""
|
||||
return self._status.get("on", False)
|
||||
|
||||
@property
|
||||
def pause_time(self) -> int | None:
|
||||
"""Return pause time of valve switch.
|
||||
|
||||
None is unknown, 1 is minimum, 24 is maximum.
|
||||
"""
|
||||
pause_time = self._status.get("timer_target")
|
||||
if pause_time is not None:
|
||||
return wilight_to_hass_pause_time(pause_time)
|
||||
return pause_time
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the state attributes."""
|
||||
attr: dict[str, Any] = {}
|
||||
|
||||
if self.pause_time is not None:
|
||||
attr[ATTR_PAUSE_TIME] = self.pause_time
|
||||
|
||||
return attr
|
||||
|
||||
@property
|
||||
def icon(self) -> str:
|
||||
"""Return the icon to use in the frontend."""
|
||||
return ICON_PAUSE
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the device on."""
|
||||
await self._client.turn_on(self._index)
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the device off."""
|
||||
await self._client.turn_off(self._index)
|
||||
|
||||
async def async_set_pause_time(self, pause_time: int) -> None:
|
||||
"""Set the pause time."""
|
||||
target_time = hass_to_wilight_pause_time(pause_time)
|
||||
await self._client.set_switch_time(self._index, target_time)
|
|
@ -2039,7 +2039,7 @@ pywebpush==1.9.2
|
|||
pywemo==0.9.1
|
||||
|
||||
# homeassistant.components.wilight
|
||||
pywilight==0.0.70
|
||||
pywilight==0.0.74
|
||||
|
||||
# homeassistant.components.wiz
|
||||
pywizlight==0.5.14
|
||||
|
|
|
@ -1378,7 +1378,7 @@ pywebpush==1.9.2
|
|||
pywemo==0.9.1
|
||||
|
||||
# homeassistant.components.wilight
|
||||
pywilight==0.0.70
|
||||
pywilight==0.0.74
|
||||
|
||||
# homeassistant.components.wiz
|
||||
pywizlight==0.5.14
|
||||
|
|
|
@ -27,6 +27,7 @@ UPNP_MODEL_NAME_DIMMER = "WiLight 0100001700020009-10010010"
|
|||
UPNP_MODEL_NAME_COLOR = "WiLight 0107001800020009-11010"
|
||||
UPNP_MODEL_NAME_LIGHT_FAN = "WiLight 0104001800010009-10"
|
||||
UPNP_MODEL_NAME_COVER = "WiLight 0103001800010009-10"
|
||||
UPNP_MODEL_NAME_SWITCH = "WiLight 0105001900010011-00000000000010"
|
||||
UPNP_MODEL_NUMBER = "123456789012345678901234567890123456"
|
||||
UPNP_SERIAL = "000000000099"
|
||||
UPNP_MAC_ADDRESS = "5C:CF:7F:8B:CA:56"
|
||||
|
|
264
tests/components/wilight/test_switch.py
Normal file
264
tests/components/wilight/test_switch.py
Normal file
|
@ -0,0 +1,264 @@
|
|||
"""Tests for the WiLight integration."""
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
import pywilight
|
||||
|
||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||
from homeassistant.components.wilight import DOMAIN as WILIGHT_DOMAIN
|
||||
from homeassistant.components.wilight.switch import (
|
||||
ATTR_PAUSE_TIME,
|
||||
ATTR_TRIGGER,
|
||||
ATTR_TRIGGER_1,
|
||||
ATTR_TRIGGER_2,
|
||||
ATTR_TRIGGER_3,
|
||||
ATTR_TRIGGER_4,
|
||||
ATTR_TRIGGER_INDEX,
|
||||
ATTR_WATERING_TIME,
|
||||
SERVICE_SET_PAUSE_TIME,
|
||||
SERVICE_SET_TRIGGER,
|
||||
SERVICE_SET_WATERING_TIME,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import (
|
||||
HOST,
|
||||
UPNP_MAC_ADDRESS,
|
||||
UPNP_MODEL_NAME_SWITCH,
|
||||
UPNP_MODEL_NUMBER,
|
||||
UPNP_SERIAL,
|
||||
WILIGHT_ID,
|
||||
setup_integration,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="dummy_device_from_host_switch")
|
||||
def mock_dummy_device_from_host_switch():
|
||||
"""Mock a valid api_devce."""
|
||||
|
||||
device = pywilight.wilight_from_discovery(
|
||||
f"http://{HOST}:45995/wilight.xml",
|
||||
UPNP_MAC_ADDRESS,
|
||||
UPNP_MODEL_NAME_SWITCH,
|
||||
UPNP_SERIAL,
|
||||
UPNP_MODEL_NUMBER,
|
||||
)
|
||||
|
||||
device.set_dummy(True)
|
||||
|
||||
with patch(
|
||||
"pywilight.device_from_host",
|
||||
return_value=device,
|
||||
):
|
||||
yield device
|
||||
|
||||
|
||||
async def test_loading_switch(
|
||||
hass: HomeAssistant,
|
||||
dummy_device_from_host_switch,
|
||||
) -> None:
|
||||
"""Test the WiLight configuration entry loading."""
|
||||
|
||||
entry = await setup_integration(hass)
|
||||
assert entry
|
||||
assert entry.unique_id == WILIGHT_ID
|
||||
|
||||
entity_registry = er.async_get(hass)
|
||||
|
||||
# First segment of the strip
|
||||
state = hass.states.get("switch.wl000000000099_1_watering")
|
||||
assert state
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
entry = entity_registry.async_get("switch.wl000000000099_1_watering")
|
||||
assert entry
|
||||
assert entry.unique_id == "WL000000000099_0"
|
||||
|
||||
# Seconnd segment of the strip
|
||||
state = hass.states.get("switch.wl000000000099_2_pause")
|
||||
assert state
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
entry = entity_registry.async_get("switch.wl000000000099_2_pause")
|
||||
assert entry
|
||||
assert entry.unique_id == "WL000000000099_1"
|
||||
|
||||
|
||||
async def test_on_off_switch_state(
|
||||
hass: HomeAssistant, dummy_device_from_host_switch
|
||||
) -> None:
|
||||
"""Test the change of state of the switch."""
|
||||
await setup_integration(hass)
|
||||
|
||||
# On - watering
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "switch.wl000000000099_1_watering"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.wl000000000099_1_watering")
|
||||
assert state
|
||||
assert state.state == STATE_ON
|
||||
|
||||
# Off - watering
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: "switch.wl000000000099_1_watering"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.wl000000000099_1_watering")
|
||||
assert state
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
# On - pause
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "switch.wl000000000099_2_pause"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.wl000000000099_2_pause")
|
||||
assert state
|
||||
assert state.state == STATE_ON
|
||||
|
||||
# Off - pause
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: "switch.wl000000000099_2_pause"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.wl000000000099_2_pause")
|
||||
assert state
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
|
||||
async def test_switch_services(
|
||||
hass: HomeAssistant, dummy_device_from_host_switch
|
||||
) -> None:
|
||||
"""Test the services of the switch."""
|
||||
await setup_integration(hass)
|
||||
|
||||
# Set watering time
|
||||
await hass.services.async_call(
|
||||
WILIGHT_DOMAIN,
|
||||
SERVICE_SET_WATERING_TIME,
|
||||
{ATTR_WATERING_TIME: 30, ATTR_ENTITY_ID: "switch.wl000000000099_1_watering"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.wl000000000099_1_watering")
|
||||
assert state
|
||||
assert state.attributes.get(ATTR_WATERING_TIME) == 30
|
||||
|
||||
# Set pause time
|
||||
await hass.services.async_call(
|
||||
WILIGHT_DOMAIN,
|
||||
SERVICE_SET_PAUSE_TIME,
|
||||
{ATTR_PAUSE_TIME: 18, ATTR_ENTITY_ID: "switch.wl000000000099_2_pause"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.wl000000000099_2_pause")
|
||||
assert state
|
||||
assert state.attributes.get(ATTR_PAUSE_TIME) == 18
|
||||
|
||||
# Set trigger_1
|
||||
await hass.services.async_call(
|
||||
WILIGHT_DOMAIN,
|
||||
SERVICE_SET_TRIGGER,
|
||||
{
|
||||
ATTR_TRIGGER_INDEX: "1",
|
||||
ATTR_TRIGGER: "12715301",
|
||||
ATTR_ENTITY_ID: "switch.wl000000000099_1_watering",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.wl000000000099_1_watering")
|
||||
assert state
|
||||
assert state.attributes.get(ATTR_TRIGGER_1) == "12715301"
|
||||
|
||||
# Set trigger_2
|
||||
await hass.services.async_call(
|
||||
WILIGHT_DOMAIN,
|
||||
SERVICE_SET_TRIGGER,
|
||||
{
|
||||
ATTR_TRIGGER_INDEX: "2",
|
||||
ATTR_TRIGGER: "12707301",
|
||||
ATTR_ENTITY_ID: "switch.wl000000000099_1_watering",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.wl000000000099_1_watering")
|
||||
assert state
|
||||
assert state.attributes.get(ATTR_TRIGGER_2) == "12707301"
|
||||
|
||||
# Set trigger_3
|
||||
await hass.services.async_call(
|
||||
WILIGHT_DOMAIN,
|
||||
SERVICE_SET_TRIGGER,
|
||||
{
|
||||
ATTR_TRIGGER_INDEX: "3",
|
||||
ATTR_TRIGGER: "00015301",
|
||||
ATTR_ENTITY_ID: "switch.wl000000000099_1_watering",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.wl000000000099_1_watering")
|
||||
assert state
|
||||
assert state.attributes.get(ATTR_TRIGGER_3) == "00015301"
|
||||
|
||||
# Set trigger_4
|
||||
await hass.services.async_call(
|
||||
WILIGHT_DOMAIN,
|
||||
SERVICE_SET_TRIGGER,
|
||||
{
|
||||
ATTR_TRIGGER_INDEX: "4",
|
||||
ATTR_TRIGGER: "00008300",
|
||||
ATTR_ENTITY_ID: "switch.wl000000000099_1_watering",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
state = hass.states.get("switch.wl000000000099_1_watering")
|
||||
assert state
|
||||
assert state.attributes.get(ATTR_TRIGGER_4) == "00008300"
|
||||
|
||||
# Set watering time using WiLight Pause Switch to raise
|
||||
with pytest.raises(ValueError) as exc_info:
|
||||
await hass.services.async_call(
|
||||
WILIGHT_DOMAIN,
|
||||
SERVICE_SET_WATERING_TIME,
|
||||
{ATTR_WATERING_TIME: 30, ATTR_ENTITY_ID: "switch.wl000000000099_2_pause"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert str(exc_info.value) == "Entity is not a WiLight valve switch"
|
Loading…
Add table
Add a link
Reference in a new issue