mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +00:00
Improve Fronius tests (#132872)
This commit is contained in:
parent
544ebcf310
commit
be6ed05aa2
@ -3,20 +3,16 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from datetime import timedelta
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
|
||||
from homeassistant.components.fronius.const import DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_HOST
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.typing import UNDEFINED, UndefinedType
|
||||
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed, load_fixture
|
||||
from tests.common import MockConfigEntry, load_fixture
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
MOCK_HOST = "http://fronius"
|
||||
@ -115,24 +111,3 @@ def mock_responses(
|
||||
f"{host}/solar_api/v1/GetOhmPilotRealtimeData.cgi?Scope=System",
|
||||
text=_load(f"{fixture_set}/GetOhmPilotRealtimeData.json", "fronius"),
|
||||
)
|
||||
|
||||
|
||||
async def enable_all_entities(
|
||||
hass: HomeAssistant,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
config_entry_id: str,
|
||||
time_till_next_update: timedelta,
|
||||
) -> None:
|
||||
"""Enable all entities for a config entry and fast forward time to receive data."""
|
||||
registry = er.async_get(hass)
|
||||
entities = er.async_entries_for_config_entry(registry, config_entry_id)
|
||||
for entry in [
|
||||
entry
|
||||
for entry in entities
|
||||
if entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION
|
||||
]:
|
||||
registry.async_update_entity(entry.entity_id, disabled_by=None)
|
||||
await hass.async_block_till_done()
|
||||
freezer.tick(time_till_next_update)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
9024
tests/components/fronius/snapshots/test_sensor.ambr
Normal file
9024
tests/components/fronius/snapshots/test_sensor.ambr
Normal file
File diff suppressed because it is too large
Load Diff
@ -44,43 +44,62 @@ MOCK_DHCP_DATA = DhcpServiceInfo(
|
||||
)
|
||||
|
||||
|
||||
async def test_form_with_logger(hass: HomeAssistant) -> None:
|
||||
"""Test we get the form."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert not result["errors"]
|
||||
|
||||
with (
|
||||
patch(
|
||||
"pyfronius.Fronius.current_logger_info",
|
||||
return_value=LOGGER_INFO_RETURN_VALUE,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.fronius.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry,
|
||||
async def assert_finish_flow_with_logger(hass: HomeAssistant, flow_id: str) -> None:
|
||||
"""Assert finishing the flow with a logger device."""
|
||||
with patch(
|
||||
"pyfronius.Fronius.current_logger_info",
|
||||
return_value=LOGGER_INFO_RETURN_VALUE,
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
flow_id,
|
||||
{
|
||||
"host": "10.9.8.1",
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert result2["title"] == "SolarNet Datalogger at 10.9.8.1"
|
||||
assert result2["data"] == {
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert result["title"] == "SolarNet Datalogger at 10.9.8.1"
|
||||
assert result["data"] == {
|
||||
"host": "10.9.8.1",
|
||||
"is_logger": True,
|
||||
}
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
assert result["result"].unique_id == "123.4567"
|
||||
|
||||
|
||||
async def assert_abort_flow_with_logger(
|
||||
hass: HomeAssistant, flow_id: str, reason: str
|
||||
) -> config_entries.ConfigFlowResult:
|
||||
"""Assert the flow was aborted when a logger device responded."""
|
||||
with patch(
|
||||
"pyfronius.Fronius.current_logger_info",
|
||||
return_value=LOGGER_INFO_RETURN_VALUE,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
flow_id,
|
||||
{
|
||||
"host": "10.9.8.1",
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == reason
|
||||
return result
|
||||
|
||||
|
||||
async def test_form_with_logger(hass: HomeAssistant) -> None:
|
||||
"""Test the basic flow with a logger device."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert not result["errors"]
|
||||
await assert_finish_flow_with_logger(hass, result["flow_id"])
|
||||
|
||||
|
||||
async def test_form_with_inverter(hass: HomeAssistant) -> None:
|
||||
"""Test we get the form."""
|
||||
"""Test the basic flow with a Gen24 device."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
@ -96,10 +115,6 @@ async def test_form_with_inverter(hass: HomeAssistant) -> None:
|
||||
"pyfronius.Fronius.inverter_info",
|
||||
return_value=INVERTER_INFO_RETURN_VALUE,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.fronius.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry,
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
@ -115,7 +130,7 @@ async def test_form_with_inverter(hass: HomeAssistant) -> None:
|
||||
"host": "10.9.1.1",
|
||||
"is_logger": False,
|
||||
}
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
assert result2["result"].unique_id == "1234567"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@ -154,6 +169,7 @@ async def test_form_cannot_connect(
|
||||
|
||||
assert result2["type"] is FlowResultType.FORM
|
||||
assert result2["errors"] == {"base": "cannot_connect"}
|
||||
await assert_finish_flow_with_logger(hass, result2["flow_id"])
|
||||
|
||||
|
||||
async def test_form_unexpected(hass: HomeAssistant) -> None:
|
||||
@ -175,13 +191,14 @@ async def test_form_unexpected(hass: HomeAssistant) -> None:
|
||||
|
||||
assert result2["type"] is FlowResultType.FORM
|
||||
assert result2["errors"] == {"base": "unknown"}
|
||||
await assert_finish_flow_with_logger(hass, result2["flow_id"])
|
||||
|
||||
|
||||
async def test_form_already_existing(hass: HomeAssistant) -> None:
|
||||
"""Test existing entry."""
|
||||
MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="123.4567",
|
||||
unique_id=LOGGER_INFO_RETURN_VALUE["unique_identifier"]["value"],
|
||||
data={CONF_HOST: "10.9.8.1", "is_logger": True},
|
||||
).add_to_hass(hass)
|
||||
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
|
||||
@ -189,20 +206,9 @@ async def test_form_already_existing(hass: HomeAssistant) -> None:
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
with patch(
|
||||
"pyfronius.Fronius.current_logger_info",
|
||||
return_value=LOGGER_INFO_RETURN_VALUE,
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"host": "10.9.8.1",
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] is FlowResultType.ABORT
|
||||
assert result2["reason"] == "already_configured"
|
||||
await assert_abort_flow_with_logger(
|
||||
hass, result["flow_id"], reason="already_configured"
|
||||
)
|
||||
|
||||
|
||||
async def test_config_flow_already_configured(
|
||||
@ -273,6 +279,7 @@ async def test_dhcp(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker) ->
|
||||
"host": MOCK_DHCP_DATA.ip,
|
||||
"is_logger": True,
|
||||
}
|
||||
assert result["result"].unique_id == "123.4567"
|
||||
|
||||
|
||||
async def test_dhcp_already_configured(
|
||||
@ -345,10 +352,6 @@ async def test_reconfigure(hass: HomeAssistant) -> None:
|
||||
"pyfronius.Fronius.inverter_info",
|
||||
return_value=INVERTER_INFO_RETURN_VALUE,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.fronius.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
@ -364,14 +367,13 @@ async def test_reconfigure(hass: HomeAssistant) -> None:
|
||||
"host": new_host,
|
||||
"is_logger": False,
|
||||
}
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
async def test_reconfigure_cannot_connect(hass: HomeAssistant) -> None:
|
||||
"""Test we handle cannot connect error."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="123.4567890",
|
||||
unique_id=LOGGER_INFO_RETURN_VALUE["unique_identifier"]["value"],
|
||||
data={
|
||||
CONF_HOST: "10.1.2.3",
|
||||
"is_logger": True,
|
||||
@ -401,12 +403,16 @@ async def test_reconfigure_cannot_connect(hass: HomeAssistant) -> None:
|
||||
assert result2["type"] is FlowResultType.FORM
|
||||
assert result2["errors"] == {"base": "cannot_connect"}
|
||||
|
||||
await assert_abort_flow_with_logger(
|
||||
hass, result2["flow_id"], reason="reconfigure_successful"
|
||||
)
|
||||
|
||||
|
||||
async def test_reconfigure_unexpected(hass: HomeAssistant) -> None:
|
||||
"""Test we handle unexpected error."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="123.4567890",
|
||||
unique_id=LOGGER_INFO_RETURN_VALUE["unique_identifier"]["value"],
|
||||
data={
|
||||
CONF_HOST: "10.1.2.3",
|
||||
"is_logger": True,
|
||||
@ -430,12 +436,16 @@ async def test_reconfigure_unexpected(hass: HomeAssistant) -> None:
|
||||
assert result2["type"] is FlowResultType.FORM
|
||||
assert result2["errors"] == {"base": "unknown"}
|
||||
|
||||
await assert_abort_flow_with_logger(
|
||||
hass, result2["flow_id"], reason="reconfigure_successful"
|
||||
)
|
||||
|
||||
async def test_reconfigure_already_configured(hass: HomeAssistant) -> None:
|
||||
"""Test reconfiguring an entry."""
|
||||
|
||||
async def test_reconfigure_to_different_device(hass: HomeAssistant) -> None:
|
||||
"""Test reconfiguring an entry to a different device."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="123.4567890",
|
||||
unique_id="999.9999999",
|
||||
data={
|
||||
CONF_HOST: "10.1.2.3",
|
||||
"is_logger": True,
|
||||
@ -447,68 +457,6 @@ async def test_reconfigure_already_configured(hass: HomeAssistant) -> None:
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "reconfigure"
|
||||
|
||||
with (
|
||||
patch(
|
||||
"pyfronius.Fronius.current_logger_info",
|
||||
return_value=LOGGER_INFO_RETURN_VALUE,
|
||||
),
|
||||
patch(
|
||||
"pyfronius.Fronius.inverter_info",
|
||||
return_value=INVERTER_INFO_RETURN_VALUE,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.fronius.async_setup_entry",
|
||||
return_value=True,
|
||||
) as mock_setup_entry,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
"host": "10.1.2.3",
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "unique_id_mismatch"
|
||||
assert len(mock_setup_entry.mock_calls) == 0
|
||||
|
||||
|
||||
async def test_reconfigure_already_existing(hass: HomeAssistant) -> None:
|
||||
"""Test reconfiguring entry to already existing device."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="123.4567890",
|
||||
data={
|
||||
CONF_HOST: "10.1.2.3",
|
||||
"is_logger": True,
|
||||
},
|
||||
await assert_abort_flow_with_logger(
|
||||
hass, result["flow_id"], reason="unique_id_mismatch"
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
entry_2_uid = "222.2222222"
|
||||
entry_2 = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id=entry_2_uid,
|
||||
data={
|
||||
CONF_HOST: "10.2.2.2",
|
||||
"is_logger": True,
|
||||
},
|
||||
)
|
||||
entry_2.add_to_hass(hass)
|
||||
|
||||
result = await entry.start_reconfigure_flow(hass)
|
||||
with patch(
|
||||
"pyfronius.Fronius.current_logger_info",
|
||||
return_value={"unique_identifier": {"value": entry_2_uid}},
|
||||
):
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
"host": "10.1.1.1",
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result2["type"] is FlowResultType.ABORT
|
||||
assert result2["reason"] == "unique_id_mismatch"
|
||||
|
@ -29,7 +29,7 @@ async def test_adaptive_update_interval(
|
||||
mock_inverter_data.reset_mock()
|
||||
|
||||
freezer.tick(FroniusInverterUpdateCoordinator.default_interval)
|
||||
async_fire_time_changed(hass, None)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
mock_inverter_data.assert_called_once()
|
||||
mock_inverter_data.reset_mock()
|
||||
@ -38,13 +38,13 @@ async def test_adaptive_update_interval(
|
||||
# first 3 bad requests at default interval - 4th has different interval
|
||||
for _ in range(3):
|
||||
freezer.tick(FroniusInverterUpdateCoordinator.default_interval)
|
||||
async_fire_time_changed(hass, None)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
assert mock_inverter_data.call_count == 3
|
||||
mock_inverter_data.reset_mock()
|
||||
|
||||
freezer.tick(FroniusInverterUpdateCoordinator.error_interval)
|
||||
async_fire_time_changed(hass, None)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
assert mock_inverter_data.call_count == 1
|
||||
mock_inverter_data.reset_mock()
|
||||
@ -52,13 +52,13 @@ async def test_adaptive_update_interval(
|
||||
mock_inverter_data.side_effect = None
|
||||
# next successful request resets to default interval
|
||||
freezer.tick(FroniusInverterUpdateCoordinator.error_interval)
|
||||
async_fire_time_changed(hass, None)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
mock_inverter_data.assert_called_once()
|
||||
mock_inverter_data.reset_mock()
|
||||
|
||||
freezer.tick(FroniusInverterUpdateCoordinator.default_interval)
|
||||
async_fire_time_changed(hass, None)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
mock_inverter_data.assert_called_once()
|
||||
mock_inverter_data.reset_mock()
|
||||
@ -68,7 +68,7 @@ async def test_adaptive_update_interval(
|
||||
# first 3 requests at default interval - 4th has different interval
|
||||
for _ in range(3):
|
||||
freezer.tick(FroniusInverterUpdateCoordinator.default_interval)
|
||||
async_fire_time_changed(hass, None)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
# BadStatusError does 3 silent retries for inverter endpoint * 3 request intervals = 9
|
||||
assert mock_inverter_data.call_count == 9
|
||||
|
@ -3,6 +3,7 @@
|
||||
from datetime import timedelta
|
||||
from unittest.mock import patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
from pyfronius import FroniusError
|
||||
|
||||
from homeassistant.components.fronius.const import DOMAIN, SOLAR_NET_RESCAN_TIMER
|
||||
@ -10,7 +11,6 @@ from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from . import mock_responses, setup_fronius_integration
|
||||
|
||||
@ -66,6 +66,7 @@ async def test_inverter_night_rescan(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test dynamic adding of an inverter discovered automatically after a Home Assistant reboot during the night."""
|
||||
mock_responses(aioclient_mock, fixture_set="igplus_v2", night=True)
|
||||
@ -78,9 +79,8 @@ async def test_inverter_night_rescan(
|
||||
|
||||
# Switch to daytime
|
||||
mock_responses(aioclient_mock, fixture_set="igplus_v2", night=False)
|
||||
async_fire_time_changed(
|
||||
hass, dt_util.utcnow() + timedelta(minutes=SOLAR_NET_RESCAN_TIMER)
|
||||
)
|
||||
freezer.tick(timedelta(minutes=SOLAR_NET_RESCAN_TIMER))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# We expect our inverter to be present now
|
||||
@ -88,9 +88,8 @@ async def test_inverter_night_rescan(
|
||||
assert inverter_1.manufacturer == "Fronius"
|
||||
|
||||
# After another re-scan we still only expect this inverter
|
||||
async_fire_time_changed(
|
||||
hass, dt_util.utcnow() + timedelta(minutes=SOLAR_NET_RESCAN_TIMER * 2)
|
||||
)
|
||||
freezer.tick(timedelta(minutes=SOLAR_NET_RESCAN_TIMER))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
inverter_1 = device_registry.async_get_device(identifiers={(DOMAIN, "203200")})
|
||||
assert inverter_1.manufacturer == "Fronius"
|
||||
@ -100,6 +99,7 @@ async def test_inverter_rescan_interruption(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test interruption of re-scan during runtime to process further."""
|
||||
mock_responses(aioclient_mock, fixture_set="igplus_v2", night=True)
|
||||
@ -115,9 +115,8 @@ async def test_inverter_rescan_interruption(
|
||||
"pyfronius.Fronius.inverter_info",
|
||||
side_effect=FroniusError,
|
||||
):
|
||||
async_fire_time_changed(
|
||||
hass, dt_util.utcnow() + timedelta(minutes=SOLAR_NET_RESCAN_TIMER)
|
||||
)
|
||||
freezer.tick(timedelta(minutes=SOLAR_NET_RESCAN_TIMER))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# No increase of devices expected because of a FroniusError
|
||||
@ -132,9 +131,8 @@ async def test_inverter_rescan_interruption(
|
||||
|
||||
# Next re-scan will pick up the new inverter. Expect 2 devices now.
|
||||
mock_responses(aioclient_mock, fixture_set="igplus_v2", night=False)
|
||||
async_fire_time_changed(
|
||||
hass, dt_util.utcnow() + timedelta(minutes=SOLAR_NET_RESCAN_TIMER * 2)
|
||||
)
|
||||
freezer.tick(timedelta(minutes=SOLAR_NET_RESCAN_TIMER))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert (
|
||||
|
@ -2,27 +2,29 @@
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.fronius.const import DOMAIN
|
||||
from homeassistant.components.fronius.coordinator import (
|
||||
FroniusInverterUpdateCoordinator,
|
||||
FroniusMeterUpdateCoordinator,
|
||||
FroniusPowerFlowUpdateCoordinator,
|
||||
)
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
|
||||
from . import enable_all_entities, mock_responses, setup_fronius_integration
|
||||
from . import mock_responses, setup_fronius_integration
|
||||
|
||||
from tests.common import async_fire_time_changed
|
||||
from tests.common import async_fire_time_changed, snapshot_platform
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_symo_inverter(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test Fronius Symo inverter entities."""
|
||||
|
||||
@ -32,15 +34,8 @@ async def test_symo_inverter(
|
||||
|
||||
# Init at night
|
||||
mock_responses(aioclient_mock, night=True)
|
||||
config_entry = await setup_fronius_integration(hass)
|
||||
await setup_fronius_integration(hass)
|
||||
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 22
|
||||
await enable_all_entities(
|
||||
hass,
|
||||
freezer,
|
||||
config_entry.entry_id,
|
||||
FroniusInverterUpdateCoordinator.default_interval,
|
||||
)
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 58
|
||||
assert_state("sensor.symo_20_dc_current", 0)
|
||||
assert_state("sensor.symo_20_energy_day", 10828)
|
||||
@ -54,13 +49,6 @@ async def test_symo_inverter(
|
||||
freezer.tick(FroniusInverterUpdateCoordinator.default_interval)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 62
|
||||
await enable_all_entities(
|
||||
hass,
|
||||
freezer,
|
||||
config_entry.entry_id,
|
||||
FroniusInverterUpdateCoordinator.default_interval,
|
||||
)
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 64
|
||||
# 4 additional AC entities
|
||||
assert_state("sensor.symo_20_dc_current", 2.19)
|
||||
@ -104,6 +92,7 @@ async def test_symo_logger(
|
||||
assert_state("sensor.solarnet_grid_import_tariff", 0.15)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_symo_meter(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
@ -117,15 +106,8 @@ async def test_symo_meter(
|
||||
assert state.state == str(expected_state)
|
||||
|
||||
mock_responses(aioclient_mock)
|
||||
config_entry = await setup_fronius_integration(hass)
|
||||
await setup_fronius_integration(hass)
|
||||
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 26
|
||||
await enable_all_entities(
|
||||
hass,
|
||||
freezer,
|
||||
config_entry.entry_id,
|
||||
FroniusMeterUpdateCoordinator.default_interval,
|
||||
)
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 64
|
||||
# states are rounded to 4 decimals
|
||||
assert_state("sensor.smart_meter_63a_current_phase_1", 7.755)
|
||||
@ -206,6 +188,7 @@ async def test_symo_meter_forged(
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_symo_power_flow(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
@ -220,15 +203,8 @@ async def test_symo_power_flow(
|
||||
|
||||
# First test at night
|
||||
mock_responses(aioclient_mock, night=True)
|
||||
config_entry = await setup_fronius_integration(hass)
|
||||
await setup_fronius_integration(hass)
|
||||
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 22
|
||||
await enable_all_entities(
|
||||
hass,
|
||||
freezer,
|
||||
config_entry.entry_id,
|
||||
FroniusInverterUpdateCoordinator.default_interval,
|
||||
)
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 58
|
||||
# states are rounded to 4 decimals
|
||||
assert_state("sensor.solarnet_energy_day", 10828)
|
||||
@ -277,10 +253,13 @@ async def test_symo_power_flow(
|
||||
assert_state("sensor.solarnet_relative_self_consumption", 0)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_gen24(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
entity_registry: er.EntityRegistry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test Fronius Gen24 inverter entities."""
|
||||
|
||||
@ -292,72 +271,10 @@ async def test_gen24(
|
||||
mock_responses(aioclient_mock, fixture_set="gen24")
|
||||
config_entry = await setup_fronius_integration(hass, is_logger=False)
|
||||
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 24
|
||||
await enable_all_entities(
|
||||
hass,
|
||||
freezer,
|
||||
config_entry.entry_id,
|
||||
FroniusMeterUpdateCoordinator.default_interval,
|
||||
)
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 58
|
||||
# inverter 1
|
||||
assert_state("sensor.inverter_name_ac_current", 0.1589)
|
||||
assert_state("sensor.inverter_name_dc_current_2", 0.0754)
|
||||
assert_state("sensor.inverter_name_status_code", 7)
|
||||
assert_state("sensor.inverter_name_status_message", "running")
|
||||
assert_state("sensor.inverter_name_dc_current", 0.0783)
|
||||
assert_state("sensor.inverter_name_dc_voltage_2", 403.4312)
|
||||
assert_state("sensor.inverter_name_ac_power", 37.3204)
|
||||
assert_state("sensor.inverter_name_error_code", 0)
|
||||
assert_state("sensor.inverter_name_dc_voltage", 411.3811)
|
||||
assert_state("sensor.inverter_name_total_energy", 1530193.42)
|
||||
assert_state("sensor.inverter_name_inverter_state", "Running")
|
||||
assert_state("sensor.inverter_name_ac_voltage", 234.9168)
|
||||
assert_state("sensor.inverter_name_frequency", 49.9917)
|
||||
# meter
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_energy_produced", 3863340.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_energy_consumed", 2013105.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_power", 653.1)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_frequency_phase_average", 49.9)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_meter_location", 0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_meter_location_description", "feed_in")
|
||||
assert_state("sensor.smart_meter_ts_65a_3_power_factor", 0.828)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_reactive_energy_consumed", 88221.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_energy_minus", 3863340.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_current_phase_2", 2.33)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_voltage_phase_1", 235.9)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_voltage_phase_1_2", 408.7)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_power_phase_2", 294.9)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_energy_plus", 2013105.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_voltage_phase_2", 236.1)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_reactive_energy_produced", 1989125.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_voltage_phase_3", 236.9)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_power_factor_phase_1", 0.441)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_voltage_phase_2_3", 409.6)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_current_phase_3", 1.825)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_power_factor_phase_3", 0.832)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_apparent_power_phase_1", 243.3)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_voltage_phase_3_1", 409.4)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_apparent_power_phase_2", 323.4)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_apparent_power_phase_3", 301.2)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_power_phase_1", 106.8)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_power_factor_phase_2", 0.934)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_power_phase_3", 251.3)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_reactive_power_phase_1", -218.6)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_reactive_power_phase_2", -132.8)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_reactive_power_phase_3", -166.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_apparent_power", 868.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_reactive_power", -517.4)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_current_phase_1", 1.145)
|
||||
# power_flow
|
||||
assert_state("sensor.solarnet_power_grid", 658.4)
|
||||
assert_state("sensor.solarnet_relative_self_consumption", 100.0)
|
||||
assert_state("sensor.solarnet_power_photovoltaics", 62.9481)
|
||||
assert_state("sensor.solarnet_power_load", -695.6827)
|
||||
assert_state("sensor.solarnet_meter_mode", "meter")
|
||||
assert_state("sensor.solarnet_relative_autonomy", 5.3592)
|
||||
assert_state("sensor.solarnet_total_energy", 1530193.42)
|
||||
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
|
||||
|
||||
assert_state("sensor.inverter_name_total_energy", 1530193.42)
|
||||
# Gen24 devices may report 0 for total energy while doing firmware updates.
|
||||
# This should yield "unknown" state instead of 0.
|
||||
mock_responses(
|
||||
@ -375,11 +292,14 @@ async def test_gen24(
|
||||
assert_state("sensor.inverter_name_total_energy", "unknown")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_gen24_storage(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
entity_registry: er.EntityRegistry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test Fronius Gen24 inverter with BYD battery and Ohmpilot entities."""
|
||||
|
||||
@ -393,87 +313,8 @@ async def test_gen24_storage(
|
||||
hass, is_logger=False, unique_id="12345678"
|
||||
)
|
||||
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 37
|
||||
await enable_all_entities(
|
||||
hass,
|
||||
freezer,
|
||||
config_entry.entry_id,
|
||||
FroniusMeterUpdateCoordinator.default_interval,
|
||||
)
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 72
|
||||
# inverter 1
|
||||
assert_state("sensor.gen24_storage_dc_current", 0.3952)
|
||||
assert_state("sensor.gen24_storage_dc_voltage_2", 318.8103)
|
||||
assert_state("sensor.gen24_storage_dc_current_2", 0.3564)
|
||||
assert_state("sensor.gen24_storage_ac_current", 1.1087)
|
||||
assert_state("sensor.gen24_storage_ac_power", 250.9093)
|
||||
assert_state("sensor.gen24_storage_error_code", 0)
|
||||
assert_state("sensor.gen24_storage_status_code", 7)
|
||||
assert_state("sensor.gen24_storage_status_message", "running")
|
||||
assert_state("sensor.gen24_storage_total_energy", 7512794.0117)
|
||||
assert_state("sensor.gen24_storage_inverter_state", "Running")
|
||||
assert_state("sensor.gen24_storage_dc_voltage", 419.1009)
|
||||
assert_state("sensor.gen24_storage_ac_voltage", 227.354)
|
||||
assert_state("sensor.gen24_storage_frequency", 49.9816)
|
||||
# meter
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_energy_produced", 1705128.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_power", 487.7)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_power_factor", 0.698)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_energy_consumed", 1247204.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_frequency_phase_average", 49.9)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_meter_location", 0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_meter_location_description", "feed_in")
|
||||
assert_state("sensor.smart_meter_ts_65a_3_reactive_power", -501.5)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_reactive_energy_produced", 3266105.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_power_phase_3", 19.6)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_current_phase_3", 0.645)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_energy_minus", 1705128.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_apparent_power_phase_2", 383.9)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_current_phase_1", 1.701)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_current_phase_2", 1.832)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_apparent_power_phase_1", 319.5)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_voltage_phase_1", 229.4)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_power_phase_2", 150.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_voltage_phase_3_1", 394.3)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_voltage_phase_2", 225.6)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_reactive_energy_consumed", 5482.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_energy_plus", 1247204.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_power_factor_phase_1", 0.995)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_power_factor_phase_3", 0.163)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_power_factor_phase_2", 0.389)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_reactive_power_phase_1", -31.3)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_reactive_power_phase_3", -116.7)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_voltage_phase_1_2", 396.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_voltage_phase_2_3", 393.0)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_reactive_power_phase_2", -353.4)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_real_power_phase_1", 317.9)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_voltage_phase_3", 228.3)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_apparent_power", 821.9)
|
||||
assert_state("sensor.smart_meter_ts_65a_3_apparent_power_phase_3", 118.4)
|
||||
# ohmpilot
|
||||
assert_state("sensor.ohmpilot_energy_consumed", 1233295.0)
|
||||
assert_state("sensor.ohmpilot_power", 0.0)
|
||||
assert_state("sensor.ohmpilot_temperature", 38.9)
|
||||
assert_state("sensor.ohmpilot_state_code", 0.0)
|
||||
assert_state("sensor.ohmpilot_state_message", "up_and_running")
|
||||
# power_flow
|
||||
assert_state("sensor.solarnet_power_grid", 2274.9)
|
||||
assert_state("sensor.solarnet_power_battery", 0.1591)
|
||||
assert_state("sensor.solarnet_power_battery_charge", 0)
|
||||
assert_state("sensor.solarnet_power_battery_discharge", 0.1591)
|
||||
assert_state("sensor.solarnet_power_load", -2459.3092)
|
||||
assert_state("sensor.solarnet_relative_self_consumption", 100.0)
|
||||
assert_state("sensor.solarnet_power_photovoltaics", 216.4328)
|
||||
assert_state("sensor.solarnet_relative_autonomy", 7.4984)
|
||||
assert_state("sensor.solarnet_meter_mode", "bidirectional")
|
||||
assert_state("sensor.solarnet_total_energy", 7512664.4042)
|
||||
# storage
|
||||
assert_state("sensor.byd_battery_box_premium_hv_dc_current", 0.0)
|
||||
assert_state("sensor.byd_battery_box_premium_hv_state_of_charge", 4.6)
|
||||
assert_state("sensor.byd_battery_box_premium_hv_maximum_capacity", 16588)
|
||||
assert_state("sensor.byd_battery_box_premium_hv_temperature", 21.5)
|
||||
assert_state("sensor.byd_battery_box_premium_hv_designed_capacity", 16588)
|
||||
assert_state("sensor.byd_battery_box_premium_hv_dc_voltage", 0.0)
|
||||
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
|
||||
|
||||
# Devices
|
||||
solar_net = device_registry.async_get_device(
|
||||
@ -507,11 +348,14 @@ async def test_gen24_storage(
|
||||
assert storage.name == "BYD Battery-Box Premium HV"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_primo_s0(
|
||||
hass: HomeAssistant,
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
entity_registry: er.EntityRegistry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test Fronius Primo dual inverter with S0 meter entities."""
|
||||
|
||||
@ -523,64 +367,8 @@ async def test_primo_s0(
|
||||
mock_responses(aioclient_mock, fixture_set="primo_s0", inverter_ids=[1, 2])
|
||||
config_entry = await setup_fronius_integration(hass, is_logger=True)
|
||||
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 31
|
||||
await enable_all_entities(
|
||||
hass,
|
||||
freezer,
|
||||
config_entry.entry_id,
|
||||
FroniusMeterUpdateCoordinator.default_interval,
|
||||
)
|
||||
assert len(hass.states.async_all(domain_filter=SENSOR_DOMAIN)) == 47
|
||||
# logger
|
||||
assert_state("sensor.solarnet_grid_export_tariff", 1)
|
||||
assert_state("sensor.solarnet_co2_factor", 0.53)
|
||||
assert_state("sensor.solarnet_grid_import_tariff", 1)
|
||||
# inverter 1
|
||||
assert_state("sensor.primo_5_0_1_total_energy", 17114940)
|
||||
assert_state("sensor.primo_5_0_1_energy_day", 22504)
|
||||
assert_state("sensor.primo_5_0_1_dc_voltage", 452.3)
|
||||
assert_state("sensor.primo_5_0_1_ac_power", 862)
|
||||
assert_state("sensor.primo_5_0_1_error_code", 0)
|
||||
assert_state("sensor.primo_5_0_1_dc_current", 4.23)
|
||||
assert_state("sensor.primo_5_0_1_status_code", 7)
|
||||
assert_state("sensor.primo_5_0_1_status_message", "running")
|
||||
assert_state("sensor.primo_5_0_1_energy_year", 7532755.5)
|
||||
assert_state("sensor.primo_5_0_1_ac_current", 3.85)
|
||||
assert_state("sensor.primo_5_0_1_ac_voltage", 223.9)
|
||||
assert_state("sensor.primo_5_0_1_frequency", 60)
|
||||
assert_state("sensor.primo_5_0_1_led_color", 2)
|
||||
assert_state("sensor.primo_5_0_1_led_state", 0)
|
||||
# inverter 2
|
||||
assert_state("sensor.primo_3_0_1_total_energy", 5796010)
|
||||
assert_state("sensor.primo_3_0_1_energy_day", 14237)
|
||||
assert_state("sensor.primo_3_0_1_dc_voltage", 329.5)
|
||||
assert_state("sensor.primo_3_0_1_ac_power", 296)
|
||||
assert_state("sensor.primo_3_0_1_error_code", 0)
|
||||
assert_state("sensor.primo_3_0_1_dc_current", 0.97)
|
||||
assert_state("sensor.primo_3_0_1_status_code", 7)
|
||||
assert_state("sensor.primo_3_0_1_status_message", "running")
|
||||
assert_state("sensor.primo_3_0_1_energy_year", 3596193.25)
|
||||
assert_state("sensor.primo_3_0_1_ac_current", 1.32)
|
||||
assert_state("sensor.primo_3_0_1_ac_voltage", 223.6)
|
||||
assert_state("sensor.primo_3_0_1_frequency", 60.01)
|
||||
assert_state("sensor.primo_3_0_1_led_color", 2)
|
||||
assert_state("sensor.primo_3_0_1_led_state", 0)
|
||||
# meter
|
||||
assert_state("sensor.s0_meter_at_inverter_1_meter_location", 1)
|
||||
assert_state(
|
||||
"sensor.s0_meter_at_inverter_1_meter_location_description", "consumption_path"
|
||||
)
|
||||
assert_state("sensor.s0_meter_at_inverter_1_real_power", -2216.7487)
|
||||
# power_flow
|
||||
assert_state("sensor.solarnet_power_load", -2218.9349)
|
||||
assert_state("sensor.solarnet_meter_mode", "vague-meter")
|
||||
assert_state("sensor.solarnet_power_photovoltaics", 1834)
|
||||
assert_state("sensor.solarnet_power_grid", 384.9349)
|
||||
assert_state("sensor.solarnet_relative_self_consumption", 100)
|
||||
assert_state("sensor.solarnet_relative_autonomy", 82.6523)
|
||||
assert_state("sensor.solarnet_total_energy", 22910919.5)
|
||||
assert_state("sensor.solarnet_energy_day", 36724)
|
||||
assert_state("sensor.solarnet_energy_year", 11128933.25)
|
||||
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
|
||||
|
||||
# Devices
|
||||
solar_net = device_registry.async_get_device(
|
||||
|
Loading…
x
Reference in New Issue
Block a user