Add vera config entries support (#29880)
* Adding vera config entries support. * Fixing lint error. * Applying minimal changes necessary to get config entries working. * Addressing PR feedback by further reducing the scope of the change. * Addressing PR feedback. * Fixing pyvera import to make it easier to patch. Addressing PR feedback regarding creation of controller and scheduling of async config flow actions. * Updating code owners file. * Small fixes. * Adding a user config flow step. * Adding optional configs for user config flow. * Updating strings to be more clear to the user. * Adding options flow. Fixing some PR feedback. * Better handling of options. PR feedback changes. * Using config registry to update config options. * Better managing config from file or config from UI Disabling config through UI if config is provided from a file. More tests to account for these adjustments. * Address PR feedback. * Fixing test, merging with master. * Disabling all Vera UI for configs managed by configuration.yml. Adding more tests. * Updating config based on unique_id. Addressing additional PR feedback. * Rebasing off dev. Addressing feedback. * Addressing PR feedback.
This commit is contained in:
parent
aef06a3544
commit
ae22b5187a
28 changed files with 876 additions and 294 deletions
|
@ -409,6 +409,7 @@ homeassistant/components/usgs_earthquakes_feed/* @exxamalte
|
||||||
homeassistant/components/utility_meter/* @dgomes
|
homeassistant/components/utility_meter/* @dgomes
|
||||||
homeassistant/components/velbus/* @Cereal2nd @brefra
|
homeassistant/components/velbus/* @Cereal2nd @brefra
|
||||||
homeassistant/components/velux/* @Julius2342
|
homeassistant/components/velux/* @Julius2342
|
||||||
|
homeassistant/components/vera/* @vangorra
|
||||||
homeassistant/components/versasense/* @flamm3blemuff1n
|
homeassistant/components/versasense/* @flamm3blemuff1n
|
||||||
homeassistant/components/version/* @fabaff
|
homeassistant/components/version/* @fabaff
|
||||||
homeassistant/components/vesync/* @markperdue @webdjoe
|
homeassistant/components/vesync/* @markperdue @webdjoe
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Support for Vera devices."""
|
"""Support for Vera devices."""
|
||||||
|
import asyncio
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -6,6 +7,8 @@ import pyvera as veraApi
|
||||||
from requests.exceptions import RequestException
|
from requests.exceptions import RequestException
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant import config_entries
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ARMED,
|
ATTR_ARMED,
|
||||||
ATTR_BATTERY_LEVEL,
|
ATTR_BATTERY_LEVEL,
|
||||||
|
@ -15,27 +18,24 @@ from homeassistant.const import (
|
||||||
CONF_LIGHTS,
|
CONF_LIGHTS,
|
||||||
EVENT_HOMEASSISTANT_STOP,
|
EVENT_HOMEASSISTANT_STOP,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers import config_validation as cv, discovery
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.util import convert, slugify
|
from homeassistant.util import convert, slugify
|
||||||
from homeassistant.util.dt import utc_from_timestamp
|
from homeassistant.util.dt import utc_from_timestamp
|
||||||
|
|
||||||
|
from .common import ControllerData, get_configured_platforms
|
||||||
|
from .config_flow import new_options
|
||||||
|
from .const import (
|
||||||
|
ATTR_CURRENT_ENERGY_KWH,
|
||||||
|
ATTR_CURRENT_POWER_W,
|
||||||
|
CONF_CONTROLLER,
|
||||||
|
DOMAIN,
|
||||||
|
VERA_ID_FORMAT,
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DOMAIN = "vera"
|
|
||||||
|
|
||||||
VERA_CONTROLLER = "vera_controller"
|
|
||||||
|
|
||||||
CONF_CONTROLLER = "vera_controller_url"
|
|
||||||
|
|
||||||
VERA_ID_FORMAT = "{}_{}"
|
|
||||||
|
|
||||||
ATTR_CURRENT_POWER_W = "current_power_w"
|
|
||||||
ATTR_CURRENT_ENERGY_KWH = "current_energy_kwh"
|
|
||||||
|
|
||||||
VERA_DEVICES = "vera_devices"
|
|
||||||
VERA_SCENES = "vera_scenes"
|
|
||||||
|
|
||||||
VERA_ID_LIST_SCHEMA = vol.Schema([int])
|
VERA_ID_LIST_SCHEMA = vol.Schema([int])
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema(
|
CONFIG_SCHEMA = vol.Schema(
|
||||||
|
@ -51,42 +51,53 @@ CONFIG_SCHEMA = vol.Schema(
|
||||||
extra=vol.ALLOW_EXTRA,
|
extra=vol.ALLOW_EXTRA,
|
||||||
)
|
)
|
||||||
|
|
||||||
VERA_COMPONENTS = [
|
|
||||||
"binary_sensor",
|
|
||||||
"sensor",
|
|
||||||
"light",
|
|
||||||
"switch",
|
|
||||||
"lock",
|
|
||||||
"climate",
|
|
||||||
"cover",
|
|
||||||
"scene",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, base_config):
|
|
||||||
"""Set up for Vera devices."""
|
|
||||||
|
|
||||||
def stop_subscription(event):
|
|
||||||
"""Shutdown Vera subscriptions and subscription thread on exit."""
|
|
||||||
_LOGGER.info("Shutting down subscriptions")
|
|
||||||
hass.data[VERA_CONTROLLER].stop()
|
|
||||||
|
|
||||||
|
async def async_setup(hass: HomeAssistant, base_config: dict) -> bool:
|
||||||
|
"""Set up for Vera controllers."""
|
||||||
config = base_config.get(DOMAIN)
|
config = base_config.get(DOMAIN)
|
||||||
|
|
||||||
# Get Vera specific configuration.
|
if not config:
|
||||||
base_url = config.get(CONF_CONTROLLER)
|
return True
|
||||||
light_ids = config.get(CONF_LIGHTS)
|
|
||||||
exclude_ids = config.get(CONF_EXCLUDE)
|
hass.async_create_task(
|
||||||
|
hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data=config,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||||
|
"""Do setup of vera."""
|
||||||
|
# Use options entered during initial config flow or provided from configuration.yml
|
||||||
|
if config_entry.data.get(CONF_LIGHTS) or config_entry.data.get(CONF_EXCLUDE):
|
||||||
|
hass.config_entries.async_update_entry(
|
||||||
|
entry=config_entry,
|
||||||
|
data=config_entry.data,
|
||||||
|
options=new_options(
|
||||||
|
config_entry.data.get(CONF_LIGHTS, []),
|
||||||
|
config_entry.data.get(CONF_EXCLUDE, []),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
base_url = config_entry.data[CONF_CONTROLLER]
|
||||||
|
light_ids = config_entry.options.get(CONF_LIGHTS, [])
|
||||||
|
exclude_ids = config_entry.options.get(CONF_EXCLUDE, [])
|
||||||
|
|
||||||
# Initialize the Vera controller.
|
# Initialize the Vera controller.
|
||||||
controller, _ = veraApi.init_controller(base_url)
|
controller = veraApi.VeraController(base_url)
|
||||||
hass.data[VERA_CONTROLLER] = controller
|
controller.start()
|
||||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_subscription)
|
|
||||||
|
hass.bus.async_listen_once(
|
||||||
|
EVENT_HOMEASSISTANT_STOP,
|
||||||
|
lambda event: hass.async_add_executor_job(controller.stop),
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
all_devices = controller.get_devices()
|
all_devices = await hass.async_add_executor_job(controller.get_devices)
|
||||||
|
|
||||||
all_scenes = controller.get_scenes()
|
all_scenes = await hass.async_add_executor_job(controller.get_scenes)
|
||||||
except RequestException:
|
except RequestException:
|
||||||
# There was a network related error connecting to the Vera controller.
|
# There was a network related error connecting to the Vera controller.
|
||||||
_LOGGER.exception("Error communicating with Vera API")
|
_LOGGER.exception("Error communicating with Vera API")
|
||||||
|
@ -102,15 +113,35 @@ def setup(hass, base_config):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
vera_devices[device_type].append(device)
|
vera_devices[device_type].append(device)
|
||||||
hass.data[VERA_DEVICES] = vera_devices
|
|
||||||
|
|
||||||
vera_scenes = []
|
vera_scenes = []
|
||||||
for scene in all_scenes:
|
for scene in all_scenes:
|
||||||
vera_scenes.append(scene)
|
vera_scenes.append(scene)
|
||||||
hass.data[VERA_SCENES] = vera_scenes
|
|
||||||
|
|
||||||
for component in VERA_COMPONENTS:
|
controller_data = ControllerData(
|
||||||
discovery.load_platform(hass, component, DOMAIN, {}, base_config)
|
controller=controller, devices=vera_devices, scenes=vera_scenes
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.data[DOMAIN] = controller_data
|
||||||
|
|
||||||
|
# Forward the config data to the necessary platforms.
|
||||||
|
for platform in get_configured_platforms(controller_data):
|
||||||
|
hass.async_create_task(
|
||||||
|
hass.config_entries.async_forward_entry_setup(config_entry, platform)
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||||
|
"""Unload Withings config entry."""
|
||||||
|
controller_data = hass.data[DOMAIN]
|
||||||
|
|
||||||
|
tasks = [
|
||||||
|
hass.config_entries.async_forward_entry_unload(config_entry, platform)
|
||||||
|
for platform in get_configured_platforms(controller_data)
|
||||||
|
]
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,34 @@
|
||||||
"""Support for Vera binary sensors."""
|
"""Support for Vera binary sensors."""
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Callable, List
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import ENTITY_ID_FORMAT, BinarySensorDevice
|
from homeassistant.components.binary_sensor import (
|
||||||
|
DOMAIN as PLATFORM_DOMAIN,
|
||||||
|
ENTITY_ID_FORMAT,
|
||||||
|
BinarySensorDevice,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
|
from . import VeraDevice
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
async def async_setup_entry(
|
||||||
"""Perform the setup for Vera controller devices."""
|
hass: HomeAssistant,
|
||||||
add_entities(
|
entry: ConfigEntry,
|
||||||
|
async_add_entities: Callable[[List[Entity], bool], None],
|
||||||
|
) -> None:
|
||||||
|
"""Set up the sensor config entry."""
|
||||||
|
controller_data = hass.data[DOMAIN]
|
||||||
|
async_add_entities(
|
||||||
[
|
[
|
||||||
VeraBinarySensor(device, hass.data[VERA_CONTROLLER])
|
VeraBinarySensor(device, controller_data.controller)
|
||||||
for device in hass.data[VERA_DEVICES]["binary_sensor"]
|
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||||
],
|
]
|
||||||
True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
"""Support for Vera thermostats."""
|
"""Support for Vera thermostats."""
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Callable, List
|
||||||
|
|
||||||
from homeassistant.components.climate import ENTITY_ID_FORMAT, ClimateDevice
|
from homeassistant.components.climate import (
|
||||||
|
DOMAIN as PLATFORM_DOMAIN,
|
||||||
|
ENTITY_ID_FORMAT,
|
||||||
|
ClimateDevice,
|
||||||
|
)
|
||||||
from homeassistant.components.climate.const import (
|
from homeassistant.components.climate.const import (
|
||||||
FAN_AUTO,
|
FAN_AUTO,
|
||||||
FAN_ON,
|
FAN_ON,
|
||||||
|
@ -12,10 +17,14 @@ from homeassistant.components.climate.const import (
|
||||||
SUPPORT_FAN_MODE,
|
SUPPORT_FAN_MODE,
|
||||||
SUPPORT_TARGET_TEMPERATURE,
|
SUPPORT_TARGET_TEMPERATURE,
|
||||||
)
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
|
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.util import convert
|
from homeassistant.util import convert
|
||||||
|
|
||||||
from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
|
from . import VeraDevice
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -25,14 +34,18 @@ SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE
|
||||||
SUPPORT_HVAC = [HVAC_MODE_COOL, HVAC_MODE_HEAT, HVAC_MODE_HEAT_COOL, HVAC_MODE_OFF]
|
SUPPORT_HVAC = [HVAC_MODE_COOL, HVAC_MODE_HEAT, HVAC_MODE_HEAT_COOL, HVAC_MODE_OFF]
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_entities_callback, discovery_info=None):
|
async def async_setup_entry(
|
||||||
"""Set up of Vera thermostats."""
|
hass: HomeAssistant,
|
||||||
add_entities_callback(
|
entry: ConfigEntry,
|
||||||
|
async_add_entities: Callable[[List[Entity], bool], None],
|
||||||
|
) -> None:
|
||||||
|
"""Set up the sensor config entry."""
|
||||||
|
controller_data = hass.data[DOMAIN]
|
||||||
|
async_add_entities(
|
||||||
[
|
[
|
||||||
VeraThermostat(device, hass.data[VERA_CONTROLLER])
|
VeraThermostat(device, controller_data.controller)
|
||||||
for device in hass.data[VERA_DEVICES]["climate"]
|
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||||
],
|
]
|
||||||
True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
29
homeassistant/components/vera/common.py
Normal file
29
homeassistant/components/vera/common.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
"""Common vera code."""
|
||||||
|
import logging
|
||||||
|
from typing import DefaultDict, List, NamedTuple, Set
|
||||||
|
|
||||||
|
import pyvera as pv
|
||||||
|
|
||||||
|
from homeassistant.components.scene import DOMAIN as SCENE_DOMAIN
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ControllerData(NamedTuple):
|
||||||
|
"""Controller data."""
|
||||||
|
|
||||||
|
controller: pv.VeraController
|
||||||
|
devices: DefaultDict[str, List[pv.VeraDevice]]
|
||||||
|
scenes: List[pv.VeraScene]
|
||||||
|
|
||||||
|
|
||||||
|
def get_configured_platforms(controller_data: ControllerData) -> Set[str]:
|
||||||
|
"""Get configured platforms for a controller."""
|
||||||
|
platforms = []
|
||||||
|
for platform in controller_data.devices:
|
||||||
|
platforms.append(platform)
|
||||||
|
|
||||||
|
if controller_data.scenes:
|
||||||
|
platforms.append(SCENE_DOMAIN)
|
||||||
|
|
||||||
|
return set(platforms)
|
130
homeassistant/components/vera/config_flow.py
Normal file
130
homeassistant/components/vera/config_flow.py
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
"""Config flow for Vera."""
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
from typing import List, cast
|
||||||
|
|
||||||
|
import pyvera as pv
|
||||||
|
from requests.exceptions import RequestException
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant import config_entries
|
||||||
|
from homeassistant.const import CONF_EXCLUDE, CONF_LIGHTS, CONF_SOURCE
|
||||||
|
from homeassistant.core import callback
|
||||||
|
|
||||||
|
from .const import CONF_CONTROLLER, DOMAIN
|
||||||
|
|
||||||
|
LIST_REGEX = re.compile("[^0-9]+")
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def str_to_int_list(data: str) -> List[str]:
|
||||||
|
"""Convert a string to an int list."""
|
||||||
|
if isinstance(str, list):
|
||||||
|
return cast(List[str], data)
|
||||||
|
|
||||||
|
return [s for s in LIST_REGEX.split(data) if len(s) > 0]
|
||||||
|
|
||||||
|
|
||||||
|
def int_list_to_str(data: List[str]) -> str:
|
||||||
|
"""Convert an int list to a string."""
|
||||||
|
return " ".join([str(i) for i in data])
|
||||||
|
|
||||||
|
|
||||||
|
def new_options(lights: List[str], exclude: List[str]) -> dict:
|
||||||
|
"""Create a standard options object."""
|
||||||
|
return {CONF_LIGHTS: lights, CONF_EXCLUDE: exclude}
|
||||||
|
|
||||||
|
|
||||||
|
def options_schema(options: dict = None) -> dict:
|
||||||
|
"""Return options schema."""
|
||||||
|
options = options or {}
|
||||||
|
return {
|
||||||
|
vol.Optional(
|
||||||
|
CONF_LIGHTS, default=int_list_to_str(options.get(CONF_LIGHTS, [])),
|
||||||
|
): str,
|
||||||
|
vol.Optional(
|
||||||
|
CONF_EXCLUDE, default=int_list_to_str(options.get(CONF_EXCLUDE, [])),
|
||||||
|
): str,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def options_data(user_input: dict) -> dict:
|
||||||
|
"""Return options dict."""
|
||||||
|
return new_options(
|
||||||
|
str_to_int_list(user_input.get(CONF_LIGHTS, "")),
|
||||||
|
str_to_int_list(user_input.get(CONF_EXCLUDE, "")),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||||
|
"""Options for the component."""
|
||||||
|
|
||||||
|
def __init__(self, config_entry: config_entries.ConfigEntry):
|
||||||
|
"""Init object."""
|
||||||
|
self.config_entry = config_entry
|
||||||
|
|
||||||
|
async def async_step_init(self, user_input=None):
|
||||||
|
"""Manage the options."""
|
||||||
|
if user_input is not None:
|
||||||
|
return self.async_create_entry(title="", data=options_data(user_input),)
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="init",
|
||||||
|
data_schema=vol.Schema(options_schema(self.config_entry.options)),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class VeraFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
|
"""Vera config flow."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@callback
|
||||||
|
def async_get_options_flow(config_entry) -> OptionsFlowHandler:
|
||||||
|
"""Get the options flow."""
|
||||||
|
return OptionsFlowHandler(config_entry)
|
||||||
|
|
||||||
|
async def async_step_user(self, user_input: dict = None):
|
||||||
|
"""Handle user initiated flow."""
|
||||||
|
if self.hass.config_entries.async_entries(DOMAIN):
|
||||||
|
return self.async_abort(reason="already_configured")
|
||||||
|
|
||||||
|
if user_input is not None:
|
||||||
|
return await self.async_step_finish(
|
||||||
|
{
|
||||||
|
**user_input,
|
||||||
|
**options_data(user_input),
|
||||||
|
**{CONF_SOURCE: config_entries.SOURCE_USER},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="user",
|
||||||
|
data_schema=vol.Schema(
|
||||||
|
{**{vol.Required(CONF_CONTROLLER): str}, **options_schema()}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_step_import(self, config: dict):
|
||||||
|
"""Handle a flow initialized by import."""
|
||||||
|
return await self.async_step_finish(
|
||||||
|
{**config, **{CONF_SOURCE: config_entries.SOURCE_IMPORT}}
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_step_finish(self, config: dict):
|
||||||
|
"""Validate and create config entry."""
|
||||||
|
base_url = config[CONF_CONTROLLER] = config[CONF_CONTROLLER].rstrip("/")
|
||||||
|
controller = pv.VeraController(base_url)
|
||||||
|
|
||||||
|
# Verify the controller is online and get the serial number.
|
||||||
|
try:
|
||||||
|
await self.hass.async_add_executor_job(controller.refresh_data)
|
||||||
|
except RequestException:
|
||||||
|
_LOGGER.error("Failed to connect to vera controller %s", base_url)
|
||||||
|
return self.async_abort(
|
||||||
|
reason="cannot_connect", description_placeholders={"base_url": base_url}
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.async_set_unique_id(controller.serial_number)
|
||||||
|
self._abort_if_unique_id_configured(config)
|
||||||
|
|
||||||
|
return self.async_create_entry(title=base_url, data=config)
|
11
homeassistant/components/vera/const.py
Normal file
11
homeassistant/components/vera/const.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
"""Vera constants."""
|
||||||
|
DOMAIN = "vera"
|
||||||
|
|
||||||
|
CONF_CONTROLLER = "vera_controller_url"
|
||||||
|
|
||||||
|
VERA_ID_FORMAT = "{}_{}"
|
||||||
|
|
||||||
|
ATTR_CURRENT_POWER_W = "current_power_w"
|
||||||
|
ATTR_CURRENT_ENERGY_KWH = "current_energy_kwh"
|
||||||
|
|
||||||
|
CONTROLLER_DATAS = "controller_datas"
|
|
@ -1,21 +1,35 @@
|
||||||
"""Support for Vera cover - curtains, rollershutters etc."""
|
"""Support for Vera cover - curtains, rollershutters etc."""
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Callable, List
|
||||||
|
|
||||||
from homeassistant.components.cover import ATTR_POSITION, ENTITY_ID_FORMAT, CoverDevice
|
from homeassistant.components.cover import (
|
||||||
|
ATTR_POSITION,
|
||||||
|
DOMAIN as PLATFORM_DOMAIN,
|
||||||
|
ENTITY_ID_FORMAT,
|
||||||
|
CoverDevice,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
|
from . import VeraDevice
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
async def async_setup_entry(
|
||||||
"""Set up the Vera covers."""
|
hass: HomeAssistant,
|
||||||
add_entities(
|
entry: ConfigEntry,
|
||||||
|
async_add_entities: Callable[[List[Entity], bool], None],
|
||||||
|
) -> None:
|
||||||
|
"""Set up the sensor config entry."""
|
||||||
|
controller_data = hass.data[DOMAIN]
|
||||||
|
async_add_entities(
|
||||||
[
|
[
|
||||||
VeraCover(device, hass.data[VERA_CONTROLLER])
|
VeraCover(device, controller_data.controller)
|
||||||
for device in hass.data[VERA_DEVICES]["cover"]
|
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||||
],
|
]
|
||||||
True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,39 @@
|
||||||
"""Support for Vera lights."""
|
"""Support for Vera lights."""
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Callable, List
|
||||||
|
|
||||||
from homeassistant.components.light import (
|
from homeassistant.components.light import (
|
||||||
ATTR_BRIGHTNESS,
|
ATTR_BRIGHTNESS,
|
||||||
ATTR_HS_COLOR,
|
ATTR_HS_COLOR,
|
||||||
|
DOMAIN as PLATFORM_DOMAIN,
|
||||||
ENTITY_ID_FORMAT,
|
ENTITY_ID_FORMAT,
|
||||||
SUPPORT_BRIGHTNESS,
|
SUPPORT_BRIGHTNESS,
|
||||||
SUPPORT_COLOR,
|
SUPPORT_COLOR,
|
||||||
Light,
|
Light,
|
||||||
)
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
import homeassistant.util.color as color_util
|
import homeassistant.util.color as color_util
|
||||||
|
|
||||||
from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
|
from . import VeraDevice
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
async def async_setup_entry(
|
||||||
"""Set up the Vera lights."""
|
hass: HomeAssistant,
|
||||||
add_entities(
|
entry: ConfigEntry,
|
||||||
|
async_add_entities: Callable[[List[Entity], bool], None],
|
||||||
|
) -> None:
|
||||||
|
"""Set up the sensor config entry."""
|
||||||
|
controller_data = hass.data[DOMAIN]
|
||||||
|
async_add_entities(
|
||||||
[
|
[
|
||||||
VeraLight(device, hass.data[VERA_CONTROLLER])
|
VeraLight(device, controller_data.controller)
|
||||||
for device in hass.data[VERA_DEVICES]["light"]
|
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||||
],
|
]
|
||||||
True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
"""Support for Vera locks."""
|
"""Support for Vera locks."""
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Callable, List
|
||||||
|
|
||||||
from homeassistant.components.lock import ENTITY_ID_FORMAT, LockDevice
|
from homeassistant.components.lock import (
|
||||||
|
DOMAIN as PLATFORM_DOMAIN,
|
||||||
|
ENTITY_ID_FORMAT,
|
||||||
|
LockDevice,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED
|
from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
|
from . import VeraDevice
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -12,14 +21,18 @@ ATTR_LAST_USER_NAME = "changed_by_name"
|
||||||
ATTR_LOW_BATTERY = "low_battery"
|
ATTR_LOW_BATTERY = "low_battery"
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
async def async_setup_entry(
|
||||||
"""Find and return Vera locks."""
|
hass: HomeAssistant,
|
||||||
add_entities(
|
entry: ConfigEntry,
|
||||||
|
async_add_entities: Callable[[List[Entity], bool], None],
|
||||||
|
) -> None:
|
||||||
|
"""Set up the sensor config entry."""
|
||||||
|
controller_data = hass.data[DOMAIN]
|
||||||
|
async_add_entities(
|
||||||
[
|
[
|
||||||
VeraLock(device, hass.data[VERA_CONTROLLER])
|
VeraLock(device, controller_data.controller)
|
||||||
for device in hass.data[VERA_DEVICES]["lock"]
|
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||||
],
|
]
|
||||||
True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
{
|
{
|
||||||
"domain": "vera",
|
"domain": "vera",
|
||||||
"name": "Vera",
|
"name": "Vera",
|
||||||
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/vera",
|
"documentation": "https://www.home-assistant.io/integrations/vera",
|
||||||
"requirements": ["pyvera==0.3.7"],
|
"requirements": ["pyvera==0.3.7"],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"codeowners": []
|
"codeowners": [
|
||||||
|
"@vangorra"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,30 @@
|
||||||
"""Support for Vera scenes."""
|
"""Support for Vera scenes."""
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Callable, List
|
||||||
|
|
||||||
from homeassistant.components.scene import Scene
|
from homeassistant.components.scene import Scene
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
from . import VERA_CONTROLLER, VERA_ID_FORMAT, VERA_SCENES
|
from .const import DOMAIN, VERA_ID_FORMAT
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
async def async_setup_entry(
|
||||||
"""Set up the Vera scenes."""
|
hass: HomeAssistant,
|
||||||
add_entities(
|
entry: ConfigEntry,
|
||||||
|
async_add_entities: Callable[[List[Entity], bool], None],
|
||||||
|
) -> None:
|
||||||
|
"""Set up the sensor config entry."""
|
||||||
|
controller_data = hass.data[DOMAIN]
|
||||||
|
async_add_entities(
|
||||||
[
|
[
|
||||||
VeraScene(scene, hass.data[VERA_CONTROLLER])
|
VeraScene(device, controller_data.controller)
|
||||||
for scene in hass.data[VERA_SCENES]
|
for device in controller_data.scenes
|
||||||
],
|
]
|
||||||
True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,37 @@
|
||||||
"""Support for Vera sensors."""
|
"""Support for Vera sensors."""
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Callable, List
|
||||||
|
|
||||||
import pyvera as veraApi
|
import pyvera as veraApi
|
||||||
|
|
||||||
from homeassistant.components.sensor import ENTITY_ID_FORMAT
|
from homeassistant.components.sensor import DOMAIN as PLATFORM_DOMAIN, ENTITY_ID_FORMAT
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT, UNIT_PERCENTAGE
|
from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT, UNIT_PERCENTAGE
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.util import convert
|
from homeassistant.util import convert
|
||||||
|
|
||||||
from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
|
from . import VeraDevice
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
SCAN_INTERVAL = timedelta(seconds=5)
|
SCAN_INTERVAL = timedelta(seconds=5)
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
async def async_setup_entry(
|
||||||
"""Set up the Vera controller devices."""
|
hass: HomeAssistant,
|
||||||
add_entities(
|
entry: ConfigEntry,
|
||||||
|
async_add_entities: Callable[[List[Entity], bool], None],
|
||||||
|
) -> None:
|
||||||
|
"""Set up the sensor config entry."""
|
||||||
|
controller_data = hass.data[DOMAIN]
|
||||||
|
async_add_entities(
|
||||||
[
|
[
|
||||||
VeraSensor(device, hass.data[VERA_CONTROLLER])
|
VeraSensor(device, controller_data.controller)
|
||||||
for device in hass.data[VERA_DEVICES]["sensor"]
|
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||||
],
|
]
|
||||||
True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
32
homeassistant/components/vera/strings.json
Normal file
32
homeassistant/components/vera/strings.json
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"title": "Vera",
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "A controller is already configured.",
|
||||||
|
"cannot_connect": "Could not connect to controller with url {base_url}"
|
||||||
|
},
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"title": "Setup Vera controller",
|
||||||
|
"description": "Provide a Vera controller url below. It should look like this: http://192.168.1.161:3480.",
|
||||||
|
"data": {
|
||||||
|
"vera_controller_url": "Controller URL",
|
||||||
|
"lights": "Vera switch device ids to treat as lights in Home Assistant.",
|
||||||
|
"exclude": "Vera device ids to exclude from Home Assistant."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"title": "Vera controller options",
|
||||||
|
"description": "See the vera documentation for details on optional parameters: https://www.home-assistant.io/integrations/vera/. Note: Any changes here will need a restart to the home assistant server. To clear values, provide a space.",
|
||||||
|
"data": {
|
||||||
|
"lights": "Vera switch device ids to treat as lights in Home Assistant.",
|
||||||
|
"exclude": "Vera device ids to exclude from Home Assistant."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,22 +1,35 @@
|
||||||
"""Support for Vera switches."""
|
"""Support for Vera switches."""
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Callable, List
|
||||||
|
|
||||||
from homeassistant.components.switch import ENTITY_ID_FORMAT, SwitchDevice
|
from homeassistant.components.switch import (
|
||||||
|
DOMAIN as PLATFORM_DOMAIN,
|
||||||
|
ENTITY_ID_FORMAT,
|
||||||
|
SwitchDevice,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.util import convert
|
from homeassistant.util import convert
|
||||||
|
|
||||||
from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
|
from . import VeraDevice
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
async def async_setup_entry(
|
||||||
"""Set up the Vera switches."""
|
hass: HomeAssistant,
|
||||||
add_entities(
|
entry: ConfigEntry,
|
||||||
|
async_add_entities: Callable[[List[Entity], bool], None],
|
||||||
|
) -> None:
|
||||||
|
"""Set up the sensor config entry."""
|
||||||
|
controller_data = hass.data[DOMAIN]
|
||||||
|
async_add_entities(
|
||||||
[
|
[
|
||||||
VeraSwitch(device, hass.data[VERA_CONTROLLER])
|
VeraSwitch(device, controller_data.controller)
|
||||||
for device in hass.data[VERA_DEVICES]["switch"]
|
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||||
],
|
]
|
||||||
True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,7 @@ FLOWS = [
|
||||||
"unifi",
|
"unifi",
|
||||||
"upnp",
|
"upnp",
|
||||||
"velbus",
|
"velbus",
|
||||||
|
"vera",
|
||||||
"vesync",
|
"vesync",
|
||||||
"vilfo",
|
"vilfo",
|
||||||
"vizio",
|
"vizio",
|
||||||
|
|
|
@ -1,47 +1,91 @@
|
||||||
"""Common code for tests."""
|
"""Common code for tests."""
|
||||||
|
|
||||||
from typing import Callable, NamedTuple, Tuple
|
from typing import Callable, Dict, NamedTuple, Tuple
|
||||||
|
|
||||||
from mock import MagicMock
|
from mock import MagicMock
|
||||||
from pyvera import VeraController, VeraDevice, VeraScene
|
import pyvera as pv
|
||||||
|
|
||||||
from homeassistant.components.vera import CONF_CONTROLLER, DOMAIN
|
from homeassistant.components.vera.const import CONF_CONTROLLER, DOMAIN
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
SetupCallback = Callable[[pv.VeraController, dict], None]
|
||||||
|
|
||||||
|
|
||||||
|
class ControllerData(NamedTuple):
|
||||||
|
"""Test data about a specific vera controller."""
|
||||||
|
|
||||||
|
controller: pv.VeraController
|
||||||
|
update_callback: Callable
|
||||||
|
|
||||||
|
|
||||||
class ComponentData(NamedTuple):
|
class ComponentData(NamedTuple):
|
||||||
"""Component data."""
|
"""Test data about the vera component."""
|
||||||
|
|
||||||
controller: VeraController
|
controller_data: ControllerData
|
||||||
|
|
||||||
|
|
||||||
|
class ControllerConfig(NamedTuple):
|
||||||
|
"""Test config for mocking a vera controller."""
|
||||||
|
|
||||||
|
config: Dict
|
||||||
|
options: Dict
|
||||||
|
config_from_file: bool
|
||||||
|
serial_number: str
|
||||||
|
devices: Tuple[pv.VeraDevice, ...]
|
||||||
|
scenes: Tuple[pv.VeraScene, ...]
|
||||||
|
setup_callback: SetupCallback
|
||||||
|
|
||||||
|
|
||||||
|
def new_simple_controller_config(
|
||||||
|
config: dict = None,
|
||||||
|
options: dict = None,
|
||||||
|
config_from_file=False,
|
||||||
|
serial_number="1111",
|
||||||
|
devices: Tuple[pv.VeraDevice, ...] = (),
|
||||||
|
scenes: Tuple[pv.VeraScene, ...] = (),
|
||||||
|
setup_callback: SetupCallback = None,
|
||||||
|
) -> ControllerConfig:
|
||||||
|
"""Create simple contorller config."""
|
||||||
|
return ControllerConfig(
|
||||||
|
config=config or {CONF_CONTROLLER: "http://127.0.0.1:123"},
|
||||||
|
options=options,
|
||||||
|
config_from_file=config_from_file,
|
||||||
|
serial_number=serial_number,
|
||||||
|
devices=devices,
|
||||||
|
scenes=scenes,
|
||||||
|
setup_callback=setup_callback,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ComponentFactory:
|
class ComponentFactory:
|
||||||
"""Factory class."""
|
"""Factory class."""
|
||||||
|
|
||||||
def __init__(self, init_controller_mock):
|
def __init__(self, vera_controller_class_mock):
|
||||||
"""Initialize component factory."""
|
"""Initialize the factory."""
|
||||||
self.init_controller_mock = init_controller_mock
|
self.vera_controller_class_mock = vera_controller_class_mock
|
||||||
|
|
||||||
async def configure_component(
|
async def configure_component(
|
||||||
self,
|
self, hass: HomeAssistant, controller_config: ControllerConfig
|
||||||
hass: HomeAssistant,
|
|
||||||
devices: Tuple[VeraDevice] = (),
|
|
||||||
scenes: Tuple[VeraScene] = (),
|
|
||||||
setup_callback: Callable[[VeraController], None] = None,
|
|
||||||
) -> ComponentData:
|
) -> ComponentData:
|
||||||
"""Configure the component with specific mock data."""
|
"""Configure the component with specific mock data."""
|
||||||
controller_url = "http://127.0.0.1:123"
|
component_config = {
|
||||||
|
**(controller_config.config or {}),
|
||||||
hass_config = {
|
**(controller_config.options or {}),
|
||||||
DOMAIN: {CONF_CONTROLLER: controller_url},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
controller = MagicMock(spec=VeraController) # type: VeraController
|
controller = MagicMock(spec=pv.VeraController) # type: pv.VeraController
|
||||||
controller.base_url = controller_url
|
controller.base_url = component_config.get(CONF_CONTROLLER)
|
||||||
controller.register = MagicMock()
|
controller.register = MagicMock()
|
||||||
controller.get_devices = MagicMock(return_value=devices or ())
|
controller.start = MagicMock()
|
||||||
controller.get_scenes = MagicMock(return_value=scenes or ())
|
controller.stop = MagicMock()
|
||||||
|
controller.refresh_data = MagicMock()
|
||||||
|
controller.temperature_units = "C"
|
||||||
|
controller.serial_number = controller_config.serial_number
|
||||||
|
controller.get_devices = MagicMock(return_value=controller_config.devices)
|
||||||
|
controller.get_scenes = MagicMock(return_value=controller_config.scenes)
|
||||||
|
|
||||||
for vera_obj in controller.get_devices() + controller.get_scenes():
|
for vera_obj in controller.get_devices() + controller.get_scenes():
|
||||||
vera_obj.vera_controller = controller
|
vera_obj.vera_controller = controller
|
||||||
|
@ -49,17 +93,39 @@ class ComponentFactory:
|
||||||
controller.get_devices.reset_mock()
|
controller.get_devices.reset_mock()
|
||||||
controller.get_scenes.reset_mock()
|
controller.get_scenes.reset_mock()
|
||||||
|
|
||||||
if setup_callback:
|
if controller_config.setup_callback:
|
||||||
setup_callback(controller, hass_config)
|
controller_config.setup_callback(controller)
|
||||||
|
|
||||||
def init_controller(base_url: str) -> list:
|
self.vera_controller_class_mock.return_value = controller
|
||||||
nonlocal controller
|
|
||||||
return [controller, True]
|
|
||||||
|
|
||||||
self.init_controller_mock.side_effect = init_controller
|
hass_config = {}
|
||||||
|
|
||||||
|
# Setup component through config file import.
|
||||||
|
if controller_config.config_from_file:
|
||||||
|
hass_config[DOMAIN] = component_config
|
||||||
|
|
||||||
# Setup Home Assistant.
|
# Setup Home Assistant.
|
||||||
assert await async_setup_component(hass, DOMAIN, hass_config)
|
assert await async_setup_component(hass, DOMAIN, hass_config)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
return ComponentData(controller=controller)
|
# Setup component through config flow.
|
||||||
|
if not controller_config.config_from_file:
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN, data=component_config, options={}, unique_id="12345"
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
update_callback = (
|
||||||
|
controller.register.call_args_list[0][0][1]
|
||||||
|
if controller.register.call_args_list
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
|
return ComponentData(
|
||||||
|
controller_data=ControllerData(
|
||||||
|
controller=controller, update_callback=update_callback
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
@ -9,5 +9,5 @@ from .common import ComponentFactory
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def vera_component_factory():
|
def vera_component_factory():
|
||||||
"""Return a factory for initializing the vera component."""
|
"""Return a factory for initializing the vera component."""
|
||||||
with patch("pyvera.init_controller") as init_controller_mock:
|
with patch("pyvera.VeraController") as vera_controller_class_mock:
|
||||||
yield ComponentFactory(init_controller_mock)
|
yield ComponentFactory(vera_controller_class_mock)
|
||||||
|
|
|
@ -1,38 +1,36 @@
|
||||||
"""Vera tests."""
|
"""Vera tests."""
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from pyvera import VeraBinarySensor
|
import pyvera as pv
|
||||||
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .common import ComponentFactory
|
from .common import ComponentFactory, new_simple_controller_config
|
||||||
|
|
||||||
|
|
||||||
async def test_binary_sensor(
|
async def test_binary_sensor(
|
||||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test function."""
|
"""Test function."""
|
||||||
vera_device = MagicMock(spec=VeraBinarySensor) # type: VeraBinarySensor
|
vera_device = MagicMock(spec=pv.VeraBinarySensor) # type: pv.VeraBinarySensor
|
||||||
vera_device.device_id = 1
|
vera_device.device_id = 1
|
||||||
|
vera_device.vera_device_id = 1
|
||||||
vera_device.name = "dev1"
|
vera_device.name = "dev1"
|
||||||
vera_device.is_tripped = False
|
vera_device.is_tripped = False
|
||||||
entity_id = "binary_sensor.dev1_1"
|
entity_id = "binary_sensor.dev1_1"
|
||||||
|
|
||||||
component_data = await vera_component_factory.configure_component(
|
component_data = await vera_component_factory.configure_component(
|
||||||
hass=hass, devices=(vera_device,)
|
hass=hass,
|
||||||
|
controller_config=new_simple_controller_config(devices=(vera_device,)),
|
||||||
)
|
)
|
||||||
controller = component_data.controller
|
update_callback = component_data.controller_data.update_callback
|
||||||
|
|
||||||
update_callback = controller.register.call_args_list[0][0][1]
|
|
||||||
|
|
||||||
vera_device.is_tripped = False
|
vera_device.is_tripped = False
|
||||||
update_callback(vera_device)
|
update_callback(vera_device)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert hass.states.get(entity_id).state == "off"
|
assert hass.states.get(entity_id).state == "off"
|
||||||
controller.register.reset_mock()
|
|
||||||
|
|
||||||
vera_device.is_tripped = True
|
vera_device.is_tripped = True
|
||||||
update_callback(vera_device)
|
update_callback(vera_device)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert hass.states.get(entity_id).state == "on"
|
assert hass.states.get(entity_id).state == "on"
|
||||||
controller.register.reset_mock()
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Vera tests."""
|
"""Vera tests."""
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from pyvera import CATEGORY_THERMOSTAT, VeraController, VeraThermostat
|
import pyvera as pv
|
||||||
|
|
||||||
from homeassistant.components.climate.const import (
|
from homeassistant.components.climate.const import (
|
||||||
FAN_AUTO,
|
FAN_AUTO,
|
||||||
|
@ -13,17 +13,17 @@ from homeassistant.components.climate.const import (
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .common import ComponentFactory
|
from .common import ComponentFactory, new_simple_controller_config
|
||||||
|
|
||||||
|
|
||||||
async def test_climate(
|
async def test_climate(
|
||||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test function."""
|
"""Test function."""
|
||||||
vera_device = MagicMock(spec=VeraThermostat) # type: VeraThermostat
|
vera_device = MagicMock(spec=pv.VeraThermostat) # type: pv.VeraThermostat
|
||||||
vera_device.device_id = 1
|
vera_device.device_id = 1
|
||||||
vera_device.name = "dev1"
|
vera_device.name = "dev1"
|
||||||
vera_device.category = CATEGORY_THERMOSTAT
|
vera_device.category = pv.CATEGORY_THERMOSTAT
|
||||||
vera_device.power = 10
|
vera_device.power = 10
|
||||||
vera_device.get_current_temperature.return_value = 71
|
vera_device.get_current_temperature.return_value = 71
|
||||||
vera_device.get_hvac_mode.return_value = "Off"
|
vera_device.get_hvac_mode.return_value = "Off"
|
||||||
|
@ -31,10 +31,10 @@ async def test_climate(
|
||||||
entity_id = "climate.dev1_1"
|
entity_id = "climate.dev1_1"
|
||||||
|
|
||||||
component_data = await vera_component_factory.configure_component(
|
component_data = await vera_component_factory.configure_component(
|
||||||
hass=hass, devices=(vera_device,),
|
hass=hass,
|
||||||
|
controller_config=new_simple_controller_config(devices=(vera_device,)),
|
||||||
)
|
)
|
||||||
controller = component_data.controller
|
update_callback = component_data.controller_data.update_callback
|
||||||
update_callback = controller.register.call_args_list[0][0][1]
|
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == HVAC_MODE_OFF
|
assert hass.states.get(entity_id).state == HVAC_MODE_OFF
|
||||||
|
|
||||||
|
@ -123,24 +123,26 @@ async def test_climate_f(
|
||||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test function."""
|
"""Test function."""
|
||||||
vera_device = MagicMock(spec=VeraThermostat) # type: VeraThermostat
|
vera_device = MagicMock(spec=pv.VeraThermostat) # type: pv.VeraThermostat
|
||||||
vera_device.device_id = 1
|
vera_device.device_id = 1
|
||||||
vera_device.name = "dev1"
|
vera_device.name = "dev1"
|
||||||
vera_device.category = CATEGORY_THERMOSTAT
|
vera_device.category = pv.CATEGORY_THERMOSTAT
|
||||||
vera_device.power = 10
|
vera_device.power = 10
|
||||||
vera_device.get_current_temperature.return_value = 71
|
vera_device.get_current_temperature.return_value = 71
|
||||||
vera_device.get_hvac_mode.return_value = "Off"
|
vera_device.get_hvac_mode.return_value = "Off"
|
||||||
vera_device.get_current_goal_temperature.return_value = 72
|
vera_device.get_current_goal_temperature.return_value = 72
|
||||||
entity_id = "climate.dev1_1"
|
entity_id = "climate.dev1_1"
|
||||||
|
|
||||||
def setup_callback(controller: VeraController, hass_config: dict) -> None:
|
def setup_callback(controller: pv.VeraController) -> None:
|
||||||
controller.temperature_units = "F"
|
controller.temperature_units = "F"
|
||||||
|
|
||||||
component_data = await vera_component_factory.configure_component(
|
component_data = await vera_component_factory.configure_component(
|
||||||
hass=hass, devices=(vera_device,), setup_callback=setup_callback
|
hass=hass,
|
||||||
|
controller_config=new_simple_controller_config(
|
||||||
|
devices=(vera_device,), setup_callback=setup_callback
|
||||||
|
),
|
||||||
)
|
)
|
||||||
controller = component_data.controller
|
update_callback = component_data.controller_data.update_callback
|
||||||
update_callback = controller.register.call_args_list[0][0][1]
|
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"climate", "set_temperature", {"entity_id": entity_id, "temperature": 30},
|
"climate", "set_temperature", {"entity_id": entity_id, "temperature": 30},
|
||||||
|
|
159
tests/components/vera/test_config_flow.py
Normal file
159
tests/components/vera/test_config_flow.py
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
"""Vera tests."""
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
from mock import patch
|
||||||
|
from requests.exceptions import RequestException
|
||||||
|
|
||||||
|
from homeassistant import config_entries, data_entry_flow
|
||||||
|
from homeassistant.components.vera import CONF_CONTROLLER, DOMAIN
|
||||||
|
from homeassistant.const import CONF_EXCLUDE, CONF_LIGHTS, CONF_SOURCE
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.data_entry_flow import (
|
||||||
|
RESULT_TYPE_ABORT,
|
||||||
|
RESULT_TYPE_CREATE_ENTRY,
|
||||||
|
RESULT_TYPE_FORM,
|
||||||
|
)
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_step_user_success(hass: HomeAssistant) -> None:
|
||||||
|
"""Test user step success."""
|
||||||
|
with patch("pyvera.VeraController") as vera_controller_class_mock:
|
||||||
|
controller = MagicMock()
|
||||||
|
controller.refresh_data = MagicMock()
|
||||||
|
controller.serial_number = "serial_number_0"
|
||||||
|
vera_controller_class_mock.return_value = controller
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
assert result["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result["step_id"] == config_entries.SOURCE_USER
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={
|
||||||
|
CONF_CONTROLLER: "http://127.0.0.1:123/",
|
||||||
|
CONF_LIGHTS: "12 13",
|
||||||
|
CONF_EXCLUDE: "14 15",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert result["title"] == "http://127.0.0.1:123"
|
||||||
|
assert result["data"] == {
|
||||||
|
CONF_CONTROLLER: "http://127.0.0.1:123",
|
||||||
|
CONF_SOURCE: config_entries.SOURCE_USER,
|
||||||
|
CONF_LIGHTS: ["12", "13"],
|
||||||
|
CONF_EXCLUDE: ["14", "15"],
|
||||||
|
}
|
||||||
|
assert result["result"].unique_id == controller.serial_number
|
||||||
|
|
||||||
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
|
assert entries
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_step_user_already_configured(hass: HomeAssistant) -> None:
|
||||||
|
"""Test user step with entry already configured."""
|
||||||
|
entry = MockConfigEntry(domain=DOMAIN, data={}, options={}, unique_id="12345")
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
assert result["type"] == RESULT_TYPE_ABORT
|
||||||
|
assert result["reason"] == "already_configured"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_step_import_success(hass: HomeAssistant) -> None:
|
||||||
|
"""Test import step success."""
|
||||||
|
with patch("pyvera.VeraController") as vera_controller_class_mock:
|
||||||
|
controller = MagicMock()
|
||||||
|
controller.refresh_data = MagicMock()
|
||||||
|
controller.serial_number = "serial_number_1"
|
||||||
|
vera_controller_class_mock.return_value = controller
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_IMPORT},
|
||||||
|
data={CONF_CONTROLLER: "http://127.0.0.1:123/"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert result["title"] == "http://127.0.0.1:123"
|
||||||
|
assert result["data"] == {
|
||||||
|
CONF_CONTROLLER: "http://127.0.0.1:123",
|
||||||
|
CONF_SOURCE: config_entries.SOURCE_IMPORT,
|
||||||
|
}
|
||||||
|
assert result["result"].unique_id == controller.serial_number
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_step_import_alredy_setup(hass: HomeAssistant) -> None:
|
||||||
|
"""Test import step with entry already setup."""
|
||||||
|
entry = MockConfigEntry(domain=DOMAIN, data={}, options={}, unique_id="12345")
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
with patch("pyvera.VeraController") as vera_controller_class_mock:
|
||||||
|
controller = MagicMock()
|
||||||
|
controller.refresh_data = MagicMock()
|
||||||
|
controller.serial_number = "12345"
|
||||||
|
vera_controller_class_mock.return_value = controller
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_IMPORT},
|
||||||
|
data={CONF_CONTROLLER: "http://localhost:445"},
|
||||||
|
)
|
||||||
|
assert result["type"] == RESULT_TYPE_ABORT
|
||||||
|
assert result["reason"] == "already_configured"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_step_finish_error(hass: HomeAssistant) -> None:
|
||||||
|
"""Test finish step with error."""
|
||||||
|
with patch("pyvera.VeraController") as vera_controller_class_mock:
|
||||||
|
controller = MagicMock()
|
||||||
|
controller.refresh_data = MagicMock(side_effect=RequestException())
|
||||||
|
vera_controller_class_mock.return_value = controller
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_IMPORT},
|
||||||
|
data={CONF_CONTROLLER: "http://127.0.0.1:123/"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "cannot_connect"
|
||||||
|
assert result["description_placeholders"] == {
|
||||||
|
"base_url": "http://127.0.0.1:123"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_options(hass):
|
||||||
|
"""Test updating options."""
|
||||||
|
base_url = "http://127.0.0.1/"
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
title=base_url,
|
||||||
|
data={CONF_CONTROLLER: "http://127.0.0.1/"},
|
||||||
|
options={CONF_LIGHTS: [1, 2, 3]},
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_init(
|
||||||
|
entry.entry_id, context={"source": "test"}, data=None
|
||||||
|
)
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
|
assert result["step_id"] == "init"
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={
|
||||||
|
CONF_LIGHTS: "1,2;3 4 5_6bb7",
|
||||||
|
CONF_EXCLUDE: "8,9;10 11 12_13bb14",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert result["data"] == {
|
||||||
|
CONF_LIGHTS: ["1", "2", "3", "4", "5", "6", "7"],
|
||||||
|
CONF_EXCLUDE: ["8", "9", "10", "11", "12", "13", "14"],
|
||||||
|
}
|
|
@ -1,30 +1,30 @@
|
||||||
"""Vera tests."""
|
"""Vera tests."""
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from pyvera import CATEGORY_CURTAIN, VeraCurtain
|
import pyvera as pv
|
||||||
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .common import ComponentFactory
|
from .common import ComponentFactory, new_simple_controller_config
|
||||||
|
|
||||||
|
|
||||||
async def test_cover(
|
async def test_cover(
|
||||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test function."""
|
"""Test function."""
|
||||||
vera_device = MagicMock(spec=VeraCurtain) # type: VeraCurtain
|
vera_device = MagicMock(spec=pv.VeraCurtain) # type: pv.VeraCurtain
|
||||||
vera_device.device_id = 1
|
vera_device.device_id = 1
|
||||||
vera_device.name = "dev1"
|
vera_device.name = "dev1"
|
||||||
vera_device.category = CATEGORY_CURTAIN
|
vera_device.category = pv.CATEGORY_CURTAIN
|
||||||
vera_device.is_closed = False
|
vera_device.is_closed = False
|
||||||
vera_device.get_level.return_value = 0
|
vera_device.get_level.return_value = 0
|
||||||
entity_id = "cover.dev1_1"
|
entity_id = "cover.dev1_1"
|
||||||
|
|
||||||
component_data = await vera_component_factory.configure_component(
|
component_data = await vera_component_factory.configure_component(
|
||||||
hass=hass, devices=(vera_device,),
|
hass=hass,
|
||||||
|
controller_config=new_simple_controller_config(devices=(vera_device,)),
|
||||||
)
|
)
|
||||||
controller = component_data.controller
|
update_callback = component_data.controller_data.update_callback
|
||||||
update_callback = controller.register.call_args_list[0][0][1]
|
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == "closed"
|
assert hass.states.get(entity_id).state == "closed"
|
||||||
assert hass.states.get(entity_id).attributes["current_position"] == 0
|
assert hass.states.get(entity_id).attributes["current_position"] == 0
|
||||||
|
|
|
@ -1,78 +1,112 @@
|
||||||
"""Vera tests."""
|
"""Vera tests."""
|
||||||
from unittest.mock import MagicMock
|
from asynctest import MagicMock
|
||||||
|
import pyvera as pv
|
||||||
|
from requests.exceptions import RequestException
|
||||||
|
|
||||||
from pyvera import (
|
from homeassistant.components.vera import CONF_CONTROLLER, DOMAIN
|
||||||
VeraArmableDevice,
|
from homeassistant.config_entries import ENTRY_STATE_NOT_LOADED
|
||||||
VeraBinarySensor,
|
|
||||||
VeraController,
|
|
||||||
VeraCurtain,
|
|
||||||
VeraDevice,
|
|
||||||
VeraDimmer,
|
|
||||||
VeraLock,
|
|
||||||
VeraScene,
|
|
||||||
VeraSceneController,
|
|
||||||
VeraSensor,
|
|
||||||
VeraSwitch,
|
|
||||||
VeraThermostat,
|
|
||||||
)
|
|
||||||
|
|
||||||
from homeassistant.components.vera import (
|
|
||||||
CONF_EXCLUDE,
|
|
||||||
CONF_LIGHTS,
|
|
||||||
DOMAIN,
|
|
||||||
VERA_DEVICES,
|
|
||||||
)
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .common import ComponentFactory
|
from .common import ComponentFactory, new_simple_controller_config
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
def new_vera_device(cls, device_id: int) -> VeraDevice:
|
|
||||||
"""Create new mocked vera device.."""
|
|
||||||
vera_device = MagicMock(spec=cls) # type: VeraDevice
|
|
||||||
vera_device.device_id = device_id
|
|
||||||
vera_device.name = f"dev${device_id}"
|
|
||||||
return vera_device
|
|
||||||
|
|
||||||
|
|
||||||
def assert_hass_vera_devices(hass: HomeAssistant, platform: str, arr_len: int) -> None:
|
|
||||||
"""Assert vera devices are present.."""
|
|
||||||
assert hass.data[VERA_DEVICES][platform]
|
|
||||||
assert len(hass.data[VERA_DEVICES][platform]) == arr_len
|
|
||||||
|
|
||||||
|
|
||||||
async def test_init(
|
async def test_init(
|
||||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test function."""
|
"""Test function."""
|
||||||
|
vera_device1 = MagicMock(spec=pv.VeraBinarySensor) # type: pv.VeraBinarySensor
|
||||||
def setup_callback(controller: VeraController, hass_config: dict) -> None:
|
vera_device1.device_id = 1
|
||||||
hass_config[DOMAIN][CONF_EXCLUDE] = [11]
|
vera_device1.vera_device_id = 1
|
||||||
hass_config[DOMAIN][CONF_LIGHTS] = [10]
|
vera_device1.name = "first_dev"
|
||||||
|
vera_device1.is_tripped = False
|
||||||
|
entity1_id = "binary_sensor.first_dev_1"
|
||||||
|
|
||||||
await vera_component_factory.configure_component(
|
await vera_component_factory.configure_component(
|
||||||
hass=hass,
|
hass=hass,
|
||||||
devices=(
|
controller_config=new_simple_controller_config(
|
||||||
new_vera_device(VeraDimmer, 1),
|
config={CONF_CONTROLLER: "http://127.0.0.1:111"},
|
||||||
new_vera_device(VeraBinarySensor, 2),
|
config_from_file=False,
|
||||||
new_vera_device(VeraSensor, 3),
|
serial_number="first_serial",
|
||||||
new_vera_device(VeraArmableDevice, 4),
|
devices=(vera_device1,),
|
||||||
new_vera_device(VeraLock, 5),
|
|
||||||
new_vera_device(VeraThermostat, 6),
|
|
||||||
new_vera_device(VeraCurtain, 7),
|
|
||||||
new_vera_device(VeraSceneController, 8),
|
|
||||||
new_vera_device(VeraSwitch, 9),
|
|
||||||
new_vera_device(VeraSwitch, 10),
|
|
||||||
new_vera_device(VeraSwitch, 11),
|
|
||||||
),
|
),
|
||||||
scenes=(MagicMock(spec=VeraScene),),
|
|
||||||
setup_callback=setup_callback,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
assert_hass_vera_devices(hass, "light", 2)
|
entity_registry = await hass.helpers.entity_registry.async_get_registry()
|
||||||
assert_hass_vera_devices(hass, "binary_sensor", 1)
|
entry1 = entity_registry.async_get(entity1_id)
|
||||||
assert_hass_vera_devices(hass, "sensor", 2)
|
|
||||||
assert_hass_vera_devices(hass, "switch", 2)
|
assert entry1
|
||||||
assert_hass_vera_devices(hass, "lock", 1)
|
|
||||||
assert_hass_vera_devices(hass, "climate", 1)
|
|
||||||
assert_hass_vera_devices(hass, "cover", 1)
|
async def test_init_from_file(
|
||||||
|
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||||
|
) -> None:
|
||||||
|
"""Test function."""
|
||||||
|
vera_device1 = MagicMock(spec=pv.VeraBinarySensor) # type: pv.VeraBinarySensor
|
||||||
|
vera_device1.device_id = 1
|
||||||
|
vera_device1.vera_device_id = 1
|
||||||
|
vera_device1.name = "first_dev"
|
||||||
|
vera_device1.is_tripped = False
|
||||||
|
entity1_id = "binary_sensor.first_dev_1"
|
||||||
|
|
||||||
|
await vera_component_factory.configure_component(
|
||||||
|
hass=hass,
|
||||||
|
controller_config=new_simple_controller_config(
|
||||||
|
config={CONF_CONTROLLER: "http://127.0.0.1:111"},
|
||||||
|
config_from_file=True,
|
||||||
|
serial_number="first_serial",
|
||||||
|
devices=(vera_device1,),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
entity_registry = await hass.helpers.entity_registry.async_get_registry()
|
||||||
|
entry1 = entity_registry.async_get(entity1_id)
|
||||||
|
assert entry1
|
||||||
|
|
||||||
|
|
||||||
|
async def test_unload(
|
||||||
|
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||||
|
) -> None:
|
||||||
|
"""Test function."""
|
||||||
|
vera_device1 = MagicMock(spec=pv.VeraBinarySensor) # type: pv.VeraBinarySensor
|
||||||
|
vera_device1.device_id = 1
|
||||||
|
vera_device1.vera_device_id = 1
|
||||||
|
vera_device1.name = "first_dev"
|
||||||
|
vera_device1.is_tripped = False
|
||||||
|
|
||||||
|
await vera_component_factory.configure_component(
|
||||||
|
hass=hass, controller_config=new_simple_controller_config()
|
||||||
|
)
|
||||||
|
|
||||||
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
|
assert entries
|
||||||
|
|
||||||
|
for config_entry in entries:
|
||||||
|
assert await hass.config_entries.async_unload(config_entry.entry_id)
|
||||||
|
assert config_entry.state == ENTRY_STATE_NOT_LOADED
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_setup_entry_error(
|
||||||
|
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||||
|
) -> None:
|
||||||
|
"""Test function."""
|
||||||
|
|
||||||
|
def setup_callback(controller: pv.VeraController) -> None:
|
||||||
|
controller.get_devices.side_effect = RequestException()
|
||||||
|
controller.get_scenes.side_effect = RequestException()
|
||||||
|
|
||||||
|
await vera_component_factory.configure_component(
|
||||||
|
hass=hass,
|
||||||
|
controller_config=new_simple_controller_config(setup_callback=setup_callback),
|
||||||
|
)
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={CONF_CONTROLLER: "http://127.0.0.1"},
|
||||||
|
options={},
|
||||||
|
unique_id="12345",
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
assert not await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
"""Vera tests."""
|
"""Vera tests."""
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from pyvera import CATEGORY_DIMMER, VeraDimmer
|
import pyvera as pv
|
||||||
|
|
||||||
from homeassistant.components.light import ATTR_BRIGHTNESS, ATTR_HS_COLOR
|
from homeassistant.components.light import ATTR_BRIGHTNESS, ATTR_HS_COLOR
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .common import ComponentFactory
|
from .common import ComponentFactory, new_simple_controller_config
|
||||||
|
|
||||||
|
|
||||||
async def test_light(
|
async def test_light(
|
||||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test function."""
|
"""Test function."""
|
||||||
vera_device = MagicMock(spec=VeraDimmer) # type: VeraDimmer
|
vera_device = MagicMock(spec=pv.VeraDimmer) # type: pv.VeraDimmer
|
||||||
vera_device.device_id = 1
|
vera_device.device_id = 1
|
||||||
vera_device.name = "dev1"
|
vera_device.name = "dev1"
|
||||||
vera_device.category = CATEGORY_DIMMER
|
vera_device.category = pv.CATEGORY_DIMMER
|
||||||
vera_device.is_switched_on = MagicMock(return_value=False)
|
vera_device.is_switched_on = MagicMock(return_value=False)
|
||||||
vera_device.get_brightness = MagicMock(return_value=0)
|
vera_device.get_brightness = MagicMock(return_value=0)
|
||||||
vera_device.get_color = MagicMock(return_value=[0, 0, 0])
|
vera_device.get_color = MagicMock(return_value=[0, 0, 0])
|
||||||
|
@ -24,10 +24,10 @@ async def test_light(
|
||||||
entity_id = "light.dev1_1"
|
entity_id = "light.dev1_1"
|
||||||
|
|
||||||
component_data = await vera_component_factory.configure_component(
|
component_data = await vera_component_factory.configure_component(
|
||||||
hass=hass, devices=(vera_device,),
|
hass=hass,
|
||||||
|
controller_config=new_simple_controller_config(devices=(vera_device,)),
|
||||||
)
|
)
|
||||||
controller = component_data.controller
|
update_callback = component_data.controller_data.update_callback
|
||||||
update_callback = controller.register.call_args_list[0][0][1]
|
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == "off"
|
assert hass.states.get(entity_id).state == "off"
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
"""Vera tests."""
|
"""Vera tests."""
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from pyvera import CATEGORY_LOCK, VeraLock
|
import pyvera as pv
|
||||||
|
|
||||||
from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED
|
from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .common import ComponentFactory
|
from .common import ComponentFactory, new_simple_controller_config
|
||||||
|
|
||||||
|
|
||||||
async def test_lock(
|
async def test_lock(
|
||||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test function."""
|
"""Test function."""
|
||||||
vera_device = MagicMock(spec=VeraLock) # type: VeraLock
|
vera_device = MagicMock(spec=pv.VeraLock) # type: pv.VeraLock
|
||||||
vera_device.device_id = 1
|
vera_device.device_id = 1
|
||||||
vera_device.name = "dev1"
|
vera_device.name = "dev1"
|
||||||
vera_device.category = CATEGORY_LOCK
|
vera_device.category = pv.CATEGORY_LOCK
|
||||||
vera_device.is_locked = MagicMock(return_value=False)
|
vera_device.is_locked = MagicMock(return_value=False)
|
||||||
entity_id = "lock.dev1_1"
|
entity_id = "lock.dev1_1"
|
||||||
|
|
||||||
component_data = await vera_component_factory.configure_component(
|
component_data = await vera_component_factory.configure_component(
|
||||||
hass=hass, devices=(vera_device,),
|
hass=hass,
|
||||||
|
controller_config=new_simple_controller_config(devices=(vera_device,)),
|
||||||
)
|
)
|
||||||
controller = component_data.controller
|
update_callback = component_data.controller_data.update_callback
|
||||||
update_callback = controller.register.call_args_list[0][0][1]
|
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == STATE_UNLOCKED
|
assert hass.states.get(entity_id).state == STATE_UNLOCKED
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
"""Vera tests."""
|
"""Vera tests."""
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from pyvera import VeraScene
|
import pyvera as pv
|
||||||
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .common import ComponentFactory
|
from .common import ComponentFactory, new_simple_controller_config
|
||||||
|
|
||||||
|
|
||||||
async def test_scene(
|
async def test_scene(
|
||||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test function."""
|
"""Test function."""
|
||||||
vera_scene = MagicMock(spec=VeraScene) # type: VeraScene
|
vera_scene = MagicMock(spec=pv.VeraScene) # type: pv.VeraScene
|
||||||
vera_scene.scene_id = 1
|
vera_scene.scene_id = 1
|
||||||
vera_scene.name = "dev1"
|
vera_scene.name = "dev1"
|
||||||
entity_id = "scene.dev1_1"
|
entity_id = "scene.dev1_1"
|
||||||
|
|
||||||
await vera_component_factory.configure_component(
|
await vera_component_factory.configure_component(
|
||||||
hass=hass, scenes=(vera_scene,),
|
hass=hass, controller_config=new_simple_controller_config(scenes=(vera_scene,)),
|
||||||
)
|
)
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
|
|
|
@ -2,21 +2,12 @@
|
||||||
from typing import Any, Callable, Tuple
|
from typing import Any, Callable, Tuple
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from pyvera import (
|
import pyvera as pv
|
||||||
CATEGORY_HUMIDITY_SENSOR,
|
|
||||||
CATEGORY_LIGHT_SENSOR,
|
|
||||||
CATEGORY_POWER_METER,
|
|
||||||
CATEGORY_SCENE_CONTROLLER,
|
|
||||||
CATEGORY_TEMPERATURE_SENSOR,
|
|
||||||
CATEGORY_UV_SENSOR,
|
|
||||||
VeraController,
|
|
||||||
VeraSensor,
|
|
||||||
)
|
|
||||||
|
|
||||||
from homeassistant.const import UNIT_PERCENTAGE
|
from homeassistant.const import UNIT_PERCENTAGE
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .common import ComponentFactory
|
from .common import ComponentFactory, new_simple_controller_config
|
||||||
|
|
||||||
|
|
||||||
async def run_sensor_test(
|
async def run_sensor_test(
|
||||||
|
@ -26,10 +17,10 @@ async def run_sensor_test(
|
||||||
class_property: str,
|
class_property: str,
|
||||||
assert_states: Tuple[Tuple[Any, Any]],
|
assert_states: Tuple[Tuple[Any, Any]],
|
||||||
assert_unit_of_measurement: str = None,
|
assert_unit_of_measurement: str = None,
|
||||||
setup_callback: Callable[[VeraController], None] = None,
|
setup_callback: Callable[[pv.VeraController], None] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test generic sensor."""
|
"""Test generic sensor."""
|
||||||
vera_device = MagicMock(spec=VeraSensor) # type: VeraSensor
|
vera_device = MagicMock(spec=pv.VeraSensor) # type: pv.VeraSensor
|
||||||
vera_device.device_id = 1
|
vera_device.device_id = 1
|
||||||
vera_device.name = "dev1"
|
vera_device.name = "dev1"
|
||||||
vera_device.category = category
|
vera_device.category = category
|
||||||
|
@ -37,10 +28,12 @@ async def run_sensor_test(
|
||||||
entity_id = "sensor.dev1_1"
|
entity_id = "sensor.dev1_1"
|
||||||
|
|
||||||
component_data = await vera_component_factory.configure_component(
|
component_data = await vera_component_factory.configure_component(
|
||||||
hass=hass, devices=(vera_device,), setup_callback=setup_callback
|
hass=hass,
|
||||||
|
controller_config=new_simple_controller_config(
|
||||||
|
devices=(vera_device,), setup_callback=setup_callback
|
||||||
|
),
|
||||||
)
|
)
|
||||||
controller = component_data.controller
|
update_callback = component_data.controller_data.update_callback
|
||||||
update_callback = controller.register.call_args_list[0][0][1]
|
|
||||||
|
|
||||||
for (initial_value, state_value) in assert_states:
|
for (initial_value, state_value) in assert_states:
|
||||||
setattr(vera_device, class_property, initial_value)
|
setattr(vera_device, class_property, initial_value)
|
||||||
|
@ -57,13 +50,13 @@ async def test_temperature_sensor_f(
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test function."""
|
"""Test function."""
|
||||||
|
|
||||||
def setup_callback(controller: VeraController, hass_config: dict) -> None:
|
def setup_callback(controller: pv.VeraController) -> None:
|
||||||
controller.temperature_units = "F"
|
controller.temperature_units = "F"
|
||||||
|
|
||||||
await run_sensor_test(
|
await run_sensor_test(
|
||||||
hass=hass,
|
hass=hass,
|
||||||
vera_component_factory=vera_component_factory,
|
vera_component_factory=vera_component_factory,
|
||||||
category=CATEGORY_TEMPERATURE_SENSOR,
|
category=pv.CATEGORY_TEMPERATURE_SENSOR,
|
||||||
class_property="temperature",
|
class_property="temperature",
|
||||||
assert_states=(("33", "1"), ("44", "7")),
|
assert_states=(("33", "1"), ("44", "7")),
|
||||||
setup_callback=setup_callback,
|
setup_callback=setup_callback,
|
||||||
|
@ -77,7 +70,7 @@ async def test_temperature_sensor_c(
|
||||||
await run_sensor_test(
|
await run_sensor_test(
|
||||||
hass=hass,
|
hass=hass,
|
||||||
vera_component_factory=vera_component_factory,
|
vera_component_factory=vera_component_factory,
|
||||||
category=CATEGORY_TEMPERATURE_SENSOR,
|
category=pv.CATEGORY_TEMPERATURE_SENSOR,
|
||||||
class_property="temperature",
|
class_property="temperature",
|
||||||
assert_states=(("33", "33"), ("44", "44")),
|
assert_states=(("33", "33"), ("44", "44")),
|
||||||
)
|
)
|
||||||
|
@ -90,7 +83,7 @@ async def test_light_sensor(
|
||||||
await run_sensor_test(
|
await run_sensor_test(
|
||||||
hass=hass,
|
hass=hass,
|
||||||
vera_component_factory=vera_component_factory,
|
vera_component_factory=vera_component_factory,
|
||||||
category=CATEGORY_LIGHT_SENSOR,
|
category=pv.CATEGORY_LIGHT_SENSOR,
|
||||||
class_property="light",
|
class_property="light",
|
||||||
assert_states=(("12", "12"), ("13", "13")),
|
assert_states=(("12", "12"), ("13", "13")),
|
||||||
assert_unit_of_measurement="lx",
|
assert_unit_of_measurement="lx",
|
||||||
|
@ -104,7 +97,7 @@ async def test_uv_sensor(
|
||||||
await run_sensor_test(
|
await run_sensor_test(
|
||||||
hass=hass,
|
hass=hass,
|
||||||
vera_component_factory=vera_component_factory,
|
vera_component_factory=vera_component_factory,
|
||||||
category=CATEGORY_UV_SENSOR,
|
category=pv.CATEGORY_UV_SENSOR,
|
||||||
class_property="light",
|
class_property="light",
|
||||||
assert_states=(("12", "12"), ("13", "13")),
|
assert_states=(("12", "12"), ("13", "13")),
|
||||||
assert_unit_of_measurement="level",
|
assert_unit_of_measurement="level",
|
||||||
|
@ -118,7 +111,7 @@ async def test_humidity_sensor(
|
||||||
await run_sensor_test(
|
await run_sensor_test(
|
||||||
hass=hass,
|
hass=hass,
|
||||||
vera_component_factory=vera_component_factory,
|
vera_component_factory=vera_component_factory,
|
||||||
category=CATEGORY_HUMIDITY_SENSOR,
|
category=pv.CATEGORY_HUMIDITY_SENSOR,
|
||||||
class_property="humidity",
|
class_property="humidity",
|
||||||
assert_states=(("12", "12"), ("13", "13")),
|
assert_states=(("12", "12"), ("13", "13")),
|
||||||
assert_unit_of_measurement=UNIT_PERCENTAGE,
|
assert_unit_of_measurement=UNIT_PERCENTAGE,
|
||||||
|
@ -132,7 +125,7 @@ async def test_power_meter_sensor(
|
||||||
await run_sensor_test(
|
await run_sensor_test(
|
||||||
hass=hass,
|
hass=hass,
|
||||||
vera_component_factory=vera_component_factory,
|
vera_component_factory=vera_component_factory,
|
||||||
category=CATEGORY_POWER_METER,
|
category=pv.CATEGORY_POWER_METER,
|
||||||
class_property="power",
|
class_property="power",
|
||||||
assert_states=(("12", "12"), ("13", "13")),
|
assert_states=(("12", "12"), ("13", "13")),
|
||||||
assert_unit_of_measurement="watts",
|
assert_unit_of_measurement="watts",
|
||||||
|
@ -144,7 +137,7 @@ async def test_trippable_sensor(
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test function."""
|
"""Test function."""
|
||||||
|
|
||||||
def setup_callback(controller: VeraController, hass_config: dict) -> None:
|
def setup_callback(controller: pv.VeraController) -> None:
|
||||||
controller.get_devices()[0].is_trippable = True
|
controller.get_devices()[0].is_trippable = True
|
||||||
|
|
||||||
await run_sensor_test(
|
await run_sensor_test(
|
||||||
|
@ -162,7 +155,7 @@ async def test_unknown_sensor(
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test function."""
|
"""Test function."""
|
||||||
|
|
||||||
def setup_callback(controller: VeraController, hass_config: dict) -> None:
|
def setup_callback(controller: pv.VeraController) -> None:
|
||||||
controller.get_devices()[0].is_trippable = False
|
controller.get_devices()[0].is_trippable = False
|
||||||
|
|
||||||
await run_sensor_test(
|
await run_sensor_test(
|
||||||
|
@ -179,21 +172,21 @@ async def test_scene_controller_sensor(
|
||||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test function."""
|
"""Test function."""
|
||||||
vera_device = MagicMock(spec=VeraSensor) # type: VeraSensor
|
vera_device = MagicMock(spec=pv.VeraSensor) # type: pv.VeraSensor
|
||||||
vera_device.device_id = 1
|
vera_device.device_id = 1
|
||||||
vera_device.name = "dev1"
|
vera_device.name = "dev1"
|
||||||
vera_device.category = CATEGORY_SCENE_CONTROLLER
|
vera_device.category = pv.CATEGORY_SCENE_CONTROLLER
|
||||||
vera_device.get_last_scene_id = MagicMock(return_value="id0")
|
vera_device.get_last_scene_id = MagicMock(return_value="id0")
|
||||||
vera_device.get_last_scene_time = MagicMock(return_value="0000")
|
vera_device.get_last_scene_time = MagicMock(return_value="0000")
|
||||||
entity_id = "sensor.dev1_1"
|
entity_id = "sensor.dev1_1"
|
||||||
|
|
||||||
component_data = await vera_component_factory.configure_component(
|
component_data = await vera_component_factory.configure_component(
|
||||||
hass=hass, devices=(vera_device,)
|
hass=hass,
|
||||||
|
controller_config=new_simple_controller_config(devices=(vera_device,)),
|
||||||
)
|
)
|
||||||
controller = component_data.controller
|
update_callback = component_data.controller_data.update_callback
|
||||||
update_callback = controller.register.call_args_list[0][0][1]
|
|
||||||
|
|
||||||
vera_device.get_last_scene_time = "1111"
|
vera_device.get_last_scene_time.return_value = "1111"
|
||||||
update_callback(vera_device)
|
update_callback(vera_device)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert hass.states.get(entity_id).state == "id0"
|
assert hass.states.get(entity_id).state == "id0"
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
"""Vera tests."""
|
"""Vera tests."""
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from pyvera import CATEGORY_SWITCH, VeraSwitch
|
import pyvera as pv
|
||||||
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .common import ComponentFactory
|
from .common import ComponentFactory, new_simple_controller_config
|
||||||
|
|
||||||
|
|
||||||
async def test_switch(
|
async def test_switch(
|
||||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test function."""
|
"""Test function."""
|
||||||
vera_device = MagicMock(spec=VeraSwitch) # type: VeraSwitch
|
vera_device = MagicMock(spec=pv.VeraSwitch) # type: pv.VeraSwitch
|
||||||
vera_device.device_id = 1
|
vera_device.device_id = 1
|
||||||
vera_device.name = "dev1"
|
vera_device.name = "dev1"
|
||||||
vera_device.category = CATEGORY_SWITCH
|
vera_device.category = pv.CATEGORY_SWITCH
|
||||||
vera_device.is_switched_on = MagicMock(return_value=False)
|
vera_device.is_switched_on = MagicMock(return_value=False)
|
||||||
entity_id = "switch.dev1_1"
|
entity_id = "switch.dev1_1"
|
||||||
|
|
||||||
component_data = await vera_component_factory.configure_component(
|
component_data = await vera_component_factory.configure_component(
|
||||||
hass=hass, devices=(vera_device,),
|
hass=hass,
|
||||||
|
controller_config=new_simple_controller_config(devices=(vera_device,)),
|
||||||
)
|
)
|
||||||
controller = component_data.controller
|
update_callback = component_data.controller_data.update_callback
|
||||||
update_callback = controller.register.call_args_list[0][0][1]
|
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == "off"
|
assert hass.states.get(entity_id).state == "off"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue