Reload enphase_envoy integration upon envoy firmware change detection (#124650)

* Reload enphase_envoy integration upon envoy firmware change detection.

* remove persistant notification
This commit is contained in:
Arie Catsman 2024-09-11 19:39:54 +02:00 committed by GitHub
parent f52f60307b
commit 66f9e06c25
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 55 additions and 0 deletions

View File

@ -24,6 +24,7 @@ SCAN_INTERVAL = timedelta(seconds=60)
TOKEN_REFRESH_CHECK_INTERVAL = timedelta(days=1) TOKEN_REFRESH_CHECK_INTERVAL = timedelta(days=1)
STALE_TOKEN_THRESHOLD = timedelta(days=30).total_seconds() STALE_TOKEN_THRESHOLD = timedelta(days=30).total_seconds()
NOTIFICATION_ID = "enphase_envoy_notification"
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -35,6 +36,7 @@ class EnphaseUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
"""DataUpdateCoordinator to gather data from any envoy.""" """DataUpdateCoordinator to gather data from any envoy."""
envoy_serial_number: str envoy_serial_number: str
envoy_firmware: str
def __init__( def __init__(
self, hass: HomeAssistant, envoy: Envoy, entry: EnphaseConfigEntry self, hass: HomeAssistant, envoy: Envoy, entry: EnphaseConfigEntry
@ -46,6 +48,7 @@ class EnphaseUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
self.username = entry_data[CONF_USERNAME] self.username = entry_data[CONF_USERNAME]
self.password = entry_data[CONF_PASSWORD] self.password = entry_data[CONF_PASSWORD]
self._setup_complete = False self._setup_complete = False
self.envoy_firmware = ""
self._cancel_token_refresh: CALLBACK_TYPE | None = None self._cancel_token_refresh: CALLBACK_TYPE | None = None
super().__init__( super().__init__(
hass, hass,
@ -158,6 +161,24 @@ class EnphaseUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
raise ConfigEntryAuthFailed from err raise ConfigEntryAuthFailed from err
except EnvoyError as err: except EnvoyError as err:
raise UpdateFailed(f"Error communicating with API: {err}") from err raise UpdateFailed(f"Error communicating with API: {err}") from err
# if we have a firmware version from previous setup, compare to current one
# when envoy gets new firmware there will be an authentication failure
# which results in getting fw version again, if so reload the integration.
if (current_firmware := self.envoy_firmware) and current_firmware != (
new_firmware := envoy.firmware
):
_LOGGER.warning(
"Envoy firmware changed from: %s to: %s, reloading enphase envoy integration",
current_firmware,
new_firmware,
)
# reload the integration to get all established again
self.hass.async_create_task(
self.hass.config_entries.async_reload(self.entry.entry_id)
)
# remember firmware version for next time
self.envoy_firmware = envoy.firmware
_LOGGER.debug("Envoy data: %s", envoy_data) _LOGGER.debug("Envoy data: %s", envoy_data)
return envoy_data.raw return envoy_data.raw

View File

@ -1,6 +1,7 @@
"""Test Enphase Envoy sensors.""" """Test Enphase Envoy sensors."""
from itertools import chain from itertools import chain
import logging
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
@ -1002,3 +1003,36 @@ async def test_sensor_missing_data(
# test the original inverter is now unknown # test the original inverter is now unknown
assert (entity_state := hass.states.get("sensor.inverter_1")) assert (entity_state := hass.states.get("sensor.inverter_1"))
assert entity_state.state == STATE_UNKNOWN assert entity_state.state == STATE_UNKNOWN
@pytest.mark.parametrize(
("mock_envoy"),
[
"envoy_metered_batt_relay",
],
indirect=["mock_envoy"],
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_fw_update(
hass: HomeAssistant,
config_entry: MockConfigEntry,
mock_envoy: AsyncMock,
entity_registry: er.EntityRegistry,
freezer: FrozenDateTimeFactory,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test enphase_envoy sensor update over fw update."""
logging.getLogger("homeassistant.components.enphase_envoy").setLevel(logging.DEBUG)
with patch("homeassistant.components.enphase_envoy.PLATFORMS", [Platform.SENSOR]):
await setup_integration(hass, config_entry)
# force HA to detect changed data by changing raw
mock_envoy.firmware = "0.0.0"
# Move time to next update
freezer.tick(SCAN_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
assert "firmware changed from: " in caplog.text
assert "to: 0.0.0, reloading enphase envoy integration" in caplog.text