Skip to content

Commit a277e82

Browse files
authored
reauth if for example device version is missing (#58)
2 parents 54c7560 + 3965ff8 commit a277e82

3 files changed

Lines changed: 86 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,80 +2,95 @@
22

33
## [2025.10.1] - 2025-10-15
44

5-
### Added
5+
### Added
6+
67
- Config flow now asks for device version (v1/v2 or v3) during setup so the integration can load the correct register map at runtime.
78
- Per-version register modules: `registers_v12.py` (v1/v2) and `registers_v3.py` (v3). The integration selects the right definitions based on the chosen version.
89

910
### Fixed
11+
1012
- Options flow: removed deprecated explicit `config_entry` assignment (compatibility with HA 2025.12).
1113
- Modbus client: properly handle CancelledError during shutdown; guard reconnection and client recreation to avoid NoneType errors and noisy ERROR logs on stop/reload.
1214
- Efficiency sensors: skip calculations when denominators are zero or required inputs are missing to avoid division-by-zero errors.
1315
- Energy sensors: ensure `state_class` is set to `total` or `total_increasing` for sensors with `device_class: energy`.
1416

1517
### Notes
16-
- `registers_v3.py` was generated from a CSV mapping but the registers are UNTESTED for v3 devices. Manual verification on actual hardware is REQUIRED before using v3 definitions in production.
18+
19+
- `registers_v3.py` is generated from CSV mapping; entries are untested and require manual verification on v3 hardware before production use.
1720

1821
## [2025.9.4] - 2025-09-22
1922

2023
### Added
24+
2125
- Configurable scan intervals (high, medium, low, very_low) through integration options.
2226
- Options flow with translated titles and descriptions.
2327

2428
### Changed
29+
2530
- Coordinator now dynamically adjusts polling interval based on the lowest configured scan interval.
2631

2732
### Fixed
33+
2834
- Corrected calculation of Actual Conversion Efficiency to properly handle charging vs discharging, avoiding efficiencies above 100%.
2935
- Properly handle Modbus client closing when disabling the integration.
3036
- Correctly apply updated polling intervals after options are changed.
3137

3238
## [2025.9.3] - 2025-09-16
3339

3440
### Added
41+
3542
- New `Actual Conversion Efficiency` calculated sensor to display the real-time charging/discharging efficiency as a percentage.
3643

3744
### Fixed
45+
3846
- Fixed proper closing of Modbus connections when disabling and enabling entities, preventing multiple open sessions.
3947
- Corrected state class for stored energy sensors to match energy device class requirements.
4048
- Corrected calculation of Actual Conversion Efficiency to properly handle charging vs discharging, avoiding efficiencies above 100%.
4149

4250
## [2025.9.2] - 2025-09-07
4351

4452
### Fixed
53+
4554
- Corrected scaling for `Number` entities, ensuring `min`, `max`, and current values reflect the defined scale.
4655
- Updated logging to include scale and unit when values are updated in Home Assistant.
4756

4857
## [2025.9.1] - 2025-09-05
4958

5059
### Fixed
60+
5161
- Switch writing fixed and now implemented with optimistic mode to handle delayed device response.
5262
- Fixed PyModbus 3.x / Python 3.9 compatibility: replaced slave with device_id.
5363

5464
## [2025.9.0] - 2025-09-03
5565

5666
### Added
67+
5768
- Dependency keys registration so required values are always fetched even if disabled in Home Assistant.
5869
- Polling now handled centrally via the DataUpdateCoordinator.
5970
- Dynamic polling intervals based on sensor definitions and dependencies.
6071

6172
### Changed
73+
6274
- Calculated sensors (Round-Trip Efficiency Total, Round-Trip Efficiency Monthly, Stored Energy) with dependency handling
6375
- Improved logging for dependency mapping, calculation, and skipping disabled entities.
6476
- Cleaned up and refactored sensor calculation logic to be reusable and PEP8 compliant.
6577

6678
## [2025.8.1] - 2025-08-12
6779

6880
### Added
81+
6982
- New Min Cell Voltage sensor (register 35043) to monitor minimum battery cell voltage
7083
- New Max Cell Voltage sensor (register 36943) to monitor maximum battery cell voltage
7184
- New Reset Device button (register 41000) to allow resetting the battery management system via Home Assistant
7285

7386
### Changed
87+
7488
- Clean up code and improve overall code quality
7589

7690
## [2025.8.0] - 2025-08-09
7791

7892
### Fixed
93+
7994
- WiFi strength sensor now reports correct negative dBm values
8095
- Corrected cell temperature reading after BMS firmware version 213
8196

custom_components/marstek_modbus/config_flow.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,50 @@ async def async_step_user(self, user_input=None):
111111
description_placeholders=description_placeholders,
112112
)
113113

114+
async def async_step_reauth(self, data=None):
115+
"""
116+
Re-authentication step triggered when a config entry is missing required
117+
information (like device_version). This shows a popup asking the user to
118+
select the correct device version.
119+
"""
120+
errors = {}
121+
122+
# Load translations for the current language to present friendly labels
123+
language = self.context.get("language", self.hass.config.language)
124+
translations = await async_get_translations(
125+
self.hass, language, category="config", integrations=DOMAIN
126+
)
127+
128+
if data is not None:
129+
# Persist the chosen device version into the existing config entry
130+
entry = self._async_current_entries()[0] if self._async_current_entries() else None
131+
if entry:
132+
try:
133+
new_data = dict(entry.data)
134+
new_data[CONF_DEVICE_VERSION] = data.get(CONF_DEVICE_VERSION)
135+
await self.hass.config_entries.async_update_entry(entry, data=new_data)
136+
return self.async_create_entry(title=entry.title or DOMAIN, data={})
137+
except Exception as exc:
138+
_LOGGER.error("Failed to update config entry during reauth: %s", exc)
139+
errors["base"] = "unknown"
140+
141+
description_placeholders = {
142+
"device_version_choices": ", ".join(
143+
[f"{v}: {translations.get(f'config.step.user.data.device_version|{v}', v)}" for v in SUPPORTED_VERSIONS]
144+
)
145+
}
146+
147+
return self.async_show_form(
148+
step_id="reauth",
149+
data_schema=vol.Schema(
150+
{
151+
vol.Required(CONF_DEVICE_VERSION, default=SUPPORTED_VERSIONS[0]): vol.In(SUPPORTED_VERSIONS)
152+
}
153+
),
154+
errors=errors,
155+
description_placeholders=description_placeholders,
156+
)
157+
114158
@staticmethod
115159
# @callback
116160
def async_get_options_flow(config_entry):

custom_components/marstek_modbus/coordinator.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,31 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry):
4747
self._scales: dict[str, float] = {}
4848

4949
# Load register/entity definitions for the device version selected in the config entry
50-
registers = get_registers(entry.data.get("device_version"))
50+
# If device_version is missing (older installs), schedule a reauth flow so the user
51+
# can pick the correct device version via a popup in the UI. Use a safe default
52+
# to initialize the coordinator so the integration does not crash while waiting
53+
# for the user to respond.
54+
raw_device_version = entry.data.get("device_version", "") or ""
55+
if not str(raw_device_version).strip():
56+
# Start a reauth flow so Home Assistant prompts the user to provide the missing value
57+
try:
58+
_LOGGER.info(
59+
"Config entry %s missing device_version; starting reauth flow",
60+
entry.entry_id,
61+
)
62+
# Use async_create_task to avoid awaiting in __init__
63+
self.hass.async_create_task(
64+
self.hass.config_entries.async_start_reauth(entry.entry_id)
65+
)
66+
except Exception:
67+
_LOGGER.debug("Failed to start reauth for entry %s", entry.entry_id)
68+
69+
# Fallback to the first supported version to allow initialization to proceed
70+
used_version = SUPPORTED_VERSIONS[0]
71+
else:
72+
used_version = raw_device_version
73+
74+
registers = get_registers(used_version)
5175
self.SENSOR_DEFINITIONS = registers.get("SENSOR_DEFINITIONS", [])
5276
self.BINARY_SENSOR_DEFINITIONS = registers.get("BINARY_SENSOR_DEFINITIONS", [])
5377
self.SELECT_DEFINITIONS = registers.get("SELECT_DEFINITIONS", [])

0 commit comments

Comments
 (0)