Fix vera config ids not being converted to integers (#35070)

This commit is contained in:
Robert Van Gorkom 2020-05-02 14:10:49 -07:00 committed by GitHub
parent 88b7aba1c8
commit ab08c1bef8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 103 additions and 18 deletions

View File

@ -25,7 +25,7 @@ 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 .config_flow import fix_device_id_list, new_options
from .const import (
ATTR_CURRENT_ENERGY_KWH,
ATTR_CURRENT_POWER_W,
@ -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)

View File

@ -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
@ -17,20 +17,22 @@ LIST_REGEX = re.compile("[^0-9]+")
_LOGGER = logging.getLogger(__name__)
def str_to_int_list(data: str) -> List[str]:
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))
def str_to_int_list(data: str) -> List[int]:
"""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]
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}
@ -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,
}

View File

@ -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
@ -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],
}

View File

@ -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
@ -110,3 +116,71 @@ async def test_async_setup_entry_error(
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