Add config flow for integration sensor (#68288)
This commit is contained in:
parent
ad1e43e083
commit
0655ebbd84
10 changed files with 471 additions and 30 deletions
|
@ -1 +1,23 @@
|
||||||
"""The integration component."""
|
"""The Integration integration."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
|
"""Set up Integration from a config entry."""
|
||||||
|
hass.config_entries.async_setup_platforms(entry, (Platform.SENSOR,))
|
||||||
|
entry.async_on_unload(entry.add_update_listener(config_entry_update_listener))
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def config_entry_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||||
|
"""Update listener, called when the config entry options are changed."""
|
||||||
|
await hass.config_entries.async_reload(entry.entry_id)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
|
"""Unload a config entry."""
|
||||||
|
return await hass.config_entries.async_unload_platforms(entry, (Platform.SENSOR,))
|
||||||
|
|
103
homeassistant/components/integration/config_flow.py
Normal file
103
homeassistant/components/integration/config_flow.py
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
"""Config flow for Integration - Riemann sum integral integration."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Mapping
|
||||||
|
from typing import Any, cast
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.const import (
|
||||||
|
CONF_METHOD,
|
||||||
|
CONF_NAME,
|
||||||
|
CONF_UNIT_OF_MEASUREMENT,
|
||||||
|
TIME_DAYS,
|
||||||
|
TIME_HOURS,
|
||||||
|
TIME_MINUTES,
|
||||||
|
TIME_SECONDS,
|
||||||
|
)
|
||||||
|
from homeassistant.helpers import selector
|
||||||
|
from homeassistant.helpers.helper_config_entry_flow import (
|
||||||
|
HelperConfigFlowHandler,
|
||||||
|
HelperFlowStep,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .const import (
|
||||||
|
CONF_ROUND_DIGITS,
|
||||||
|
CONF_SOURCE_SENSOR,
|
||||||
|
CONF_UNIT_PREFIX,
|
||||||
|
CONF_UNIT_TIME,
|
||||||
|
DOMAIN,
|
||||||
|
METHOD_LEFT,
|
||||||
|
METHOD_RIGHT,
|
||||||
|
METHOD_TRAPEZOIDAL,
|
||||||
|
)
|
||||||
|
|
||||||
|
UNIT_PREFIXES = [
|
||||||
|
{"value": "none", "label": "none"},
|
||||||
|
{"value": "k", "label": "k (kilo)"},
|
||||||
|
{"value": "M", "label": "M (mega)"},
|
||||||
|
{"value": "G", "label": "T (tera)"},
|
||||||
|
{"value": "T", "label": "P (peta)"},
|
||||||
|
]
|
||||||
|
TIME_UNITS = [
|
||||||
|
{"value": TIME_SECONDS, "label": "s (seconds)"},
|
||||||
|
{"value": TIME_MINUTES, "label": "min (minutes)"},
|
||||||
|
{"value": TIME_HOURS, "label": "h (hours)"},
|
||||||
|
{"value": TIME_DAYS, "label": "d (days)"},
|
||||||
|
]
|
||||||
|
INTEGRATION_METHODS = [
|
||||||
|
{"value": METHOD_TRAPEZOIDAL, "label": "Trapezoidal rule"},
|
||||||
|
{"value": METHOD_LEFT, "label": "Left Riemann sum"},
|
||||||
|
{"value": METHOD_RIGHT, "label": "Right Riemann sum"},
|
||||||
|
]
|
||||||
|
|
||||||
|
OPTIONS_SCHEMA = vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_ROUND_DIGITS, default=2): selector.selector(
|
||||||
|
{"number": {"min": 0, "max": 6, "mode": "box"}}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_NAME): selector.selector({"text": {}}),
|
||||||
|
vol.Required(CONF_SOURCE_SENSOR): selector.selector(
|
||||||
|
{"entity": {"domain": "sensor"}},
|
||||||
|
),
|
||||||
|
vol.Required(CONF_METHOD, default=METHOD_TRAPEZOIDAL): selector.selector(
|
||||||
|
{"select": {"options": INTEGRATION_METHODS}}
|
||||||
|
),
|
||||||
|
vol.Required(CONF_ROUND_DIGITS, default=2): selector.selector(
|
||||||
|
{
|
||||||
|
"number": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 6,
|
||||||
|
"mode": "box",
|
||||||
|
CONF_UNIT_OF_MEASUREMENT: "decimals",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
vol.Required(CONF_UNIT_PREFIX, default="none"): selector.selector(
|
||||||
|
{"select": {"options": UNIT_PREFIXES}}
|
||||||
|
),
|
||||||
|
vol.Required(CONF_UNIT_TIME, default=TIME_HOURS): selector.selector(
|
||||||
|
{"select": {"options": TIME_UNITS}}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_FLOW = {"user": HelperFlowStep(CONFIG_SCHEMA)}
|
||||||
|
|
||||||
|
OPTIONS_FLOW = {"init": HelperFlowStep(OPTIONS_SCHEMA)}
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigFlowHandler(HelperConfigFlowHandler, domain=DOMAIN):
|
||||||
|
"""Handle a config or options flow for Integration."""
|
||||||
|
|
||||||
|
config_flow = CONFIG_FLOW
|
||||||
|
options_flow = OPTIONS_FLOW
|
||||||
|
|
||||||
|
def async_config_entry_title(self, options: Mapping[str, Any]) -> str:
|
||||||
|
"""Return config entry title."""
|
||||||
|
return cast(str, options["name"])
|
14
homeassistant/components/integration/const.py
Normal file
14
homeassistant/components/integration/const.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
"""Constants for the Integration - Riemann sum integral integration."""
|
||||||
|
|
||||||
|
DOMAIN = "integration"
|
||||||
|
|
||||||
|
CONF_ROUND_DIGITS = "round"
|
||||||
|
CONF_SOURCE_SENSOR = "source"
|
||||||
|
CONF_UNIT_OF_MEASUREMENT = "unit"
|
||||||
|
CONF_UNIT_PREFIX = "unit_prefix"
|
||||||
|
CONF_UNIT_TIME = "unit_time"
|
||||||
|
|
||||||
|
METHOD_TRAPEZOIDAL = "trapezoidal"
|
||||||
|
METHOD_LEFT = "left"
|
||||||
|
METHOD_RIGHT = "right"
|
||||||
|
INTEGRATION_METHODS = [METHOD_TRAPEZOIDAL, METHOD_LEFT, METHOD_RIGHT]
|
|
@ -2,7 +2,10 @@
|
||||||
"domain": "integration",
|
"domain": "integration",
|
||||||
"name": "Integration - Riemann sum integral",
|
"name": "Integration - Riemann sum integral",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/integration",
|
"documentation": "https://www.home-assistant.io/integrations/integration",
|
||||||
"codeowners": ["@dgomes"],
|
"codeowners": [
|
||||||
|
"@dgomes"
|
||||||
|
],
|
||||||
"quality_scale": "internal",
|
"quality_scale": "internal",
|
||||||
"iot_class": "local_push"
|
"iot_class": "local_push",
|
||||||
|
"config_flow": true
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ from homeassistant.components.sensor import (
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
SensorStateClass,
|
SensorStateClass,
|
||||||
)
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_DEVICE_CLASS,
|
ATTR_DEVICE_CLASS,
|
||||||
ATTR_UNIT_OF_MEASUREMENT,
|
ATTR_UNIT_OF_MEASUREMENT,
|
||||||
|
@ -25,29 +26,30 @@ from homeassistant.const import (
|
||||||
TIME_SECONDS,
|
TIME_SECONDS,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
import homeassistant.helpers.config_validation as cv
|
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.event import async_track_state_change_event
|
from homeassistant.helpers.event import async_track_state_change_event
|
||||||
from homeassistant.helpers.restore_state import RestoreEntity
|
from homeassistant.helpers.restore_state import RestoreEntity
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
|
from .const import (
|
||||||
|
CONF_ROUND_DIGITS,
|
||||||
|
CONF_SOURCE_SENSOR,
|
||||||
|
CONF_UNIT_OF_MEASUREMENT,
|
||||||
|
CONF_UNIT_PREFIX,
|
||||||
|
CONF_UNIT_TIME,
|
||||||
|
INTEGRATION_METHODS,
|
||||||
|
METHOD_LEFT,
|
||||||
|
METHOD_RIGHT,
|
||||||
|
METHOD_TRAPEZOIDAL,
|
||||||
|
)
|
||||||
|
|
||||||
# mypy: allow-untyped-defs, no-check-untyped-defs
|
# mypy: allow-untyped-defs, no-check-untyped-defs
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
ATTR_SOURCE_ID = "source"
|
ATTR_SOURCE_ID = "source"
|
||||||
|
|
||||||
CONF_SOURCE_SENSOR = "source"
|
|
||||||
CONF_ROUND_DIGITS = "round"
|
|
||||||
CONF_UNIT_PREFIX = "unit_prefix"
|
|
||||||
CONF_UNIT_TIME = "unit_time"
|
|
||||||
CONF_UNIT_OF_MEASUREMENT = "unit"
|
|
||||||
|
|
||||||
TRAPEZOIDAL_METHOD = "trapezoidal"
|
|
||||||
LEFT_METHOD = "left"
|
|
||||||
RIGHT_METHOD = "right"
|
|
||||||
INTEGRATION_METHOD = [TRAPEZOIDAL_METHOD, LEFT_METHOD, RIGHT_METHOD]
|
|
||||||
|
|
||||||
# SI Metric prefixes
|
# SI Metric prefixes
|
||||||
UNIT_PREFIXES = {None: 1, "k": 10**3, "M": 10**6, "G": 10**9, "T": 10**12}
|
UNIT_PREFIXES = {None: 1, "k": 10**3, "M": 10**6, "G": 10**9, "T": 10**12}
|
||||||
|
|
||||||
|
@ -73,14 +75,44 @@ PLATFORM_SCHEMA = vol.All(
|
||||||
vol.Optional(CONF_UNIT_PREFIX, default=None): vol.In(UNIT_PREFIXES),
|
vol.Optional(CONF_UNIT_PREFIX, default=None): vol.In(UNIT_PREFIXES),
|
||||||
vol.Optional(CONF_UNIT_TIME, default=TIME_HOURS): vol.In(UNIT_TIME),
|
vol.Optional(CONF_UNIT_TIME, default=TIME_HOURS): vol.In(UNIT_TIME),
|
||||||
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
|
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
|
||||||
vol.Optional(CONF_METHOD, default=TRAPEZOIDAL_METHOD): vol.In(
|
vol.Optional(CONF_METHOD, default=METHOD_TRAPEZOIDAL): vol.In(
|
||||||
INTEGRATION_METHOD
|
INTEGRATION_METHODS
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize Integration - Riemann sum integral config entry."""
|
||||||
|
registry = er.async_get(hass)
|
||||||
|
# Validate + resolve entity registry id to entity_id
|
||||||
|
source_entity_id = er.async_validate_entity_id(
|
||||||
|
registry, config_entry.options[CONF_SOURCE_SENSOR]
|
||||||
|
)
|
||||||
|
|
||||||
|
unit_prefix = config_entry.options[CONF_UNIT_PREFIX]
|
||||||
|
if unit_prefix == "none":
|
||||||
|
unit_prefix = None
|
||||||
|
|
||||||
|
integral = IntegrationSensor(
|
||||||
|
integration_method=config_entry.options[CONF_METHOD],
|
||||||
|
name=config_entry.title,
|
||||||
|
round_digits=int(config_entry.options[CONF_ROUND_DIGITS]),
|
||||||
|
source_entity=source_entity_id,
|
||||||
|
unique_id=config_entry.entry_id,
|
||||||
|
unit_of_measurement=None,
|
||||||
|
unit_prefix=unit_prefix,
|
||||||
|
unit_time=config_entry.options[CONF_UNIT_TIME],
|
||||||
|
)
|
||||||
|
|
||||||
|
async_add_entities([integral])
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(
|
async def async_setup_platform(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config: ConfigType,
|
config: ConfigType,
|
||||||
|
@ -89,13 +121,14 @@ async def async_setup_platform(
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the integration sensor."""
|
"""Set up the integration sensor."""
|
||||||
integral = IntegrationSensor(
|
integral = IntegrationSensor(
|
||||||
config[CONF_SOURCE_SENSOR],
|
integration_method=config[CONF_METHOD],
|
||||||
config.get(CONF_NAME),
|
name=config.get(CONF_NAME),
|
||||||
config[CONF_ROUND_DIGITS],
|
round_digits=config[CONF_ROUND_DIGITS],
|
||||||
config[CONF_UNIT_PREFIX],
|
source_entity=config[CONF_SOURCE_SENSOR],
|
||||||
config[CONF_UNIT_TIME],
|
unique_id=None,
|
||||||
config.get(CONF_UNIT_OF_MEASUREMENT),
|
unit_of_measurement=config.get(CONF_UNIT_OF_MEASUREMENT),
|
||||||
config[CONF_METHOD],
|
unit_prefix=config[CONF_UNIT_PREFIX],
|
||||||
|
unit_time=config[CONF_UNIT_TIME],
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities([integral])
|
async_add_entities([integral])
|
||||||
|
@ -106,15 +139,18 @@ class IntegrationSensor(RestoreEntity, SensorEntity):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
source_entity: str,
|
*,
|
||||||
|
integration_method: str,
|
||||||
name: str | None,
|
name: str | None,
|
||||||
round_digits: int,
|
round_digits: int,
|
||||||
|
source_entity: str,
|
||||||
|
unique_id: str | None,
|
||||||
|
unit_of_measurement: str | None,
|
||||||
unit_prefix: str | None,
|
unit_prefix: str | None,
|
||||||
unit_time: str,
|
unit_time: str,
|
||||||
unit_of_measurement: str | None,
|
|
||||||
integration_method: str,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the integration sensor."""
|
"""Initialize the integration sensor."""
|
||||||
|
self._attr_unique_id = unique_id
|
||||||
self._sensor_source_id = source_entity
|
self._sensor_source_id = source_entity
|
||||||
self._round_digits = round_digits
|
self._round_digits = round_digits
|
||||||
self._state = None
|
self._state = None
|
||||||
|
@ -187,15 +223,15 @@ class IntegrationSensor(RestoreEntity, SensorEntity):
|
||||||
new_state.last_updated - old_state.last_updated
|
new_state.last_updated - old_state.last_updated
|
||||||
).total_seconds()
|
).total_seconds()
|
||||||
|
|
||||||
if self._method == TRAPEZOIDAL_METHOD:
|
if self._method == METHOD_TRAPEZOIDAL:
|
||||||
area = (
|
area = (
|
||||||
(Decimal(new_state.state) + Decimal(old_state.state))
|
(Decimal(new_state.state) + Decimal(old_state.state))
|
||||||
* Decimal(elapsed_time)
|
* Decimal(elapsed_time)
|
||||||
/ 2
|
/ 2
|
||||||
)
|
)
|
||||||
elif self._method == LEFT_METHOD:
|
elif self._method == METHOD_LEFT:
|
||||||
area = Decimal(old_state.state) * Decimal(elapsed_time)
|
area = Decimal(old_state.state) * Decimal(elapsed_time)
|
||||||
elif self._method == RIGHT_METHOD:
|
elif self._method == METHOD_RIGHT:
|
||||||
area = Decimal(new_state.state) * Decimal(elapsed_time)
|
area = Decimal(new_state.state) * Decimal(elapsed_time)
|
||||||
|
|
||||||
integral = area / (self._unit_prefix * self._unit_time)
|
integral = area / (self._unit_prefix * self._unit_time)
|
||||||
|
|
28
homeassistant/components/integration/strings.json
Normal file
28
homeassistant/components/integration/strings.json
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"title": "New Integration sensor",
|
||||||
|
"description": "Precision controls the number of decimal digits in the output.\nThe sum will be scaled according to the selected metric prefix and integration time.",
|
||||||
|
"data": {
|
||||||
|
"method": "Integration method",
|
||||||
|
"name": "Name",
|
||||||
|
"round": "Precision",
|
||||||
|
"source": "Input sensor",
|
||||||
|
"unit_prefix": "Metric prefix",
|
||||||
|
"unit_time": "Integration time"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"options": {
|
||||||
|
"description": "Precision controls the number of decimal digits in the output.",
|
||||||
|
"data": {
|
||||||
|
"round": "[%key:component::integration::config::step::user::data::round%]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
homeassistant/components/integration/translations/en.json
Normal file
28
homeassistant/components/integration/translations/en.json
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"method": "Integration method",
|
||||||
|
"name": "Name",
|
||||||
|
"round": "Precision",
|
||||||
|
"source": "Input sensor",
|
||||||
|
"unit_prefix": "Metric prefix",
|
||||||
|
"unit_time": "Integration time"
|
||||||
|
},
|
||||||
|
"description": "Precision controls the number of decimal digits in the output.\nThe sum will be scaled according to the selected metric prefix and integration time.",
|
||||||
|
"title": "New Integration sensor"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"options": {
|
||||||
|
"data": {
|
||||||
|
"round": "Precision"
|
||||||
|
},
|
||||||
|
"description": "Precision controls the number of decimal digits in the output."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -157,6 +157,7 @@ FLOWS = [
|
||||||
"icloud",
|
"icloud",
|
||||||
"ifttt",
|
"ifttt",
|
||||||
"insteon",
|
"insteon",
|
||||||
|
"integration",
|
||||||
"intellifire",
|
"intellifire",
|
||||||
"ios",
|
"ios",
|
||||||
"iotawatt",
|
"iotawatt",
|
||||||
|
|
145
tests/components/integration/test_config_flow.py
Normal file
145
tests/components/integration/test_config_flow.py
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
"""Test the Integration - Riemann sum integral config flow."""
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant import config_entries
|
||||||
|
from homeassistant.components.integration.const import DOMAIN
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.data_entry_flow import RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_FORM
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("platform", ("sensor",))
|
||||||
|
async def test_config_flow(hass: HomeAssistant, platform) -> None:
|
||||||
|
"""Test the config flow."""
|
||||||
|
input_sensor_entity_id = "sensor.input"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
assert result["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result["errors"] is None
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.integration.async_setup_entry",
|
||||||
|
return_value=True,
|
||||||
|
) as mock_setup_entry:
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{
|
||||||
|
"method": "left",
|
||||||
|
"name": "My integration",
|
||||||
|
"round": 1,
|
||||||
|
"source": input_sensor_entity_id,
|
||||||
|
"unit_prefix": "none",
|
||||||
|
"unit_time": "min",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert result["title"] == "My integration"
|
||||||
|
assert result["data"] == {}
|
||||||
|
assert result["options"] == {
|
||||||
|
"method": "left",
|
||||||
|
"name": "My integration",
|
||||||
|
"round": 1.0,
|
||||||
|
"source": "sensor.input",
|
||||||
|
"unit_prefix": "none",
|
||||||
|
"unit_time": "min",
|
||||||
|
}
|
||||||
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
|
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
|
||||||
|
assert config_entry.data == {}
|
||||||
|
assert config_entry.options == {
|
||||||
|
"method": "left",
|
||||||
|
"name": "My integration",
|
||||||
|
"round": 1.0,
|
||||||
|
"source": "sensor.input",
|
||||||
|
"unit_prefix": "none",
|
||||||
|
"unit_time": "min",
|
||||||
|
}
|
||||||
|
assert config_entry.title == "My integration"
|
||||||
|
|
||||||
|
|
||||||
|
def get_suggested(schema, key):
|
||||||
|
"""Get suggested value for key in voluptuous schema."""
|
||||||
|
for k in schema.keys():
|
||||||
|
if k == key:
|
||||||
|
if k.description is None or "suggested_value" not in k.description:
|
||||||
|
return None
|
||||||
|
return k.description["suggested_value"]
|
||||||
|
# Wanted key absent from schema
|
||||||
|
raise Exception
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("platform", ("sensor",))
|
||||||
|
async def test_options(hass: HomeAssistant, platform) -> None:
|
||||||
|
"""Test reconfiguring."""
|
||||||
|
# Setup the config entry
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
data={},
|
||||||
|
domain=DOMAIN,
|
||||||
|
options={
|
||||||
|
"method": "left",
|
||||||
|
"name": "My integration",
|
||||||
|
"round": 1.0,
|
||||||
|
"source": "sensor.input",
|
||||||
|
"unit_prefix": "k",
|
||||||
|
"unit_time": "min",
|
||||||
|
},
|
||||||
|
title="My integration",
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||||
|
assert result["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result["step_id"] == "init"
|
||||||
|
schema = result["data_schema"].schema
|
||||||
|
assert get_suggested(schema, "round") == 1.0
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={
|
||||||
|
"round": 2.0,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert result["data"] == {
|
||||||
|
"method": "left",
|
||||||
|
"name": "My integration",
|
||||||
|
"round": 2.0,
|
||||||
|
"source": "sensor.input",
|
||||||
|
"unit_prefix": "k",
|
||||||
|
"unit_time": "min",
|
||||||
|
}
|
||||||
|
assert config_entry.data == {}
|
||||||
|
assert config_entry.options == {
|
||||||
|
"method": "left",
|
||||||
|
"name": "My integration",
|
||||||
|
"round": 2.0,
|
||||||
|
"source": "sensor.input",
|
||||||
|
"unit_prefix": "k",
|
||||||
|
"unit_time": "min",
|
||||||
|
}
|
||||||
|
assert config_entry.title == "My integration"
|
||||||
|
|
||||||
|
# Check config entry is reloaded with new options
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# Check the entity was updated, no new entity was created
|
||||||
|
assert len(hass.states.async_all()) == 1
|
||||||
|
|
||||||
|
# Check the state of the entity has changed as expected
|
||||||
|
hass.states.async_set("sensor.input", 10, {"unit_of_measurement": "dog"})
|
||||||
|
hass.states.async_set("sensor.input", 11, {"unit_of_measurement": "dog"})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get(f"{platform}.my_integration")
|
||||||
|
assert state.state != "unknown"
|
||||||
|
assert state.attributes["unit_of_measurement"] == "kdogmin"
|
61
tests/components/integration/test_init.py
Normal file
61
tests/components/integration/test_init.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
"""Test the Integration - Riemann sum integral integration."""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.integration.const import DOMAIN
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("platform", ("sensor",))
|
||||||
|
async def test_setup_and_remove_config_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
platform: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test setting up and removing a config entry."""
|
||||||
|
input_sensor_entity_id = "sensor.input"
|
||||||
|
registry = er.async_get(hass)
|
||||||
|
integration_entity_id = f"{platform}.my_integration"
|
||||||
|
|
||||||
|
# Setup the config entry
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
data={},
|
||||||
|
domain=DOMAIN,
|
||||||
|
options={
|
||||||
|
"method": "trapezoidal",
|
||||||
|
"name": "My integration",
|
||||||
|
"round": 1.0,
|
||||||
|
"source": "sensor.input",
|
||||||
|
"unit_prefix": "k",
|
||||||
|
"unit_time": "min",
|
||||||
|
},
|
||||||
|
title="My integration",
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# Check the entity is registered in the entity registry
|
||||||
|
assert registry.async_get(integration_entity_id) is not None
|
||||||
|
|
||||||
|
# Check the platform is setup correctly
|
||||||
|
state = hass.states.get(integration_entity_id)
|
||||||
|
assert state.state == "unknown"
|
||||||
|
assert "unit_of_measurement" not in state.attributes
|
||||||
|
assert state.attributes["source"] == "sensor.input"
|
||||||
|
|
||||||
|
hass.states.async_set(input_sensor_entity_id, 10, {"unit_of_measurement": "cat"})
|
||||||
|
hass.states.async_set(input_sensor_entity_id, 11, {"unit_of_measurement": "cat"})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
state = hass.states.get(integration_entity_id)
|
||||||
|
assert state.state != "unknown"
|
||||||
|
assert state.attributes["unit_of_measurement"] == "kcatmin"
|
||||||
|
|
||||||
|
# Remove the config entry
|
||||||
|
assert await hass.config_entries.async_remove(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# Check the state and entity registry entry are removed
|
||||||
|
assert hass.states.get(integration_entity_id) is None
|
||||||
|
assert registry.async_get(integration_entity_id) is None
|
Loading…
Add table
Add a link
Reference in a new issue