diff --git a/.coveragerc b/.coveragerc index 778af8db89a..e85c97ef80c 100644 --- a/.coveragerc +++ b/.coveragerc @@ -750,7 +750,6 @@ omit = homeassistant/components/velbus/switch.py homeassistant/components/velux/* homeassistant/components/venstar/climate.py - homeassistant/components/vera/* homeassistant/components/verisure/* homeassistant/components/versasense/* homeassistant/components/vesync/__init__.py diff --git a/homeassistant/components/vera/climate.py b/homeassistant/components/vera/climate.py index 50c897d0fc1..60e73d48978 100644 --- a/homeassistant/components/vera/climate.py +++ b/homeassistant/components/vera/climate.py @@ -92,6 +92,8 @@ class VeraThermostat(VeraDevice, ClimateDevice): else: self.vera_device.fan_auto() + self.schedule_update_ha_state() + @property def current_power_w(self): """Return the current power usage in W.""" @@ -129,6 +131,8 @@ class VeraThermostat(VeraDevice, ClimateDevice): if kwargs.get(ATTR_TEMPERATURE) is not None: self.vera_device.set_temperature(kwargs.get(ATTR_TEMPERATURE)) + self.schedule_update_ha_state() + def set_hvac_mode(self, hvac_mode): """Set new target hvac mode.""" if hvac_mode == HVAC_MODE_OFF: @@ -139,3 +143,5 @@ class VeraThermostat(VeraDevice, ClimateDevice): self.vera_device.turn_cool_on() elif hvac_mode == HVAC_MODE_HEAT: self.vera_device.turn_heat_on() + + self.schedule_update_ha_state() diff --git a/homeassistant/components/vera/manifest.json b/homeassistant/components/vera/manifest.json index 120ec241d60..70abc098431 100644 --- a/homeassistant/components/vera/manifest.json +++ b/homeassistant/components/vera/manifest.json @@ -3,7 +3,7 @@ "name": "Vera", "documentation": "https://www.home-assistant.io/integrations/vera", "requirements": [ - "pyvera==0.3.6" + "pyvera==0.3.7" ], "dependencies": [], "codeowners": [] diff --git a/requirements_all.txt b/requirements_all.txt index 360898df055..87ca2a46177 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1670,7 +1670,7 @@ pyuptimerobot==0.0.5 # pyuserinput==0.1.11 # homeassistant.components.vera -pyvera==0.3.6 +pyvera==0.3.7 # homeassistant.components.versasense pyversasense==0.0.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index fff9af5b32d..405e632c0cc 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -536,6 +536,9 @@ pytraccar==0.9.0 # homeassistant.components.tradfri pytradfri[async]==6.4.0 +# homeassistant.components.vera +pyvera==0.3.7 + # homeassistant.components.vesync pyvesync==1.1.0 diff --git a/tests/components/vera/__init__.py b/tests/components/vera/__init__.py new file mode 100644 index 00000000000..4e0919be042 --- /dev/null +++ b/tests/components/vera/__init__.py @@ -0,0 +1 @@ +"""Tests for the Vera component.""" diff --git a/tests/components/vera/common.py b/tests/components/vera/common.py new file mode 100644 index 00000000000..d78a536e95c --- /dev/null +++ b/tests/components/vera/common.py @@ -0,0 +1,61 @@ +"""Common code for tests.""" + +from typing import Callable, NamedTuple, Tuple + +from mock import MagicMock +from pyvera import VeraController, VeraDevice, VeraScene + +from homeassistant.components.vera import CONF_CONTROLLER, DOMAIN +from homeassistant.core import HomeAssistant +from homeassistant.setup import async_setup_component + +ComponentData = NamedTuple("ComponentData", (("controller", VeraController),)) + + +class ComponentFactory: + """Factory class.""" + + def __init__(self, init_controller_mock): + """Constructor.""" + self.init_controller_mock = init_controller_mock + + async def configure_component( + self, + hass: HomeAssistant, + devices: Tuple[VeraDevice] = (), + scenes: Tuple[VeraScene] = (), + setup_callback: Callable[[VeraController], None] = None, + ) -> ComponentData: + """Configure the component with specific mock data.""" + controller_url = "http://127.0.0.1:123" + + hass_config = { + DOMAIN: {CONF_CONTROLLER: controller_url}, + } + + controller = MagicMock(spec=VeraController) # type: VeraController + controller.base_url = controller_url + controller.register = MagicMock() + controller.get_devices = MagicMock(return_value=devices or ()) + controller.get_scenes = MagicMock(return_value=scenes or ()) + + for vera_obj in controller.get_devices() + controller.get_scenes(): + vera_obj.vera_controller = controller + + controller.get_devices.reset_mock() + controller.get_scenes.reset_mock() + + if setup_callback: + setup_callback(controller, hass_config) + + def init_controller(base_url: str) -> list: + nonlocal controller + return [controller, True] + + self.init_controller_mock.side_effect = init_controller + + # Setup home assistant. + assert await async_setup_component(hass, DOMAIN, hass_config) + await hass.async_block_till_done() + + return ComponentData(controller=controller) diff --git a/tests/components/vera/conftest.py b/tests/components/vera/conftest.py new file mode 100644 index 00000000000..b94a40135d8 --- /dev/null +++ b/tests/components/vera/conftest.py @@ -0,0 +1,13 @@ +"""Fixtures for tests.""" + +from mock import patch +import pytest + +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) diff --git a/tests/components/vera/test_binary_sensor.py b/tests/components/vera/test_binary_sensor.py new file mode 100644 index 00000000000..2c2e2b86388 --- /dev/null +++ b/tests/components/vera/test_binary_sensor.py @@ -0,0 +1,38 @@ +"""Vera tests.""" +from unittest.mock import MagicMock + +from pyvera import VeraBinarySensor + +from homeassistant.core import HomeAssistant + +from .common import ComponentFactory + + +async def test_binary_sensor( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + vera_device = MagicMock(spec=VeraBinarySensor) # type: VeraBinarySensor + vera_device.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,) + ) + controller = component_data.controller + + update_callback = controller.register.call_args_list[0][0][1] + + 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() diff --git a/tests/components/vera/test_climate.py b/tests/components/vera/test_climate.py new file mode 100644 index 00000000000..c27a72865fd --- /dev/null +++ b/tests/components/vera/test_climate.py @@ -0,0 +1,155 @@ +"""Vera tests.""" +from unittest.mock import MagicMock + +from pyvera import CATEGORY_THERMOSTAT, VeraController, VeraThermostat + +from homeassistant.components.climate.const import ( + FAN_AUTO, + FAN_ON, + HVAC_MODE_COOL, + HVAC_MODE_HEAT, + HVAC_MODE_HEAT_COOL, + HVAC_MODE_OFF, +) +from homeassistant.core import HomeAssistant + +from .common import ComponentFactory + + +async def test_climate( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + vera_device = MagicMock(spec=VeraThermostat) # type: VeraThermostat + vera_device.device_id = 1 + vera_device.name = "dev1" + vera_device.category = 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" + + component_data = await vera_component_factory.configure_component( + hass=hass, devices=(vera_device,), + ) + controller = component_data.controller + update_callback = controller.register.call_args_list[0][0][1] + + assert hass.states.get(entity_id).state == HVAC_MODE_OFF + + await hass.services.async_call( + "climate", + "set_hvac_mode", + {"entity_id": entity_id, "hvac_mode": HVAC_MODE_COOL}, + ) + await hass.async_block_till_done() + vera_device.turn_cool_on.assert_called() + vera_device.get_hvac_mode.return_value = "CoolOn" + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == HVAC_MODE_COOL + + await hass.services.async_call( + "climate", + "set_hvac_mode", + {"entity_id": entity_id, "hvac_mode": HVAC_MODE_HEAT}, + ) + await hass.async_block_till_done() + vera_device.turn_heat_on.assert_called() + vera_device.get_hvac_mode.return_value = "HeatOn" + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == HVAC_MODE_HEAT + + await hass.services.async_call( + "climate", + "set_hvac_mode", + {"entity_id": entity_id, "hvac_mode": HVAC_MODE_HEAT_COOL}, + ) + await hass.async_block_till_done() + vera_device.turn_auto_on.assert_called() + vera_device.get_hvac_mode.return_value = "AutoChangeOver" + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == HVAC_MODE_HEAT_COOL + + await hass.services.async_call( + "climate", + "set_hvac_mode", + {"entity_id": entity_id, "hvac_mode": HVAC_MODE_OFF}, + ) + await hass.async_block_till_done() + vera_device.turn_auto_on.assert_called() + vera_device.get_hvac_mode.return_value = "Off" + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == HVAC_MODE_OFF + + await hass.services.async_call( + "climate", "set_fan_mode", {"entity_id": entity_id, "fan_mode": "on"}, + ) + await hass.async_block_till_done() + vera_device.turn_auto_on.assert_called() + vera_device.get_fan_mode.return_value = "ContinuousOn" + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).attributes["fan_mode"] == FAN_ON + + await hass.services.async_call( + "climate", "set_fan_mode", {"entity_id": entity_id, "fan_mode": "off"}, + ) + await hass.async_block_till_done() + vera_device.turn_auto_on.assert_called() + vera_device.get_fan_mode.return_value = "Auto" + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).attributes["fan_mode"] == FAN_AUTO + + await hass.services.async_call( + "climate", "set_temperature", {"entity_id": entity_id, "temperature": 30}, + ) + await hass.async_block_till_done() + vera_device.set_temperature.assert_called_with(30) + vera_device.get_current_goal_temperature.return_value = 30 + vera_device.get_current_temperature.return_value = 25 + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).attributes["current_temperature"] == 25 + assert hass.states.get(entity_id).attributes["temperature"] == 30 + + +async def test_climate_f( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + vera_device = MagicMock(spec=VeraThermostat) # type: VeraThermostat + vera_device.device_id = 1 + vera_device.name = "dev1" + vera_device.category = 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: + controller.temperature_units = "F" + + component_data = await vera_component_factory.configure_component( + hass=hass, devices=(vera_device,), setup_callback=setup_callback + ) + controller = component_data.controller + update_callback = controller.register.call_args_list[0][0][1] + + await hass.services.async_call( + "climate", "set_temperature", {"entity_id": entity_id, "temperature": 30}, + ) + await hass.async_block_till_done() + vera_device.set_temperature.assert_called_with(86) + vera_device.get_current_goal_temperature.return_value = 30 + vera_device.get_current_temperature.return_value = 25 + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).attributes["current_temperature"] == -3.9 + assert hass.states.get(entity_id).attributes["temperature"] == -1.1 diff --git a/tests/components/vera/test_cover.py b/tests/components/vera/test_cover.py new file mode 100644 index 00000000000..79cb4adedfb --- /dev/null +++ b/tests/components/vera/test_cover.py @@ -0,0 +1,76 @@ +"""Vera tests.""" +from unittest.mock import MagicMock + +from pyvera import CATEGORY_CURTAIN, VeraCurtain + +from homeassistant.core import HomeAssistant + +from .common import ComponentFactory + + +async def test_cover( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + vera_device = MagicMock(spec=VeraCurtain) # type: VeraCurtain + vera_device.device_id = 1 + vera_device.name = "dev1" + vera_device.category = 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,), + ) + controller = component_data.controller + update_callback = controller.register.call_args_list[0][0][1] + + assert hass.states.get(entity_id).state == "closed" + assert hass.states.get(entity_id).attributes["current_position"] == 0 + + await hass.services.async_call( + "cover", "open_cover", {"entity_id": entity_id}, + ) + await hass.async_block_till_done() + vera_device.open.assert_called() + vera_device.is_open.return_value = True + vera_device.get_level.return_value = 100 + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == "open" + assert hass.states.get(entity_id).attributes["current_position"] == 100 + + await hass.services.async_call( + "cover", "set_cover_position", {"entity_id": entity_id, "position": 50}, + ) + await hass.async_block_till_done() + vera_device.set_level.assert_called_with(50) + vera_device.is_open.return_value = True + vera_device.get_level.return_value = 50 + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == "open" + assert hass.states.get(entity_id).attributes["current_position"] == 50 + + await hass.services.async_call( + "cover", "stop_cover", {"entity_id": entity_id}, + ) + await hass.async_block_till_done() + vera_device.stop.assert_called() + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == "open" + assert hass.states.get(entity_id).attributes["current_position"] == 50 + + await hass.services.async_call( + "cover", "close_cover", {"entity_id": entity_id}, + ) + await hass.async_block_till_done() + vera_device.close.assert_called() + vera_device.is_open.return_value = False + vera_device.get_level.return_value = 00 + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == "closed" + assert hass.states.get(entity_id).attributes["current_position"] == 00 diff --git a/tests/components/vera/test_init.py b/tests/components/vera/test_init.py new file mode 100644 index 00000000000..9ff6cb4058b --- /dev/null +++ b/tests/components/vera/test_init.py @@ -0,0 +1,78 @@ +"""Vera tests.""" +from unittest.mock import MagicMock + +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.core import HomeAssistant + +from .common import ComponentFactory + + +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( + 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] + + 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), + ), + 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) diff --git a/tests/components/vera/test_light.py b/tests/components/vera/test_light.py new file mode 100644 index 00000000000..fa63ce63454 --- /dev/null +++ b/tests/components/vera/test_light.py @@ -0,0 +1,76 @@ +"""Vera tests.""" +from unittest.mock import MagicMock + +from pyvera import CATEGORY_DIMMER, VeraDimmer + +from homeassistant.components.light import ATTR_BRIGHTNESS, ATTR_HS_COLOR +from homeassistant.core import HomeAssistant + +from .common import ComponentFactory + + +async def test_light( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + vera_device = MagicMock(spec=VeraDimmer) # type: VeraDimmer + vera_device.device_id = 1 + vera_device.name = "dev1" + vera_device.category = 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]) + vera_device.is_dimmable = True + entity_id = "light.dev1_1" + + component_data = await vera_component_factory.configure_component( + hass=hass, devices=(vera_device,), + ) + controller = component_data.controller + update_callback = controller.register.call_args_list[0][0][1] + + assert hass.states.get(entity_id).state == "off" + + await hass.services.async_call( + "light", "turn_on", {"entity_id": entity_id}, + ) + await hass.async_block_till_done() + vera_device.switch_on.assert_called() + vera_device.is_switched_on.return_value = True + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == "on" + + await hass.services.async_call( + "light", "turn_on", {"entity_id": entity_id, ATTR_HS_COLOR: [300, 70]}, + ) + await hass.async_block_till_done() + vera_device.set_color.assert_called_with((255, 76, 255)) + vera_device.is_switched_on.return_value = True + vera_device.get_color.return_value = (255, 76, 255) + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == "on" + assert hass.states.get(entity_id).attributes["hs_color"] == (300.0, 70.196) + + await hass.services.async_call( + "light", "turn_on", {"entity_id": entity_id, ATTR_BRIGHTNESS: 55}, + ) + await hass.async_block_till_done() + vera_device.set_brightness.assert_called_with(55) + vera_device.is_switched_on.return_value = True + vera_device.get_brightness.return_value = 55 + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == "on" + assert hass.states.get(entity_id).attributes["brightness"] == 55 + + await hass.services.async_call( + "light", "turn_off", {"entity_id": entity_id}, + ) + await hass.async_block_till_done() + vera_device.switch_off.assert_called() + vera_device.is_switched_on.return_value = False + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == "off" diff --git a/tests/components/vera/test_lock.py b/tests/components/vera/test_lock.py new file mode 100644 index 00000000000..362bdbeddc0 --- /dev/null +++ b/tests/components/vera/test_lock.py @@ -0,0 +1,49 @@ +"""Vera tests.""" +from unittest.mock import MagicMock + +from pyvera import CATEGORY_LOCK, VeraLock + +from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED +from homeassistant.core import HomeAssistant + +from .common import ComponentFactory + + +async def test_lock( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + vera_device = MagicMock(spec=VeraLock) # type: VeraLock + vera_device.device_id = 1 + vera_device.name = "dev1" + vera_device.category = 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,), + ) + controller = component_data.controller + update_callback = controller.register.call_args_list[0][0][1] + + assert hass.states.get(entity_id).state == STATE_UNLOCKED + + await hass.services.async_call( + "lock", "lock", {"entity_id": entity_id}, + ) + await hass.async_block_till_done() + vera_device.lock.assert_called() + vera_device.is_locked.return_value = True + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == STATE_LOCKED + + await hass.services.async_call( + "lock", "unlock", {"entity_id": entity_id}, + ) + await hass.async_block_till_done() + vera_device.unlock.assert_called() + vera_device.is_locked.return_value = False + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == STATE_UNLOCKED diff --git a/tests/components/vera/test_scene.py b/tests/components/vera/test_scene.py new file mode 100644 index 00000000000..136227ffa71 --- /dev/null +++ b/tests/components/vera/test_scene.py @@ -0,0 +1,27 @@ +"""Vera tests.""" +from unittest.mock import MagicMock + +from pyvera import VeraScene + +from homeassistant.core import HomeAssistant + +from .common import ComponentFactory + + +async def test_scene( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + vera_scene = MagicMock(spec=VeraScene) # type: 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,), + ) + + await hass.services.async_call( + "scene", "turn_on", {"entity_id": entity_id}, + ) + await hass.async_block_till_done() diff --git a/tests/components/vera/test_sensor.py b/tests/components/vera/test_sensor.py new file mode 100644 index 00000000000..da28fc225e0 --- /dev/null +++ b/tests/components/vera/test_sensor.py @@ -0,0 +1,198 @@ +"""Vera tests.""" +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, +) + +from homeassistant.core import HomeAssistant + +from .common import ComponentFactory + + +async def run_sensor_test( + hass: HomeAssistant, + vera_component_factory: ComponentFactory, + category: int, + class_property: str, + assert_states: Tuple[Tuple[Any, Any]], + assert_unit_of_measurement: str = None, + setup_callback: Callable[[VeraController], None] = None, +) -> None: + """Test generic sensor.""" + vera_device = MagicMock(spec=VeraSensor) # type: VeraSensor + vera_device.device_id = 1 + vera_device.name = "dev1" + vera_device.category = category + setattr(vera_device, class_property, "33") + entity_id = "sensor.dev1_1" + + component_data = await vera_component_factory.configure_component( + hass=hass, devices=(vera_device,), setup_callback=setup_callback + ) + controller = component_data.controller + update_callback = controller.register.call_args_list[0][0][1] + + for (initial_value, state_value) in assert_states: + setattr(vera_device, class_property, initial_value) + update_callback(vera_device) + await hass.async_block_till_done() + state = hass.states.get(entity_id) + assert state.state == state_value + if assert_unit_of_measurement: + assert state.attributes["unit_of_measurement"] == assert_unit_of_measurement + + +async def test_temperature_sensor_f( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + + def setup_callback(controller: VeraController, hass_config: dict) -> None: + controller.temperature_units = "F" + + await run_sensor_test( + hass=hass, + vera_component_factory=vera_component_factory, + category=CATEGORY_TEMPERATURE_SENSOR, + class_property="temperature", + assert_states=(("33", "1"), ("44", "7"),), + setup_callback=setup_callback, + ) + + +async def test_temperature_sensor_c( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + await run_sensor_test( + hass=hass, + vera_component_factory=vera_component_factory, + category=CATEGORY_TEMPERATURE_SENSOR, + class_property="temperature", + assert_states=(("33", "33"), ("44", "44"),), + ) + + +async def test_light_sensor( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + await run_sensor_test( + hass=hass, + vera_component_factory=vera_component_factory, + category=CATEGORY_LIGHT_SENSOR, + class_property="light", + assert_states=(("12", "12"), ("13", "13"),), + assert_unit_of_measurement="lx", + ) + + +async def test_uv_sensor( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + await run_sensor_test( + hass=hass, + vera_component_factory=vera_component_factory, + category=CATEGORY_UV_SENSOR, + class_property="light", + assert_states=(("12", "12"), ("13", "13"),), + assert_unit_of_measurement="level", + ) + + +async def test_humidity_sensor( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + await run_sensor_test( + hass=hass, + vera_component_factory=vera_component_factory, + category=CATEGORY_HUMIDITY_SENSOR, + class_property="humidity", + assert_states=(("12", "12"), ("13", "13"),), + assert_unit_of_measurement="%", + ) + + +async def test_power_meter_sensor( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + await run_sensor_test( + hass=hass, + vera_component_factory=vera_component_factory, + category=CATEGORY_POWER_METER, + class_property="power", + assert_states=(("12", "12"), ("13", "13"),), + assert_unit_of_measurement="watts", + ) + + +async def test_trippable_sensor( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + + def setup_callback(controller: VeraController, hass_config: dict) -> None: + controller.get_devices()[0].is_trippable = True + + await run_sensor_test( + hass=hass, + vera_component_factory=vera_component_factory, + category=999, + class_property="is_tripped", + assert_states=((True, "Tripped"), (False, "Not Tripped"), (True, "Tripped"),), + setup_callback=setup_callback, + ) + + +async def test_unknown_sensor( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + + def setup_callback(controller: VeraController, hass_config: dict) -> None: + controller.get_devices()[0].is_trippable = False + + await run_sensor_test( + hass=hass, + vera_component_factory=vera_component_factory, + category=999, + class_property="is_tripped", + assert_states=((True, "Unknown"), (False, "Unknown"), (True, "Unknown"),), + setup_callback=setup_callback, + ) + + +async def test_scene_controller_sensor( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + vera_device = MagicMock(spec=VeraSensor) # type: VeraSensor + vera_device.device_id = 1 + vera_device.name = "dev1" + vera_device.category = 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,), + ) + controller = component_data.controller + update_callback = controller.register.call_args_list[0][0][1] + + vera_device.get_last_scene_time = "1111" + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == "id0" diff --git a/tests/components/vera/test_switch.py b/tests/components/vera/test_switch.py new file mode 100644 index 00000000000..ba09068e7e6 --- /dev/null +++ b/tests/components/vera/test_switch.py @@ -0,0 +1,48 @@ +"""Vera tests.""" +from unittest.mock import MagicMock + +from pyvera import CATEGORY_SWITCH, VeraSwitch + +from homeassistant.core import HomeAssistant + +from .common import ComponentFactory + + +async def test_switch( + hass: HomeAssistant, vera_component_factory: ComponentFactory +) -> None: + """Test function.""" + vera_device = MagicMock(spec=VeraSwitch) # type: VeraSwitch + vera_device.device_id = 1 + vera_device.name = "dev1" + vera_device.category = 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,), + ) + controller = component_data.controller + update_callback = controller.register.call_args_list[0][0][1] + + assert hass.states.get(entity_id).state == "off" + + await hass.services.async_call( + "switch", "turn_on", {"entity_id": entity_id}, + ) + await hass.async_block_till_done() + vera_device.switch_on.assert_called() + vera_device.is_switched_on.return_value = True + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == "on" + + await hass.services.async_call( + "switch", "turn_off", {"entity_id": entity_id}, + ) + await hass.async_block_till_done() + vera_device.switch_off.assert_called() + vera_device.is_switched_on.return_value = False + update_callback(vera_device) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == "off"