Allow removal of sensor settings in scrape (#90412)
* Allow removal of sensor settings in scrape * Adjust * Adjust * Add comment * Simplify * Simplify * Adjust * Don't allow empty string * Only allow None * Use default as None * Use sentinel "none" * Not needed * Adjust unit of measurement * Add translation keys for "none" * Use translations * Sort * Add enum and timestamp * Use translation references * Remove default and set suggested_values * Disallow enum device class * Adjust tests * Adjust _strip_sentinelpull/90579/head
parent
ea32cc5d92
commit
4f54e33f67
|
@ -95,6 +95,8 @@ RESOURCE_SETUP = {
|
||||||
vol.Optional(CONF_ENCODING, default=DEFAULT_ENCODING): TextSelector(),
|
vol.Optional(CONF_ENCODING, default=DEFAULT_ENCODING): TextSelector(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NONE_SENTINEL = "none"
|
||||||
|
|
||||||
SENSOR_SETUP = {
|
SENSOR_SETUP = {
|
||||||
vol.Required(CONF_SELECT): TextSelector(),
|
vol.Required(CONF_SELECT): TextSelector(),
|
||||||
vol.Optional(CONF_INDEX, default=0): NumberSelector(
|
vol.Optional(CONF_INDEX, default=0): NumberSelector(
|
||||||
|
@ -102,28 +104,45 @@ SENSOR_SETUP = {
|
||||||
),
|
),
|
||||||
vol.Optional(CONF_ATTRIBUTE): TextSelector(),
|
vol.Optional(CONF_ATTRIBUTE): TextSelector(),
|
||||||
vol.Optional(CONF_VALUE_TEMPLATE): TemplateSelector(),
|
vol.Optional(CONF_VALUE_TEMPLATE): TemplateSelector(),
|
||||||
vol.Optional(CONF_DEVICE_CLASS): SelectSelector(
|
vol.Required(CONF_DEVICE_CLASS): SelectSelector(
|
||||||
SelectSelectorConfig(
|
SelectSelectorConfig(
|
||||||
options=[cls.value for cls in SensorDeviceClass],
|
options=[NONE_SENTINEL]
|
||||||
|
+ sorted(
|
||||||
|
[
|
||||||
|
cls.value
|
||||||
|
for cls in SensorDeviceClass
|
||||||
|
if cls != SensorDeviceClass.ENUM
|
||||||
|
]
|
||||||
|
),
|
||||||
mode=SelectSelectorMode.DROPDOWN,
|
mode=SelectSelectorMode.DROPDOWN,
|
||||||
|
translation_key="device_class",
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
vol.Optional(CONF_STATE_CLASS): SelectSelector(
|
vol.Required(CONF_STATE_CLASS): SelectSelector(
|
||||||
SelectSelectorConfig(
|
SelectSelectorConfig(
|
||||||
options=[cls.value for cls in SensorStateClass],
|
options=[NONE_SENTINEL] + sorted([cls.value for cls in SensorStateClass]),
|
||||||
mode=SelectSelectorMode.DROPDOWN,
|
mode=SelectSelectorMode.DROPDOWN,
|
||||||
|
translation_key="state_class",
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
vol.Optional(CONF_UNIT_OF_MEASUREMENT): SelectSelector(
|
vol.Required(CONF_UNIT_OF_MEASUREMENT): SelectSelector(
|
||||||
SelectSelectorConfig(
|
SelectSelectorConfig(
|
||||||
options=[cls.value for cls in UnitOfTemperature],
|
options=[NONE_SENTINEL] + sorted([cls.value for cls in UnitOfTemperature]),
|
||||||
custom_value=True,
|
custom_value=True,
|
||||||
mode=SelectSelectorMode.DROPDOWN,
|
mode=SelectSelectorMode.DROPDOWN,
|
||||||
|
translation_key="unit_of_measurement",
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_sentinel(options: dict[str, Any]) -> None:
|
||||||
|
"""Convert sentinel to None."""
|
||||||
|
for key in (CONF_DEVICE_CLASS, CONF_STATE_CLASS, CONF_UNIT_OF_MEASUREMENT):
|
||||||
|
if options[key] == NONE_SENTINEL:
|
||||||
|
options.pop(key)
|
||||||
|
|
||||||
|
|
||||||
async def validate_rest_setup(
|
async def validate_rest_setup(
|
||||||
handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
|
handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
|
@ -150,6 +169,7 @@ async def validate_sensor_setup(
|
||||||
# Standard behavior is to merge the result with the options.
|
# Standard behavior is to merge the result with the options.
|
||||||
# In this case, we want to add a sub-item so we update the options directly.
|
# In this case, we want to add a sub-item so we update the options directly.
|
||||||
sensors: list[dict[str, Any]] = handler.options.setdefault(SENSOR_DOMAIN, [])
|
sensors: list[dict[str, Any]] = handler.options.setdefault(SENSOR_DOMAIN, [])
|
||||||
|
_strip_sentinel(user_input)
|
||||||
sensors.append(user_input)
|
sensors.append(user_input)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
@ -181,7 +201,11 @@ async def get_edit_sensor_suggested_values(
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Return suggested values for sensor editing."""
|
"""Return suggested values for sensor editing."""
|
||||||
idx: int = handler.flow_state["_idx"]
|
idx: int = handler.flow_state["_idx"]
|
||||||
return cast(dict[str, Any], handler.options[SENSOR_DOMAIN][idx])
|
suggested_values: dict[str, Any] = dict(handler.options[SENSOR_DOMAIN][idx])
|
||||||
|
for key in (CONF_DEVICE_CLASS, CONF_STATE_CLASS, CONF_UNIT_OF_MEASUREMENT):
|
||||||
|
if not suggested_values.get(key):
|
||||||
|
suggested_values[key] = NONE_SENTINEL
|
||||||
|
return suggested_values
|
||||||
|
|
||||||
|
|
||||||
async def validate_sensor_edit(
|
async def validate_sensor_edit(
|
||||||
|
@ -194,6 +218,7 @@ async def validate_sensor_edit(
|
||||||
# In this case, we want to add a sub-item so we update the options directly.
|
# In this case, we want to add a sub-item so we update the options directly.
|
||||||
idx: int = handler.flow_state["_idx"]
|
idx: int = handler.flow_state["_idx"]
|
||||||
handler.options[SENSOR_DOMAIN][idx].update(user_input)
|
handler.options[SENSOR_DOMAIN][idx].update(user_input)
|
||||||
|
_strip_sentinel(handler.options[SENSOR_DOMAIN][idx])
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -125,5 +125,72 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"selector": {
|
||||||
|
"device_class": {
|
||||||
|
"options": {
|
||||||
|
"none": "No device class",
|
||||||
|
"date": "[%key:component::sensor::entity_component::date::name%]",
|
||||||
|
"duration": "[%key:component::sensor::entity_component::duration::name%]",
|
||||||
|
"apparent_power": "[%key:component::sensor::entity_component::apparent_power::name%]",
|
||||||
|
"aqi": "[%key:component::sensor::entity_component::aqi::name%]",
|
||||||
|
"atmospheric_pressure": "[%key:component::sensor::entity_component::atmospheric_pressure::name%]",
|
||||||
|
"battery": "[%key:component::sensor::entity_component::battery::name%]",
|
||||||
|
"carbon_monoxide": "[%key:component::sensor::entity_component::carbon_monoxide::name%]",
|
||||||
|
"carbon_dioxide": "[%key:component::sensor::entity_component::carbon_dioxide::name%]",
|
||||||
|
"current": "[%key:component::sensor::entity_component::current::name%]",
|
||||||
|
"data_rate": "[%key:component::sensor::entity_component::data_rate::name%]",
|
||||||
|
"data_size": "[%key:component::sensor::entity_component::data_size::name%]",
|
||||||
|
"distance": "[%key:component::sensor::entity_component::distance::name%]",
|
||||||
|
"energy": "[%key:component::sensor::entity_component::energy::name%]",
|
||||||
|
"energy_storage": "[%key:component::sensor::entity_component::energy_storage::name%]",
|
||||||
|
"frequency": "[%key:component::sensor::entity_component::frequency::name%]",
|
||||||
|
"gas": "[%key:component::sensor::entity_component::gas::name%]",
|
||||||
|
"humidity": "[%key:component::sensor::entity_component::humidity::name%]",
|
||||||
|
"illuminance": "[%key:component::sensor::entity_component::illuminance::name%]",
|
||||||
|
"irradiance": "[%key:component::sensor::entity_component::irradiance::name%]",
|
||||||
|
"moisture": "[%key:component::sensor::entity_component::moisture::name%]",
|
||||||
|
"monetary": "[%key:component::sensor::entity_component::monetary::name%]",
|
||||||
|
"nitrogen_dioxide": "[%key:component::sensor::entity_component::nitrogen_dioxide::name%]",
|
||||||
|
"nitrogen_monoxide": "[%key:component::sensor::entity_component::nitrogen_monoxide::name%]",
|
||||||
|
"nitrous_oxide": "[%key:component::sensor::entity_component::nitrous_oxide::name%]",
|
||||||
|
"ozone": "[%key:component::sensor::entity_component::ozone::name%]",
|
||||||
|
"pm1": "[%key:component::sensor::entity_component::pm1::name%]",
|
||||||
|
"pm10": "[%key:component::sensor::entity_component::pm10::name%]",
|
||||||
|
"pm25": "[%key:component::sensor::entity_component::pm25::name%]",
|
||||||
|
"power_factor": "[%key:component::sensor::entity_component::power_factor::name%]",
|
||||||
|
"power": "[%key:component::sensor::entity_component::power::name%]",
|
||||||
|
"precipitation": "[%key:component::sensor::entity_component::precipitation::name%]",
|
||||||
|
"precipitation_intensity": "[%key:component::sensor::entity_component::precipitation_intensity::name%]",
|
||||||
|
"pressure": "[%key:component::sensor::entity_component::pressure::name%]",
|
||||||
|
"reactive_power": "[%key:component::sensor::entity_component::reactive_power::name%]",
|
||||||
|
"signal_strength": "[%key:component::sensor::entity_component::signal_strength::name%]",
|
||||||
|
"sound_pressure": "[%key:component::sensor::entity_component::sound_pressure::name%]",
|
||||||
|
"speed": "[%key:component::sensor::entity_component::speed::name%]",
|
||||||
|
"sulphur_dioxide": "[%key:component::sensor::entity_component::sulphur_dioxide::name%]",
|
||||||
|
"temperature": "[%key:component::sensor::entity_component::temperature::name%]",
|
||||||
|
"timestamp": "[%key:component::sensor::entity_component::timestamp::name%]",
|
||||||
|
"volatile_organic_compounds": "[%key:component::sensor::entity_component::volatile_organic_compounds::name%]",
|
||||||
|
"voltage": "[%key:component::sensor::entity_component::voltage::name%]",
|
||||||
|
"volume": "[%key:component::sensor::entity_component::volume::name%]",
|
||||||
|
"volume_storage": "[%key:component::sensor::entity_component::volume_storage::name%]",
|
||||||
|
"water": "[%key:component::sensor::entity_component::water::name%]",
|
||||||
|
"weight": "[%key:component::sensor::entity_component::weight::name%]",
|
||||||
|
"wind_speed": "[%key:component::sensor::entity_component::wind_speed::name%]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"state_class": {
|
||||||
|
"options": {
|
||||||
|
"none": "No state class",
|
||||||
|
"measurement": "[%key:component::sensor::entity_component::_::state_attributes::state_class::state::measurement%]",
|
||||||
|
"total": "[%key:component::sensor::entity_component::_::state_attributes::state_class::state::total%]",
|
||||||
|
"total_increasing": "[%key:component::sensor::entity_component::_::state_attributes::state_class::state::total_increasing%]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unit_of_measurement": {
|
||||||
|
"options": {
|
||||||
|
"none": "No unit of measurement"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
"""Fixtures for the Scrape integration."""
|
"""Fixtures for the Scrape integration."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Generator
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import AsyncMock, patch
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -32,6 +33,16 @@ from . import MockRestData
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_setup_entry() -> Generator[AsyncMock, None, None]:
|
||||||
|
"""Automatically path uuid generator."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.scrape.async_setup_entry",
|
||||||
|
return_value=True,
|
||||||
|
) as mock_setup_entry:
|
||||||
|
yield mock_setup_entry
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="get_config")
|
@pytest.fixture(name="get_config")
|
||||||
async def get_config_to_integration_load() -> dict[str, Any]:
|
async def get_config_to_integration_load() -> dict[str, Any]:
|
||||||
"""Return default minimal configuration.
|
"""Return default minimal configuration.
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
"""Test the Scrape config flow."""
|
"""Test the Scrape config flow."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import AsyncMock, patch
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.rest.data import DEFAULT_TIMEOUT
|
from homeassistant.components.rest.data import DEFAULT_TIMEOUT
|
||||||
from homeassistant.components.rest.schema import DEFAULT_METHOD
|
from homeassistant.components.rest.schema import DEFAULT_METHOD
|
||||||
from homeassistant.components.scrape import DOMAIN
|
from homeassistant.components.scrape import DOMAIN
|
||||||
|
from homeassistant.components.scrape.config_flow import NONE_SENTINEL
|
||||||
from homeassistant.components.scrape.const import (
|
from homeassistant.components.scrape.const import (
|
||||||
CONF_ENCODING,
|
CONF_ENCODING,
|
||||||
CONF_INDEX,
|
CONF_INDEX,
|
||||||
|
@ -15,14 +16,18 @@ from homeassistant.components.scrape.const import (
|
||||||
DEFAULT_ENCODING,
|
DEFAULT_ENCODING,
|
||||||
DEFAULT_VERIFY_SSL,
|
DEFAULT_VERIFY_SSL,
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.sensor import CONF_STATE_CLASS
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
CONF_DEVICE_CLASS,
|
||||||
CONF_METHOD,
|
CONF_METHOD,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_PASSWORD,
|
CONF_PASSWORD,
|
||||||
CONF_RESOURCE,
|
CONF_RESOURCE,
|
||||||
CONF_TIMEOUT,
|
CONF_TIMEOUT,
|
||||||
CONF_UNIQUE_ID,
|
CONF_UNIQUE_ID,
|
||||||
|
CONF_UNIT_OF_MEASUREMENT,
|
||||||
CONF_USERNAME,
|
CONF_USERNAME,
|
||||||
|
CONF_VALUE_TEMPLATE,
|
||||||
CONF_VERIFY_SSL,
|
CONF_VERIFY_SSL,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
@ -34,7 +39,9 @@ from . import MockRestData
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
async def test_form(hass: HomeAssistant, get_data: MockRestData) -> None:
|
async def test_form(
|
||||||
|
hass: HomeAssistant, get_data: MockRestData, mock_setup_entry: AsyncMock
|
||||||
|
) -> None:
|
||||||
"""Test we get the form."""
|
"""Test we get the form."""
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
@ -46,10 +53,7 @@ async def test_form(hass: HomeAssistant, get_data: MockRestData) -> None:
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.rest.RestData",
|
"homeassistant.components.rest.RestData",
|
||||||
return_value=get_data,
|
return_value=get_data,
|
||||||
) as mock_data, patch(
|
) as mock_data:
|
||||||
"homeassistant.components.scrape.async_setup_entry",
|
|
||||||
return_value=True,
|
|
||||||
) as mock_setup_entry:
|
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
{
|
{
|
||||||
|
@ -66,6 +70,9 @@ async def test_form(hass: HomeAssistant, get_data: MockRestData) -> None:
|
||||||
CONF_NAME: "Current version",
|
CONF_NAME: "Current version",
|
||||||
CONF_SELECT: ".current-version h1",
|
CONF_SELECT: ".current-version h1",
|
||||||
CONF_INDEX: 0.0,
|
CONF_INDEX: 0.0,
|
||||||
|
CONF_DEVICE_CLASS: NONE_SENTINEL,
|
||||||
|
CONF_STATE_CLASS: NONE_SENTINEL,
|
||||||
|
CONF_UNIT_OF_MEASUREMENT: NONE_SENTINEL,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
@ -92,7 +99,9 @@ async def test_form(hass: HomeAssistant, get_data: MockRestData) -> None:
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_flow_fails(hass: HomeAssistant, get_data: MockRestData) -> None:
|
async def test_flow_fails(
|
||||||
|
hass: HomeAssistant, get_data: MockRestData, mock_setup_entry: AsyncMock
|
||||||
|
) -> None:
|
||||||
"""Test config flow error."""
|
"""Test config flow error."""
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
@ -137,9 +146,6 @@ async def test_flow_fails(hass: HomeAssistant, get_data: MockRestData) -> None:
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.rest.RestData",
|
"homeassistant.components.rest.RestData",
|
||||||
return_value=get_data,
|
return_value=get_data,
|
||||||
), patch(
|
|
||||||
"homeassistant.components.scrape.async_setup_entry",
|
|
||||||
return_value=True,
|
|
||||||
):
|
):
|
||||||
result3 = await hass.config_entries.flow.async_configure(
|
result3 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
|
@ -157,6 +163,9 @@ async def test_flow_fails(hass: HomeAssistant, get_data: MockRestData) -> None:
|
||||||
CONF_NAME: "Current version",
|
CONF_NAME: "Current version",
|
||||||
CONF_SELECT: ".current-version h1",
|
CONF_SELECT: ".current-version h1",
|
||||||
CONF_INDEX: 0.0,
|
CONF_INDEX: 0.0,
|
||||||
|
CONF_DEVICE_CLASS: NONE_SENTINEL,
|
||||||
|
CONF_STATE_CLASS: NONE_SENTINEL,
|
||||||
|
CONF_UNIT_OF_MEASUREMENT: NONE_SENTINEL,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
@ -278,6 +287,9 @@ async def test_options_add_remove_sensor_flow(
|
||||||
CONF_NAME: "Template",
|
CONF_NAME: "Template",
|
||||||
CONF_SELECT: "template",
|
CONF_SELECT: "template",
|
||||||
CONF_INDEX: 0.0,
|
CONF_INDEX: 0.0,
|
||||||
|
CONF_DEVICE_CLASS: NONE_SENTINEL,
|
||||||
|
CONF_STATE_CLASS: NONE_SENTINEL,
|
||||||
|
CONF_UNIT_OF_MEASUREMENT: NONE_SENTINEL,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
@ -405,6 +417,9 @@ async def test_options_edit_sensor_flow(
|
||||||
user_input={
|
user_input={
|
||||||
CONF_SELECT: "template",
|
CONF_SELECT: "template",
|
||||||
CONF_INDEX: 0.0,
|
CONF_INDEX: 0.0,
|
||||||
|
CONF_DEVICE_CLASS: NONE_SENTINEL,
|
||||||
|
CONF_STATE_CLASS: NONE_SENTINEL,
|
||||||
|
CONF_UNIT_OF_MEASUREMENT: NONE_SENTINEL,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
@ -434,3 +449,161 @@ async def test_options_edit_sensor_flow(
|
||||||
# Check the state of the entity has changed as expected
|
# Check the state of the entity has changed as expected
|
||||||
state = hass.states.get("sensor.current_version")
|
state = hass.states.get("sensor.current_version")
|
||||||
assert state.state == "Trying to get"
|
assert state.state == "Trying to get"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_sensor_options_add_device_class(
|
||||||
|
hass: HomeAssistant, mock_setup_entry: AsyncMock
|
||||||
|
) -> None:
|
||||||
|
"""Test options flow to edit a sensor."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
options={
|
||||||
|
CONF_RESOURCE: "https://www.home-assistant.io",
|
||||||
|
CONF_METHOD: DEFAULT_METHOD,
|
||||||
|
CONF_VERIFY_SSL: DEFAULT_VERIFY_SSL,
|
||||||
|
CONF_TIMEOUT: DEFAULT_TIMEOUT,
|
||||||
|
CONF_ENCODING: DEFAULT_ENCODING,
|
||||||
|
"sensor": [
|
||||||
|
{
|
||||||
|
CONF_NAME: "Current Temp",
|
||||||
|
CONF_SELECT: ".current-temp h3",
|
||||||
|
CONF_INDEX: 0,
|
||||||
|
CONF_VALUE_TEMPLATE: "{{ value.split(':')[1] }}",
|
||||||
|
CONF_UNIQUE_ID: "3699ef88-69e6-11ed-a1eb-0242ac120002",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
entry_id="1",
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_init(entry.entry_id)
|
||||||
|
assert result["type"] == FlowResultType.MENU
|
||||||
|
assert result["step_id"] == "init"
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{"next_step_id": "select_edit_sensor"},
|
||||||
|
)
|
||||||
|
assert result["type"] == FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "select_edit_sensor"
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{"index": "0"},
|
||||||
|
)
|
||||||
|
assert result["type"] == FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "edit_sensor"
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={
|
||||||
|
CONF_SELECT: ".current-temp h3",
|
||||||
|
CONF_INDEX: 0.0,
|
||||||
|
CONF_VALUE_TEMPLATE: "{{ value.split(':')[1] }}",
|
||||||
|
CONF_DEVICE_CLASS: "temperature",
|
||||||
|
CONF_STATE_CLASS: "measurement",
|
||||||
|
CONF_UNIT_OF_MEASUREMENT: "°C",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] == FlowResultType.CREATE_ENTRY
|
||||||
|
assert result["data"] == {
|
||||||
|
CONF_RESOURCE: "https://www.home-assistant.io",
|
||||||
|
CONF_METHOD: "GET",
|
||||||
|
CONF_VERIFY_SSL: True,
|
||||||
|
CONF_TIMEOUT: 10,
|
||||||
|
CONF_ENCODING: "UTF-8",
|
||||||
|
"sensor": [
|
||||||
|
{
|
||||||
|
CONF_NAME: "Current Temp",
|
||||||
|
CONF_SELECT: ".current-temp h3",
|
||||||
|
CONF_VALUE_TEMPLATE: "{{ value.split(':')[1] }}",
|
||||||
|
CONF_INDEX: 0,
|
||||||
|
CONF_DEVICE_CLASS: "temperature",
|
||||||
|
CONF_STATE_CLASS: "measurement",
|
||||||
|
CONF_UNIT_OF_MEASUREMENT: "°C",
|
||||||
|
CONF_UNIQUE_ID: "3699ef88-69e6-11ed-a1eb-0242ac120002",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_sensor_options_remove_device_class(
|
||||||
|
hass: HomeAssistant, mock_setup_entry: AsyncMock
|
||||||
|
) -> None:
|
||||||
|
"""Test options flow to edit a sensor."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
options={
|
||||||
|
CONF_RESOURCE: "https://www.home-assistant.io",
|
||||||
|
CONF_METHOD: DEFAULT_METHOD,
|
||||||
|
CONF_VERIFY_SSL: DEFAULT_VERIFY_SSL,
|
||||||
|
CONF_TIMEOUT: DEFAULT_TIMEOUT,
|
||||||
|
CONF_ENCODING: DEFAULT_ENCODING,
|
||||||
|
"sensor": [
|
||||||
|
{
|
||||||
|
CONF_NAME: "Current Temp",
|
||||||
|
CONF_SELECT: ".current-temp h3",
|
||||||
|
CONF_INDEX: 0,
|
||||||
|
CONF_VALUE_TEMPLATE: "{{ value.split(':')[1] }}",
|
||||||
|
CONF_DEVICE_CLASS: "temperature",
|
||||||
|
CONF_STATE_CLASS: "measurement",
|
||||||
|
CONF_UNIT_OF_MEASUREMENT: "°C",
|
||||||
|
CONF_UNIQUE_ID: "3699ef88-69e6-11ed-a1eb-0242ac120002",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
entry_id="1",
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_init(entry.entry_id)
|
||||||
|
assert result["type"] == FlowResultType.MENU
|
||||||
|
assert result["step_id"] == "init"
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{"next_step_id": "select_edit_sensor"},
|
||||||
|
)
|
||||||
|
assert result["type"] == FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "select_edit_sensor"
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{"index": "0"},
|
||||||
|
)
|
||||||
|
assert result["type"] == FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "edit_sensor"
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={
|
||||||
|
CONF_SELECT: ".current-temp h3",
|
||||||
|
CONF_INDEX: 0.0,
|
||||||
|
CONF_VALUE_TEMPLATE: "{{ value.split(':')[1] }}",
|
||||||
|
CONF_DEVICE_CLASS: NONE_SENTINEL,
|
||||||
|
CONF_STATE_CLASS: NONE_SENTINEL,
|
||||||
|
CONF_UNIT_OF_MEASUREMENT: NONE_SENTINEL,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] == FlowResultType.CREATE_ENTRY
|
||||||
|
assert result["data"] == {
|
||||||
|
CONF_RESOURCE: "https://www.home-assistant.io",
|
||||||
|
CONF_METHOD: "GET",
|
||||||
|
CONF_VERIFY_SSL: True,
|
||||||
|
CONF_TIMEOUT: 10,
|
||||||
|
CONF_ENCODING: "UTF-8",
|
||||||
|
"sensor": [
|
||||||
|
{
|
||||||
|
CONF_NAME: "Current Temp",
|
||||||
|
CONF_SELECT: ".current-temp h3",
|
||||||
|
CONF_VALUE_TEMPLATE: "{{ value.split(':')[1] }}",
|
||||||
|
CONF_INDEX: 0,
|
||||||
|
CONF_UNIQUE_ID: "3699ef88-69e6-11ed-a1eb-0242ac120002",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue