Add diagnostics support for Sofar (#180854)

This commit is contained in:
darkrain-nl
2026-08-30 21:47:49 +03:00
committed by GitHub
parent 46ae12ca54
commit 8281b2faff
4 changed files with 222 additions and 1 deletions
@@ -0,0 +1,35 @@
"""Diagnostics support for Sofar."""
from typing import Any
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.core import HomeAssistant
from .coordinator import SofarConfigEntry
TO_REDACT = {"serial_number"}
_SERIAL_NUMBER_REGISTERS = range(0x0445, 0x044C)
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, entry: SofarConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
device = entry.runtime_data.readings.device
raw = await device.async_read_raw()
if (holding := raw.get("holding")) is not None:
for address in _SERIAL_NUMBER_REGISTERS:
holding.pop(address, None)
return async_redact_data(
{
"model": device.model,
"inverter_type": device.inverter_type,
"serial_number": device.serial_number,
"readings_components": device.readings_components,
"settings_components": device.settings_components,
"raw": raw,
},
TO_REDACT,
)
@@ -49,7 +49,7 @@ rules:
# Gold
devices: done
diagnostics: todo
diagnostics: done
discovery-update-info:
status: exempt
comment: Modbus TCP gateways have no discovery protocol to update network info from.
@@ -0,0 +1,151 @@
# serializer version: 1
# name: test_diagnostics
dict({
'inverter_type': 1537,
'model': '4.4 KTLX-G3',
'raw': dict({
'holding': dict({
'1028': 2,
'1029': 0,
'1030': 0,
'1031': 0,
'1032': 0,
'1033': 0,
'1034': 0,
'1035': 0,
'1036': 0,
'1037': 0,
'1038': 0,
'1039': 0,
'1040': 0,
'1041': 0,
'1042': 0,
'1043': 0,
'1044': 0,
'1045': 0,
'1046': 0,
'1047': 0,
'1048': 0,
'1049': 0,
'1050': 0,
'1051': 0,
'1052': 0,
'1053': 0,
'1054': 0,
'1055': 0,
'1056': 0,
'1057': 0,
'1068': 0,
'1069': 0,
'1070': 0,
'1071': 0,
'1072': 0,
'1073': 0,
'1100': 0,
'1101': 22065,
'1102': 12336,
'1103': 22066,
'1104': 12848,
'1105': 0,
'1106': 0,
'1156': 5000,
'1157': 0,
'1158': 0,
'1159': 0,
'1160': 0,
'1161': 0,
'1162': 0,
'1163': 0,
'1164': 0,
'1165': 0,
'1166': 0,
'1167': 0,
'1168': 0,
'1169': 0,
'1170': 0,
'1171': 0,
'1172': 0,
'1173': 0,
'1174': 0,
'1175': 0,
'1176': 0,
'1177': 0,
'1178': 0,
'1179': 0,
'1180': 0,
'1181': 0,
'1182': 0,
'1183': 0,
'1184': 0,
'1185': 0,
'1186': 0,
'1187': 0,
'1188': 0,
'1189': 0,
'1190': 0,
'1191': 0,
'1192': 0,
'1193': 0,
'1194': 0,
'1195': 0,
'1196': 0,
'1197': 0,
'1198': 0,
'1199': 0,
'1200': 0,
'1201': 0,
'1202': 0,
'1203': 0,
'1204': 0,
'1205': 0,
'1206': 0,
'1207': 0,
'1208': 0,
'1209': 0,
'1210': 0,
'1211': 0,
'1212': 0,
'1412': 0,
'1413': 0,
'1414': 250,
'1415': 0,
'1416': 0,
'1417': 180,
'1476': 43,
'1668': 0,
'1669': 1000,
'1670': 0,
'1671': 150,
'1672': 0,
'1673': 0,
'1674': 0,
'1675': 0,
'1676': 0,
'1677': 0,
'1678': 0,
'1679': 0,
'1680': 0,
'1681': 0,
'1682': 0,
'1683': 0,
'4131': 0,
'4132': 0,
'4356': 0,
'4357': 0,
'4358': 0,
}),
}),
'readings_components': list([
'state',
'grid',
'pv_1_2',
'energy',
]),
'serial_number': '**REDACTED**',
'settings_components': list([
'feed_in',
'remote',
'active_power_control',
]),
})
# ---
@@ -0,0 +1,35 @@
"""Test the Sofar Inverter Modbus diagnostics."""
from syrupy.assertion import SnapshotAssertion
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator
async def test_diagnostics(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
init_integration: MockConfigEntry,
snapshot: SnapshotAssertion,
) -> None:
"""Test generating diagnostics for a config entry."""
diag = await get_diagnostics_for_config_entry(hass, hass_client, init_integration)
assert diag == snapshot
async def test_diagnostics_redacts_serial_number(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
init_integration: MockConfigEntry,
) -> None:
"""Test the serial number is redacted, both as a field and as raw ASCII."""
diag = await get_diagnostics_for_config_entry(hass, hass_client, init_integration)
assert diag["serial_number"] == "**REDACTED**"
holding = diag["raw"]["holding"]
for address in range(0x0445, 0x044C):
assert str(address) not in holding