Add morning and evening damping to Forecast solar (#98721)

Co-authored-by: Franck Nijhof <frenck@frenck.nl>
This commit is contained in:
Joost Lekkerkerker 2023-08-21 21:43:09 +02:00 committed by GitHub
parent a1d554d1cb
commit 30d3df2d96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 132 additions and 21 deletions

View file

@ -5,12 +5,38 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from .const import DOMAIN
from .const import (
CONF_DAMPING,
CONF_DAMPING_EVENING,
CONF_DAMPING_MORNING,
CONF_MODULES_POWER,
DOMAIN,
)
from .coordinator import ForecastSolarDataUpdateCoordinator
PLATFORMS = [Platform.SENSOR]
async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Migrate old config entry."""
if entry.version == 1:
new_options = entry.options.copy()
new_options |= {
CONF_MODULES_POWER: new_options.pop("modules power"),
CONF_DAMPING_MORNING: new_options.get(CONF_DAMPING, 0.0),
CONF_DAMPING_EVENING: new_options.pop(CONF_DAMPING, 0.0),
}
entry.version = 2
hass.config_entries.async_update_entry(
entry, data=entry.data, options=new_options
)
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Forecast.Solar from a config entry."""
coordinator = ForecastSolarDataUpdateCoordinator(hass, entry)

View file

@ -14,7 +14,8 @@ from homeassistant.helpers import config_validation as cv
from .const import (
CONF_AZIMUTH,
CONF_DAMPING,
CONF_DAMPING_EVENING,
CONF_DAMPING_MORNING,
CONF_DECLINATION,
CONF_INVERTER_SIZE,
CONF_MODULES_POWER,
@ -27,7 +28,7 @@ RE_API_KEY = re.compile(r"^[a-zA-Z0-9]{16}$")
class ForecastSolarFlowHandler(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Forecast.Solar."""
VERSION = 1
VERSION = 2
@staticmethod
@callback
@ -127,8 +128,16 @@ class ForecastSolarOptionFlowHandler(OptionsFlow):
default=self.config_entry.options[CONF_MODULES_POWER],
): vol.Coerce(int),
vol.Optional(
CONF_DAMPING,
default=self.config_entry.options.get(CONF_DAMPING, 0.0),
CONF_DAMPING_MORNING,
default=self.config_entry.options.get(
CONF_DAMPING_MORNING, 0.0
),
): vol.Coerce(float),
vol.Optional(
CONF_DAMPING_EVENING,
default=self.config_entry.options.get(
CONF_DAMPING_EVENING, 0.0
),
): vol.Coerce(float),
vol.Optional(
CONF_INVERTER_SIZE,

View file

@ -8,6 +8,8 @@ LOGGER = logging.getLogger(__package__)
CONF_DECLINATION = "declination"
CONF_AZIMUTH = "azimuth"
CONF_MODULES_POWER = "modules power"
CONF_MODULES_POWER = "modules_power"
CONF_DAMPING = "damping"
CONF_DAMPING_MORNING = "damping_morning"
CONF_DAMPING_EVENING = "damping_evening"
CONF_INVERTER_SIZE = "inverter_size"

View file

@ -13,7 +13,8 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import (
CONF_AZIMUTH,
CONF_DAMPING,
CONF_DAMPING_EVENING,
CONF_DAMPING_MORNING,
CONF_DECLINATION,
CONF_INVERTER_SIZE,
CONF_MODULES_POWER,
@ -48,7 +49,8 @@ class ForecastSolarDataUpdateCoordinator(DataUpdateCoordinator[Estimate]):
declination=entry.options[CONF_DECLINATION],
azimuth=(entry.options[CONF_AZIMUTH] - 180),
kwp=(entry.options[CONF_MODULES_POWER] / 1000),
damping=entry.options.get(CONF_DAMPING, 0),
damping_morning=entry.options.get(CONF_DAMPING_MORNING, 0.0),
damping_evening=entry.options.get(CONF_DAMPING_EVENING, 0.0),
inverter=inverter_size,
)

View file

@ -24,10 +24,11 @@
"data": {
"api_key": "Forecast.Solar API Key (optional)",
"azimuth": "[%key:component::forecast_solar::config::step::user::data::azimuth%]",
"damping": "Damping factor: adjusts the results in the morning and evening",
"damping_morning": "Damping factor: adjusts the results in the morning",
"damping_evening": "Damping factor: adjusts the results in the evening",
"inverter_size": "Inverter size (Watt)",
"declination": "[%key:component::forecast_solar::config::step::user::data::declination%]",
"modules power": "[%key:component::forecast_solar::config::step::user::data::modules_power%]"
"modules_power": "[%key:component::forecast_solar::config::step::user::data::modules_power%]"
}
}
}

View file

@ -9,7 +9,8 @@ import pytest
from homeassistant.components.forecast_solar.const import (
CONF_AZIMUTH,
CONF_DAMPING,
CONF_DAMPING_EVENING,
CONF_DAMPING_MORNING,
CONF_DECLINATION,
CONF_INVERTER_SIZE,
CONF_MODULES_POWER,
@ -37,6 +38,7 @@ def mock_config_entry() -> MockConfigEntry:
return MockConfigEntry(
title="Green House",
unique_id="unique",
version=2,
domain=DOMAIN,
data={
CONF_LATITUDE: 52.42,
@ -47,7 +49,8 @@ def mock_config_entry() -> MockConfigEntry:
CONF_DECLINATION: 30,
CONF_AZIMUTH: 190,
CONF_MODULES_POWER: 5100,
CONF_DAMPING: 0.5,
CONF_DAMPING_MORNING: 0.5,
CONF_DAMPING_EVENING: 0.5,
CONF_INVERTER_SIZE: 2000,
},
)

View file

@ -33,10 +33,11 @@
'options': dict({
'api_key': '**REDACTED**',
'azimuth': 190,
'damping': 0.5,
'damping_evening': 0.5,
'damping_morning': 0.5,
'declination': 30,
'inverter_size': 2000,
'modules power': 5100,
'modules_power': 5100,
}),
'title': 'Green House',
}),

View file

@ -0,0 +1,27 @@
# serializer version: 1
# name: test_migration
ConfigEntrySnapshot({
'data': dict({
'latitude': 52.42,
'longitude': 4.42,
}),
'disabled_by': None,
'domain': 'forecast_solar',
'entry_id': <ANY>,
'options': dict({
'api_key': 'abcdef12345',
'azimuth': 190,
'damping_evening': 0.5,
'damping_morning': 0.5,
'declination': 30,
'inverter_size': 2000,
'modules_power': 5100,
}),
'pref_disable_new_entities': False,
'pref_disable_polling': False,
'source': 'user',
'title': 'Green House',
'unique_id': 'unique',
'version': 2,
})
# ---

View file

@ -3,7 +3,8 @@ from unittest.mock import AsyncMock
from homeassistant.components.forecast_solar.const import (
CONF_AZIMUTH,
CONF_DAMPING,
CONF_DAMPING_EVENING,
CONF_DAMPING_MORNING,
CONF_DECLINATION,
CONF_INVERTER_SIZE,
CONF_MODULES_POWER,
@ -75,7 +76,8 @@ async def test_options_flow_invalid_api(
CONF_DECLINATION: 21,
CONF_AZIMUTH: 22,
CONF_MODULES_POWER: 2122,
CONF_DAMPING: 0.25,
CONF_DAMPING_MORNING: 0.25,
CONF_DAMPING_EVENING: 0.25,
CONF_INVERTER_SIZE: 2000,
},
)
@ -108,7 +110,8 @@ async def test_options_flow(
CONF_DECLINATION: 21,
CONF_AZIMUTH: 22,
CONF_MODULES_POWER: 2122,
CONF_DAMPING: 0.25,
CONF_DAMPING_MORNING: 0.25,
CONF_DAMPING_EVENING: 0.25,
CONF_INVERTER_SIZE: 2000,
},
)
@ -120,7 +123,8 @@ async def test_options_flow(
CONF_DECLINATION: 21,
CONF_AZIMUTH: 22,
CONF_MODULES_POWER: 2122,
CONF_DAMPING: 0.25,
CONF_DAMPING_MORNING: 0.25,
CONF_DAMPING_EVENING: 0.25,
CONF_INVERTER_SIZE: 2000,
}
@ -147,7 +151,8 @@ async def test_options_flow_without_key(
CONF_DECLINATION: 21,
CONF_AZIMUTH: 22,
CONF_MODULES_POWER: 2122,
CONF_DAMPING: 0.25,
CONF_DAMPING_MORNING: 0.25,
CONF_DAMPING_EVENING: 0.25,
CONF_INVERTER_SIZE: 2000,
},
)
@ -159,6 +164,7 @@ async def test_options_flow_without_key(
CONF_DECLINATION: 21,
CONF_AZIMUTH: 22,
CONF_MODULES_POWER: 2122,
CONF_DAMPING: 0.25,
CONF_DAMPING_MORNING: 0.25,
CONF_DAMPING_EVENING: 0.25,
CONF_INVERTER_SIZE: 2000,
}

View file

@ -2,9 +2,17 @@
from unittest.mock import MagicMock, patch
from forecast_solar import ForecastSolarConnectionError
from syrupy import SnapshotAssertion
from homeassistant.components.forecast_solar.const import DOMAIN
from homeassistant.components.forecast_solar.const import (
CONF_AZIMUTH,
CONF_DAMPING,
CONF_DECLINATION,
CONF_INVERTER_SIZE,
DOMAIN,
)
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
@ -44,3 +52,29 @@ 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(
title="Green House",
unique_id="unique",
domain=DOMAIN,
data={
CONF_LATITUDE: 52.42,
CONF_LONGITUDE: 4.42,
},
options={
CONF_API_KEY: "abcdef12345",
CONF_DECLINATION: 30,
CONF_AZIMUTH: 190,
"modules power": 5100,
CONF_DAMPING: 0.5,
CONF_INVERTER_SIZE: 2000,
},
)
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