Skip to content

Commit 135ce99

Browse files
Merge pull request #977 from WillCodeForCats/status-vendor-4
Add Status Vendor 4 sensor
2 parents c5e135b + e03f334 commit 135ce99

4 files changed

Lines changed: 132 additions & 0 deletions

File tree

custom_components/solaredge_modbus_multi/const.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
re.IGNORECASE,
3131
)
3232

33+
STATUS_VENDOR4_VERSION = "3.20.0"
34+
3335

3436
class ModbusExceptions:
3537
"""An enumeration of the valid modbus exceptions."""
@@ -270,6 +272,34 @@ class SunSpecNotImpl(IntEnum):
270272
256: "Arc Detected",
271273
}
272274

275+
VENDOR4_STATUS: dict[int, dict[int, str]] = {
276+
# controller: {error_code: "description"}
277+
0x3: {
278+
0x2: "Inverter Communication Error",
279+
0x1C: "Battery without Firmware",
280+
0x6B: "Battery Communication Error",
281+
0x6E: "Meter Communication Error",
282+
0xA5: "Modbus Routing Packets Debug",
283+
},
284+
0x18: {
285+
0x14: "Inv. Power Error - No Code",
286+
0x1C: "V-L1 Min1",
287+
0x3D: "I-RCD Step",
288+
0x40: "F-L1 Max1",
289+
0x61: "Vin Buck Max",
290+
0xA5: "Tz Over Current 3",
291+
0xB5: "Vcap11 Surge",
292+
0xB6: "Vcap12 Surge",
293+
0xB9: "Vcap31 Surge",
294+
0xBA: "Vcap33 Surge",
295+
0xBE: "Swing Rdiff Overheat",
296+
0xBF: "Swing Rcommon Overheat",
297+
0xC7: "Rapid Shutdown (RSD) Error",
298+
0xD6: "Multiple Seq. GB",
299+
0x100: "Arc Detected",
300+
},
301+
}
302+
273303
SUNSPEC_DID = {
274304
101: "Single Phase Inverter",
275305
102: "Split Phase Inverter",

custom_components/solaredge_modbus_multi/diagnostics.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ async def async_get_config_entry_diagnostics(
6060
"mmppt": format_values(inverter.decoded_mmppt),
6161
"has_battery": inverter.has_battery,
6262
"storage_control": format_values(inverter.decoded_storage_control),
63+
"use_status_vendor4": inverter.use_status_vendor4,
6364
}
6465
}
6566

custom_components/solaredge_modbus_multi/hub.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
import inspect
77
import logging
88

9+
from awesomeversion import AwesomeVersion
10+
from awesomeversion.exceptions import (
11+
AwesomeVersionCompareException,
12+
AwesomeVersionStrategyException,
13+
)
914
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT
1015
from homeassistant.core import HomeAssistant
1116
from homeassistant.exceptions import HomeAssistantError
@@ -28,6 +33,7 @@
2833
DOMAIN,
2934
METER_REG_BASE,
3035
PYMODBUS_REQUIRED_VERSION,
36+
STATUS_VENDOR4_VERSION,
3137
ConfDefaultFlag,
3238
ConfDefaultInt,
3339
ConfDefaultStr,
@@ -844,6 +850,7 @@ def __init__(self, device_id: int, hub: SolarEdgeModbusMultiHub) -> None:
844850
self.site_limit_control = None
845851
self._grid_status = None
846852
self._last_update_timestamp = None
853+
self._use_status_vendor4 = False
847854

848855
async def init_device(self) -> None:
849856
"""Set up data about the device from modbus."""
@@ -1036,6 +1043,16 @@ async def init_device(self) -> None:
10361043
self.name = f"{self.hub.hub_id.capitalize()} I{self.inverter_unit_id}"
10371044
self.uid_base = f"{self.model}_{self.serial}"
10381045

1046+
try:
1047+
this_ver = AwesomeVersion(self.decoded_common["C_Version"])
1048+
self._use_status_vendor4 = this_ver >= AwesomeVersion(
1049+
STATUS_VENDOR4_VERSION
1050+
)
1051+
except (AwesomeVersionCompareException, AwesomeVersionStrategyException) as e:
1052+
_LOGGER.error(
1053+
f"Error checking inverter version: {e}. Please report this issue."
1054+
)
1055+
10391056
if self.decoded_mmppt is not None:
10401057
for unit_index in range(self.decoded_mmppt["mmppt_Units"]):
10411058
self.mmppt_units.append(SolarEdgeMMPPTUnit(self, self.hub, unit_index))
@@ -1127,6 +1144,7 @@ async def read_modbus_data(self) -> None:
11271144
+ [inverter_data.registers[28]]
11281145
+ inverter_data.registers[30:40]
11291146
)
1147+
11301148
self.decoded_model.update(
11311149
dict(
11321150
zip(
@@ -1154,6 +1172,24 @@ async def read_modbus_data(self) -> None:
11541172
)
11551173
)
11561174

1175+
if self.use_status_vendor4:
1176+
inverter_data = await self.hub.modbus_read_holding_registers(
1177+
unit=self.inverter_unit_id, address=40119, rcount=2
1178+
)
1179+
self.decoded_model.update(
1180+
dict(
1181+
[
1182+
(
1183+
"I_Status_Vendor4",
1184+
ModbusClientMixin.convert_from_registers(
1185+
inverter_data.registers[0:2],
1186+
data_type=ModbusClientMixin.DATATYPE.UINT32,
1187+
),
1188+
),
1189+
]
1190+
)
1191+
)
1192+
11571193
if (
11581194
self.decoded_model["C_SunSpec_DID"] == SunSpecNotImpl.UINT16
11591195
or self.decoded_model["C_SunSpec_DID"] not in [101, 102, 103]
@@ -1913,6 +1949,10 @@ def is_mmppt(self) -> bool:
19131949
def last_update(self) -> datetime.datetime | None:
19141950
return self._last_update_timestamp
19151951

1952+
@property
1953+
def use_status_vendor4(self) -> bool:
1954+
return self._use_status_vendor4
1955+
19161956

19171957
class SolarEdgeMMPPTUnit:
19181958
"""Defines a SolarEdge inverter MMPPT unit."""

custom_components/solaredge_modbus_multi/sensor.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
RRCR_STATUS,
4242
SUNSPEC_DID,
4343
SUNSPEC_SF_RANGE,
44+
VENDOR4_STATUS,
4445
VENDOR_STATUS,
4546
BatteryLimit,
4647
SunSpecAccum,
@@ -67,6 +68,8 @@ async def async_setup_entry(
6768
entities.append(Version(inverter, config_entry, coordinator))
6869
entities.append(SolarEdgeInverterStatus(inverter, config_entry, coordinator))
6970
entities.append(StatusVendor(inverter, config_entry, coordinator))
71+
if inverter.use_status_vendor4:
72+
entities.append(StatusVendor4(inverter, config_entry, coordinator))
7073
entities.append(ACCurrentSensor(inverter, config_entry, coordinator))
7174
entities.append(ACCurrentSensor(inverter, config_entry, coordinator, "A"))
7275
entities.append(ACCurrentSensor(inverter, config_entry, coordinator, "B"))
@@ -1399,6 +1402,10 @@ def unique_id(self) -> str:
13991402
def name(self) -> str:
14001403
return "Status Vendor"
14011404

1405+
@property
1406+
def entity_registry_enabled_default(self) -> bool:
1407+
return not self._platform.use_status_vendor4
1408+
14021409
@property
14031410
def native_value(self):
14041411
try:
@@ -1428,6 +1435,60 @@ def extra_state_attributes(self):
14281435
return None
14291436

14301437

1438+
class StatusVendor4(SolarEdgeSensorBase):
1439+
entity_category = EntityCategory.DIAGNOSTIC
1440+
1441+
@property
1442+
def unique_id(self) -> str:
1443+
return f"{self._platform.uid_base}_status_vendor4"
1444+
1445+
@property
1446+
def name(self) -> str:
1447+
return "Status Vendor 4"
1448+
1449+
@property
1450+
def available(self) -> bool:
1451+
return (
1452+
super().available
1453+
and "I_Status_Vendor4" in self._platform.decoded_model
1454+
and self._platform.decoded_model["I_Status_Vendor4"]
1455+
!= SunSpecNotImpl.UINT32
1456+
)
1457+
1458+
@property
1459+
def native_value(self):
1460+
try:
1461+
value = self._platform.decoded_model["I_Status_Vendor4"]
1462+
controller = (value >> 24) & 0xFF
1463+
error = value & 0xFFFF
1464+
return f"{controller:X}x{error:X}"
1465+
except TypeError:
1466+
return None
1467+
1468+
@property
1469+
def extra_state_attributes(self):
1470+
try:
1471+
value = self._platform.decoded_model["I_Status_Vendor4"]
1472+
1473+
controller = (value >> 24) & 0xFF
1474+
error = value & 0xFFFF
1475+
attrs = {
1476+
"controller": hex(controller),
1477+
"error_code": hex(error),
1478+
}
1479+
1480+
if controller in VENDOR4_STATUS and error in VENDOR4_STATUS[controller]:
1481+
attrs["description"] = VENDOR4_STATUS[controller][error]
1482+
1483+
return attrs
1484+
1485+
except KeyError:
1486+
return None
1487+
1488+
except TypeError:
1489+
return None
1490+
1491+
14311492
class SolarEdgeGlobalPowerControlBlock(SolarEdgeSensorBase):
14321493
@property
14331494
def available(self) -> bool:

0 commit comments

Comments
 (0)