mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 08:47:57 +00:00
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
@ -409,6 +409,7 @@ homeassistant/components/usgs_earthquakes_feed/* @exxamalte
|
||||
homeassistant/components/utility_meter/* @dgomes
|
||||
homeassistant/components/velbus/* @Cereal2nd @brefra
|
||||
homeassistant/components/velux/* @Julius2342
|
||||
homeassistant/components/vera/* @vangorra
|
||||
homeassistant/components/versasense/* @flamm3blemuff1n
|
||||
homeassistant/components/version/* @fabaff
|
||||
homeassistant/components/vesync/* @markperdue @webdjoe
|
||||
|
@ -1,4 +1,5 @@
|
||||
"""Support for Vera devices."""
|
||||
import asyncio
|
||||
from collections import defaultdict
|
||||
import logging
|
||||
|
||||
@ -6,6 +7,8 @@ import pyvera as veraApi
|
||||
from requests.exceptions import RequestException
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
ATTR_ARMED,
|
||||
ATTR_BATTERY_LEVEL,
|
||||
@ -15,27 +18,24 @@ from homeassistant.const import (
|
||||
CONF_LIGHTS,
|
||||
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.util import convert, slugify
|
||||
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__)
|
||||
|
||||
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])
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
@ -51,42 +51,53 @@ CONFIG_SCHEMA = vol.Schema(
|
||||
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)
|
||||
|
||||
# Get Vera specific configuration.
|
||||
base_url = config.get(CONF_CONTROLLER)
|
||||
light_ids = config.get(CONF_LIGHTS)
|
||||
exclude_ids = config.get(CONF_EXCLUDE)
|
||||
if not config:
|
||||
return True
|
||||
|
||||
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.
|
||||
controller, _ = veraApi.init_controller(base_url)
|
||||
hass.data[VERA_CONTROLLER] = controller
|
||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_subscription)
|
||||
controller = veraApi.VeraController(base_url)
|
||||
controller.start()
|
||||
|
||||
hass.bus.async_listen_once(
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
lambda event: hass.async_add_executor_job(controller.stop),
|
||||
)
|
||||
|
||||
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:
|
||||
# There was a network related error connecting to the Vera controller.
|
||||
_LOGGER.exception("Error communicating with Vera API")
|
||||
@ -102,15 +113,35 @@ def setup(hass, base_config):
|
||||
continue
|
||||
|
||||
vera_devices[device_type].append(device)
|
||||
hass.data[VERA_DEVICES] = vera_devices
|
||||
|
||||
vera_scenes = []
|
||||
for scene in all_scenes:
|
||||
vera_scenes.append(scene)
|
||||
hass.data[VERA_SCENES] = vera_scenes
|
||||
|
||||
for component in VERA_COMPONENTS:
|
||||
discovery.load_platform(hass, component, DOMAIN, {}, base_config)
|
||||
controller_data = ControllerData(
|
||||
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
|
||||
|
||||
|
@ -1,21 +1,34 @@
|
||||
"""Support for Vera binary sensors."""
|
||||
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__)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Perform the setup for Vera controller devices."""
|
||||
add_entities(
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
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])
|
||||
for device in hass.data[VERA_DEVICES]["binary_sensor"]
|
||||
],
|
||||
True,
|
||||
VeraBinarySensor(device, controller_data.controller)
|
||||
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
@ -1,7 +1,12 @@
|
||||
"""Support for Vera thermostats."""
|
||||
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 (
|
||||
FAN_AUTO,
|
||||
FAN_ON,
|
||||
@ -12,10 +17,14 @@ from homeassistant.components.climate.const import (
|
||||
SUPPORT_FAN_MODE,
|
||||
SUPPORT_TARGET_TEMPERATURE,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
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 . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
|
||||
from . import VeraDevice
|
||||
from .const import DOMAIN
|
||||
|
||||
_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]
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities_callback, discovery_info=None):
|
||||
"""Set up of Vera thermostats."""
|
||||
add_entities_callback(
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
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])
|
||||
for device in hass.data[VERA_DEVICES]["climate"]
|
||||
],
|
||||
True,
|
||||
VeraThermostat(device, controller_data.controller)
|
||||
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
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."""
|
||||
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__)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Vera covers."""
|
||||
add_entities(
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
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])
|
||||
for device in hass.data[VERA_DEVICES]["cover"]
|
||||
],
|
||||
True,
|
||||
VeraCover(device, controller_data.controller)
|
||||
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
@ -1,29 +1,39 @@
|
||||
"""Support for Vera lights."""
|
||||
import logging
|
||||
from typing import Callable, List
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_HS_COLOR,
|
||||
DOMAIN as PLATFORM_DOMAIN,
|
||||
ENTITY_ID_FORMAT,
|
||||
SUPPORT_BRIGHTNESS,
|
||||
SUPPORT_COLOR,
|
||||
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
|
||||
|
||||
from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
|
||||
from . import VeraDevice
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Vera lights."""
|
||||
add_entities(
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
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])
|
||||
for device in hass.data[VERA_DEVICES]["light"]
|
||||
],
|
||||
True,
|
||||
VeraLight(device, controller_data.controller)
|
||||
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
@ -1,10 +1,19 @@
|
||||
"""Support for Vera locks."""
|
||||
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.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__)
|
||||
|
||||
@ -12,14 +21,18 @@ ATTR_LAST_USER_NAME = "changed_by_name"
|
||||
ATTR_LOW_BATTERY = "low_battery"
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Find and return Vera locks."""
|
||||
add_entities(
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
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])
|
||||
for device in hass.data[VERA_DEVICES]["lock"]
|
||||
],
|
||||
True,
|
||||
VeraLock(device, controller_data.controller)
|
||||
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
@ -1,8 +1,11 @@
|
||||
{
|
||||
"domain": "vera",
|
||||
"name": "Vera",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/vera",
|
||||
"requirements": ["pyvera==0.3.7"],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
"codeowners": [
|
||||
"@vangorra"
|
||||
]
|
||||
}
|
||||
|
@ -1,22 +1,30 @@
|
||||
"""Support for Vera scenes."""
|
||||
import logging
|
||||
from typing import Callable, List
|
||||
|
||||
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 . import VERA_CONTROLLER, VERA_ID_FORMAT, VERA_SCENES
|
||||
from .const import DOMAIN, VERA_ID_FORMAT
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Vera scenes."""
|
||||
add_entities(
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
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])
|
||||
for scene in hass.data[VERA_SCENES]
|
||||
],
|
||||
True,
|
||||
VeraScene(device, controller_data.controller)
|
||||
for device in controller_data.scenes
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
@ -1,29 +1,37 @@
|
||||
"""Support for Vera sensors."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Callable, List
|
||||
|
||||
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.core import HomeAssistant
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.util import convert
|
||||
|
||||
from . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
|
||||
from . import VeraDevice
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=5)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Vera controller devices."""
|
||||
add_entities(
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
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])
|
||||
for device in hass.data[VERA_DEVICES]["sensor"]
|
||||
],
|
||||
True,
|
||||
VeraSensor(device, controller_data.controller)
|
||||
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
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."""
|
||||
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 . import VERA_CONTROLLER, VERA_DEVICES, VeraDevice
|
||||
from . import VeraDevice
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Vera switches."""
|
||||
add_entities(
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
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])
|
||||
for device in hass.data[VERA_DEVICES]["switch"]
|
||||
],
|
||||
True,
|
||||
VeraSwitch(device, controller_data.controller)
|
||||
for device in controller_data.devices.get(PLATFORM_DOMAIN)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
@ -122,6 +122,7 @@ FLOWS = [
|
||||
"unifi",
|
||||
"upnp",
|
||||
"velbus",
|
||||
"vera",
|
||||
"vesync",
|
||||
"vilfo",
|
||||
"vizio",
|
||||
|
@ -1,47 +1,91 @@
|
||||
"""Common code for tests."""
|
||||
|
||||
from typing import Callable, NamedTuple, Tuple
|
||||
from typing import Callable, Dict, NamedTuple, Tuple
|
||||
|
||||
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.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):
|
||||
"""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:
|
||||
"""Factory class."""
|
||||
|
||||
def __init__(self, init_controller_mock):
|
||||
"""Initialize component factory."""
|
||||
self.init_controller_mock = init_controller_mock
|
||||
def __init__(self, vera_controller_class_mock):
|
||||
"""Initialize the factory."""
|
||||
self.vera_controller_class_mock = vera_controller_class_mock
|
||||
|
||||
async def configure_component(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
devices: Tuple[VeraDevice] = (),
|
||||
scenes: Tuple[VeraScene] = (),
|
||||
setup_callback: Callable[[VeraController], None] = None,
|
||||
self, hass: HomeAssistant, controller_config: ControllerConfig
|
||||
) -> ComponentData:
|
||||
"""Configure the component with specific mock data."""
|
||||
controller_url = "http://127.0.0.1:123"
|
||||
|
||||
hass_config = {
|
||||
DOMAIN: {CONF_CONTROLLER: controller_url},
|
||||
component_config = {
|
||||
**(controller_config.config or {}),
|
||||
**(controller_config.options or {}),
|
||||
}
|
||||
|
||||
controller = MagicMock(spec=VeraController) # type: VeraController
|
||||
controller.base_url = controller_url
|
||||
controller = MagicMock(spec=pv.VeraController) # type: pv.VeraController
|
||||
controller.base_url = component_config.get(CONF_CONTROLLER)
|
||||
controller.register = MagicMock()
|
||||
controller.get_devices = MagicMock(return_value=devices or ())
|
||||
controller.get_scenes = MagicMock(return_value=scenes or ())
|
||||
controller.start = MagicMock()
|
||||
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():
|
||||
vera_obj.vera_controller = controller
|
||||
@ -49,17 +93,39 @@ class ComponentFactory:
|
||||
controller.get_devices.reset_mock()
|
||||
controller.get_scenes.reset_mock()
|
||||
|
||||
if setup_callback:
|
||||
setup_callback(controller, hass_config)
|
||||
if controller_config.setup_callback:
|
||||
controller_config.setup_callback(controller)
|
||||
|
||||
def init_controller(base_url: str) -> list:
|
||||
nonlocal controller
|
||||
return [controller, True]
|
||||
self.vera_controller_class_mock.return_value = controller
|
||||
|
||||
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.
|
||||
assert await async_setup_component(hass, DOMAIN, hass_config)
|
||||
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()
|
||||
def vera_component_factory():
|
||||
"""Return a factory for initializing the vera component."""
|
||||
with patch("pyvera.init_controller") as init_controller_mock:
|
||||
yield ComponentFactory(init_controller_mock)
|
||||
with patch("pyvera.VeraController") as vera_controller_class_mock:
|
||||
yield ComponentFactory(vera_controller_class_mock)
|
||||
|
@ -1,38 +1,36 @@
|
||||
"""Vera tests."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from pyvera import VeraBinarySensor
|
||||
import pyvera as pv
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .common import ComponentFactory
|
||||
from .common import ComponentFactory, new_simple_controller_config
|
||||
|
||||
|
||||
async def test_binary_sensor(
|
||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||
) -> None:
|
||||
"""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.vera_device_id = 1
|
||||
vera_device.name = "dev1"
|
||||
vera_device.is_tripped = False
|
||||
entity_id = "binary_sensor.dev1_1"
|
||||
|
||||
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 = controller.register.call_args_list[0][0][1]
|
||||
update_callback = component_data.controller_data.update_callback
|
||||
|
||||
vera_device.is_tripped = False
|
||||
update_callback(vera_device)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(entity_id).state == "off"
|
||||
controller.register.reset_mock()
|
||||
|
||||
vera_device.is_tripped = True
|
||||
update_callback(vera_device)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(entity_id).state == "on"
|
||||
controller.register.reset_mock()
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""Vera tests."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from pyvera import CATEGORY_THERMOSTAT, VeraController, VeraThermostat
|
||||
import pyvera as pv
|
||||
|
||||
from homeassistant.components.climate.const import (
|
||||
FAN_AUTO,
|
||||
@ -13,17 +13,17 @@ from homeassistant.components.climate.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .common import ComponentFactory
|
||||
from .common import ComponentFactory, new_simple_controller_config
|
||||
|
||||
|
||||
async def test_climate(
|
||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||
) -> None:
|
||||
"""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.name = "dev1"
|
||||
vera_device.category = CATEGORY_THERMOSTAT
|
||||
vera_device.category = pv.CATEGORY_THERMOSTAT
|
||||
vera_device.power = 10
|
||||
vera_device.get_current_temperature.return_value = 71
|
||||
vera_device.get_hvac_mode.return_value = "Off"
|
||||
@ -31,10 +31,10 @@ async def test_climate(
|
||||
entity_id = "climate.dev1_1"
|
||||
|
||||
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 = controller.register.call_args_list[0][0][1]
|
||||
update_callback = component_data.controller_data.update_callback
|
||||
|
||||
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
|
||||
) -> None:
|
||||
"""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.name = "dev1"
|
||||
vera_device.category = CATEGORY_THERMOSTAT
|
||||
vera_device.category = pv.CATEGORY_THERMOSTAT
|
||||
vera_device.power = 10
|
||||
vera_device.get_current_temperature.return_value = 71
|
||||
vera_device.get_hvac_mode.return_value = "Off"
|
||||
vera_device.get_current_goal_temperature.return_value = 72
|
||||
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"
|
||||
|
||||
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 = controller.register.call_args_list[0][0][1]
|
||||
update_callback = component_data.controller_data.update_callback
|
||||
|
||||
await hass.services.async_call(
|
||||
"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."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from pyvera import CATEGORY_CURTAIN, VeraCurtain
|
||||
import pyvera as pv
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .common import ComponentFactory
|
||||
from .common import ComponentFactory, new_simple_controller_config
|
||||
|
||||
|
||||
async def test_cover(
|
||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||
) -> None:
|
||||
"""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.name = "dev1"
|
||||
vera_device.category = CATEGORY_CURTAIN
|
||||
vera_device.category = pv.CATEGORY_CURTAIN
|
||||
vera_device.is_closed = False
|
||||
vera_device.get_level.return_value = 0
|
||||
entity_id = "cover.dev1_1"
|
||||
|
||||
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 = controller.register.call_args_list[0][0][1]
|
||||
update_callback = component_data.controller_data.update_callback
|
||||
|
||||
assert hass.states.get(entity_id).state == "closed"
|
||||
assert hass.states.get(entity_id).attributes["current_position"] == 0
|
||||
|
@ -1,78 +1,112 @@
|
||||
"""Vera tests."""
|
||||
from unittest.mock import MagicMock
|
||||
from asynctest import MagicMock
|
||||
import pyvera as pv
|
||||
from requests.exceptions import RequestException
|
||||
|
||||
from pyvera import (
|
||||
VeraArmableDevice,
|
||||
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.components.vera import CONF_CONTROLLER, DOMAIN
|
||||
from homeassistant.config_entries import ENTRY_STATE_NOT_LOADED
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .common import ComponentFactory
|
||||
from .common import ComponentFactory, new_simple_controller_config
|
||||
|
||||
|
||||
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
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_init(
|
||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||
) -> None:
|
||||
"""Test function."""
|
||||
|
||||
def setup_callback(controller: VeraController, hass_config: dict) -> None:
|
||||
hass_config[DOMAIN][CONF_EXCLUDE] = [11]
|
||||
hass_config[DOMAIN][CONF_LIGHTS] = [10]
|
||||
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,
|
||||
devices=(
|
||||
new_vera_device(VeraDimmer, 1),
|
||||
new_vera_device(VeraBinarySensor, 2),
|
||||
new_vera_device(VeraSensor, 3),
|
||||
new_vera_device(VeraArmableDevice, 4),
|
||||
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),
|
||||
controller_config=new_simple_controller_config(
|
||||
config={CONF_CONTROLLER: "http://127.0.0.1:111"},
|
||||
config_from_file=False,
|
||||
serial_number="first_serial",
|
||||
devices=(vera_device1,),
|
||||
),
|
||||
scenes=(MagicMock(spec=VeraScene),),
|
||||
setup_callback=setup_callback,
|
||||
)
|
||||
|
||||
assert_hass_vera_devices(hass, "light", 2)
|
||||
assert_hass_vera_devices(hass, "binary_sensor", 1)
|
||||
assert_hass_vera_devices(hass, "sensor", 2)
|
||||
assert_hass_vera_devices(hass, "switch", 2)
|
||||
assert_hass_vera_devices(hass, "lock", 1)
|
||||
assert_hass_vera_devices(hass, "climate", 1)
|
||||
assert_hass_vera_devices(hass, "cover", 1)
|
||||
entity_registry = await hass.helpers.entity_registry.async_get_registry()
|
||||
entry1 = entity_registry.async_get(entity1_id)
|
||||
|
||||
assert entry1
|
||||
|
||||
|
||||
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."""
|
||||
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.core import HomeAssistant
|
||||
|
||||
from .common import ComponentFactory
|
||||
from .common import ComponentFactory, new_simple_controller_config
|
||||
|
||||
|
||||
async def test_light(
|
||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||
) -> None:
|
||||
"""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.name = "dev1"
|
||||
vera_device.category = CATEGORY_DIMMER
|
||||
vera_device.category = pv.CATEGORY_DIMMER
|
||||
vera_device.is_switched_on = MagicMock(return_value=False)
|
||||
vera_device.get_brightness = MagicMock(return_value=0)
|
||||
vera_device.get_color = MagicMock(return_value=[0, 0, 0])
|
||||
@ -24,10 +24,10 @@ async def test_light(
|
||||
entity_id = "light.dev1_1"
|
||||
|
||||
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 = controller.register.call_args_list[0][0][1]
|
||||
update_callback = component_data.controller_data.update_callback
|
||||
|
||||
assert hass.states.get(entity_id).state == "off"
|
||||
|
||||
|
@ -1,30 +1,30 @@
|
||||
"""Vera tests."""
|
||||
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.core import HomeAssistant
|
||||
|
||||
from .common import ComponentFactory
|
||||
from .common import ComponentFactory, new_simple_controller_config
|
||||
|
||||
|
||||
async def test_lock(
|
||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||
) -> None:
|
||||
"""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.name = "dev1"
|
||||
vera_device.category = CATEGORY_LOCK
|
||||
vera_device.category = pv.CATEGORY_LOCK
|
||||
vera_device.is_locked = MagicMock(return_value=False)
|
||||
entity_id = "lock.dev1_1"
|
||||
|
||||
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 = controller.register.call_args_list[0][0][1]
|
||||
update_callback = component_data.controller_data.update_callback
|
||||
|
||||
assert hass.states.get(entity_id).state == STATE_UNLOCKED
|
||||
|
||||
|
@ -1,24 +1,24 @@
|
||||
"""Vera tests."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from pyvera import VeraScene
|
||||
import pyvera as pv
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .common import ComponentFactory
|
||||
from .common import ComponentFactory, new_simple_controller_config
|
||||
|
||||
|
||||
async def test_scene(
|
||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||
) -> None:
|
||||
"""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.name = "dev1"
|
||||
entity_id = "scene.dev1_1"
|
||||
|
||||
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(
|
||||
|
@ -2,21 +2,12 @@
|
||||
from typing import Any, Callable, Tuple
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from pyvera import (
|
||||
CATEGORY_HUMIDITY_SENSOR,
|
||||
CATEGORY_LIGHT_SENSOR,
|
||||
CATEGORY_POWER_METER,
|
||||
CATEGORY_SCENE_CONTROLLER,
|
||||
CATEGORY_TEMPERATURE_SENSOR,
|
||||
CATEGORY_UV_SENSOR,
|
||||
VeraController,
|
||||
VeraSensor,
|
||||
)
|
||||
import pyvera as pv
|
||||
|
||||
from homeassistant.const import UNIT_PERCENTAGE
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .common import ComponentFactory
|
||||
from .common import ComponentFactory, new_simple_controller_config
|
||||
|
||||
|
||||
async def run_sensor_test(
|
||||
@ -26,10 +17,10 @@ async def run_sensor_test(
|
||||
class_property: str,
|
||||
assert_states: Tuple[Tuple[Any, Any]],
|
||||
assert_unit_of_measurement: str = None,
|
||||
setup_callback: Callable[[VeraController], None] = None,
|
||||
setup_callback: Callable[[pv.VeraController], None] = None,
|
||||
) -> None:
|
||||
"""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.name = "dev1"
|
||||
vera_device.category = category
|
||||
@ -37,10 +28,12 @@ async def run_sensor_test(
|
||||
entity_id = "sensor.dev1_1"
|
||||
|
||||
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 = controller.register.call_args_list[0][0][1]
|
||||
update_callback = component_data.controller_data.update_callback
|
||||
|
||||
for (initial_value, state_value) in assert_states:
|
||||
setattr(vera_device, class_property, initial_value)
|
||||
@ -57,13 +50,13 @@ async def test_temperature_sensor_f(
|
||||
) -> None:
|
||||
"""Test function."""
|
||||
|
||||
def setup_callback(controller: VeraController, hass_config: dict) -> None:
|
||||
def setup_callback(controller: pv.VeraController) -> None:
|
||||
controller.temperature_units = "F"
|
||||
|
||||
await run_sensor_test(
|
||||
hass=hass,
|
||||
vera_component_factory=vera_component_factory,
|
||||
category=CATEGORY_TEMPERATURE_SENSOR,
|
||||
category=pv.CATEGORY_TEMPERATURE_SENSOR,
|
||||
class_property="temperature",
|
||||
assert_states=(("33", "1"), ("44", "7")),
|
||||
setup_callback=setup_callback,
|
||||
@ -77,7 +70,7 @@ async def test_temperature_sensor_c(
|
||||
await run_sensor_test(
|
||||
hass=hass,
|
||||
vera_component_factory=vera_component_factory,
|
||||
category=CATEGORY_TEMPERATURE_SENSOR,
|
||||
category=pv.CATEGORY_TEMPERATURE_SENSOR,
|
||||
class_property="temperature",
|
||||
assert_states=(("33", "33"), ("44", "44")),
|
||||
)
|
||||
@ -90,7 +83,7 @@ async def test_light_sensor(
|
||||
await run_sensor_test(
|
||||
hass=hass,
|
||||
vera_component_factory=vera_component_factory,
|
||||
category=CATEGORY_LIGHT_SENSOR,
|
||||
category=pv.CATEGORY_LIGHT_SENSOR,
|
||||
class_property="light",
|
||||
assert_states=(("12", "12"), ("13", "13")),
|
||||
assert_unit_of_measurement="lx",
|
||||
@ -104,7 +97,7 @@ async def test_uv_sensor(
|
||||
await run_sensor_test(
|
||||
hass=hass,
|
||||
vera_component_factory=vera_component_factory,
|
||||
category=CATEGORY_UV_SENSOR,
|
||||
category=pv.CATEGORY_UV_SENSOR,
|
||||
class_property="light",
|
||||
assert_states=(("12", "12"), ("13", "13")),
|
||||
assert_unit_of_measurement="level",
|
||||
@ -118,7 +111,7 @@ async def test_humidity_sensor(
|
||||
await run_sensor_test(
|
||||
hass=hass,
|
||||
vera_component_factory=vera_component_factory,
|
||||
category=CATEGORY_HUMIDITY_SENSOR,
|
||||
category=pv.CATEGORY_HUMIDITY_SENSOR,
|
||||
class_property="humidity",
|
||||
assert_states=(("12", "12"), ("13", "13")),
|
||||
assert_unit_of_measurement=UNIT_PERCENTAGE,
|
||||
@ -132,7 +125,7 @@ async def test_power_meter_sensor(
|
||||
await run_sensor_test(
|
||||
hass=hass,
|
||||
vera_component_factory=vera_component_factory,
|
||||
category=CATEGORY_POWER_METER,
|
||||
category=pv.CATEGORY_POWER_METER,
|
||||
class_property="power",
|
||||
assert_states=(("12", "12"), ("13", "13")),
|
||||
assert_unit_of_measurement="watts",
|
||||
@ -144,7 +137,7 @@ async def test_trippable_sensor(
|
||||
) -> None:
|
||||
"""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
|
||||
|
||||
await run_sensor_test(
|
||||
@ -162,7 +155,7 @@ async def test_unknown_sensor(
|
||||
) -> None:
|
||||
"""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
|
||||
|
||||
await run_sensor_test(
|
||||
@ -179,21 +172,21 @@ async def test_scene_controller_sensor(
|
||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||
) -> None:
|
||||
"""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.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_time = MagicMock(return_value="0000")
|
||||
entity_id = "sensor.dev1_1"
|
||||
|
||||
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 = controller.register.call_args_list[0][0][1]
|
||||
update_callback = component_data.controller_data.update_callback
|
||||
|
||||
vera_device.get_last_scene_time = "1111"
|
||||
vera_device.get_last_scene_time.return_value = "1111"
|
||||
update_callback(vera_device)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(entity_id).state == "id0"
|
||||
|
@ -1,29 +1,29 @@
|
||||
"""Vera tests."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from pyvera import CATEGORY_SWITCH, VeraSwitch
|
||||
import pyvera as pv
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .common import ComponentFactory
|
||||
from .common import ComponentFactory, new_simple_controller_config
|
||||
|
||||
|
||||
async def test_switch(
|
||||
hass: HomeAssistant, vera_component_factory: ComponentFactory
|
||||
) -> None:
|
||||
"""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.name = "dev1"
|
||||
vera_device.category = CATEGORY_SWITCH
|
||||
vera_device.category = pv.CATEGORY_SWITCH
|
||||
vera_device.is_switched_on = MagicMock(return_value=False)
|
||||
entity_id = "switch.dev1_1"
|
||||
|
||||
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 = controller.register.call_args_list[0][0][1]
|
||||
update_callback = component_data.controller_data.update_callback
|
||||
|
||||
assert hass.states.get(entity_id).state == "off"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user