Add port to config flow of P1 Monitor integration (#128324)

pull/128532/head
Klaas Schoute 2024-10-16 19:40:20 +02:00 committed by GitHub
parent 5497697cf2
commit a0637a6ff8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 129 additions and 19 deletions

View File

@ -3,11 +3,11 @@
from __future__ import annotations
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.const import CONF_HOST, CONF_PORT, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from .const import DOMAIN
from .const import DOMAIN, LOGGER
from .coordinator import P1MonitorDataUpdateCoordinator
PLATFORMS = [Platform.SENSOR]
@ -30,6 +30,29 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return True
async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Migrate old entry."""
LOGGER.debug("Migrating from version %s", config_entry.version)
if config_entry.version == 1:
# Migrate to split host and port
host = config_entry.data[CONF_HOST]
if ":" in host:
host, port = host.split(":")
else:
port = 80
new_data = {
**config_entry.data,
CONF_HOST: host,
CONF_PORT: int(port),
}
hass.config_entries.async_update_entry(config_entry, data=new_data, version=2)
LOGGER.debug("Migration to version %s successful", config_entry.version)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload P1 Monitor config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

View File

@ -8,7 +8,7 @@ from p1monitor import P1Monitor, P1MonitorError
import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_HOST
from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.selector import TextSelector
@ -18,7 +18,7 @@ from .const import DOMAIN
class P1MonitorFlowHandler(ConfigFlow, domain=DOMAIN):
"""Config flow for P1 Monitor."""
VERSION = 1
VERSION = 2
async def async_step_user(
self, user_input: dict[str, Any] | None = None
@ -31,7 +31,9 @@ class P1MonitorFlowHandler(ConfigFlow, domain=DOMAIN):
session = async_get_clientsession(self.hass)
try:
async with P1Monitor(
host=user_input[CONF_HOST], session=session
host=user_input[CONF_HOST],
port=user_input[CONF_PORT],
session=session,
) as client:
await client.smartmeter()
except P1MonitorError:
@ -41,6 +43,7 @@ class P1MonitorFlowHandler(ConfigFlow, domain=DOMAIN):
title="P1 Monitor",
data={
CONF_HOST: user_input[CONF_HOST],
CONF_PORT: user_input[CONF_PORT],
},
)
@ -49,6 +52,7 @@ class P1MonitorFlowHandler(ConfigFlow, domain=DOMAIN):
data_schema=vol.Schema(
{
vol.Required(CONF_HOST): TextSelector(),
vol.Required(CONF_PORT, default=80): int,
}
),
errors=errors,

View File

@ -15,7 +15,7 @@ from p1monitor import (
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST
from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
@ -59,7 +59,9 @@ class P1MonitorDataUpdateCoordinator(DataUpdateCoordinator[P1MonitorData]):
)
self.p1monitor = P1Monitor(
self.config_entry.data[CONF_HOST], session=async_get_clientsession(hass)
host=self.config_entry.data[CONF_HOST],
port=self.config_entry.data[CONF_PORT],
session=async_get_clientsession(hass),
)
async def _async_update_data(self) -> P1MonitorData:

View File

@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Any, cast
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST
from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.core import HomeAssistant
from .const import (
@ -22,9 +22,7 @@ from .coordinator import P1MonitorDataUpdateCoordinator
if TYPE_CHECKING:
from _typeshed import DataclassInstance
TO_REDACT = {
CONF_HOST,
}
TO_REDACT = {CONF_HOST, CONF_PORT}
async def async_get_config_entry_diagnostics(

View File

@ -4,10 +4,12 @@
"user": {
"description": "Set up P1 Monitor to integrate with Home Assistant.",
"data": {
"host": "[%key:common::config_flow::data::host%]"
"host": "[%key:common::config_flow::data::host%]",
"port": "[%key:common::config_flow::data::port%]"
},
"data_description": {
"host": "The IP address or hostname of your P1 Monitor installation."
"host": "The IP address or hostname of your P1 Monitor installation.",
"port": "The port of your P1 Monitor installation."
}
}
},

View File

@ -7,7 +7,7 @@ from p1monitor import Phases, Settings, SmartMeter, WaterMeter
import pytest
from homeassistant.components.p1_monitor.const import DOMAIN
from homeassistant.const import CONF_HOST
from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, load_fixture
@ -19,8 +19,9 @@ def mock_config_entry() -> MockConfigEntry:
return MockConfigEntry(
title="monitor",
domain=DOMAIN,
data={CONF_HOST: "example"},
data={CONF_HOST: "example", CONF_PORT: 80},
unique_id="unique_thingy",
version=2,
)

View File

@ -0,0 +1,45 @@
# serializer version: 1
# name: test_migration
ConfigEntrySnapshot({
'data': dict({
'host': 'example',
'port': 80,
}),
'disabled_by': None,
'discovery_keys': dict({
}),
'domain': 'p1_monitor',
'entry_id': <ANY>,
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
'pref_disable_polling': False,
'source': 'user',
'title': 'Mock Title',
'unique_id': 'unique_thingy',
'version': 2,
})
# ---
# name: test_port_migration
ConfigEntrySnapshot({
'data': dict({
'host': 'example',
'port': 80,
}),
'disabled_by': None,
'discovery_keys': dict({
}),
'domain': 'p1_monitor',
'entry_id': <ANY>,
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
'pref_disable_polling': False,
'source': 'user',
'title': 'Mock Title',
'unique_id': 'unique_thingy',
'version': 2,
})
# ---

View File

@ -6,7 +6,7 @@ from p1monitor import P1MonitorError
from homeassistant.components.p1_monitor.const import DOMAIN
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import CONF_HOST
from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
@ -30,12 +30,12 @@ async def test_full_user_flow(hass: HomeAssistant) -> None:
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_HOST: "example.com"},
user_input={CONF_HOST: "example.com", CONF_PORT: 80},
)
assert result2.get("type") is FlowResultType.CREATE_ENTRY
assert result2.get("title") == "P1 Monitor"
assert result2.get("data") == {CONF_HOST: "example.com"}
assert result2.get("data") == {CONF_HOST: "example.com", CONF_PORT: 80}
assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_p1monitor.mock_calls) == 1
@ -50,7 +50,7 @@ async def test_api_error(hass: HomeAssistant) -> None:
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_USER},
data={CONF_HOST: "example.com"},
data={CONF_HOST: "example.com", CONF_PORT: 80},
)
assert result.get("type") is FlowResultType.FORM

View File

@ -21,6 +21,7 @@ async def test_diagnostics(
"title": "monitor",
"data": {
"host": REDACTED,
"port": REDACTED,
},
},
"data": {

View File

@ -3,9 +3,11 @@
from unittest.mock import AsyncMock, MagicMock, patch
from p1monitor import P1MonitorConnectionError
from syrupy import SnapshotAssertion
from homeassistant.components.p1_monitor.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
@ -44,3 +46,35 @@ async def test_config_entry_not_ready(
assert mock_request.call_count == 1
assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY
async def test_migration(hass: HomeAssistant, snapshot: SnapshotAssertion) -> None:
"""Test config entry version 1 -> 2 migration."""
mock_config_entry = MockConfigEntry(
unique_id="unique_thingy",
domain=DOMAIN,
data={CONF_HOST: "example"},
version=1,
)
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert hass.config_entries.async_get_entry(mock_config_entry.entry_id) == snapshot
async def test_port_migration(hass: HomeAssistant, snapshot: SnapshotAssertion) -> None:
"""Test migration of host:port to separate host and port."""
mock_config_entry = MockConfigEntry(
unique_id="unique_thingy",
domain=DOMAIN,
data={CONF_HOST: "example:80"},
version=1,
)
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert hass.config_entries.async_get_entry(mock_config_entry.entry_id) == snapshot