From 0da84a5a6e96295d69b9af1153d342ff0b3c22bf Mon Sep 17 00:00:00 2001 From: James Mackay Date: Thu, 8 Oct 2026 09:03:42 +0100 Subject: [PATCH] refactor(sensor): Current App sensor falls back to the connection manager StateStore and refreshes on store updates --- custom_components/nvidia_shield/sensor.py | 50 ++++++++++++++++++----- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/custom_components/nvidia_shield/sensor.py b/custom_components/nvidia_shield/sensor.py index 095aa11..2ee132e 100644 --- a/custom_components/nvidia_shield/sensor.py +++ b/custom_components/nvidia_shield/sensor.py @@ -10,6 +10,7 @@ from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.event import async_track_state_change_event +from .connection import ShieldConnectionManager from .const import ( CONF_ANDROIDTV_ENTITY, CONF_JELLYFIN_ENTITY, @@ -60,7 +61,12 @@ class NvidiaShieldSensorBase(SensorEntity): class NvidiaShieldCurrentAppSensor(NvidiaShieldSensorBase): - """Current running app on the Shield.""" + """Current running app on the Shield. + + Primary source: the androidtv entity's own state. When that entity is + unavailable, falls back to the ShieldConnectionManager's StateStore + (most recent visible ADB recent-task app). + """ _attr_name = "Current App" _attr_icon = "mdi:application" @@ -70,33 +76,57 @@ class NvidiaShieldCurrentAppSensor(NvidiaShieldSensorBase): self._androidtv_entity = entry.data[CONF_ANDROIDTV_ENTITY] self._attr_unique_id = f"{DOMAIN}_{entry.entry_id}_current_app" + def _manager(self) -> ShieldConnectionManager | None: + manager = getattr(self._entry, "runtime_data", None) + return manager if isinstance(manager, ShieldConnectionManager) else None + async def async_added_to_hass(self) -> None: self._unsub_listeners.append( async_track_state_change_event( self.hass, [self._androidtv_entity], self._handle_state_change ) ) + manager = self._manager() + if manager is not None: + # Refresh when the connection manager updates its store. + self._unsub_listeners.append(manager.register_listener(self._handle_store_update)) @callback def _handle_state_change(self, event: Event) -> None: self.async_write_ha_state() + @callback + def _handle_store_update(self) -> None: + self.async_write_ha_state() + @property def native_value(self) -> str | None: state = self.hass.states.get(self._androidtv_entity) - if not state: - return None - return state.attributes.get("app_name") or state.attributes.get("app_id") + if state: + return state.attributes.get("app_name") or state.attributes.get("app_id") + + # androidtv entity unavailable — StateStore fallback (ADB recents) + manager = self._manager() + if manager is not None: + running = manager.running_apps + if running: + return running[0].get("package") + return None @property def extra_state_attributes(self) -> dict: state = self.hass.states.get(self._androidtv_entity) - if not state: - return {} - return { - "app_id": state.attributes.get("app_id"), - "app_name": state.attributes.get("app_name"), - } + if state: + return { + "app_id": state.attributes.get("app_id"), + "app_name": state.attributes.get("app_name"), + } + manager = self._manager() + if manager is not None: + running = manager.running_apps + if running: + return {"app_id": running[0].get("package")} + return {} class NvidiaShieldNowPlayingSensor(NvidiaShieldSensorBase):