Skip to content

Commit d43be7b

Browse files
committed
Making new integrations deployment use the latest auto debounce interval which is more effective than the old hardcoded 30 seconds. Users who changed this value will not move automatically to the new dynamic setting.
1 parent c328f08 commit d43be7b

6 files changed

Lines changed: 179 additions & 14 deletions

File tree

custom_components/victron_mqtt/__init__.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,25 @@
44

55
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, Platform
66
from homeassistant.core import Event, HomeAssistant, ServiceCall
7-
from homeassistant.helpers import device_registry as dr, entity_registry as er
7+
from homeassistant.helpers import device_registry as dr
88
from homeassistant.helpers.typing import ConfigType
99
from homeassistant.exceptions import HomeAssistantError
1010
import homeassistant.helpers.config_validation as cv
1111

1212

13-
from .const import ATTR_DEVICE_ID, ATTR_METRIC_ID, ATTR_VALUE, CONF_SIMPLE_NAMING, DOMAIN, SERVICE_PUBLISH
13+
from .const import (
14+
ATTR_DEVICE_ID,
15+
ATTR_METRIC_ID,
16+
ATTR_VALUE,
17+
CONF_SIMPLE_NAMING,
18+
CONF_UPDATE_FREQUENCY_MODE,
19+
CONF_UPDATE_FREQUENCY_SECONDS,
20+
DEFAULT_UPDATE_FREQUENCY_SECONDS,
21+
DOMAIN,
22+
SERVICE_PUBLISH,
23+
UPDATE_FREQUENCY_MODE_AUTO,
24+
UPDATE_FREQUENCY_MODE_MANUAL,
25+
)
1426
from .hub import Hub, VictronGxConfigEntry
1527
from ._vendor import VICTRON_MQTT_VERSION
1628

@@ -95,6 +107,19 @@ async def async_migrate_entry(hass: HomeAssistant, config_entry: VictronGxConfig
95107
hass.config_entries.async_update_entry(config_entry, data=new_data, version=2)
96108
_LOGGER.info("Migration to version 2 successful")
97109

110+
if config_entry.version == 2:
111+
new_data = {**config_entry.data}
112+
# The old default update frequency was 30 seconds. Users who kept that
113+
# default (or never set one) are moved to the new "auto" mode. Any other
114+
# explicit interval is preserved as a manual setting.
115+
frequency = new_data.get(CONF_UPDATE_FREQUENCY_SECONDS)
116+
if frequency is None or frequency == DEFAULT_UPDATE_FREQUENCY_SECONDS:
117+
new_data[CONF_UPDATE_FREQUENCY_MODE] = UPDATE_FREQUENCY_MODE_AUTO
118+
else:
119+
new_data[CONF_UPDATE_FREQUENCY_MODE] = UPDATE_FREQUENCY_MODE_MANUAL
120+
hass.config_entries.async_update_entry(config_entry, data=new_data, version=3)
121+
_LOGGER.info("Migration to version 3 successful")
122+
98123
return True
99124

100125

custom_components/victron_mqtt/config_flow.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,16 @@
4646
CONF_ROOT_TOPIC_PREFIX,
4747
CONF_SERIAL,
4848
CONF_SIMPLE_NAMING,
49+
CONF_UPDATE_FREQUENCY_MODE,
4950
CONF_UPDATE_FREQUENCY_SECONDS,
5051
DEFAULT_HOST,
5152
DEFAULT_PORT,
5253
DEFAULT_SIMPLE_NAMING,
54+
DEFAULT_UPDATE_FREQUENCY_MODE,
5355
DEFAULT_UPDATE_FREQUENCY_SECONDS,
5456
DOMAIN,
57+
UPDATE_FREQUENCY_MODE_AUTO,
58+
UPDATE_FREQUENCY_MODE_MANUAL,
5559
)
5660

5761
_LOGGER = logging.getLogger(__name__)
@@ -113,6 +117,23 @@ def default_port_for(use_ssl: bool) -> int:
113117
),
114118
vol.Optional(CONF_SIMPLE_NAMING, default=DEFAULT_SIMPLE_NAMING): bool,
115119
vol.Optional(CONF_ROOT_TOPIC_PREFIX): str,
120+
vol.Required(
121+
CONF_UPDATE_FREQUENCY_MODE, default=DEFAULT_UPDATE_FREQUENCY_MODE
122+
): SelectSelector(
123+
SelectSelectorConfig(
124+
options=[
125+
SelectOptionDict(
126+
value=UPDATE_FREQUENCY_MODE_AUTO,
127+
label="Auto (library decides per metric, recommended)",
128+
),
129+
SelectOptionDict(
130+
value=UPDATE_FREQUENCY_MODE_MANUAL,
131+
label="Manual (fixed interval below)",
132+
),
133+
],
134+
mode=SelectSelectorMode.LIST,
135+
)
136+
),
116137
vol.Optional(CONF_UPDATE_FREQUENCY_SECONDS, default=DEFAULT_UPDATE_FREQUENCY_SECONDS): int,
117138
vol.Optional(CONF_EXCLUDED_DEVICES, default=[]): SelectSelector(
118139
SelectSelectorConfig(
@@ -170,7 +191,7 @@ async def validate_input(data: dict[str, Any]) -> str:
170191
class VictronMQTTConfigFlow(ConfigFlow, domain=DOMAIN):
171192
"""Handle a config flow for victronvenus."""
172193

173-
VERSION = 2
194+
VERSION = 3
174195

175196
def __init__(self) -> None:
176197
"""Initialize."""

custom_components/victron_mqtt/const.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
CONF_SERIAL = "serial"
1414
CONF_ROOT_TOPIC_PREFIX = "root_topic_prefix"
1515
CONF_UPDATE_FREQUENCY_SECONDS = "update_frequency"
16+
CONF_UPDATE_FREQUENCY_MODE = "update_frequency_mode"
1617
CONF_OPERATION_MODE = "operation_mode"
1718
CONF_EXCLUDED_DEVICES = "excluded_devices"
1819
CONF_SIMPLE_NAMING = "simple_naming"
@@ -25,6 +26,12 @@
2526
DEFAULT_PORT = 1883
2627
DEFAULT_UPDATE_FREQUENCY_SECONDS = 30
2728

29+
# Update frequency mode: either the library-driven "auto" profile or a fixed
30+
# manual interval (in seconds).
31+
UPDATE_FREQUENCY_MODE_AUTO = "auto"
32+
UPDATE_FREQUENCY_MODE_MANUAL = "manual"
33+
DEFAULT_UPDATE_FREQUENCY_MODE = UPDATE_FREQUENCY_MODE_AUTO
34+
2835
# Service names
2936
SERVICE_PUBLISH = "publish"
3037

custom_components/victron_mqtt/hub.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
"""Main Hub class."""
22

3-
from collections.abc import Callable
3+
from collections.abc import Callable, Mapping
44
import logging
5+
from typing import Any
56

67
from ._vendor.victron_mqtt import (
78
AuthenticationError,
@@ -12,6 +13,7 @@
1213
Metric as VictronVenusMetric,
1314
MetricKind,
1415
OperationMode,
16+
UPDATE_FREQUENCY_AUTO,
1517
)
1618

1719
from homeassistant.config_entries import ConfigEntry
@@ -36,9 +38,12 @@
3638
CONF_ROOT_TOPIC_PREFIX,
3739
CONF_SERIAL,
3840
CONF_SIMPLE_NAMING,
41+
CONF_UPDATE_FREQUENCY_MODE,
3942
CONF_UPDATE_FREQUENCY_SECONDS,
43+
DEFAULT_UPDATE_FREQUENCY_MODE,
4044
DEFAULT_UPDATE_FREQUENCY_SECONDS,
4145
DOMAIN,
46+
UPDATE_FREQUENCY_MODE_MANUAL,
4247
)
4348

4449
_LOGGER = logging.getLogger(__name__)
@@ -51,6 +56,19 @@
5156
[VictronVenusDevice, VictronVenusMetric, DeviceInfo, str], None
5257
]
5358

59+
60+
def _resolve_update_frequency(config: Mapping[str, Any]) -> int | str:
61+
"""Resolve the configured update frequency into the value the library expects.
62+
63+
In "auto" mode the library picks a per-metric interval; in "manual" mode a
64+
fixed interval (in seconds) is used.
65+
"""
66+
mode = config.get(CONF_UPDATE_FREQUENCY_MODE, DEFAULT_UPDATE_FREQUENCY_MODE)
67+
if mode == UPDATE_FREQUENCY_MODE_MANUAL:
68+
return config.get(CONF_UPDATE_FREQUENCY_SECONDS, DEFAULT_UPDATE_FREQUENCY_SECONDS)
69+
return UPDATE_FREQUENCY_AUTO
70+
71+
5472
class Hub:
5573
"""Victron MQTT Hub for managing communication and sensors."""
5674

@@ -101,9 +119,7 @@ def __init__(self, hass: HomeAssistant, entry: VictronGxConfigEntry) -> None:
101119
topic_log_info=config.get(CONF_ELEVATED_TRACING) or None,
102120
operation_mode=operation_mode,
103121
device_type_exclude_filter=excluded_device_types,
104-
update_frequency_seconds=config.get(
105-
CONF_UPDATE_FREQUENCY_SECONDS, DEFAULT_UPDATE_FREQUENCY_SECONDS
106-
),
122+
update_frequency_seconds=_resolve_update_frequency(config),
107123
)
108124
self._hub.on_new_metric = self._on_new_metric
109125
self._config_entry_id = entry.entry_id

custom_components/victron_mqtt/translations/en.json

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
"root_topic_prefix": "Optional root topic prefix",
2929
"simple_naming": "Simple naming (no installation id in entity ids)",
3030
"ssl": "Use SSL",
31-
"update_frequency": "Update frequency (seconds)",
31+
"update_frequency_mode": "Update frequency mode",
32+
"update_frequency": "Manual update frequency (seconds)",
3233
"username": "Username"
3334
},
3435
"data_description": {
@@ -41,7 +42,8 @@
4142
"root_topic_prefix": "Root topic prefix if used via MQTT gateway.",
4243
"simple_naming": "Use simple naming for entities, can work only when you have single Cerbo on the network.",
4344
"ssl": "Indicates whether to use SSL to connect to the Victron Device. Normally it is disabled.",
44-
"update_frequency": "Update frequency in seconds. Default is 30 seconds. Set to 0 to update always.",
45+
"update_frequency_mode": "'Auto' lets the library choose an update interval per metric (fast-changing values like power update more often). 'Manual' uses the fixed interval below for all metrics.",
46+
"update_frequency": "Only used in 'Manual' mode. Update frequency in seconds. Set to 0 to update always.",
4547
"username": "Username for the MQTT server, default is empty. Not needed by Victron devices. This is only needed if you use route your mqtt messages through non Victron server and it does require username."
4648
}
4749
}
@@ -2909,7 +2911,8 @@
29092911
"root_topic_prefix": "Optional root topic prefix",
29102912
"simple_naming": "Simple naming (no installation id in entity ids)",
29112913
"ssl": "Use SSL",
2912-
"update_frequency": "Update frequency (seconds)",
2914+
"update_frequency_mode": "Update frequency mode",
2915+
"update_frequency": "Manual update frequency (seconds)",
29132916
"username": "Username"
29142917
},
29152918
"data_description": {
@@ -2922,7 +2925,8 @@
29222925
"root_topic_prefix": "Root topic prefix if used via MQTT gateway.",
29232926
"simple_naming": "Use simple naming for entities, can work only when you have single Cerbo on the network.",
29242927
"ssl": "Indicates whether to use SSL to connect to the Victron Device. Normally it is disabled.",
2925-
"update_frequency": "Update frequency in seconds. Default is 30 seconds. Set to 0 to update always.",
2928+
"update_frequency_mode": "'Auto' lets the library choose an update interval per metric (fast-changing values like power update more often). 'Manual' uses the fixed interval below for all metrics.",
2929+
"update_frequency": "Only used in 'Manual' mode. Update frequency in seconds. Set to 0 to update always.",
29262930
"username": "Username for the MQTT server, default is empty. Not needed by Victron devices. This is only needed if you use route your mqtt messages through non Victron server and it does require username."
29272931
}
29282932
}

tests/test_config_flow.py

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@
1414
CONF_ROOT_TOPIC_PREFIX,
1515
CONF_SERIAL,
1616
CONF_SIMPLE_NAMING,
17+
CONF_UPDATE_FREQUENCY_MODE,
1718
CONF_UPDATE_FREQUENCY_SECONDS,
1819
DEFAULT_PORT,
1920
DEFAULT_SIMPLE_NAMING,
2021
DEFAULT_UPDATE_FREQUENCY_SECONDS,
2122
DOMAIN,
23+
UPDATE_FREQUENCY_MODE_AUTO,
24+
UPDATE_FREQUENCY_MODE_MANUAL,
2225
)
2326
from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_SSDP, SOURCE_USER
2427
from homeassistant.const import (
@@ -77,6 +80,7 @@ async def test_user_flow_full_config(hass: HomeAssistant) -> None:
7780
CONF_SSL: False,
7881
CONF_SIMPLE_NAMING: True,
7982
CONF_ROOT_TOPIC_PREFIX: "N/test",
83+
CONF_UPDATE_FREQUENCY_MODE: UPDATE_FREQUENCY_MODE_MANUAL,
8084
CONF_UPDATE_FREQUENCY_SECONDS: 60,
8185
},
8286
)
@@ -95,6 +99,7 @@ async def test_user_flow_full_config(hass: HomeAssistant) -> None:
9599
CONF_SSL: False,
96100
CONF_SIMPLE_NAMING: True,
97101
CONF_ROOT_TOPIC_PREFIX: "N/test",
102+
CONF_UPDATE_FREQUENCY_MODE: UPDATE_FREQUENCY_MODE_MANUAL,
98103
CONF_UPDATE_FREQUENCY_SECONDS: 60,
99104
CONF_EXCLUDED_DEVICES: [],
100105
CONF_INSTALLATION_ID: MOCK_INSTALLATION_ID,
@@ -131,6 +136,7 @@ async def test_user_flow_minimal_config(hass: HomeAssistant) -> None:
131136
CONF_PORT: DEFAULT_PORT,
132137
CONF_SSL: False,
133138
CONF_SIMPLE_NAMING: False,
139+
CONF_UPDATE_FREQUENCY_MODE: UPDATE_FREQUENCY_MODE_AUTO,
134140
CONF_UPDATE_FREQUENCY_SECONDS: DEFAULT_UPDATE_FREQUENCY_SECONDS,
135141
CONF_OPERATION_MODE: OperationMode.FULL.value,
136142
CONF_EXCLUDED_DEVICES: [],
@@ -397,6 +403,7 @@ async def test_options_flow_success(hass: HomeAssistant) -> None:
397403
CONF_SSL: True,
398404
CONF_SIMPLE_NAMING: True,
399405
CONF_ROOT_TOPIC_PREFIX: "N/updated",
406+
CONF_UPDATE_FREQUENCY_MODE: UPDATE_FREQUENCY_MODE_MANUAL,
400407
CONF_UPDATE_FREQUENCY_SECONDS: 45,
401408
},
402409
)
@@ -410,6 +417,7 @@ async def test_options_flow_success(hass: HomeAssistant) -> None:
410417
CONF_SSL: True,
411418
CONF_SIMPLE_NAMING: True,
412419
CONF_ROOT_TOPIC_PREFIX: "N/updated",
420+
CONF_UPDATE_FREQUENCY_MODE: UPDATE_FREQUENCY_MODE_MANUAL,
413421
CONF_UPDATE_FREQUENCY_SECONDS: 45,
414422
CONF_OPERATION_MODE: OperationMode.FULL.value,
415423
CONF_EXCLUDED_DEVICES: [],
@@ -844,7 +852,8 @@ async def test_migration_v1_to_v2_without_simple_naming(hass: HomeAssistant) ->
844852
result = await async_migrate_entry(hass, mock_config_entry)
845853
assert result is True
846854
assert mock_config_entry.data[CONF_SIMPLE_NAMING] is False
847-
assert mock_config_entry.version == 2
855+
assert mock_config_entry.data[CONF_UPDATE_FREQUENCY_MODE] == UPDATE_FREQUENCY_MODE_AUTO
856+
assert mock_config_entry.version == 3
848857

849858

850859
async def test_migration_v1_to_v2_with_simple_naming_true(hass: HomeAssistant) -> None:
@@ -869,7 +878,8 @@ async def test_migration_v1_to_v2_with_simple_naming_true(hass: HomeAssistant) -
869878
result = await async_migrate_entry(hass, mock_config_entry)
870879
assert result is True
871880
assert mock_config_entry.data[CONF_SIMPLE_NAMING] is True
872-
assert mock_config_entry.version == 2
881+
assert mock_config_entry.data[CONF_UPDATE_FREQUENCY_MODE] == UPDATE_FREQUENCY_MODE_AUTO
882+
assert mock_config_entry.version == 3
873883

874884

875885
async def test_migration_v1_to_v2_with_simple_naming_false(hass: HomeAssistant) -> None:
@@ -894,4 +904,86 @@ async def test_migration_v1_to_v2_with_simple_naming_false(hass: HomeAssistant)
894904
result = await async_migrate_entry(hass, mock_config_entry)
895905
assert result is True
896906
assert mock_config_entry.data[CONF_SIMPLE_NAMING] is False
897-
assert mock_config_entry.version == 2
907+
assert mock_config_entry.data[CONF_UPDATE_FREQUENCY_MODE] == UPDATE_FREQUENCY_MODE_AUTO
908+
assert mock_config_entry.version == 3
909+
910+
911+
async def test_migration_v2_to_v3_custom_frequency_becomes_manual(
912+
hass: HomeAssistant,
913+
) -> None:
914+
"""Test v2->v3 migration marks a non-default interval as manual mode."""
915+
mock_config_entry = MockConfigEntry(
916+
domain=DOMAIN,
917+
unique_id=MOCK_INSTALLATION_ID,
918+
version=2,
919+
data={
920+
CONF_HOST: MOCK_HOST,
921+
CONF_PORT: DEFAULT_PORT,
922+
CONF_INSTALLATION_ID: MOCK_INSTALLATION_ID,
923+
CONF_SSL: False,
924+
CONF_SIMPLE_NAMING: False,
925+
CONF_UPDATE_FREQUENCY_SECONDS: 45,
926+
},
927+
)
928+
mock_config_entry.add_to_hass(hass)
929+
930+
from custom_components.victron_mqtt import async_migrate_entry
931+
932+
result = await async_migrate_entry(hass, mock_config_entry)
933+
assert result is True
934+
assert mock_config_entry.data[CONF_UPDATE_FREQUENCY_MODE] == UPDATE_FREQUENCY_MODE_MANUAL
935+
assert mock_config_entry.data[CONF_UPDATE_FREQUENCY_SECONDS] == 45
936+
assert mock_config_entry.version == 3
937+
938+
939+
async def test_migration_v2_to_v3_default_frequency_becomes_auto(
940+
hass: HomeAssistant,
941+
) -> None:
942+
"""Test v2->v3 migration moves the old default interval to auto mode."""
943+
mock_config_entry = MockConfigEntry(
944+
domain=DOMAIN,
945+
unique_id=MOCK_INSTALLATION_ID,
946+
version=2,
947+
data={
948+
CONF_HOST: MOCK_HOST,
949+
CONF_PORT: DEFAULT_PORT,
950+
CONF_INSTALLATION_ID: MOCK_INSTALLATION_ID,
951+
CONF_SSL: False,
952+
CONF_SIMPLE_NAMING: False,
953+
CONF_UPDATE_FREQUENCY_SECONDS: DEFAULT_UPDATE_FREQUENCY_SECONDS,
954+
},
955+
)
956+
mock_config_entry.add_to_hass(hass)
957+
958+
from custom_components.victron_mqtt import async_migrate_entry
959+
960+
result = await async_migrate_entry(hass, mock_config_entry)
961+
assert result is True
962+
assert mock_config_entry.data[CONF_UPDATE_FREQUENCY_MODE] == UPDATE_FREQUENCY_MODE_AUTO
963+
assert mock_config_entry.version == 3
964+
965+
966+
async def test_migration_v2_to_v3_missing_frequency_becomes_auto(
967+
hass: HomeAssistant,
968+
) -> None:
969+
"""Test v2->v3 migration defaults to auto mode when no interval is set."""
970+
mock_config_entry = MockConfigEntry(
971+
domain=DOMAIN,
972+
unique_id=MOCK_INSTALLATION_ID,
973+
version=2,
974+
data={
975+
CONF_HOST: MOCK_HOST,
976+
CONF_PORT: DEFAULT_PORT,
977+
CONF_INSTALLATION_ID: MOCK_INSTALLATION_ID,
978+
CONF_SSL: False,
979+
CONF_SIMPLE_NAMING: False,
980+
},
981+
)
982+
mock_config_entry.add_to_hass(hass)
983+
984+
from custom_components.victron_mqtt import async_migrate_entry
985+
986+
result = await async_migrate_entry(hass, mock_config_entry)
987+
assert result is True
988+
assert mock_config_entry.data[CONF_UPDATE_FREQUENCY_MODE] == UPDATE_FREQUENCY_MODE_AUTO
989+
assert mock_config_entry.version == 3

0 commit comments

Comments
 (0)