From 13e3811c746effe209e75ac017f03f09e3780bb0 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Thu, 19 Dec 2024 06:39:51 +0100 Subject: [PATCH] feat: Add experimental Battery Capacity sensor - Deye --- .../inverter_definitions/deye_hybrid.yaml | 9 +++++++ .../inverter_definitions/deye_p3.yaml | 10 +++++++ custom_components/solarman/sensor.py | 26 +++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/custom_components/solarman/inverter_definitions/deye_hybrid.yaml b/custom_components/solarman/inverter_definitions/deye_hybrid.yaml index 03d6bd7..72a7008 100644 --- a/custom_components/solarman/inverter_definitions/deye_hybrid.yaml +++ b/custom_components/solarman/inverter_definitions/deye_hybrid.yaml @@ -688,6 +688,15 @@ parameters: registers: [0x00BF] icon: "mdi:current-dc" + - name: "Battery Capacity" + description: Estimates capacity of the battery during charging + class: "power" + state_class: "measurement" + uom: "kW" + rule: 0 + digits: 2 + icon: "mdi:battery-check" + - group: Grid items: - name: "Grid Frequency" diff --git a/custom_components/solarman/inverter_definitions/deye_p3.yaml b/custom_components/solarman/inverter_definitions/deye_p3.yaml index 49e6d4a..ef3b313 100644 --- a/custom_components/solarman/inverter_definitions/deye_p3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_p3.yaml @@ -1988,6 +1988,16 @@ parameters: digits: 2 icon: "mdi:battery-heart" + # Battery - Capacity + - name: "Battery Capacity" + description: Estimates capacity of the battery during charging + class: "power" + state_class: "measurement" + uom: "kW" + rule: 0 + digits: 2 + icon: "mdi:battery-check" + # Battery - The state of battery - name: "Battery State" description: Determines battery state from battery power by +-50 W diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index 9a85154..57b6db8 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -35,6 +35,8 @@ def _create_entity(coordinator, description, options): return SolarmanBatteryCustomSensor(coordinator, description, battery_nominal_voltage, battery_life_cycle_rating) elif battery_nominal_voltage > 0 and battery_life_cycle_rating > 0 and name in ("Battery SOH", "Today Battery Life Cycles", "Total Battery Life Cycles"): return SolarmanBatteryCustomSensor(coordinator, description, battery_nominal_voltage, battery_life_cycle_rating) + elif name == "Battery Capacity": + return SolarmanBatteryCapacitySensor(coordinator, description) if "persistent" in description: return SolarmanPersistentSensor(coordinator, description) @@ -113,6 +115,30 @@ def __init__(self, coordinator, sensor, battery_nominal_voltage, battery_life_cy if battery_nominal_voltage > 0 and battery_life_cycle_rating > 0: self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "Nominal Voltage": battery_nominal_voltage, "Life Cycle Rating": battery_life_cycle_rating } +class SolarmanBatteryCapacitySensor(SolarmanRestoreSensor): + def __init__(self, coordinator, sensor): + super().__init__(coordinator, sensor) + self._states = [] + + def update(self): + if (power := get_tuple(self.coordinator.data.get("battery_power_sensor"))): + if power > -500: + self._states = [] + return + if (soc := get_tuple(self.coordinator.data.get("battery_sensor"))) is not None and (tbc := get_tuple(self.coordinator.data.get("total_battery_charge_sensor"))) is not None: + self._states.append((power, soc, tbc)) + h = l = (soc, tbc) + for i in reversed(self._states): + s = (i[1], i[2]) + if h[1] > l[1] > s[1]: + break + if h[1] == s[1]: + h = l = s + if l[1] >= s[1]: + l = s + if h[1] > l[1] > s[1] and (diff := h[0] - l[0]) > 0: + self.set_state((h[1] - l[1]) * (100 / (diff))) + class SolarmanBatteryCustomSensor(SolarmanSensor): def __init__(self, coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating): super().__init__(coordinator, sensor)