Skip to content

fix: clear battery_level_percentage when player goes offline#187

Open
sethfitz wants to merge 1 commit into
cdnninja:masterfrom
sethfitz:fix-battery-clears-on-offline
Open

fix: clear battery_level_percentage when player goes offline#187
sethfitz wants to merge 1 commit into
cdnninja:masterfrom
sethfitz:fix-battery-clears-on-offline

Conversation

@sethfitz
Copy link
Copy Markdown

@sethfitz sethfitz commented May 26, 2026

Problem

When a Yoto device powers down, the library's polling cycle sends a command/status/request via MQTT. The device responds with a batteryLevel that doesn't reflect its actual charge level at power-off.

_apply_status_patch stores this value faithfully, and because _set_online(player, False) never touched battery_level_percentage, the stale reading persisted until the device came back online and sent a fresh status response. In practice this means Home Assistant shows a misleading battery percentage (observed: consistently 86%, unrelated to actual charge level) any time the device is powered off.

Root cause

_set_online sets is_online but leaves all other status fields unchanged, so the stale polling response outlives the online state.

Fix

Clear battery_level_percentage in _set_online(player, False). Battery level is only meaningful while the device is live; when the REST poll confirms offline, the value from the last status response is no longer reliable.

Going back online does not clear the field, so a legitimate reading received via MQTT right after power-on is preserved.

Tests

Two new cases in OnlineConsolidationTests:

  • test_going_offline_clears_battery_level — simulates a stale battery value arriving, then REST detecting offline; asserts the field becomes None.
  • test_going_online_preserves_battery_level — confirms _set_online(True) leaves an existing reading intact.

Meta

This patch was produced by Claude Code (Sonnet 4.6) with human (@sethfitz) oversight.

When a device powers down, the last status response the library receives
carries a batteryLevel reading that doesn't reflect the actual charge
level at power-off. Because _set_online(player, False) left
battery_level_percentage unchanged, that stale value persisted until the
device came back online — commonly appearing as a fixed 86% regardless
of the true charge state.

Clear battery_level_percentage in _set_online(False) so callers see
unknown rather than a misleading value while the device is off.
@sethfitz sethfitz force-pushed the fix-battery-clears-on-offline branch from 526f807 to b4dd222 Compare May 26, 2026 17:04
@piitaya
Copy link
Copy Markdown
Collaborator

piitaya commented May 27, 2026

Hi 👋 How are you using yoto-api? yoto-ha is still using an old version of the yoto-api (migration PR here : cdnninja/yoto_ha#259)

Otherwise, many home assistant device don't clear the battery level when the device is offline. Even the official Yoto app still display the battery when the device is offline.

@cdnninja
Copy link
Copy Markdown
Owner

Agreed I'm not sure you want to clear battery. It could be consumed offline but more likely it's off so you want o know if low so you can charge it.

@sethfitz
Copy link
Copy Markdown
Author

@piitaya I'm carrying a patch to yoto_ha's sensor.py that prevents HA from accepting battery levels when the player is offline. It means that there are data gaps for periods when the player is offline, but I'm working around that by keeping a "last known battery level" metric that I use to trigger an alert in the morning (when the player is usually offline, but when it's feasible for me) to plug it in and charge it.

--- upstream/sensor.py
+++ local/sensor.py
@@ -120,6 +120,11 @@
     @property
     def native_value(self):
         """Return the value reported by the sensor."""
+        # Workaround for yoto_api v2.x not clearing battery_level_percentage on
+        # offline: the shutdown MQTT status carries a stale reading that persists.
+        # Remove when https://github.com/cdnninja/yoto_api/pull/187 ships.
+        if self._key == 'battery_level_percentage' and not self.player.online:
+            return None
         return getattr(self.player, self._key)

@cdnninja I'll look for a way to drop the first battery update after going offline (using the previous, known-good value). I agree that having the last-good level would be best (esp. since it avoids the workaround above), but in the absence of that, no data (because it's offline and can't produce valid values) seems like it makes almost as much sense.

@piitaya
Copy link
Copy Markdown
Collaborator

piitaya commented May 28, 2026

Can you describe why you are trying to solve that?
Setting the battery to None when the device is offline is not a common pattern in Home Assistant and Yoto already return the last valid value.

@sethfitz
Copy link
Copy Markdown
Author

The underlying problem I'm trying to address is that HA (and therefore Yoto Cloud / the MQTT message received after shutting down) an incorrect battery level (86%) which persists in HA (and Yoto Cloud, but we have no control) until the player comes back online.

I have a patch that uses an online → offline state transition (via REST API calls triggered by HA) to revert to last-known-good battery levels, but I want to better understand the root cause and when MQTT messages are triggered. I'll follow up later with more.

@piitaya
Copy link
Copy Markdown
Collaborator

piitaya commented May 30, 2026

Yoto has been added as a official integration in 2026.6 release. Currently only media player is supported but sensor will be added probably next release.

I'm also in discussion with Yoto dev to fully rely on MQTT for live data instead of REST. For example, the official HA integration will not use REST for battery, only MQTT data. Let's see if it fix the issue before adding another patch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants