diff --git a/custom_components/solaredge_modbus_multi/helpers.py b/custom_components/solaredge_modbus_multi/helpers.py index 9ba147a1..08d3e64a 100644 --- a/custom_components/solaredge_modbus_multi/helpers.py +++ b/custom_components/solaredge_modbus_multi/helpers.py @@ -1,3 +1,6 @@ +import struct + + def scale_factor(value: int, sf: int): try: return value * (10 ** sf) @@ -9,6 +12,10 @@ def watts_to_kilowatts(value): return round(value * 0.001, 3) +def float_to_hex(f): + return hex(struct.unpack(" str: s = s.decode(encoding="utf-8", errors="ignore") s = s.replace("\x00", "").rstrip() diff --git a/custom_components/solaredge_modbus_multi/sensor.py b/custom_components/solaredge_modbus_multi/sensor.py index 0f40d728..9250a0c5 100644 --- a/custom_components/solaredge_modbus_multi/sensor.py +++ b/custom_components/solaredge_modbus_multi/sensor.py @@ -41,7 +41,7 @@ SUNSPEC_SF_RANGE, VENDOR_STATUS, ) -from .helpers import scale_factor, update_accum, watts_to_kilowatts +from .helpers import float_to_hex, scale_factor, update_accum, watts_to_kilowatts _LOGGER = logging.getLogger(__name__) @@ -256,17 +256,45 @@ def extra_state_attributes(self): attrs = {} try: - attrs["batt_charge_peak"] = self._platform.decoded_common[ - "B_MaxChargePeakPower" - ] - attrs["batt_discharge_peak"] = self._platform.decoded_common[ - "B_MaxDischargePeakPower" - ] - attrs["batt_max_charge"] = self._platform.decoded_common["B_MaxChargePower"] - attrs["batt_max_discharge"] = self._platform.decoded_common[ - "B_MaxDischargePower" - ] - attrs["batt_rated_energy"] = self._platform.decoded_common["B_RatedEnergy"] + if ( + float_to_hex(self._platform.decoded_common["B_MaxChargePeakPower"]) + != 0xFF7FFFFF + ): + attrs["batt_charge_peak"] = self._platform.decoded_common[ + "B_MaxChargePeakPower" + ] + + if ( + float_to_hex(self._platform.decoded_common["B_MaxDischargePeakPower"]) + != 0xFF7FFFFF + ): + attrs["batt_discharge_peak"] = self._platform.decoded_common[ + "B_MaxDischargePeakPower" + ] + + if ( + float_to_hex(self._platform.decoded_common["B_MaxChargePower"]) + != 0xFF7FFFFF + ): + attrs["batt_max_charge"] = self._platform.decoded_common[ + "B_MaxChargePower" + ] + + if ( + float_to_hex(self._platform.decoded_common["B_MaxDischargePower"]) + != 0xFF7FFFFF + ): + attrs["batt_max_discharge"] = self._platform.decoded_common[ + "B_MaxDischargePower" + ] + + if ( + float_to_hex(self._platform.decoded_common["B_RatedEnergy"]) + != 0xFF7FFFFF + ): + attrs["batt_rated_energy"] = self._platform.decoded_common[ + "B_RatedEnergy" + ] except KeyError: pass @@ -1466,10 +1494,12 @@ def name(self) -> str: def native_value(self): try: if ( - self._platform.decoded_model["B_Temp_Average"] + float_to_hex(self._platform.decoded_model["B_Temp_Average"]) == SUNSPEC_NOT_IMPL_FLOAT32 - or self._platform.decoded_model["B_Temp_Average"] == 0xFF7FFFFF - or self._platform.decoded_model["B_Temp_Average"] == 0x7F7FFFFF + or float_to_hex(self._platform.decoded_model["B_Temp_Average"]) + == 0xFF7FFFFF + or float_to_hex(self._platform.decoded_model["B_Temp_Average"]) + == 0x7F7FFFFF ): return None @@ -1497,9 +1527,12 @@ def entity_registry_enabled_default(self) -> bool: def native_value(self): try: if ( - self._platform.decoded_model["B_Temp_Max"] == SUNSPEC_NOT_IMPL_FLOAT32 - or self._platform.decoded_model["B_Temp_Max"] == 0xFF7FFFFF - or self._platform.decoded_model["B_Temp_Max"] == 0x7F7FFFFF + float_to_hex(self._platform.decoded_model["B_Temp_Max"]) + == SUNSPEC_NOT_IMPL_FLOAT32 + or float_to_hex(self._platform.decoded_model["B_Temp_Max"]) + == 0xFF7FFFFF + or float_to_hex(self._platform.decoded_model["B_Temp_Max"]) + == 0x7F7FFFFF ): return None @@ -1515,9 +1548,12 @@ class SolarEdgeBatteryVoltage(DCVoltage): def native_value(self): try: if ( - self._platform.decoded_model["B_DC_Voltage"] == SUNSPEC_NOT_IMPL_FLOAT32 - or self._platform.decoded_model["B_DC_Voltage"] == 0xFF7FFFFF - or self._platform.decoded_model["B_DC_Voltage"] == 0x7F7FFFFF + float_to_hex(self._platform.decoded_model["B_DC_Voltage"]) + == SUNSPEC_NOT_IMPL_FLOAT32 + or float_to_hex(self._platform.decoded_model["B_DC_Voltage"]) + == 0xFF7FFFFF + or float_to_hex(self._platform.decoded_model["B_DC_Voltage"]) + == 0x7F7FFFFF ): return None @@ -1536,9 +1572,12 @@ class SolarEdgeBatteryCurrent(DCCurrent): def native_value(self): try: if ( - self._platform.decoded_model["B_DC_Current"] == SUNSPEC_NOT_IMPL_FLOAT32 - or self._platform.decoded_model["B_DC_Current"] == 0xFF7FFFFF - or self._platform.decoded_model["B_DC_Current"] == 0x7F7FFFFF + float_to_hex(self._platform.decoded_model["B_DC_Current"]) + == SUNSPEC_NOT_IMPL_FLOAT32 + or float_to_hex(self._platform.decoded_model["B_DC_Current"]) + == 0xFF7FFFFF + or float_to_hex(self._platform.decoded_model["B_DC_Current"]) + == 0x7F7FFFFF ): return None @@ -1559,9 +1598,12 @@ class SolarEdgeBatteryPower(DCPower): def native_value(self): try: if ( - self._platform.decoded_model["B_DC_Power"] == SUNSPEC_NOT_IMPL_FLOAT32 - or self._platform.decoded_model["B_DC_Power"] == 0xFF7FFFFF - or self._platform.decoded_model["B_DC_Power"] == 0x7F7FFFFF + float_to_hex(self._platform.decoded_model["B_DC_Power"]) + == SUNSPEC_NOT_IMPL_FLOAT32 + or float_to_hex(self._platform.decoded_model["B_DC_Power"]) + == 0xFF7FFFFF + or float_to_hex(self._platform.decoded_model["B_DC_Power"]) + == 0x7F7FFFFF ): return None @@ -1673,9 +1715,10 @@ def name(self) -> str: @property def native_value(self): if ( - self._platform.decoded_model["B_Energy_Max"] == SUNSPEC_NOT_IMPL_FLOAT32 - or self._platform.decoded_model["B_Energy_Max"] == 0xFF7FFFFF - or self._platform.decoded_model["B_Energy_Max"] == 0x7F7FFFFF + float_to_hex(self._platform.decoded_model["B_Energy_Max"]) + == SUNSPEC_NOT_IMPL_FLOAT32 + or float_to_hex(self._platform.decoded_model["B_Energy_Max"]) == 0xFF7FFFFF + or float_to_hex(self._platform.decoded_model["B_Energy_Max"]) == 0x7F7FFFFF ): return None @@ -1703,10 +1746,12 @@ def name(self) -> str: @property def native_value(self): if ( - self._platform.decoded_model["B_Energy_Available"] + float_to_hex(self._platform.decoded_model["B_Energy_Available"]) == SUNSPEC_NOT_IMPL_FLOAT32 - or self._platform.decoded_model["B_Energy_Available"] == 0xFF7FFFFF - or self._platform.decoded_model["B_Energy_Available"] == 0x7F7FFFFF + or float_to_hex(self._platform.decoded_model["B_Energy_Available"]) + == 0xFF7FFFFF + or float_to_hex(self._platform.decoded_model["B_Energy_Available"]) + == 0x7F7FFFFF ): return None @@ -1736,9 +1781,10 @@ def name(self) -> str: @property def native_value(self): if ( - self._platform.decoded_model["B_SOH"] == SUNSPEC_NOT_IMPL_FLOAT32 - or self._platform.decoded_model["B_SOH"] == 0xFF7FFFFF - or self._platform.decoded_model["B_SOH"] == 0x7F7FFFFF + float_to_hex(self._platform.decoded_model["B_SOH"]) + == SUNSPEC_NOT_IMPL_FLOAT32 + or float_to_hex(self._platform.decoded_model["B_SOH"]) == 0xFF7FFFFF + or float_to_hex(self._platform.decoded_model["B_SOH"]) == 0x7F7FFFFF or self._platform.decoded_model["B_SOH"] < 0 or self._platform.decoded_model["B_SOH"] > 100 ): @@ -1767,9 +1813,10 @@ def name(self) -> str: @property def native_value(self): if ( - self._platform.decoded_model["B_SOE"] == SUNSPEC_NOT_IMPL_FLOAT32 - or self._platform.decoded_model["B_SOE"] == 0xFF7FFFFF - or self._platform.decoded_model["B_SOE"] == 0x7F7FFFFF + float_to_hex(self._platform.decoded_model["B_SOE"]) + == SUNSPEC_NOT_IMPL_FLOAT32 + or float_to_hex(self._platform.decoded_model["B_SOE"]) == 0xFF7FFFFF + or float_to_hex(self._platform.decoded_model["B_SOE"]) == 0x7F7FFFFF or self._platform.decoded_model["B_SOE"] < 0 or self._platform.decoded_model["B_SOE"] > 100 ): @@ -1800,10 +1847,9 @@ def extra_state_attributes(self): attrs = {} try: - if self._platform.decoded_model["B_Status"] in BATTERY_STATUS: - attrs["status_text"] = BATTERY_STATUS[ - self._platform.decoded_model["B_Status"] - ] + attrs["status_text"] = BATTERY_STATUS[ + self._platform.decoded_model["B_Status"] + ] except KeyError: pass