From 77a267bc2f6fb75c918e4c2c76973c29dc03199d Mon Sep 17 00:00:00 2001 From: NANI <9637751+AndyTempel@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:37:49 +0200 Subject: [PATCH] Updated VRM client and accounted for missing forecasts (#153464) --- .../victron_remote_monitoring/config_flow.py | 6 +- .../victron_remote_monitoring/coordinator.py | 8 +- .../victron_remote_monitoring/manifest.json | 2 +- .../victron_remote_monitoring/sensor.py | 80 ++++++++++++++----- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 6 files changed, 72 insertions(+), 28 deletions(-) diff --git a/homeassistant/components/victron_remote_monitoring/config_flow.py b/homeassistant/components/victron_remote_monitoring/config_flow.py index 83649e8e5c5a..53c33757e3c8 100644 --- a/homeassistant/components/victron_remote_monitoring/config_flow.py +++ b/homeassistant/components/victron_remote_monitoring/config_flow.py @@ -13,7 +13,7 @@ import voluptuous as vol from homeassistant.config_entries import ConfigFlow, ConfigFlowResult from homeassistant.exceptions import HomeAssistantError -from homeassistant.helpers.httpx_client import get_async_client +from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.selector import ( SelectOptionDict, SelectSelector, @@ -69,7 +69,7 @@ class VictronRemoteMonitoringFlowHandler(ConfigFlow, domain=DOMAIN): """ client = VictronVRMClient( token=api_token, - client_session=get_async_client(self.hass), + client_session=async_get_clientsession(self.hass), ) try: sites = await client.users.list_sites() @@ -86,7 +86,7 @@ class VictronRemoteMonitoringFlowHandler(ConfigFlow, domain=DOMAIN): """Validate access to the selected site and return its data.""" client = VictronVRMClient( token=api_token, - client_session=get_async_client(self.hass), + client_session=async_get_clientsession(self.hass), ) try: site_data = await client.users.get_site(site_id) diff --git a/homeassistant/components/victron_remote_monitoring/coordinator.py b/homeassistant/components/victron_remote_monitoring/coordinator.py index 68cae39813dc..a7a58fbbe4ae 100644 --- a/homeassistant/components/victron_remote_monitoring/coordinator.py +++ b/homeassistant/components/victron_remote_monitoring/coordinator.py @@ -11,7 +11,7 @@ from victron_vrm.utils import dt_now from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed -from homeassistant.helpers.httpx_client import get_async_client +from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import CONF_API_TOKEN, CONF_SITE_ID, DOMAIN, LOGGER @@ -26,8 +26,8 @@ class VRMForecastStore: """Class to hold the forecast data.""" site_id: int - solar: ForecastAggregations - consumption: ForecastAggregations + solar: ForecastAggregations | None + consumption: ForecastAggregations | None async def get_forecast(client: VictronVRMClient, site_id: int) -> VRMForecastStore: @@ -75,7 +75,7 @@ class VictronRemoteMonitoringDataUpdateCoordinator( """Initialize.""" self.client = VictronVRMClient( token=config_entry.data[CONF_API_TOKEN], - client_session=get_async_client(hass), + client_session=async_get_clientsession(hass), ) self.site_id = config_entry.data[CONF_SITE_ID] super().__init__( diff --git a/homeassistant/components/victron_remote_monitoring/manifest.json b/homeassistant/components/victron_remote_monitoring/manifest.json index 1ce45ad24758..d6a7b2f95867 100644 --- a/homeassistant/components/victron_remote_monitoring/manifest.json +++ b/homeassistant/components/victron_remote_monitoring/manifest.json @@ -7,5 +7,5 @@ "integration_type": "service", "iot_class": "cloud_polling", "quality_scale": "bronze", - "requirements": ["victron-vrm==0.1.7"] + "requirements": ["victron-vrm==0.1.8"] } diff --git a/homeassistant/components/victron_remote_monitoring/sensor.py b/homeassistant/components/victron_remote_monitoring/sensor.py index 8876f784fa85..6d5e97c92cf8 100644 --- a/homeassistant/components/victron_remote_monitoring/sensor.py +++ b/homeassistant/components/victron_remote_monitoring/sensor.py @@ -39,7 +39,9 @@ SENSORS: tuple[VRMForecastsSensorEntityDescription, ...] = ( VRMForecastsSensorEntityDescription( key="energy_production_estimate_yesterday", translation_key="energy_production_estimate_yesterday", - value_fn=lambda estimate: estimate.solar.yesterday_total, + value_fn=lambda store: ( + store.solar.yesterday_total if store.solar is not None else None + ), device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL, native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, @@ -49,7 +51,9 @@ SENSORS: tuple[VRMForecastsSensorEntityDescription, ...] = ( VRMForecastsSensorEntityDescription( key="energy_production_estimate_today", translation_key="energy_production_estimate_today", - value_fn=lambda estimate: estimate.solar.today_total, + value_fn=lambda store: ( + store.solar.today_total if store.solar is not None else None + ), device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL, native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, @@ -59,7 +63,9 @@ SENSORS: tuple[VRMForecastsSensorEntityDescription, ...] = ( VRMForecastsSensorEntityDescription( key="energy_production_estimate_today_remaining", translation_key="energy_production_estimate_today_remaining", - value_fn=lambda estimate: estimate.solar.today_left_total, + value_fn=lambda store: ( + store.solar.today_left_total if store.solar is not None else None + ), device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL, native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, @@ -69,7 +75,9 @@ SENSORS: tuple[VRMForecastsSensorEntityDescription, ...] = ( VRMForecastsSensorEntityDescription( key="energy_production_estimate_tomorrow", translation_key="energy_production_estimate_tomorrow", - value_fn=lambda estimate: estimate.solar.tomorrow_total, + value_fn=lambda store: ( + store.solar.tomorrow_total if store.solar is not None else None + ), device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL, native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, @@ -79,25 +87,33 @@ SENSORS: tuple[VRMForecastsSensorEntityDescription, ...] = ( VRMForecastsSensorEntityDescription( key="power_highest_peak_time_yesterday", translation_key="power_highest_peak_time_yesterday", - value_fn=lambda estimate: estimate.solar.yesterday_peak_time, + value_fn=lambda store: ( + store.solar.yesterday_peak_time if store.solar is not None else None + ), device_class=SensorDeviceClass.TIMESTAMP, ), VRMForecastsSensorEntityDescription( key="power_highest_peak_time_today", translation_key="power_highest_peak_time_today", - value_fn=lambda estimate: estimate.solar.today_peak_time, + value_fn=lambda store: ( + store.solar.today_peak_time if store.solar is not None else None + ), device_class=SensorDeviceClass.TIMESTAMP, ), VRMForecastsSensorEntityDescription( key="power_highest_peak_time_tomorrow", translation_key="power_highest_peak_time_tomorrow", - value_fn=lambda estimate: estimate.solar.tomorrow_peak_time, + value_fn=lambda store: ( + store.solar.tomorrow_peak_time if store.solar is not None else None + ), device_class=SensorDeviceClass.TIMESTAMP, ), VRMForecastsSensorEntityDescription( key="energy_production_current_hour", translation_key="energy_production_current_hour", - value_fn=lambda estimate: estimate.solar.current_hour_total, + value_fn=lambda store: ( + store.solar.current_hour_total if store.solar is not None else None + ), device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL, native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, @@ -107,7 +123,9 @@ SENSORS: tuple[VRMForecastsSensorEntityDescription, ...] = ( VRMForecastsSensorEntityDescription( key="energy_production_next_hour", translation_key="energy_production_next_hour", - value_fn=lambda estimate: estimate.solar.next_hour_total, + value_fn=lambda store: ( + store.solar.next_hour_total if store.solar is not None else None + ), device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL, native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, @@ -118,7 +136,9 @@ SENSORS: tuple[VRMForecastsSensorEntityDescription, ...] = ( VRMForecastsSensorEntityDescription( key="energy_consumption_estimate_yesterday", translation_key="energy_consumption_estimate_yesterday", - value_fn=lambda estimate: estimate.consumption.yesterday_total, + value_fn=lambda store: ( + store.consumption.yesterday_total if store.consumption is not None else None + ), device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL, native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, @@ -128,7 +148,9 @@ SENSORS: tuple[VRMForecastsSensorEntityDescription, ...] = ( VRMForecastsSensorEntityDescription( key="energy_consumption_estimate_today", translation_key="energy_consumption_estimate_today", - value_fn=lambda estimate: estimate.consumption.today_total, + value_fn=lambda store: ( + store.consumption.today_total if store.consumption is not None else None + ), device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL, native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, @@ -138,7 +160,11 @@ SENSORS: tuple[VRMForecastsSensorEntityDescription, ...] = ( VRMForecastsSensorEntityDescription( key="energy_consumption_estimate_today_remaining", translation_key="energy_consumption_estimate_today_remaining", - value_fn=lambda estimate: estimate.consumption.today_left_total, + value_fn=lambda store: ( + store.consumption.today_left_total + if store.consumption is not None + else None + ), device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL, native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, @@ -148,7 +174,9 @@ SENSORS: tuple[VRMForecastsSensorEntityDescription, ...] = ( VRMForecastsSensorEntityDescription( key="energy_consumption_estimate_tomorrow", translation_key="energy_consumption_estimate_tomorrow", - value_fn=lambda estimate: estimate.consumption.tomorrow_total, + value_fn=lambda store: ( + store.consumption.tomorrow_total if store.consumption is not None else None + ), device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL, native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, @@ -158,25 +186,39 @@ SENSORS: tuple[VRMForecastsSensorEntityDescription, ...] = ( VRMForecastsSensorEntityDescription( key="consumption_highest_peak_time_yesterday", translation_key="consumption_highest_peak_time_yesterday", - value_fn=lambda estimate: estimate.consumption.yesterday_peak_time, + value_fn=lambda store: ( + store.consumption.yesterday_peak_time + if store.consumption is not None + else None + ), device_class=SensorDeviceClass.TIMESTAMP, ), VRMForecastsSensorEntityDescription( key="consumption_highest_peak_time_today", translation_key="consumption_highest_peak_time_today", - value_fn=lambda estimate: estimate.consumption.today_peak_time, + value_fn=lambda store: ( + store.consumption.today_peak_time if store.consumption is not None else None + ), device_class=SensorDeviceClass.TIMESTAMP, ), VRMForecastsSensorEntityDescription( key="consumption_highest_peak_time_tomorrow", translation_key="consumption_highest_peak_time_tomorrow", - value_fn=lambda estimate: estimate.consumption.tomorrow_peak_time, + value_fn=lambda store: ( + store.consumption.tomorrow_peak_time + if store.consumption is not None + else None + ), device_class=SensorDeviceClass.TIMESTAMP, ), VRMForecastsSensorEntityDescription( key="energy_consumption_current_hour", translation_key="energy_consumption_current_hour", - value_fn=lambda estimate: estimate.consumption.current_hour_total, + value_fn=lambda store: ( + store.consumption.current_hour_total + if store.consumption is not None + else None + ), device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL, native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, @@ -186,7 +228,9 @@ SENSORS: tuple[VRMForecastsSensorEntityDescription, ...] = ( VRMForecastsSensorEntityDescription( key="energy_consumption_next_hour", translation_key="energy_consumption_next_hour", - value_fn=lambda estimate: estimate.consumption.next_hour_total, + value_fn=lambda store: ( + store.consumption.next_hour_total if store.consumption is not None else None + ), device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL, native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, diff --git a/requirements_all.txt b/requirements_all.txt index 62d26d522a5a..51883cb95fd2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -3092,7 +3092,7 @@ velbus-aio==2025.8.0 venstarcolortouch==0.21 # homeassistant.components.victron_remote_monitoring -victron-vrm==0.1.7 +victron-vrm==0.1.8 # homeassistant.components.vilfo vilfo-api-client==0.5.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 740711dfcd35..a8f3abb88752 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2566,7 +2566,7 @@ velbus-aio==2025.8.0 venstarcolortouch==0.21 # homeassistant.components.victron_remote_monitoring -victron-vrm==0.1.7 +victron-vrm==0.1.8 # homeassistant.components.vilfo vilfo-api-client==0.5.0