mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Remove deprecated YAML configuration from DSMR (#61008)
This commit is contained in:
parent
f5d7adc018
commit
5efb88f3f1
@ -19,7 +19,6 @@ from homeassistant.config_entries import ConfigEntry
|
|||||||
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE
|
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TYPE
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
from homeassistant.helpers.typing import ConfigType
|
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_DSMR_VERSION,
|
CONF_DSMR_VERSION,
|
||||||
@ -303,31 +302,6 @@ class DSMRFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
async def async_step_import(self, import_config: ConfigType) -> FlowResult:
|
|
||||||
"""Handle the initial step."""
|
|
||||||
host = import_config.get(CONF_HOST)
|
|
||||||
port = import_config[CONF_PORT]
|
|
||||||
|
|
||||||
status = self._abort_if_host_port_configured(port, host, import_config)
|
|
||||||
if status is not None:
|
|
||||||
return status
|
|
||||||
|
|
||||||
try:
|
|
||||||
info = await _validate_dsmr_connection(self.hass, import_config)
|
|
||||||
except CannotConnect:
|
|
||||||
return self.async_abort(reason="cannot_connect")
|
|
||||||
except CannotCommunicate:
|
|
||||||
return self.async_abort(reason="cannot_communicate")
|
|
||||||
|
|
||||||
name = f"{host}:{port}" if host is not None else port
|
|
||||||
data = {**import_config, **info}
|
|
||||||
|
|
||||||
if info[CONF_SERIAL_ID]:
|
|
||||||
await self.async_set_unique_id(info[CONF_SERIAL_ID])
|
|
||||||
self._abort_if_unique_id_configured(data)
|
|
||||||
|
|
||||||
return self.async_create_entry(title=name, data=data)
|
|
||||||
|
|
||||||
|
|
||||||
class DSMROptionFlowHandler(config_entries.OptionsFlow):
|
class DSMROptionFlowHandler(config_entries.OptionsFlow):
|
||||||
"""Handle options."""
|
"""Handle options."""
|
||||||
|
@ -6,16 +6,14 @@ from asyncio import CancelledError
|
|||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from dsmr_parser import obis_references as obis_ref
|
from dsmr_parser import obis_references as obis_ref
|
||||||
from dsmr_parser.clients.protocol import create_dsmr_reader, create_tcp_dsmr_reader
|
from dsmr_parser.clients.protocol import create_dsmr_reader, create_tcp_dsmr_reader
|
||||||
from dsmr_parser.objects import DSMRObject
|
from dsmr_parser.objects import DSMRObject
|
||||||
import serial
|
import serial
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
|
from homeassistant.components.sensor import SensorEntity
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_HOST,
|
CONF_HOST,
|
||||||
CONF_PORT,
|
CONF_PORT,
|
||||||
@ -23,10 +21,9 @@ from homeassistant.const import (
|
|||||||
VOLUME_CUBIC_METERS,
|
VOLUME_CUBIC_METERS,
|
||||||
)
|
)
|
||||||
from homeassistant.core import CoreState, HomeAssistant, callback
|
from homeassistant.core import CoreState, HomeAssistant, callback
|
||||||
from homeassistant.helpers import config_validation as cv
|
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import ConfigType, EventType, StateType
|
from homeassistant.helpers.typing import EventType, StateType
|
||||||
from homeassistant.util import Throttle
|
from homeassistant.util import Throttle
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -37,55 +34,20 @@ from .const import (
|
|||||||
CONF_SERIAL_ID_GAS,
|
CONF_SERIAL_ID_GAS,
|
||||||
CONF_TIME_BETWEEN_UPDATE,
|
CONF_TIME_BETWEEN_UPDATE,
|
||||||
DATA_TASK,
|
DATA_TASK,
|
||||||
DEFAULT_DSMR_VERSION,
|
|
||||||
DEFAULT_PORT,
|
|
||||||
DEFAULT_PRECISION,
|
DEFAULT_PRECISION,
|
||||||
DEFAULT_RECONNECT_INTERVAL,
|
DEFAULT_RECONNECT_INTERVAL,
|
||||||
DEFAULT_TIME_BETWEEN_UPDATE,
|
DEFAULT_TIME_BETWEEN_UPDATE,
|
||||||
DEVICE_NAME_ENERGY,
|
DEVICE_NAME_ENERGY,
|
||||||
DEVICE_NAME_GAS,
|
DEVICE_NAME_GAS,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
DSMR_VERSIONS,
|
|
||||||
LOGGER,
|
LOGGER,
|
||||||
SENSORS,
|
SENSORS,
|
||||||
)
|
)
|
||||||
from .models import DSMRSensorEntityDescription
|
from .models import DSMRSensorEntityDescription
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|
||||||
{
|
|
||||||
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.string,
|
|
||||||
vol.Optional(CONF_HOST): cv.string,
|
|
||||||
vol.Optional(CONF_DSMR_VERSION, default=DEFAULT_DSMR_VERSION): vol.All(
|
|
||||||
cv.string, vol.In(DSMR_VERSIONS)
|
|
||||||
),
|
|
||||||
vol.Optional(CONF_RECONNECT_INTERVAL, default=DEFAULT_RECONNECT_INTERVAL): int,
|
|
||||||
vol.Optional(CONF_PRECISION, default=DEFAULT_PRECISION): vol.Coerce(int),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
UNIT_CONVERSION = {"m3": VOLUME_CUBIC_METERS}
|
UNIT_CONVERSION = {"m3": VOLUME_CUBIC_METERS}
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
config: ConfigType,
|
|
||||||
async_add_entities: AddEntitiesCallback,
|
|
||||||
discovery_info: dict[str, Any] | None = None,
|
|
||||||
) -> None:
|
|
||||||
"""Import the platform into a config entry."""
|
|
||||||
LOGGER.warning(
|
|
||||||
"Configuration of the DSMR platform in YAML is deprecated and will be "
|
|
||||||
"removed in Home Assistant 2021.9; Your existing configuration "
|
|
||||||
"has been imported into the UI automatically and can be safely removed "
|
|
||||||
"from your configuration.yaml file"
|
|
||||||
)
|
|
||||||
hass.async_create_task(
|
|
||||||
hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN, context={"source": SOURCE_IMPORT}, data=config
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
"""Test the DSMR config flow."""
|
"""Test the DSMR config flow."""
|
||||||
import asyncio
|
|
||||||
from itertools import chain, repeat
|
from itertools import chain, repeat
|
||||||
import os
|
import os
|
||||||
from unittest.mock import DEFAULT, AsyncMock, MagicMock, patch, sentinel
|
from unittest.mock import DEFAULT, AsyncMock, MagicMock, patch, sentinel
|
||||||
@ -225,188 +224,6 @@ async def test_setup_serial_wrong_telegram(
|
|||||||
assert result["errors"] == {"base": "cannot_communicate"}
|
assert result["errors"] == {"base": "cannot_communicate"}
|
||||||
|
|
||||||
|
|
||||||
async def test_import_usb(hass, dsmr_connection_send_validate_fixture):
|
|
||||||
"""Test we can import."""
|
|
||||||
|
|
||||||
entry_data = {
|
|
||||||
"port": "/dev/ttyUSB0",
|
|
||||||
"dsmr_version": "2.2",
|
|
||||||
"precision": 4,
|
|
||||||
"reconnect_interval": 30,
|
|
||||||
}
|
|
||||||
|
|
||||||
with patch("homeassistant.components.dsmr.async_setup_entry", return_value=True):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={"source": config_entries.SOURCE_IMPORT},
|
|
||||||
data=entry_data,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "create_entry"
|
|
||||||
assert result["title"] == "/dev/ttyUSB0"
|
|
||||||
assert result["data"] == {**entry_data, **SERIAL_DATA}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_import_usb_failed_connection(
|
|
||||||
hass, dsmr_connection_send_validate_fixture
|
|
||||||
):
|
|
||||||
"""Test we can import."""
|
|
||||||
(connection_factory, transport, protocol) = dsmr_connection_send_validate_fixture
|
|
||||||
|
|
||||||
entry_data = {
|
|
||||||
"port": "/dev/ttyUSB0",
|
|
||||||
"dsmr_version": "2.2",
|
|
||||||
"precision": 4,
|
|
||||||
"reconnect_interval": 30,
|
|
||||||
}
|
|
||||||
|
|
||||||
# override the mock to have it fail the first time and succeed after
|
|
||||||
first_fail_connection_factory = AsyncMock(
|
|
||||||
return_value=(transport, protocol),
|
|
||||||
side_effect=chain([serial.serialutil.SerialException], repeat(DEFAULT)),
|
|
||||||
)
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.dsmr.async_setup_entry", return_value=True
|
|
||||||
), patch(
|
|
||||||
"homeassistant.components.dsmr.config_flow.create_dsmr_reader",
|
|
||||||
first_fail_connection_factory,
|
|
||||||
):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={"source": config_entries.SOURCE_IMPORT},
|
|
||||||
data=entry_data,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "abort"
|
|
||||||
assert result["reason"] == "cannot_connect"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_import_usb_no_data(hass, dsmr_connection_send_validate_fixture):
|
|
||||||
"""Test we can import."""
|
|
||||||
(connection_factory, transport, protocol) = dsmr_connection_send_validate_fixture
|
|
||||||
|
|
||||||
entry_data = {
|
|
||||||
"port": "/dev/ttyUSB0",
|
|
||||||
"dsmr_version": "2.2",
|
|
||||||
"precision": 4,
|
|
||||||
"reconnect_interval": 30,
|
|
||||||
}
|
|
||||||
|
|
||||||
# override the mock to have it fail the first time and succeed after
|
|
||||||
wait_closed = AsyncMock(
|
|
||||||
return_value=(transport, protocol),
|
|
||||||
side_effect=chain([asyncio.TimeoutError], repeat(DEFAULT)),
|
|
||||||
)
|
|
||||||
|
|
||||||
protocol.wait_closed = wait_closed
|
|
||||||
|
|
||||||
with patch("homeassistant.components.dsmr.async_setup_entry", return_value=True):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={"source": config_entries.SOURCE_IMPORT},
|
|
||||||
data=entry_data,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "abort"
|
|
||||||
assert result["reason"] == "cannot_communicate"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_import_usb_wrong_telegram(hass, dsmr_connection_send_validate_fixture):
|
|
||||||
"""Test we can import."""
|
|
||||||
(connection_factory, transport, protocol) = dsmr_connection_send_validate_fixture
|
|
||||||
|
|
||||||
entry_data = {
|
|
||||||
"port": "/dev/ttyUSB0",
|
|
||||||
"dsmr_version": "2.2",
|
|
||||||
"precision": 4,
|
|
||||||
"reconnect_interval": 30,
|
|
||||||
}
|
|
||||||
|
|
||||||
protocol.telegram = {}
|
|
||||||
|
|
||||||
with patch("homeassistant.components.dsmr.async_setup_entry", return_value=True):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={"source": config_entries.SOURCE_IMPORT},
|
|
||||||
data=entry_data,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "abort"
|
|
||||||
assert result["reason"] == "cannot_communicate"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_import_network(hass, dsmr_connection_send_validate_fixture):
|
|
||||||
"""Test we can import from network."""
|
|
||||||
|
|
||||||
entry_data = {
|
|
||||||
"host": "localhost",
|
|
||||||
"port": "1234",
|
|
||||||
"dsmr_version": "2.2",
|
|
||||||
"precision": 4,
|
|
||||||
"reconnect_interval": 30,
|
|
||||||
}
|
|
||||||
|
|
||||||
with patch("homeassistant.components.dsmr.async_setup_entry", return_value=True):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={"source": config_entries.SOURCE_IMPORT},
|
|
||||||
data=entry_data,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "create_entry"
|
|
||||||
assert result["title"] == "localhost:1234"
|
|
||||||
assert result["data"] == {**entry_data, **SERIAL_DATA}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_import_update(hass, dsmr_connection_send_validate_fixture):
|
|
||||||
"""Test we can import."""
|
|
||||||
|
|
||||||
entry_data = {
|
|
||||||
"port": "/dev/ttyUSB0",
|
|
||||||
"dsmr_version": "2.2",
|
|
||||||
"precision": 4,
|
|
||||||
"reconnect_interval": 30,
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = MockConfigEntry(
|
|
||||||
domain=DOMAIN,
|
|
||||||
data=entry_data,
|
|
||||||
unique_id="/dev/ttyUSB0",
|
|
||||||
)
|
|
||||||
entry.add_to_hass(hass)
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.dsmr.async_setup_entry", return_value=True
|
|
||||||
), patch("homeassistant.components.dsmr.async_unload_entry", return_value=True):
|
|
||||||
await hass.config_entries.async_setup(entry.entry_id)
|
|
||||||
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
new_entry_data = {
|
|
||||||
"port": "/dev/ttyUSB0",
|
|
||||||
"dsmr_version": "2.2",
|
|
||||||
"precision": 3,
|
|
||||||
"reconnect_interval": 30,
|
|
||||||
}
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.dsmr.async_setup_entry", return_value=True
|
|
||||||
), patch("homeassistant.components.dsmr.async_unload_entry", return_value=True):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={"source": config_entries.SOURCE_IMPORT},
|
|
||||||
data=new_entry_data,
|
|
||||||
)
|
|
||||||
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert result["type"] == "abort"
|
|
||||||
assert result["reason"] == "already_configured"
|
|
||||||
|
|
||||||
assert entry.data["precision"] == 3
|
|
||||||
|
|
||||||
|
|
||||||
async def test_options_flow(hass):
|
async def test_options_flow(hass):
|
||||||
"""Test options flow."""
|
"""Test options flow."""
|
||||||
|
|
||||||
@ -446,50 +263,6 @@ async def test_options_flow(hass):
|
|||||||
assert entry.options == {"time_between_update": 15}
|
assert entry.options == {"time_between_update": 15}
|
||||||
|
|
||||||
|
|
||||||
async def test_import_luxembourg(hass, dsmr_connection_send_validate_fixture):
|
|
||||||
"""Test we can import."""
|
|
||||||
|
|
||||||
entry_data = {
|
|
||||||
"port": "/dev/ttyUSB0",
|
|
||||||
"dsmr_version": "5L",
|
|
||||||
"precision": 4,
|
|
||||||
"reconnect_interval": 30,
|
|
||||||
}
|
|
||||||
|
|
||||||
with patch("homeassistant.components.dsmr.async_setup_entry", return_value=True):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={"source": config_entries.SOURCE_IMPORT},
|
|
||||||
data=entry_data,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "create_entry"
|
|
||||||
assert result["title"] == "/dev/ttyUSB0"
|
|
||||||
assert result["data"] == {**entry_data, **SERIAL_DATA}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_import_sweden(hass, dsmr_connection_send_validate_fixture):
|
|
||||||
"""Test we can import."""
|
|
||||||
|
|
||||||
entry_data = {
|
|
||||||
"port": "/dev/ttyUSB0",
|
|
||||||
"dsmr_version": "5S",
|
|
||||||
"precision": 4,
|
|
||||||
"reconnect_interval": 30,
|
|
||||||
}
|
|
||||||
|
|
||||||
with patch("homeassistant.components.dsmr.async_setup_entry", return_value=True):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={"source": config_entries.SOURCE_IMPORT},
|
|
||||||
data=entry_data,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "create_entry"
|
|
||||||
assert result["title"] == "/dev/ttyUSB0"
|
|
||||||
assert result["data"] == {**entry_data, **SERIAL_DATA_SWEDEN}
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_serial_by_id_no_dir():
|
def test_get_serial_by_id_no_dir():
|
||||||
"""Test serial by id conversion if there's no /dev/serial/by-id."""
|
"""Test serial by id conversion if there's no /dev/serial/by-id."""
|
||||||
p1 = patch("os.path.isdir", MagicMock(return_value=False))
|
p1 = patch("os.path.isdir", MagicMock(return_value=False))
|
||||||
|
@ -12,10 +12,8 @@ from itertools import chain, repeat
|
|||||||
from unittest.mock import DEFAULT, MagicMock
|
from unittest.mock import DEFAULT, MagicMock
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.dsmr.const import DOMAIN
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
ATTR_STATE_CLASS,
|
ATTR_STATE_CLASS,
|
||||||
DOMAIN as SENSOR_DOMAIN,
|
|
||||||
SensorDeviceClass,
|
SensorDeviceClass,
|
||||||
SensorStateClass,
|
SensorStateClass,
|
||||||
)
|
)
|
||||||
@ -28,49 +26,10 @@ from homeassistant.const import (
|
|||||||
VOLUME_CUBIC_METERS,
|
VOLUME_CUBIC_METERS,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
from homeassistant.setup import async_setup_component
|
|
||||||
|
|
||||||
from tests.common import MockConfigEntry, patch
|
from tests.common import MockConfigEntry, patch
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_platform(hass, dsmr_connection_fixture):
|
|
||||||
"""Test setup of platform."""
|
|
||||||
async_add_entities = MagicMock()
|
|
||||||
|
|
||||||
entry_data = {
|
|
||||||
"platform": DOMAIN,
|
|
||||||
"port": "/dev/ttyUSB0",
|
|
||||||
"dsmr_version": "2.2",
|
|
||||||
"precision": 4,
|
|
||||||
"reconnect_interval": 30,
|
|
||||||
}
|
|
||||||
|
|
||||||
serial_data = {"serial_id": "1234", "serial_id_gas": "5678"}
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.dsmr.async_setup_entry", return_value=True
|
|
||||||
), patch(
|
|
||||||
"homeassistant.components.dsmr.config_flow._validate_dsmr_connection",
|
|
||||||
return_value=serial_data,
|
|
||||||
):
|
|
||||||
assert await async_setup_component(
|
|
||||||
hass, SENSOR_DOMAIN, {SENSOR_DOMAIN: entry_data}
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert not async_add_entities.called
|
|
||||||
|
|
||||||
# Check config entry
|
|
||||||
conf_entries = hass.config_entries.async_entries(DOMAIN)
|
|
||||||
|
|
||||||
assert len(conf_entries) == 1
|
|
||||||
|
|
||||||
entry = conf_entries[0]
|
|
||||||
|
|
||||||
assert entry.state == config_entries.ConfigEntryState.LOADED
|
|
||||||
assert entry.data == {**entry_data, **serial_data}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_default_setup(hass, dsmr_connection_fixture):
|
async def test_default_setup(hass, dsmr_connection_fixture):
|
||||||
"""Test the default setup."""
|
"""Test the default setup."""
|
||||||
(connection_factory, transport, protocol) = dsmr_connection_fixture
|
(connection_factory, transport, protocol) = dsmr_connection_fixture
|
||||||
|
Loading…
x
Reference in New Issue
Block a user