mirror of
https://github.com/home-assistant/core.git
synced 2026-09-16 13:38:26 +01:00
victron_gx: Bump victron-mqtt to 2026.9.2 (#181452)
This commit is contained in:
@@ -51,6 +51,8 @@ async def async_setup_entry(
|
||||
class VictronButton(VictronBaseEntity, ButtonEntity):
|
||||
"""Implementation of a Victron GX button entity."""
|
||||
|
||||
_follow_metric_availability = False
|
||||
|
||||
@callback
|
||||
@override
|
||||
def _on_update_cb(self, _value: Any) -> None:
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
"""Support for Victron GX device tracker."""
|
||||
|
||||
from typing import Any, override
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from victron_mqtt import (
|
||||
Device as VictronVenusDevice,
|
||||
GpsLocation,
|
||||
Metric as VictronVenusMetric,
|
||||
MetricKind,
|
||||
MetricValue,
|
||||
)
|
||||
|
||||
from homeassistant.components.device_tracker import TrackerEntity
|
||||
@@ -63,11 +64,16 @@ class VictronDeviceTracker(VictronBaseEntity, TrackerEntity):
|
||||
) -> None:
|
||||
"""Initialize the device tracker."""
|
||||
super().__init__(device, metric, device_info, installation_id)
|
||||
self._update_from_location(metric.value)
|
||||
value = metric.value
|
||||
if TYPE_CHECKING:
|
||||
assert value is None or isinstance(value, GpsLocation)
|
||||
self._update_from_location(value)
|
||||
|
||||
@callback
|
||||
@override
|
||||
def _on_update_cb(self, value: Any) -> None:
|
||||
def _on_update_cb(self, value: MetricValue) -> None:
|
||||
if TYPE_CHECKING:
|
||||
assert value is None or isinstance(value, GpsLocation)
|
||||
self._update_from_location(value)
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
"""Base entity for entities in victron_gx integration."""
|
||||
|
||||
from abc import abstractmethod
|
||||
from typing import Any, override
|
||||
from typing import override
|
||||
|
||||
from victron_mqtt import (
|
||||
Device as VictronVenusDevice,
|
||||
Metric as VictronVenusMetric,
|
||||
MetricType,
|
||||
MetricValue,
|
||||
)
|
||||
|
||||
from homeassistant.const import EntityCategory
|
||||
@@ -51,6 +52,7 @@ class VictronBaseEntity(Entity):
|
||||
|
||||
_attr_should_poll = False
|
||||
_attr_has_entity_name = True
|
||||
_follow_metric_availability = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -62,6 +64,8 @@ class VictronBaseEntity(Entity):
|
||||
"""Initialize the entity."""
|
||||
self._device = device
|
||||
self._metric = metric
|
||||
if self._follow_metric_availability:
|
||||
self._attr_available = metric.available
|
||||
self._attr_device_info = device_info
|
||||
self._attr_unique_id = f"{installation_id}_{metric.unique_id}"
|
||||
self._attr_suggested_display_precision = metric.precision
|
||||
@@ -111,11 +115,17 @@ class VictronBaseEntity(Entity):
|
||||
|
||||
@callback
|
||||
@abstractmethod
|
||||
def _on_update_cb(self, value: Any) -> None:
|
||||
def _on_update_cb(self, value: MetricValue) -> None:
|
||||
"""Handle the metric update. Must be implemented by subclasses."""
|
||||
|
||||
@callback
|
||||
def _on_update(self, _: VictronVenusMetric, value: Any) -> None:
|
||||
def _on_update(self, metric: VictronVenusMetric, value: MetricValue) -> None:
|
||||
if self._follow_metric_availability and not metric.available:
|
||||
if self._attr_available:
|
||||
self._attr_available = False
|
||||
self.async_write_ha_state()
|
||||
return
|
||||
self._attr_available = True
|
||||
self._on_update_cb(value)
|
||||
|
||||
@override
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"integration_type": "hub",
|
||||
"iot_class": "local_push",
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["victron-mqtt==2026.8.4"],
|
||||
"requirements": ["victron-mqtt==2026.9.2"],
|
||||
"ssdp": [
|
||||
{
|
||||
"X_MqttOnLan": "1",
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
"""Support for Victron GX number entities."""
|
||||
|
||||
from typing import TYPE_CHECKING, Any, override
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from victron_mqtt import (
|
||||
Device as VictronVenusDevice,
|
||||
Metric as VictronVenusMetric,
|
||||
MetricKind,
|
||||
MetricType,
|
||||
MetricValue,
|
||||
WritableMetric as VictronVenusWritableMetric,
|
||||
)
|
||||
|
||||
@@ -77,7 +78,10 @@ class VictronNumber(VictronBaseEntity, NumberEntity):
|
||||
"""Initialize the number entity."""
|
||||
super().__init__(device, metric, device_info, installation_id)
|
||||
self._attr_device_class = METRIC_TYPE_TO_DEVICE_CLASS.get(metric.metric_type)
|
||||
self._attr_native_value = metric.value
|
||||
value = metric.value
|
||||
if TYPE_CHECKING:
|
||||
assert value is None or isinstance(value, int | float)
|
||||
self._attr_native_value = value
|
||||
if metric.min_value is not None:
|
||||
self._attr_native_min_value = metric.min_value
|
||||
if metric.max_value is not None:
|
||||
@@ -93,7 +97,9 @@ class VictronNumber(VictronBaseEntity, NumberEntity):
|
||||
|
||||
@callback
|
||||
@override
|
||||
def _on_update_cb(self, value: Any) -> None:
|
||||
def _on_update_cb(self, value: MetricValue) -> None:
|
||||
if TYPE_CHECKING:
|
||||
assert value is None or isinstance(value, int | float)
|
||||
self._attr_native_value = value
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
@@ -338,6 +338,12 @@
|
||||
"hub4_ac_grid_setpoint": {
|
||||
"name": "AC grid setpoint"
|
||||
},
|
||||
"hub4_max_charge_power": {
|
||||
"name": "Maximum charge power"
|
||||
},
|
||||
"hub4_max_discharge_power": {
|
||||
"name": "Maximum discharge power"
|
||||
},
|
||||
"multi_ess_min_soc_limit": {
|
||||
"name": "ESS minimum SoC limit"
|
||||
},
|
||||
@@ -347,6 +353,9 @@
|
||||
"multiplus_assist_current_boost_factor": {
|
||||
"name": "Assist current boost factor"
|
||||
},
|
||||
"pvinverter_power_limit": {
|
||||
"name": "Power limit"
|
||||
},
|
||||
"solarcharger_charge_current_limit": {
|
||||
"name": "[%key:component::victron_gx::common::charge_current_limit%]"
|
||||
},
|
||||
@@ -987,6 +996,18 @@
|
||||
"dcload_voltage": {
|
||||
"name": "[%key:component::victron_gx::common::voltage%]"
|
||||
},
|
||||
"dcsource_current": {
|
||||
"name": "[%key:component::victron_gx::common::current%]"
|
||||
},
|
||||
"dcsource_power": {
|
||||
"name": "[%key:component::victron_gx::common::power%]"
|
||||
},
|
||||
"dcsource_temperature": {
|
||||
"name": "[%key:component::victron_gx::common::temperature%]"
|
||||
},
|
||||
"dcsource_voltage": {
|
||||
"name": "[%key:component::victron_gx::common::voltage%]"
|
||||
},
|
||||
"dcsystem_aux_voltage": {
|
||||
"name": "Auxiliary voltage"
|
||||
},
|
||||
@@ -1525,6 +1546,21 @@
|
||||
"platform_venus_firmware_installed_version": {
|
||||
"name": "Installed version"
|
||||
},
|
||||
"platform_venus_firmware_progress": {
|
||||
"name": "Firmware update progress"
|
||||
},
|
||||
"platform_venus_firmware_state": {
|
||||
"name": "Firmware update state",
|
||||
"state": {
|
||||
"checking": "Checking",
|
||||
"downloading_and_installing": "Downloading and installing",
|
||||
"error_during_check": "Error during check",
|
||||
"error_during_update": "Error during update",
|
||||
"idle": "[%key:common::state::idle%]",
|
||||
"rebooting": "Rebooting",
|
||||
"update_file_not_found": "Update file not found"
|
||||
}
|
||||
},
|
||||
"pvinverter_current_phase": {
|
||||
"name": "Current {phase}"
|
||||
},
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
|
||||
from datetime import time
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, Any, override
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from victron_mqtt import (
|
||||
Device as VictronVenusDevice,
|
||||
Metric as VictronVenusMetric,
|
||||
MetricKind,
|
||||
MetricValue,
|
||||
WritableMetric as VictronVenusWritableMetric,
|
||||
)
|
||||
|
||||
@@ -58,11 +59,16 @@ class VictronTime(VictronBaseEntity, TimeEntity):
|
||||
) -> None:
|
||||
"""Initialize the time entity."""
|
||||
super().__init__(device, metric, device_info, installation_id)
|
||||
self._attr_native_value = VictronTime.victron_time_to_time(metric.value)
|
||||
value = metric.value
|
||||
if TYPE_CHECKING:
|
||||
assert value is None or isinstance(value, int | float)
|
||||
self._attr_native_value = VictronTime.victron_time_to_time(value)
|
||||
|
||||
@callback
|
||||
@override
|
||||
def _on_update_cb(self, value: Any) -> None:
|
||||
def _on_update_cb(self, value: MetricValue) -> None:
|
||||
if TYPE_CHECKING:
|
||||
assert value is None or isinstance(value, int | float)
|
||||
self._attr_native_value = VictronTime.victron_time_to_time(value)
|
||||
self.async_write_ha_state()
|
||||
|
||||
@@ -81,7 +87,7 @@ class VictronTime(VictronBaseEntity, TimeEntity):
|
||||
self._metric.set(total_minutes)
|
||||
|
||||
@staticmethod
|
||||
def victron_time_to_time(value: int | None) -> time | None:
|
||||
def victron_time_to_time(value: float | None) -> time | None:
|
||||
"""Convert minutes since midnight to time object."""
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
Generated
+1
-1
@@ -3382,7 +3382,7 @@ viaggiatreno_ha==0.2.4
|
||||
victron-ble-ha-parser==0.7.0
|
||||
|
||||
# homeassistant.components.victron_gx
|
||||
victron-mqtt==2026.8.4
|
||||
victron-mqtt==2026.9.2
|
||||
|
||||
# homeassistant.components.victron_remote_monitoring
|
||||
victron-vrm==0.1.12
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
"""Tests for Victron GX MQTT device trackers."""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from victron_mqtt import Hub as VictronVenusHub
|
||||
from victron_mqtt.testing import finalize_injection, inject_message
|
||||
|
||||
from homeassistant.components.device_tracker import SourceType, TrackingType
|
||||
from homeassistant.components.victron_gx.const import DOMAIN
|
||||
from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
|
||||
@@ -122,6 +125,7 @@ async def test_victron_device_tracker(
|
||||
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
assert state.state == STATE_UNKNOWN
|
||||
assert state.attributes == {
|
||||
"source_type": SourceType.GPS,
|
||||
"altitude": None,
|
||||
@@ -131,3 +135,12 @@ async def test_victron_device_tracker(
|
||||
"in_zones": [],
|
||||
"tracking_type": TrackingType.POSITION,
|
||||
}
|
||||
|
||||
metric = victron_hub.devices["gps_0"].get_metric("gps_location")
|
||||
assert metric is not None
|
||||
metric._keepalive(force_invalidate=True, log_debug=MagicMock())
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
assert state.state == STATE_UNAVAILABLE
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
"""Tests for Victron GX MQTT number entities."""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from victron_mqtt import Hub as VictronVenusHub
|
||||
from victron_mqtt.testing import finalize_injection, inject_message
|
||||
|
||||
from homeassistant.components.number import NumberDeviceClass
|
||||
from homeassistant.components.victron_gx.const import DOMAIN
|
||||
from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
|
||||
@@ -98,6 +101,54 @@ async def test_victron_number_update(
|
||||
assert state.state == "58.0"
|
||||
|
||||
|
||||
async def test_nullable_number_availability(
|
||||
hass: HomeAssistant,
|
||||
init_integration: tuple[VictronVenusHub, MockConfigEntry],
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test nullable values remain distinct from source unavailability."""
|
||||
victron_hub, mock_config_entry = init_integration
|
||||
topic = f"N/{MOCK_INSTALLATION_ID}/hub4/0/Overrides/MaxChargePower"
|
||||
|
||||
await inject_message(victron_hub, topic, '{"value": 1200.0}')
|
||||
await finalize_injection(victron_hub, disconnect=False)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity = next(
|
||||
entity
|
||||
for entity in er.async_entries_for_config_entry(
|
||||
entity_registry, mock_config_entry.entry_id
|
||||
)
|
||||
if entity.translation_key == "hub4_max_charge_power"
|
||||
)
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
assert state.state == "1200.0"
|
||||
|
||||
await inject_message(victron_hub, topic, '{"value": null}')
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
assert state.state == STATE_UNKNOWN
|
||||
|
||||
metric = victron_hub.devices["hub4_0"].get_metric("hub4_max_charge_power")
|
||||
assert metric is not None
|
||||
metric._keepalive(force_invalidate=True, log_debug=MagicMock())
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
assert state.state == STATE_UNAVAILABLE
|
||||
|
||||
await inject_message(victron_hub, topic, '{"value": 1300.0}')
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
assert state.state == "1300.0"
|
||||
|
||||
|
||||
async def test_victron_number_actions(
|
||||
hass: HomeAssistant,
|
||||
init_integration: tuple[VictronVenusHub, MockConfigEntry],
|
||||
|
||||
Reference in New Issue
Block a user