0.8.9
Changes Made by @pvandenh
Bug 1 — Sensors not going unavailable when device is unreachable (sensor.py)
Root cause
BenyWifiSensor extended plain Entity rather than CoordinatorEntity. This meant the coordinator's last_update_success flag (set to False on UpdateFailed) was never propagated to sensor entities. Sensors simply held their last known state indefinitely when the device went offline.
The DLB control entities (switch, select, number) were already using CoordinatorEntity and correctly went unavailable — the inconsistency made this straightforward to diagnose.
Fix
BenyWifiSensor now extends CoordinatorEntity instead of Entity. This gives all sensor subclasses — charger_state, voltage, current, temperature, energy, timer, and power — the same automatic unavailability behaviour that the control entities already had. The manual async_update() method was removed as it is redundant when using CoordinatorEntity (updates are pushed via the coordinator listener).
A custom available override on BenyWifiPowerSensor layers per-field DLB staleness checking on top of CoordinatorEntity.available, so DLB power sensors can go unavailable independently of the overall coordinator state.
Before — BUG
class BenyWifiSensor(Entity):
...
async def async_update(self):
await self.coordinator.async_request_refresh()
After — FIXED
class BenyWifiSensor(CoordinatorEntity):
def __init__(self, coordinator, key, ...):
super().__init__(coordinator) # registers coordinator listener
...
# async_update removed — CoordinatorEntity handles this
Bug 2 — DLB solar power showing unavailable if the value is negative (communication.py)
Root cause
The SEND_DLB and SEND_DLB_3P parsers treated solar_power, ev_power, and house_power as unsigned 16-bit integers, with a sentinel check that returned None for any value >= 0xFF00. grid_power already had correct signed 16-bit handling.
A PCAP capture of the Z-Box mobile app revealed that valid solar readings in a net-flow CT setup (solar line also measuring home battery charge/discharge) consistently fall in the 0xFF95–0xFF9B range — all above 0xFF00 and therefore all silently discarded as sentinels on every single poll. For example:
Raw: 0xFF9A = 65434 unsigned → blocked as sentinel
0xFF9A = -102 signed → -1.02 kW ✓ correct
The sentinel threshold 0xFF00 was originally derived from observed error spike values (~0xFF1D–0xFF56), but this range completely overlaps with valid large-negative two's complement readings for any setup where the CT measures net flow rather than unidirectional power.
Fix
The sentinel threshold check is removed entirely for solar_power, ev_power, and house_power. All four DLB power fields now use consistent signed 16-bit two's complement decoding. This is the same approach already used for grid_power and is correct for all CT orientations.
Before — BUG: sentinel threshold blocked valid negative values
elif param in ["ev_power", "house_power", "solar_power"]:
if value >= _DLB_SENTINEL_THRESHOLD: # 0xFF00 — too broad
msg[param] = None # discarded valid readings
else:
msg[param] = float(value) / _DLB_POWER_DIVISOR
After — FIXED: signed 16-bit for all fields
elif param in ["ev_power", "house_power", "solar_power"]:
if value >= 0x8000:
value = value - 0x10000 # two's complement
msg[param] = float(value) / _DLB_POWER_DIVISOR
The same fix is applied to the per-phase fields in the SEND_DLB_3P parser.
Implementation Notes
- sensor.py: Base class change from Entity to CoordinatorEntity affects all sensor subclasses. No entity files outside sensor.py are affected.
- coordinator.py: Stale threshold and _async_update_data changes are self-contained. All DLB config management, command methods, and persistence logic are unaffected.
- communication.py: Parser changes are isolated to the SEND_DLB and SEND_DLB_3P blocks. No other message types are affected.
Non-DLB users are unaffected by all changes — the DLB fetch block, stale counting, and DLB field parsing are all guarded by the DLB config flag.
Testing
Hardware: Beny Charger BCP-A2N-L (firmware 1.28) with Solar DLB module
Verified:
- All sensors (charger_state, voltage, temperature, power, etc.) correctly go unavailable within ~90 seconds of the device being powered off
- DLB control entities (switch, select, number) continue to go unavailable
- solar_power now reports correct negative kW values (e.g. -1.02 kW) consistently without toggling to unavailable
- grid_power, ev_power, house_power unaffected — continue to report correctly
- PCAP-confirmed: raw value 0xFF9A now decodes to -1.02 kW instead of being discarded
Breaking Changes
None. All fixes align runtime behaviour with what the integration already intended to do. No config entry structure, entity IDs, or service interfaces have changed.
Checklist
- Root cause identified for all bugs
- PCAP capture used to confirm solar DLB encoding
- sensor.py: BenyWifiSensor converted to CoordinatorEntity
- coordinator.py: STALE_THRESHOLD applied; total fetch failure now increments DLB stale counts
- communication.py: Signed 16-bit decoding applied to all four DLB power fields in both 1P and 3P parsers
- All sensors verified to go unavailable when device powered off
- Solar power verified to show correct negative values
- All modified files pass Python syntax check