diff --git a/custom_components/solaredge_modbus_multi/sensor.py b/custom_components/solaredge_modbus_multi/sensor.py index ef07f733..a57b9c40 100644 --- a/custom_components/solaredge_modbus_multi/sensor.py +++ b/custom_components/solaredge_modbus_multi/sensor.py @@ -138,6 +138,7 @@ async def async_setup_entry( entities.append(ACPower(meter, config_entry, coordinator, "A")) entities.append(ACPower(meter, config_entry, coordinator, "B")) entities.append(ACPower(meter, config_entry, coordinator, "C")) + entities.append(ACPowerInverted(meter, config_entry, coordinator)) entities.append(ACVoltAmp(meter, config_entry, coordinator)) entities.append(ACVoltAmp(meter, config_entry, coordinator, "A")) entities.append(ACVoltAmp(meter, config_entry, coordinator, "B")) @@ -203,6 +204,9 @@ async def async_setup_entry( entities.append(SolarEdgeBatteryVoltage(battery, config_entry, coordinator)) entities.append(SolarEdgeBatteryCurrent(battery, config_entry, coordinator)) entities.append(SolarEdgeBatteryPower(battery, config_entry, coordinator)) + entities.append( + SolarEdgeBatteryPowerInverted(battery, config_entry, coordinator) + ) entities.append( SolarEdgeBatteryEnergyExport(battery, config_entry, coordinator) ) @@ -603,6 +607,37 @@ def suggested_display_precision(self): return abs(self._platform.decoded_model["AC_Power_SF"]) +class ACPowerInverted(ACPower): + """Inverted AC power sensor for Home Assistant energy dashboard compatibility. + + This class exists solely due to a design decision by the Home Assistant team + for their energy dashboard, which requires power to be represented opposite + to how a grid-tie inverter normally reports it. The native_value is negated + to meet this requirement. + + This does not represent how the inverter or SolarEdge dashboard will represent + the same sensor. You should normally refer to the non-inverted version. + """ + + def __init__(self, platform, config_entry, coordinator): + super().__init__(platform, config_entry, coordinator) + + @property + def unique_id(self) -> str: + return f"{super().unique_id}_inverted" + + @property + def name(self) -> str: + return f"{super().name} Inverted" + + @property + def native_value(self): + value = super().native_value + if value is None: + return None + return -value + + class ACFrequency(SolarEdgeSensorBase): device_class = SensorDeviceClass.FREQUENCY state_class = SensorStateClass.MEASUREMENT @@ -1385,14 +1420,12 @@ def extra_state_attributes(self): class SolarEdgeGlobalPowerControlBlock(SolarEdgeSensorBase): - @property def available(self) -> bool: return super().available and self._platform.global_power_control class SolarEdgeRRCR(SolarEdgeGlobalPowerControlBlock): - @property def unique_id(self) -> str: return f"{self._platform.uid_base}_rrcr" @@ -1921,6 +1954,37 @@ def native_value(self): return None +class SolarEdgeBatteryPowerInverted(SolarEdgeBatteryPower): + """Inverted battery power sensor for Home Assistant energy dashboard compatibility. + + This class exists solely due to a design decision by the Home Assistant team + for their energy dashboard, which requires power to be represented opposite + to how a grid-tie inverter normally reports it. The native_value is negated + to meet this requirement. + + This does not represent how the inverter or SolarEdge dashboard will represent + the same sensor. You should normally refer to the non-inverted version. + """ + + def __init__(self, platform, config_entry, coordinator): + super().__init__(platform, config_entry, coordinator) + + @property + def unique_id(self) -> str: + return f"{super().unique_id}_inverted" + + @property + def name(self) -> str: + return f"{super().name} Inverted" + + @property + def native_value(self): + value = super().native_value + if value is None: + return None + return -value + + class SolarEdgeBatteryEnergyExport(SolarEdgeSensorBase): device_class = SensorDeviceClass.ENERGY state_class = SensorStateClass.TOTAL_INCREASING @@ -2138,7 +2202,6 @@ class SolarEdgeBatteryPowerBase(SolarEdgeSensorBase): class SolarEdgeBatteryMaxChargePower(SolarEdgeBatteryPowerBase): - @property def unique_id(self) -> str: return f"{self._platform.uid_base}_max_charge_power" @@ -2164,7 +2227,6 @@ def native_value(self): class SolarEdgeBatteryMaxChargePeakPower(SolarEdgeBatteryPowerBase): - @property def unique_id(self) -> str: return f"{self._platform.uid_base}_max_charge_peak_power" @@ -2190,7 +2252,6 @@ def native_value(self): class SolarEdgeBatteryMaxDischargePower(SolarEdgeBatteryPowerBase): - @property def unique_id(self) -> str: return f"{self._platform.uid_base}_max_discharge_power" @@ -2216,7 +2277,6 @@ def native_value(self): class SolarEdgeBatteryMaxDischargePeakPower(SolarEdgeBatteryPowerBase): - @property def unique_id(self) -> str: return f"{self._platform.uid_base}_max_discharge_peak_power" @@ -2343,7 +2403,6 @@ def native_value(self): class SolarEdgeAdvancedPowerControlBlock(SolarEdgeSensorBase): - @property def available(self) -> bool: return super().available and self._platform.advanced_power_control