Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions homeassistant/components/vera/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from homeassistant.util.dt import utc_from_timestamp

from .common import ControllerData, get_configured_platforms
from .config_flow import new_options
from .config_flow import fix_device_id_list, new_options
from .const import (
ATTR_CURRENT_ENERGY_KWH,
ATTR_CURRENT_POWER_W,
Expand Down Expand Up @@ -81,9 +81,18 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
),
)

saved_light_ids = config_entry.options.get(CONF_LIGHTS, [])
saved_exclude_ids = config_entry.options.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, [])
light_ids = fix_device_id_list(saved_light_ids)
exclude_ids = fix_device_id_list(saved_exclude_ids)

# If the ids were corrected. Update the config entry.
if light_ids != saved_light_ids or exclude_ids != saved_exclude_ids:
hass.config_entries.async_update_entry(
entry=config_entry, options=new_options(light_ids, exclude_ids)
)

# Initialize the Vera controller.
controller = veraApi.VeraController(base_url)
Expand Down
22 changes: 12 additions & 10 deletions homeassistant/components/vera/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Config flow for Vera."""
import logging
import re
from typing import List, cast
from typing import Any, List

import pyvera as pv
from requests.exceptions import RequestException
Expand All @@ -17,20 +17,22 @@
_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)
def fix_device_id_list(data: List[Any]) -> List[int]:
"""Fix the id list by converting it to a supported int list."""
return str_to_int_list(list_to_str(data))


return [s for s in LIST_REGEX.split(data) if len(s) > 0]
def str_to_int_list(data: str) -> List[int]:
"""Convert a string to an int list."""
return [int(s) for s in LIST_REGEX.split(data) if len(s) > 0]


def int_list_to_str(data: List[str]) -> str:
def list_to_str(data: List[Any]) -> 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:
def new_options(lights: List[int], exclude: List[int]) -> dict:
"""Create a standard options object."""
return {CONF_LIGHTS: lights, CONF_EXCLUDE: exclude}

Expand All @@ -40,10 +42,10 @@ def options_schema(options: dict = None) -> dict:
options = options or {}
return {
vol.Optional(
CONF_LIGHTS, default=int_list_to_str(options.get(CONF_LIGHTS, [])),
CONF_LIGHTS, default=list_to_str(options.get(CONF_LIGHTS, [])),
): str,
vol.Optional(
CONF_EXCLUDE, default=int_list_to_str(options.get(CONF_EXCLUDE, [])),
CONF_EXCLUDE, default=list_to_str(options.get(CONF_EXCLUDE, [])),
): str,
}

Expand Down
8 changes: 4 additions & 4 deletions tests/components/vera/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ async def test_async_step_user_success(hass: HomeAssistant) -> None:
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"],
CONF_LIGHTS: [12, 13],
CONF_EXCLUDE: [14, 15],
}
assert result["result"].unique_id == controller.serial_number

Expand Down Expand Up @@ -154,6 +154,6 @@ async def test_options(hass):
)
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"],
CONF_LIGHTS: [1, 2, 3, 4, 5, 6, 7],
CONF_EXCLUDE: [8, 9, 10, 11, 12, 13, 14],
}
76 changes: 75 additions & 1 deletion tests/components/vera/test_init.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
"""Vera tests."""
import pytest
import pyvera as pv
from requests.exceptions import RequestException

from homeassistant.components.vera import CONF_CONTROLLER, DOMAIN
from homeassistant.components.vera import (
CONF_CONTROLLER,
CONF_EXCLUDE,
CONF_LIGHTS,
DOMAIN,
)
from homeassistant.config_entries import ENTRY_STATE_NOT_LOADED
from homeassistant.core import HomeAssistant

Expand Down Expand Up @@ -110,3 +116,71 @@ def setup_callback(controller: pv.VeraController) -> None:
entry.add_to_hass(hass)

assert not await hass.config_entries.async_setup(entry.entry_id)


@pytest.mark.parametrize(
["options"],
[
[{CONF_LIGHTS: [4, 10, 12, "AAA"], CONF_EXCLUDE: [1, "BBB"]}],
[{CONF_LIGHTS: ["4", "10", "12", "AAA"], CONF_EXCLUDE: ["1", "BBB"]}],
],
)
async def test_exclude_and_light_ids(
hass: HomeAssistant, vera_component_factory: ComponentFactory, options
) -> None:
"""Test device exclusion, marking switches as lights and fixing the data type."""
vera_device1 = MagicMock(spec=pv.VeraBinarySensor) # type: pv.VeraBinarySensor
vera_device1.device_id = 1
vera_device1.vera_device_id = 1
vera_device1.name = "dev1"
vera_device1.is_tripped = False
entity_id1 = "binary_sensor.dev1_1"

vera_device2 = MagicMock(spec=pv.VeraBinarySensor) # type: pv.VeraBinarySensor
vera_device2.device_id = 2
vera_device2.vera_device_id = 2
vera_device2.name = "dev2"
vera_device2.is_tripped = False
entity_id2 = "binary_sensor.dev2_2"

vera_device3 = MagicMock(spec=pv.VeraSwitch) # type: pv.VeraSwitch
vera_device3.device_id = 3
vera_device3.name = "dev3"
vera_device3.category = pv.CATEGORY_SWITCH
vera_device3.is_switched_on = MagicMock(return_value=False)
entity_id3 = "switch.dev3_3"

vera_device4 = MagicMock(spec=pv.VeraSwitch) # type: pv.VeraSwitch
vera_device4.device_id = 4
vera_device4.name = "dev4"
vera_device4.category = pv.CATEGORY_SWITCH
vera_device4.is_switched_on = MagicMock(return_value=False)
entity_id4 = "light.dev4_4"

component_data = await vera_component_factory.configure_component(
hass=hass,
controller_config=new_simple_controller_config(
devices=(vera_device1, vera_device2, vera_device3, vera_device4),
config={**{CONF_CONTROLLER: "http://127.0.0.1:123"}, **options},
),
)

# Assert the entries were setup correctly.
config_entry = next(iter(hass.config_entries.async_entries(DOMAIN)))
assert config_entry.options == {
CONF_LIGHTS: [4, 10, 12],
CONF_EXCLUDE: [1],
}

update_callback = component_data.controller_data.update_callback

update_callback(vera_device1)
update_callback(vera_device2)
update_callback(vera_device3)
update_callback(vera_device4)
await hass.async_block_till_done()

assert hass.states.get(entity_id1) is None
assert hass.states.get(entity_id2) is not None
assert hass.states.get(entity_id3) is not None
assert hass.states.get(entity_id4) is not None