Skip to content

Commit abc929d

Browse files
committed
Add value function for Proto>=100 Remaining Battery Energy
The "Remaining Battery Energy" sensor is not documented in the most recent protocol docs, and is reported to no longer provide a sensible value. For newer protocols, calculate this value based on either: * The total capacity and Chargeable Battery Energy sensor if available * The total capacity and SoC for each battery stack.
1 parent 2178c86 commit abc929d

1 file changed

Lines changed: 29 additions & 0 deletions

File tree

custom_components/solax_modbus/plugin_solax.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,22 @@ def value_function_battery_capacity_gen5(initval: int, descr: Any, datadict: dic
13451345
return 0
13461346

13471347

1348+
def value_function_remaining_battery_capacity(initval: int, descr: Any, datadict: dict[str, Any]) -> int | float:
1349+
# Sum BMS reported capacities to get total available
1350+
bat1_capacity: int | float = datadict.get("bms_battery_capacity", 0)
1351+
bat2_capacity: int | float = datadict.get("bms_2_battery_capacity", 0)
1352+
# Check if we have a chargeable capacity sensor
1353+
chargeable_capacity: int | float = datadict.get("chargeable_battery_capacity", -1)
1354+
if chargeable_capacity >= 0:
1355+
# If so, remaining capacity is total less chargeable (clamp to strictly non-negative)
1356+
return max(bat1_capacity + bat2_capacity - chargeable_capacity, 0)
1357+
# Otherwise base value on per-battery nominal capacity and SoC %. We do not account for SoH
1358+
# as this is an approximation and SoH sensors may be unavailable.
1359+
bat1_soc = float(datadict.get("battery_1_capacity_charge", 0)) / 100.0
1360+
bat2_soc = float(datadict.get("battery_2_capacity_charge", 0)) / 100.0
1361+
return bat1_capacity * bat1_soc + bat2_capacity * bat2_soc
1362+
1363+
13481364
def value_function_software_version_g2(initval: int, descr: Any, datadict: dict[str, Any]) -> str | None:
13491365
# AC/HYBRID GEN2: split registers hold raw minor versions with a fixed major of 2
13501366
return f"DSP v2.{datadict.get('firmware_dsp_minor')} ARM v2.{datadict.get('firmware_arm_minor')}"
@@ -8464,6 +8480,19 @@ def value_function_bms_2_max_charge(initval: int, descr: Any, datadict: dict[str
84648480
register=0x118,
84658481
register_type=REG_INPUT,
84668482
register_data_type=REGISTER_U32,
8483+
modbus_max=99,
8484+
allowedtypes=AC | HYBRID | GEN4 | GEN5 | GEN6,
8485+
),
8486+
SolaXModbusSensorEntityDescription(
8487+
name="Remaining Battery Energy",
8488+
key="remaining_battery_capacity",
8489+
value_function=value_function_remaining_battery_capacity,
8490+
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
8491+
device_class=SensorDeviceClass.ENERGY_STORAGE,
8492+
state_class=SensorStateClass.MEASUREMENT,
8493+
entity_registry_enabled_default=False,
8494+
depends_on=["bms_battery_capacity", "bms_2_battery_capacity", "chargeable_battery_capacity"],
8495+
modbus_min=100,
84678496
allowedtypes=AC | HYBRID | GEN4 | GEN5 | GEN6,
84688497
),
84698498
SolaXModbusSensorEntityDescription(

0 commit comments

Comments
 (0)