mirror of
https://github.com/home-assistant/core.git
synced 2025-06-25 01:21:51 +02:00
Replace Solarlog unmaintained library (#117484)
Co-authored-by: Robert Resch <robert@resch.dev>
This commit is contained in:
@ -1305,8 +1305,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/solaredge/ @frenck @bdraco
|
||||
/tests/components/solaredge/ @frenck @bdraco
|
||||
/homeassistant/components/solaredge_local/ @drobtravels @scheric
|
||||
/homeassistant/components/solarlog/ @Ernst79
|
||||
/tests/components/solarlog/ @Ernst79
|
||||
/homeassistant/components/solarlog/ @Ernst79 @dontinelli
|
||||
/tests/components/solarlog/ @Ernst79 @dontinelli
|
||||
/homeassistant/components/solax/ @squishykid
|
||||
/tests/components/solax/ @squishykid
|
||||
/homeassistant/components/soma/ @ratsept @sebfortier2288
|
||||
|
@ -1,12 +1,17 @@
|
||||
"""Solar-Log integration."""
|
||||
|
||||
import logging
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import SolarlogData
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
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:
|
||||
"""Unload a config entry."""
|
||||
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
|
||||
|
@ -1,13 +1,14 @@
|
||||
"""Config flow for solarlog integration."""
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
from urllib.parse import ParseResult, urlparse
|
||||
|
||||
from requests.exceptions import HTTPError, Timeout
|
||||
from sunwatcher.solarlog.solarlog import SolarLog
|
||||
from solarlog_cli.solarlog_connector import SolarLogConnector
|
||||
from solarlog_cli.solarlog_exceptions import SolarLogConnectionError, SolarLogError
|
||||
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.core import HomeAssistant, callback
|
||||
from homeassistant.util import slugify
|
||||
@ -29,6 +30,7 @@ class SolarLogConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for solarlog."""
|
||||
|
||||
VERSION = 1
|
||||
MINOR_VERSION = 2
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize the config flow."""
|
||||
@ -40,37 +42,44 @@ class SolarLogConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
return True
|
||||
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):
|
||||
"""Check if we can connect to the Solar-Log device."""
|
||||
solarlog = SolarLogConnector(host)
|
||||
try:
|
||||
await self.hass.async_add_executor_job(SolarLog, host)
|
||||
except (OSError, HTTPError, Timeout):
|
||||
self._errors[CONF_HOST] = "cannot_connect"
|
||||
_LOGGER.error(
|
||||
"Could not connect to Solar-Log device at %s, check host ip address",
|
||||
host,
|
||||
)
|
||||
await solarlog.test_connection()
|
||||
except SolarLogConnectionError:
|
||||
self._errors = {CONF_HOST: "cannot_connect"}
|
||||
return False
|
||||
except SolarLogError: # pylint: disable=broad-except
|
||||
self._errors = {CONF_HOST: "unknown"}
|
||||
return False
|
||||
finally:
|
||||
solarlog.client.close()
|
||||
|
||||
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."""
|
||||
self._errors = {}
|
||||
if user_input is not None:
|
||||
# set some defaults in case we need to return to the form
|
||||
name = slugify(user_input.get(CONF_NAME, DEFAULT_NAME))
|
||||
host_entry = user_input.get(CONF_HOST, DEFAULT_HOST)
|
||||
user_input[CONF_NAME] = slugify(user_input[CONF_NAME])
|
||||
user_input[CONF_HOST] = self._parse_url(user_input[CONF_HOST])
|
||||
|
||||
url = urlparse(host_entry, "http")
|
||||
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):
|
||||
if self._host_in_configuration_exists(user_input[CONF_HOST]):
|
||||
self._errors[CONF_HOST] = "already_configured"
|
||||
elif await self._test_connection(host):
|
||||
return self.async_create_entry(title=name, data={CONF_HOST: host})
|
||||
elif await self._test_connection(user_input[CONF_HOST]):
|
||||
return self.async_create_entry(
|
||||
title=user_input[CONF_NAME], data=user_input
|
||||
)
|
||||
else:
|
||||
user_input = {}
|
||||
user_input[CONF_NAME] = DEFAULT_NAME
|
||||
@ -86,21 +95,25 @@ class SolarLogConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
vol.Required(
|
||||
CONF_HOST, default=user_input.get(CONF_HOST, DEFAULT_HOST)
|
||||
): str,
|
||||
vol.Required("extended_data", default=False): bool,
|
||||
}
|
||||
),
|
||||
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."""
|
||||
host_entry = user_input.get(CONF_HOST, DEFAULT_HOST)
|
||||
|
||||
url = urlparse(host_entry, "http")
|
||||
netloc = url.netloc or url.path
|
||||
path = url.path if url.netloc else ""
|
||||
url = ParseResult("http", netloc, path, *url[3:])
|
||||
host = url.geturl()
|
||||
user_input = {
|
||||
CONF_HOST: DEFAULT_HOST,
|
||||
CONF_NAME: DEFAULT_NAME,
|
||||
"extended_data": False,
|
||||
**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 await self.async_step_user(user_input)
|
||||
|
@ -4,12 +4,16 @@ from datetime import timedelta
|
||||
import logging
|
||||
from urllib.parse import ParseResult, urlparse
|
||||
|
||||
from requests.exceptions import HTTPError, Timeout
|
||||
from sunwatcher.solarlog.solarlog import SolarLog
|
||||
from solarlog_cli.solarlog_connector import SolarLogConnector
|
||||
from solarlog_cli.solarlog_exceptions import (
|
||||
SolarLogConnectionError,
|
||||
SolarLogUpdateError,
|
||||
)
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_HOST
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import update_coordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -34,24 +38,23 @@ class SolarlogData(update_coordinator.DataUpdateCoordinator):
|
||||
self.name = entry.title
|
||||
self.host = url.geturl()
|
||||
|
||||
async def _async_update_data(self):
|
||||
"""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
|
||||
extended_data = entry.data["extended_data"]
|
||||
|
||||
if data.time.year == 1999:
|
||||
raise update_coordinator.UpdateFailed(
|
||||
"Invalid data returned (can happen after Solarlog restart)."
|
||||
)
|
||||
|
||||
self.logger.debug(
|
||||
(
|
||||
"Connection to Solarlog successful. Retrieving latest Solarlog update"
|
||||
" of %s"
|
||||
),
|
||||
data.time,
|
||||
self.solarlog = SolarLogConnector(
|
||||
self.host, extended_data, hass.config.time_zone
|
||||
)
|
||||
|
||||
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
|
||||
|
@ -1,10 +1,10 @@
|
||||
{
|
||||
"domain": "solarlog",
|
||||
"name": "Solar-Log",
|
||||
"codeowners": ["@Ernst79"],
|
||||
"codeowners": ["@Ernst79", "@dontinelli"],
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/solarlog",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["sunwatcher"],
|
||||
"requirements": ["sunwatcher==0.2.1"]
|
||||
"loggers": ["solarlog_cli"],
|
||||
"requirements": ["solarlog_cli==0.1.5"]
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
from homeassistant.util.dt import as_local
|
||||
|
||||
from . import SolarlogData
|
||||
from .const import DOMAIN
|
||||
@ -36,10 +35,9 @@ class SolarLogSensorEntityDescription(SensorEntityDescription):
|
||||
|
||||
SENSOR_TYPES: tuple[SolarLogSensorEntityDescription, ...] = (
|
||||
SolarLogSensorEntityDescription(
|
||||
key="time",
|
||||
key="last_updated",
|
||||
translation_key="last_update",
|
||||
device_class=SensorDeviceClass.TIMESTAMP,
|
||||
value=as_local,
|
||||
),
|
||||
SolarLogSensorEntityDescription(
|
||||
key="power_ac",
|
||||
@ -231,7 +229,8 @@ class SolarlogSensor(CoordinatorEntity[SolarlogData], SensorEntity):
|
||||
@property
|
||||
def native_value(self):
|
||||
"""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:
|
||||
return self.entity_description.value(raw_attr)
|
||||
return raw_attr
|
||||
|
@ -5,7 +5,8 @@
|
||||
"title": "Define your Solar-Log connection",
|
||||
"data": {
|
||||
"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": {
|
||||
"host": "The hostname or IP address of your Solar-Log device."
|
||||
@ -14,7 +15,8 @@
|
||||
},
|
||||
"error": {
|
||||
"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": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
|
@ -2601,6 +2601,9 @@ soco==0.30.4
|
||||
# homeassistant.components.solaredge_local
|
||||
solaredge-local==0.2.3
|
||||
|
||||
# homeassistant.components.solarlog
|
||||
solarlog_cli==0.1.5
|
||||
|
||||
# homeassistant.components.solax
|
||||
solax==3.1.1
|
||||
|
||||
@ -2661,9 +2664,6 @@ stringcase==1.2.0
|
||||
# homeassistant.components.subaru
|
||||
subarulink==0.7.11
|
||||
|
||||
# homeassistant.components.solarlog
|
||||
sunwatcher==0.2.1
|
||||
|
||||
# homeassistant.components.sunweg
|
||||
sunweg==3.0.1
|
||||
|
||||
|
@ -2020,6 +2020,9 @@ snapcast==2.3.6
|
||||
# homeassistant.components.sonos
|
||||
soco==0.30.4
|
||||
|
||||
# homeassistant.components.solarlog
|
||||
solarlog_cli==0.1.5
|
||||
|
||||
# homeassistant.components.solax
|
||||
solax==3.1.1
|
||||
|
||||
@ -2077,9 +2080,6 @@ stringcase==1.2.0
|
||||
# homeassistant.components.subaru
|
||||
subarulink==0.7.11
|
||||
|
||||
# homeassistant.components.solarlog
|
||||
sunwatcher==0.2.1
|
||||
|
||||
# homeassistant.components.sunweg
|
||||
sunweg==3.0.1
|
||||
|
||||
|
54
tests/components/solarlog/conftest.py
Normal file
54
tests/components/solarlog/conftest.py
Normal 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)
|
@ -1,8 +1,9 @@
|
||||
"""Test the solarlog config flow."""
|
||||
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
from solarlog_cli.solarlog_exceptions import SolarLogConnectionError, SolarLogError
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.solarlog import config_flow
|
||||
@ -17,7 +18,7 @@ NAME = "Solarlog test 1 2 3"
|
||||
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."""
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
@ -29,34 +30,22 @@ async def test_form(hass: HomeAssistant) -> None:
|
||||
with (
|
||||
patch(
|
||||
"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,
|
||||
) as mock_setup_entry,
|
||||
),
|
||||
):
|
||||
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()
|
||||
|
||||
assert result2["type"] is FlowResultType.CREATE_ENTRY
|
||||
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
|
||||
|
||||
|
||||
@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):
|
||||
"""Init a configuration flow."""
|
||||
flow = config_flow.SolarLogConfigFlow()
|
||||
@ -64,19 +53,75 @@ def init_config_flow(hass):
|
||||
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."""
|
||||
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)
|
||||
|
||||
result = await flow.async_step_user()
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
|
||||
# tets with all provided
|
||||
result = await flow.async_step_user({CONF_NAME: NAME, CONF_HOST: HOST})
|
||||
mock_solarlog.return_value.test_connection.side_effect = exception
|
||||
|
||||
# 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["title"] == "solarlog_test_1_2_3"
|
||||
assert result["data"][CONF_HOST] == HOST
|
||||
assert result["data"]["extended_data"] is False
|
||||
|
||||
|
||||
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
|
||||
result = await flow.async_step_import({CONF_HOST: HOST})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert result["title"] == "solarlog"
|
||||
assert result["data"][CONF_HOST] == HOST
|
||||
|
||||
# import with only 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["title"] == "solarlog_test_1_2_3"
|
||||
assert result["data"][CONF_HOST] == DEFAULT_HOST
|
||||
|
||||
# import with host and 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["title"] == "solarlog_test_1_2_3"
|
||||
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)
|
||||
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["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
|
||||
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["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
|
||||
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["title"] == "solarlog_test_1_2_3"
|
||||
assert result["data"][CONF_HOST] == "http://2.2.2.2"
|
||||
|
57
tests/components/solarlog/test_init.py
Normal file
57
tests/components/solarlog/test_init.py
Normal 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
|
Reference in New Issue
Block a user