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
Tom Puttemans 2022-09-26 05:15:50 +02:00 committed by GitHub
parent f26fadbdfc
commit 7aa53feff4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 185 additions and 6 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,3 @@
"""Constant values for DSMR Reader."""
DOMAIN = "dsmr_reader"

View File

@ -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"
}

View File

@ -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)

View File

@ -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."
}
}
}

View File

@ -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"
}
}
}

View File

@ -83,6 +83,7 @@ FLOWS = {
"dnsip",
"doorbird",
"dsmr",
"dsmr_reader",
"dunehd",
"dynalite",
"eafm",

View File

@ -4,6 +4,9 @@ To update, run python3 -m script.hassfest
"""
MQTT = {
"dsmr_reader": [
"dsmr/#",
],
"tasmota": [
"tasmota/discovery/#",
],

View File

@ -0,0 +1 @@
"""Tests for the dsmr_reader component."""

View File

@ -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"