Replace Solarlog unmaintained library (#117484)

Co-authored-by: Robert Resch <robert@resch.dev>
This commit is contained in:
dontinelli 2024-06-18 09:06:22 +02:00 committed by GitHub
parent faa55de538
commit 2555827030
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 320 additions and 91 deletions

View File

@ -1305,8 +1305,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/solaredge/ @frenck @bdraco /homeassistant/components/solaredge/ @frenck @bdraco
/tests/components/solaredge/ @frenck @bdraco /tests/components/solaredge/ @frenck @bdraco
/homeassistant/components/solaredge_local/ @drobtravels @scheric /homeassistant/components/solaredge_local/ @drobtravels @scheric
/homeassistant/components/solarlog/ @Ernst79 /homeassistant/components/solarlog/ @Ernst79 @dontinelli
/tests/components/solarlog/ @Ernst79 /tests/components/solarlog/ @Ernst79 @dontinelli
/homeassistant/components/solax/ @squishykid /homeassistant/components/solax/ @squishykid
/tests/components/solax/ @squishykid /tests/components/solax/ @squishykid
/homeassistant/components/soma/ @ratsept @sebfortier2288 /homeassistant/components/soma/ @ratsept @sebfortier2288

View File

@ -1,12 +1,17 @@
"""Solar-Log integration.""" """Solar-Log integration."""
import logging
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .const import DOMAIN from .const import DOMAIN
from .coordinator import SolarlogData from .coordinator import SolarlogData
_LOGGER = logging.getLogger(__name__)
PLATFORMS = [Platform.SENSOR] PLATFORMS = [Platform.SENSOR]
@ -22,3 +27,46 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry.""" """Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
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:
# This means the user has downgraded from a future version
return False
if config_entry.version == 1:
if config_entry.minor_version < 2:
# migrate old entity unique id
entity_reg = er.async_get(hass)
entities: list[er.RegistryEntry] = er.async_entries_for_config_entry(
entity_reg, config_entry.entry_id
)
for entity in entities:
if "time" in entity.unique_id:
new_uid = entity.unique_id.replace("time", "last_updated")
_LOGGER.debug(
"migrate unique id '%s' to '%s'", entity.unique_id, new_uid
)
entity_reg.async_update_entity(
entity.entity_id, new_unique_id=new_uid
)
# migrate config_entry
new = {**config_entry.data}
new["extended_data"] = False
hass.config_entries.async_update_entry(
config_entry, data=new, minor_version=2, version=1
)
_LOGGER.debug(
"Migration to version %s.%s successful",
config_entry.version,
config_entry.minor_version,
)
return True

View File

@ -1,13 +1,14 @@
"""Config flow for solarlog integration.""" """Config flow for solarlog integration."""
import logging import logging
from typing import Any
from urllib.parse import ParseResult, urlparse from urllib.parse import ParseResult, urlparse
from requests.exceptions import HTTPError, Timeout from solarlog_cli.solarlog_connector import SolarLogConnector
from sunwatcher.solarlog.solarlog import SolarLog from solarlog_cli.solarlog_exceptions import SolarLogConnectionError, SolarLogError
import voluptuous as vol import voluptuous as vol
from homeassistant.config_entries import ConfigFlow from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_HOST, CONF_NAME from homeassistant.const import CONF_HOST, CONF_NAME
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.util import slugify from homeassistant.util import slugify
@ -29,6 +30,7 @@ class SolarLogConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for solarlog.""" """Handle a config flow for solarlog."""
VERSION = 1 VERSION = 1
MINOR_VERSION = 2
def __init__(self) -> None: def __init__(self) -> None:
"""Initialize the config flow.""" """Initialize the config flow."""
@ -40,37 +42,44 @@ class SolarLogConfigFlow(ConfigFlow, domain=DOMAIN):
return True return True
return False return False
def _parse_url(self, host: str) -> str:
"""Return parsed host url."""
url = urlparse(host, "http")
netloc = url.netloc or url.path
path = url.path if url.netloc else ""
url = ParseResult("http", netloc, path, *url[3:])
return url.geturl()
async def _test_connection(self, host): async def _test_connection(self, host):
"""Check if we can connect to the Solar-Log device.""" """Check if we can connect to the Solar-Log device."""
solarlog = SolarLogConnector(host)
try: try:
await self.hass.async_add_executor_job(SolarLog, host) await solarlog.test_connection()
except (OSError, HTTPError, Timeout): except SolarLogConnectionError:
self._errors[CONF_HOST] = "cannot_connect" self._errors = {CONF_HOST: "cannot_connect"}
_LOGGER.error(
"Could not connect to Solar-Log device at %s, check host ip address",
host,
)
return False return False
except SolarLogError: # pylint: disable=broad-except
self._errors = {CONF_HOST: "unknown"}
return False
finally:
solarlog.client.close()
return True return True
async def async_step_user(self, user_input=None): async def async_step_user(self, user_input=None) -> ConfigFlowResult:
"""Step when user initializes a integration.""" """Step when user initializes a integration."""
self._errors = {} self._errors = {}
if user_input is not None: if user_input is not None:
# set some defaults in case we need to return to the form # set some defaults in case we need to return to the form
name = slugify(user_input.get(CONF_NAME, DEFAULT_NAME)) user_input[CONF_NAME] = slugify(user_input[CONF_NAME])
host_entry = user_input.get(CONF_HOST, DEFAULT_HOST) user_input[CONF_HOST] = self._parse_url(user_input[CONF_HOST])
url = urlparse(host_entry, "http") if self._host_in_configuration_exists(user_input[CONF_HOST]):
netloc = url.netloc or url.path
path = url.path if url.netloc else ""
url = ParseResult("http", netloc, path, *url[3:])
host = url.geturl()
if self._host_in_configuration_exists(host):
self._errors[CONF_HOST] = "already_configured" self._errors[CONF_HOST] = "already_configured"
elif await self._test_connection(host): elif await self._test_connection(user_input[CONF_HOST]):
return self.async_create_entry(title=name, data={CONF_HOST: host}) return self.async_create_entry(
title=user_input[CONF_NAME], data=user_input
)
else: else:
user_input = {} user_input = {}
user_input[CONF_NAME] = DEFAULT_NAME user_input[CONF_NAME] = DEFAULT_NAME
@ -86,21 +95,25 @@ class SolarLogConfigFlow(ConfigFlow, domain=DOMAIN):
vol.Required( vol.Required(
CONF_HOST, default=user_input.get(CONF_HOST, DEFAULT_HOST) CONF_HOST, default=user_input.get(CONF_HOST, DEFAULT_HOST)
): str, ): str,
vol.Required("extended_data", default=False): bool,
} }
), ),
errors=self._errors, errors=self._errors,
) )
async def async_step_import(self, user_input=None): async def async_step_import(self, user_input: dict[str, Any]) -> ConfigFlowResult:
"""Import a config entry.""" """Import a config entry."""
host_entry = user_input.get(CONF_HOST, DEFAULT_HOST)
url = urlparse(host_entry, "http") user_input = {
netloc = url.netloc or url.path CONF_HOST: DEFAULT_HOST,
path = url.path if url.netloc else "" CONF_NAME: DEFAULT_NAME,
url = ParseResult("http", netloc, path, *url[3:]) "extended_data": False,
host = url.geturl() **user_input,
}
if self._host_in_configuration_exists(host): user_input[CONF_HOST] = self._parse_url(user_input[CONF_HOST])
if self._host_in_configuration_exists(user_input[CONF_HOST]):
return self.async_abort(reason="already_configured") return self.async_abort(reason="already_configured")
return await self.async_step_user(user_input) return await self.async_step_user(user_input)

View File

@ -4,12 +4,16 @@ from datetime import timedelta
import logging import logging
from urllib.parse import ParseResult, urlparse from urllib.parse import ParseResult, urlparse
from requests.exceptions import HTTPError, Timeout from solarlog_cli.solarlog_connector import SolarLogConnector
from sunwatcher.solarlog.solarlog import SolarLog from solarlog_cli.solarlog_exceptions import (
SolarLogConnectionError,
SolarLogUpdateError,
)
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import update_coordinator from homeassistant.helpers import update_coordinator
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -34,24 +38,23 @@ class SolarlogData(update_coordinator.DataUpdateCoordinator):
self.name = entry.title self.name = entry.title
self.host = url.geturl() self.host = url.geturl()
async def _async_update_data(self): extended_data = entry.data["extended_data"]
"""Update the data from the SolarLog device."""
try:
data = await self.hass.async_add_executor_job(SolarLog, self.host)
except (OSError, Timeout, HTTPError) as err:
raise update_coordinator.UpdateFailed(err) from err
if data.time.year == 1999: self.solarlog = SolarLogConnector(
raise update_coordinator.UpdateFailed( self.host, extended_data, hass.config.time_zone
"Invalid data returned (can happen after Solarlog restart)."
)
self.logger.debug(
(
"Connection to Solarlog successful. Retrieving latest Solarlog update"
" of %s"
),
data.time,
) )
async def _async_update_data(self):
"""Update the data from the SolarLog device."""
_LOGGER.debug("Start data update")
try:
data = await self.solarlog.update_data()
except SolarLogConnectionError as err:
raise ConfigEntryNotReady(err) from err
except SolarLogUpdateError as err:
raise update_coordinator.UpdateFailed(err) from err
_LOGGER.debug("Data successfully updated")
return data return data

View File

@ -1,10 +1,10 @@
{ {
"domain": "solarlog", "domain": "solarlog",
"name": "Solar-Log", "name": "Solar-Log",
"codeowners": ["@Ernst79"], "codeowners": ["@Ernst79", "@dontinelli"],
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/solarlog", "documentation": "https://www.home-assistant.io/integrations/solarlog",
"iot_class": "local_polling", "iot_class": "local_polling",
"loggers": ["sunwatcher"], "loggers": ["solarlog_cli"],
"requirements": ["sunwatcher==0.2.1"] "requirements": ["solarlog_cli==0.1.5"]
} }

View File

@ -21,7 +21,6 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util.dt import as_local
from . import SolarlogData from . import SolarlogData
from .const import DOMAIN from .const import DOMAIN
@ -36,10 +35,9 @@ class SolarLogSensorEntityDescription(SensorEntityDescription):
SENSOR_TYPES: tuple[SolarLogSensorEntityDescription, ...] = ( SENSOR_TYPES: tuple[SolarLogSensorEntityDescription, ...] = (
SolarLogSensorEntityDescription( SolarLogSensorEntityDescription(
key="time", key="last_updated",
translation_key="last_update", translation_key="last_update",
device_class=SensorDeviceClass.TIMESTAMP, device_class=SensorDeviceClass.TIMESTAMP,
value=as_local,
), ),
SolarLogSensorEntityDescription( SolarLogSensorEntityDescription(
key="power_ac", key="power_ac",
@ -231,7 +229,8 @@ class SolarlogSensor(CoordinatorEntity[SolarlogData], SensorEntity):
@property @property
def native_value(self): def native_value(self):
"""Return the native sensor value.""" """Return the native sensor value."""
raw_attr = getattr(self.coordinator.data, self.entity_description.key) raw_attr = self.coordinator.data.get(self.entity_description.key)
if self.entity_description.value: if self.entity_description.value:
return self.entity_description.value(raw_attr) return self.entity_description.value(raw_attr)
return raw_attr return raw_attr

View File

@ -5,7 +5,8 @@
"title": "Define your Solar-Log connection", "title": "Define your Solar-Log connection",
"data": { "data": {
"host": "[%key:common::config_flow::data::host%]", "host": "[%key:common::config_flow::data::host%]",
"name": "The prefix to be used for your Solar-Log sensors" "name": "The prefix to be used for your Solar-Log sensors",
"extended_data": "Get additional data from Solar-Log. Extended data is only accessible, if no password is set for the Solar-Log. Use at your own risk!"
}, },
"data_description": { "data_description": {
"host": "The hostname or IP address of your Solar-Log device." "host": "The hostname or IP address of your Solar-Log device."
@ -14,7 +15,8 @@
}, },
"error": { "error": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]", "already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]" "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
}, },
"abort": { "abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]" "already_configured": "[%key:common::config_flow::abort::already_configured_device%]"

View File

@ -2601,6 +2601,9 @@ soco==0.30.4
# homeassistant.components.solaredge_local # homeassistant.components.solaredge_local
solaredge-local==0.2.3 solaredge-local==0.2.3
# homeassistant.components.solarlog
solarlog_cli==0.1.5
# homeassistant.components.solax # homeassistant.components.solax
solax==3.1.1 solax==3.1.1
@ -2661,9 +2664,6 @@ stringcase==1.2.0
# homeassistant.components.subaru # homeassistant.components.subaru
subarulink==0.7.11 subarulink==0.7.11
# homeassistant.components.solarlog
sunwatcher==0.2.1
# homeassistant.components.sunweg # homeassistant.components.sunweg
sunweg==3.0.1 sunweg==3.0.1

View File

@ -2020,6 +2020,9 @@ snapcast==2.3.6
# homeassistant.components.sonos # homeassistant.components.sonos
soco==0.30.4 soco==0.30.4
# homeassistant.components.solarlog
solarlog_cli==0.1.5
# homeassistant.components.solax # homeassistant.components.solax
solax==3.1.1 solax==3.1.1
@ -2077,9 +2080,6 @@ stringcase==1.2.0
# homeassistant.components.subaru # homeassistant.components.subaru
subarulink==0.7.11 subarulink==0.7.11
# homeassistant.components.solarlog
sunwatcher==0.2.1
# homeassistant.components.sunweg # homeassistant.components.sunweg
sunweg==3.0.1 sunweg==3.0.1

View File

@ -0,0 +1,54 @@
"""Test helpers."""
from collections.abc import Generator
from unittest.mock import AsyncMock, patch
import pytest
from homeassistant.core import HomeAssistant
from tests.common import mock_device_registry, mock_registry
@pytest.fixture
def mock_solarlog():
"""Build a fixture for the SolarLog API that connects successfully and returns one device."""
mock_solarlog_api = AsyncMock()
with patch(
"homeassistant.components.solarlog.config_flow.SolarLogConnector",
return_value=mock_solarlog_api,
) as mock_solarlog_api:
mock_solarlog_api.return_value.test_connection.return_value = True
yield mock_solarlog_api
@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock, None, None]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.solarlog.async_setup_entry", return_value=True
) as mock_setup_entry:
yield mock_setup_entry
@pytest.fixture(name="test_connect")
def mock_test_connection():
"""Mock a successful _test_connection."""
with patch(
"homeassistant.components.solarlog.config_flow.SolarLogConfigFlow._test_connection",
return_value=True,
):
yield
@pytest.fixture(name="device_reg")
def device_reg_fixture(hass: HomeAssistant):
"""Return an empty, loaded, registry."""
return mock_device_registry(hass)
@pytest.fixture(name="entity_reg")
def entity_reg_fixture(hass: HomeAssistant):
"""Return an empty, loaded, registry."""
return mock_registry(hass)

View File

@ -1,8 +1,9 @@
"""Test the solarlog config flow.""" """Test the solarlog config flow."""
from unittest.mock import patch from unittest.mock import AsyncMock, patch
import pytest import pytest
from solarlog_cli.solarlog_exceptions import SolarLogConnectionError, SolarLogError
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.solarlog import config_flow from homeassistant.components.solarlog import config_flow
@ -17,7 +18,7 @@ NAME = "Solarlog test 1 2 3"
HOST = "http://1.1.1.1" HOST = "http://1.1.1.1"
async def test_form(hass: HomeAssistant) -> None: async def test_form(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None:
"""Test we get the form.""" """Test we get the form."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -29,34 +30,22 @@ async def test_form(hass: HomeAssistant) -> None:
with ( with (
patch( patch(
"homeassistant.components.solarlog.config_flow.SolarLogConfigFlow._test_connection", "homeassistant.components.solarlog.config_flow.SolarLogConfigFlow._test_connection",
return_value={"title": "solarlog test 1 2 3"},
),
patch(
"homeassistant.components.solarlog.async_setup_entry",
return_value=True, return_value=True,
) as mock_setup_entry, ),
): ):
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], {"host": HOST, "name": NAME} result["flow_id"],
{CONF_HOST: HOST, CONF_NAME: NAME, "extended_data": False},
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == "solarlog_test_1_2_3" assert result2["title"] == "solarlog_test_1_2_3"
assert result2["data"] == {"host": "http://1.1.1.1"} assert result2["data"][CONF_HOST] == "http://1.1.1.1"
assert result2["data"]["extended_data"] is False
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
@pytest.fixture(name="test_connect")
def mock_controller():
"""Mock a successful _host_in_configuration_exists."""
with patch(
"homeassistant.components.solarlog.config_flow.SolarLogConfigFlow._test_connection",
return_value=True,
):
yield
def init_config_flow(hass): def init_config_flow(hass):
"""Init a configuration flow.""" """Init a configuration flow."""
flow = config_flow.SolarLogConfigFlow() flow = config_flow.SolarLogConfigFlow()
@ -64,19 +53,75 @@ def init_config_flow(hass):
return flow return flow
async def test_user(hass: HomeAssistant, test_connect) -> None: @pytest.mark.usefixtures("test_connect")
async def test_user(
hass: HomeAssistant,
mock_solarlog: AsyncMock,
mock_setup_entry: AsyncMock,
) -> None:
"""Test user config.""" """Test user config."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] is FlowResultType.FORM
assert result["errors"] == {}
# tests with all provided
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {CONF_HOST: HOST, CONF_NAME: NAME, "extended_data": False}
)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "solarlog_test_1_2_3"
assert result["data"][CONF_HOST] == HOST
assert len(mock_setup_entry.mock_calls) == 1
@pytest.mark.parametrize(
("exception", "error"),
[
(SolarLogConnectionError, {CONF_HOST: "cannot_connect"}),
(SolarLogError, {CONF_HOST: "unknown"}),
],
)
async def test_form_exceptions(
hass: HomeAssistant,
exception: Exception,
error: dict[str, str],
mock_solarlog: AsyncMock,
) -> None:
"""Test we can handle Form exceptions."""
flow = init_config_flow(hass) flow = init_config_flow(hass)
result = await flow.async_step_user() result = await flow.async_step_user()
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user" assert result["step_id"] == "user"
# tets with all provided mock_solarlog.return_value.test_connection.side_effect = exception
result = await flow.async_step_user({CONF_NAME: NAME, CONF_HOST: HOST})
# tests with connection error
result = await flow.async_step_user(
{CONF_NAME: NAME, CONF_HOST: HOST, "extended_data": False}
)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
assert result["errors"] == error
mock_solarlog.return_value.test_connection.side_effect = None
# tests with all provided
result = await flow.async_step_user(
{CONF_NAME: NAME, CONF_HOST: HOST, "extended_data": False}
)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "solarlog_test_1_2_3" assert result["title"] == "solarlog_test_1_2_3"
assert result["data"][CONF_HOST] == HOST assert result["data"][CONF_HOST] == HOST
assert result["data"]["extended_data"] is False
async def test_import(hass: HomeAssistant, test_connect) -> None: async def test_import(hass: HomeAssistant, test_connect) -> None:
@ -85,18 +130,24 @@ async def test_import(hass: HomeAssistant, test_connect) -> None:
# import with only host # import with only host
result = await flow.async_step_import({CONF_HOST: HOST}) result = await flow.async_step_import({CONF_HOST: HOST})
await hass.async_block_till_done()
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "solarlog" assert result["title"] == "solarlog"
assert result["data"][CONF_HOST] == HOST assert result["data"][CONF_HOST] == HOST
# import with only name # import with only name
result = await flow.async_step_import({CONF_NAME: NAME}) result = await flow.async_step_import({CONF_NAME: NAME})
await hass.async_block_till_done()
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "solarlog_test_1_2_3" assert result["title"] == "solarlog_test_1_2_3"
assert result["data"][CONF_HOST] == DEFAULT_HOST assert result["data"][CONF_HOST] == DEFAULT_HOST
# import with host and name # import with host and name
result = await flow.async_step_import({CONF_HOST: HOST, CONF_NAME: NAME}) result = await flow.async_step_import({CONF_HOST: HOST, CONF_NAME: NAME})
await hass.async_block_till_done()
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "solarlog_test_1_2_3" assert result["title"] == "solarlog_test_1_2_3"
assert result["data"][CONF_HOST] == HOST assert result["data"][CONF_HOST] == HOST
@ -111,7 +162,7 @@ async def test_abort_if_already_setup(hass: HomeAssistant, test_connect) -> None
# Should fail, same HOST different NAME (default) # Should fail, same HOST different NAME (default)
result = await flow.async_step_import( result = await flow.async_step_import(
{CONF_HOST: HOST, CONF_NAME: "solarlog_test_7_8_9"} {CONF_HOST: HOST, CONF_NAME: "solarlog_test_7_8_9", "extended_data": False}
) )
assert result["type"] is FlowResultType.ABORT assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"
@ -123,7 +174,7 @@ async def test_abort_if_already_setup(hass: HomeAssistant, test_connect) -> None
# SHOULD pass, diff HOST (without http://), different NAME # SHOULD pass, diff HOST (without http://), different NAME
result = await flow.async_step_import( result = await flow.async_step_import(
{CONF_HOST: "2.2.2.2", CONF_NAME: "solarlog_test_7_8_9"} {CONF_HOST: "2.2.2.2", CONF_NAME: "solarlog_test_7_8_9", "extended_data": False}
) )
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "solarlog_test_7_8_9" assert result["title"] == "solarlog_test_7_8_9"
@ -131,8 +182,10 @@ async def test_abort_if_already_setup(hass: HomeAssistant, test_connect) -> None
# SHOULD pass, diff HOST, same NAME # SHOULD pass, diff HOST, same NAME
result = await flow.async_step_import( result = await flow.async_step_import(
{CONF_HOST: "http://2.2.2.2", CONF_NAME: NAME} {CONF_HOST: "http://2.2.2.2", CONF_NAME: NAME, "extended_data": False}
) )
await hass.async_block_till_done()
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "solarlog_test_1_2_3" assert result["title"] == "solarlog_test_1_2_3"
assert result["data"][CONF_HOST] == "http://2.2.2.2" assert result["data"][CONF_HOST] == "http://2.2.2.2"

View File

@ -0,0 +1,57 @@
"""Test the initialization."""
from homeassistant.components.solarlog.const import DOMAIN
from homeassistant.const import CONF_HOST, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceRegistry
from homeassistant.helpers.entity_registry import EntityRegistry
from .test_config_flow import HOST, NAME
from tests.common import MockConfigEntry
async def test_migrate_config_entry(
hass: HomeAssistant, device_reg: DeviceRegistry, entity_reg: EntityRegistry
) -> None:
"""Test successful migration of entry data."""
entry = MockConfigEntry(
domain=DOMAIN,
title=NAME,
data={
CONF_HOST: HOST,
},
version=1,
minor_version=1,
)
entry.add_to_hass(hass)
device = device_reg.async_get_or_create(
config_entry_id=entry.entry_id,
identifiers={(DOMAIN, entry.entry_id)},
manufacturer="Solar-Log",
name="solarlog",
)
sensor_entity = entity_reg.async_get_or_create(
config_entry=entry,
platform=DOMAIN,
domain=Platform.SENSOR,
unique_id=f"{entry.entry_id}_time",
device_id=device.id,
)
assert entry.version == 1
assert entry.minor_version == 1
assert sensor_entity.unique_id == f"{entry.entry_id}_time"
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
entity_migrated = entity_reg.async_get(sensor_entity.entity_id)
assert entity_migrated
assert entity_migrated.unique_id == f"{entry.entry_id}_last_updated"
assert entry.version == 1
assert entry.minor_version == 2
assert entry.data[CONF_HOST] == HOST
assert entry.data["extended_data"] is False