Add config flow and MQTT autodiscover to dsmr_reader integration (#71617)
Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: G Johansson <goran.johansson@shiftit.se> Co-authored-by: Paulus Schoutsen <balloob@gmail.com>pull/79079/head
parent
f26fadbdfc
commit
7aa53feff4
|
@ -238,7 +238,9 @@ omit =
|
|||
homeassistant/components/doorbird/util.py
|
||||
homeassistant/components/dovado/*
|
||||
homeassistant/components/downloader/*
|
||||
homeassistant/components/dsmr_reader/*
|
||||
homeassistant/components/dsmr_reader/__init__.py
|
||||
homeassistant/components/dsmr_reader/definitions.py
|
||||
homeassistant/components/dsmr_reader/sensor.py
|
||||
homeassistant/components/dte_energy_bridge/sensor.py
|
||||
homeassistant/components/dublin_bus_transport/sensor.py
|
||||
homeassistant/components/dunehd/__init__.py
|
||||
|
|
|
@ -263,7 +263,8 @@ build.json @home-assistant/supervisor
|
|||
/tests/components/doorbird/ @oblogic7 @bdraco @flacjacket
|
||||
/homeassistant/components/dsmr/ @Robbie1221 @frenck
|
||||
/tests/components/dsmr/ @Robbie1221 @frenck
|
||||
/homeassistant/components/dsmr_reader/ @depl0y
|
||||
/homeassistant/components/dsmr_reader/ @depl0y @glodenox
|
||||
/tests/components/dsmr_reader/ @depl0y @glodenox
|
||||
/homeassistant/components/dunehd/ @bieniu
|
||||
/tests/components/dunehd/ @bieniu
|
||||
/homeassistant/components/dwd_weather_warnings/ @runningman84 @stephan192 @Hummel95
|
||||
|
|
|
@ -1 +1,19 @@
|
|||
"""The DSMR Reader component."""
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
PLATFORMS = [Platform.SENSOR]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up the DSMR Reader integration."""
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Unload the DSMR Reader integration."""
|
||||
# no data stored in hass.data
|
||||
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
"""Config flow to configure DSMR Reader."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Awaitable
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers.config_entry_flow import DiscoveryFlowHandler
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def _async_has_devices(_: HomeAssistant) -> bool:
|
||||
"""MQTT is set as dependency, so that should be sufficient."""
|
||||
return True
|
||||
|
||||
|
||||
class DsmrReaderFlowHandler(DiscoveryFlowHandler[Awaitable[bool]], domain=DOMAIN):
|
||||
"""Handle DSMR Reader config flow. The MQTT step is inherited from the parent class."""
|
||||
|
||||
VERSION = 1
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Set up the config flow."""
|
||||
super().__init__(DOMAIN, "DSMR Reader", _async_has_devices)
|
||||
|
||||
async def async_step_confirm(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Confirm setup."""
|
||||
if user_input is None:
|
||||
return self.async_show_form(
|
||||
step_id="confirm",
|
||||
)
|
||||
|
||||
return await super().async_step_confirm(user_input)
|
|
@ -0,0 +1,3 @@
|
|||
"""Constant values for DSMR Reader."""
|
||||
|
||||
DOMAIN = "dsmr_reader"
|
|
@ -1,8 +1,10 @@
|
|||
{
|
||||
"domain": "dsmr_reader",
|
||||
"name": "DSMR Reader",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/dsmr_reader",
|
||||
"dependencies": ["mqtt"],
|
||||
"codeowners": ["@depl0y"],
|
||||
"mqtt": ["dsmr/#"],
|
||||
"codeowners": ["@depl0y", "@glodenox"],
|
||||
"iot_class": "local_push"
|
||||
}
|
||||
|
|
|
@ -3,15 +3,16 @@ from __future__ import annotations
|
|||
|
||||
from homeassistant.components import mqtt
|
||||
from homeassistant.components.sensor import SensorEntity
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from .const import DOMAIN
|
||||
from .definitions import SENSORS, DSMRReaderSensorEntityDescription
|
||||
|
||||
DOMAIN = "dsmr_reader"
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass: HomeAssistant,
|
||||
|
@ -19,7 +20,31 @@ async def async_setup_platform(
|
|||
async_add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up DSMR Reader sensors."""
|
||||
"""Set up DSMR Reader sensors via configuration.yaml and show deprecation warning."""
|
||||
async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"deprecated_yaml",
|
||||
breaks_in_ha_version="2022.12.0",
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecated_yaml",
|
||||
)
|
||||
hass.async_create_task(
|
||||
hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
data=config,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up DSMR Reader sensors from config entry."""
|
||||
async_add_entities(DSMRSensor(description) for description in SENSORS)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
|
||||
},
|
||||
"step": {
|
||||
"confirm": {
|
||||
"description": "Make sure to configure the 'split topic' data sources in DSMR Reader."
|
||||
}
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"deprecated_yaml": {
|
||||
"title": "The DSMR Reader configuration is being removed",
|
||||
"description": "Configuring DSMR Reader using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the DSMR Reader YAML configuration from your configuration.yaml file and restart Home Assistant to fix this issue."
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"single_instance_allowed": "Already configured. Only a single configuration possible."
|
||||
},
|
||||
"step": {
|
||||
"confirm": {
|
||||
"description": "Make sure to configure the 'split topic' data sources in DSMR Reader."
|
||||
}
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"deprecated_yaml": {
|
||||
"description": "Configuring DSMR Reader using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the DSMR Reader YAML configuration from your configuration.yaml file and restart Home Assistant to fix this issue.",
|
||||
"title": "The DSMR Reader configuration is being removed"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -83,6 +83,7 @@ FLOWS = {
|
|||
"dnsip",
|
||||
"doorbird",
|
||||
"dsmr",
|
||||
"dsmr_reader",
|
||||
"dunehd",
|
||||
"dynalite",
|
||||
"eafm",
|
||||
|
|
|
@ -4,6 +4,9 @@ To update, run python3 -m script.hassfest
|
|||
"""
|
||||
|
||||
MQTT = {
|
||||
"dsmr_reader": [
|
||||
"dsmr/#",
|
||||
],
|
||||
"tasmota": [
|
||||
"tasmota/discovery/#",
|
||||
],
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
"""Tests for the dsmr_reader component."""
|
|
@ -0,0 +1,47 @@
|
|||
"""Tests for the config flow."""
|
||||
from homeassistant.components.dsmr_reader.const import DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
|
||||
|
||||
async def test_import_step(hass: HomeAssistant):
|
||||
"""Test the import step."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
)
|
||||
assert result["type"] == FlowResultType.CREATE_ENTRY
|
||||
assert result["title"] == "DSMR Reader"
|
||||
|
||||
second_result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
)
|
||||
assert second_result["type"] == FlowResultType.ABORT
|
||||
assert second_result["reason"] == "single_instance_allowed"
|
||||
|
||||
|
||||
async def test_user_step(hass: HomeAssistant):
|
||||
"""Test the user step call."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}
|
||||
)
|
||||
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "confirm"
|
||||
assert result["errors"] is None
|
||||
|
||||
config_result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={}
|
||||
)
|
||||
|
||||
assert config_result["type"] == FlowResultType.CREATE_ENTRY
|
||||
assert config_result["title"] == "DSMR Reader"
|
||||
|
||||
duplicate_result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}
|
||||
)
|
||||
|
||||
assert duplicate_result["type"] == FlowResultType.ABORT
|
||||
assert duplicate_result["reason"] == "single_instance_allowed"
|
Loading…
Reference in New Issue