From 2bc335a808839cbb27478dcab787f2b4ece83af9 Mon Sep 17 00:00:00 2001 From: Brett Adams Date: Sun, 6 Sep 2026 16:42:05 +1000 Subject: [PATCH] Bump teslemetry-stream to 0.13.1 (#181411) Co-authored-by: Simon Lamon <32477463+silamon@users.noreply.github.com> --- .../components/teslemetry/__init__.py | 17 ++++++++++------- .../components/teslemetry/manifest.json | 2 +- homeassistant/components/teslemetry/sensor.py | 11 ++++------- requirements_all.txt | 2 +- tests/components/teslemetry/conftest.py | 2 +- .../teslemetry/snapshots/test_diagnostics.ambr | 1 - tests/components/teslemetry/test_init.py | 18 ++++++++++++++++++ tests/components/teslemetry/test_sensor.py | 9 +++++++-- 8 files changed, 42 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/teslemetry/__init__.py b/homeassistant/components/teslemetry/__init__.py index 01321782525a..a587c860125c 100644 --- a/homeassistant/components/teslemetry/__init__.py +++ b/homeassistant/components/teslemetry/__init__.py @@ -18,7 +18,7 @@ from tesla_fleet_api.exceptions import ( ) from tesla_fleet_api.tesla import EnergySiteRouter from tesla_fleet_api.teslemetry import EnergySite, Teslemetry -from teslemetry_stream import TeslemetryStream +from teslemetry_stream import TeslemetryStream, TeslemetryStreamAuthenticationError from teslemetry_stream.const import SseTopic from homeassistant.components.application_credentials import ( @@ -681,7 +681,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslemetryConfigEntry) - create_handle_energy_stream_connection(energysites) ) ) - entry.async_create_background_task(hass, stream.listen(), "Teslemetry Stream") + + async def listen() -> None: + """Listen to the stream, prompting reauth if the token is rejected.""" + try: + await stream.listen() + except TeslemetryStreamAuthenticationError: + entry.async_start_reauth(hass) + + entry.async_create_background_task(hass, listen(), "Teslemetry Stream") return True @@ -901,11 +909,6 @@ async def async_setup_stream( ) -> None: """Set up the stream for a vehicle.""" await vehicle.stream_vehicle.get_config() - entry.async_create_background_task( - hass, - vehicle.stream_vehicle.prefer_typed(True), - f"Prefer typed for {vehicle.vin}", - ) entry.async_on_unload( vehicle.stream_vehicle.listen_Version( diff --git a/homeassistant/components/teslemetry/manifest.json b/homeassistant/components/teslemetry/manifest.json index a3deb29380da..2257ff2b3354 100644 --- a/homeassistant/components/teslemetry/manifest.json +++ b/homeassistant/components/teslemetry/manifest.json @@ -12,6 +12,6 @@ "requirements": [ "aiopowerwall==0.2.0", "tesla-fleet-api==1.12.4", - "teslemetry-stream==0.10.0" + "teslemetry-stream==0.13.1" ] } diff --git a/homeassistant/components/teslemetry/sensor.py b/homeassistant/components/teslemetry/sensor.py index 7b7881fc9701..3feffe7139eb 100644 --- a/homeassistant/components/teslemetry/sensor.py +++ b/homeassistant/components/teslemetry/sensor.py @@ -3,10 +3,11 @@ from collections.abc import Callable from dataclasses import dataclass from datetime import datetime, timedelta -from typing import Any, override +from typing import override from tesla_fleet_api import firmware_at_least from teslemetry_stream import TeslemetryStream, TeslemetryStreamVehicle +from teslemetry_stream.const import CreditsEvent from homeassistant.components.sensor import ( RestoreSensor, @@ -1992,13 +1993,9 @@ class TeslemetryCreditQuotaSensor(RestoreSensor): self.async_on_remove(self.stream.listen_Credits(self._async_update)) - def _async_update(self, credits: dict[str, Any]) -> None: + def _async_update(self, credits: CreditsEvent) -> None: """Handle updated data from the stream.""" - quota = credits.get("quota") - if not isinstance(quota, dict): - return - - fraction = quota.get("fraction") + fraction = credits.quota.get("fraction") if not isinstance(fraction, (float, int)) or isinstance(fraction, bool): return diff --git a/requirements_all.txt b/requirements_all.txt index de98cd82fe55..ee8fd6425198 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -3242,7 +3242,7 @@ tesla-powerwall==0.5.3 tesla-wall-connector==1.2.0 # homeassistant.components.teslemetry -teslemetry-stream==0.10.0 +teslemetry-stream==0.13.1 # homeassistant.components.tessie tessie-api==0.1.3 diff --git a/tests/components/teslemetry/conftest.py b/tests/components/teslemetry/conftest.py index 0b2c0f244ce5..681b800b59cc 100644 --- a/tests/components/teslemetry/conftest.py +++ b/tests/components/teslemetry/conftest.py @@ -172,7 +172,7 @@ def mock_add_listener(): def unsubscribe() -> None: return - def side_effect(callback, filters): + def side_effect(callback, filters, internal=False): mock_add_listener.listeners.append((callback, filters)) return unsubscribe diff --git a/tests/components/teslemetry/snapshots/test_diagnostics.ambr b/tests/components/teslemetry/snapshots/test_diagnostics.ambr index 50e849e27b7f..ed042ae2c20f 100644 --- a/tests/components/teslemetry/snapshots/test_diagnostics.ambr +++ b/tests/components/teslemetry/snapshots/test_diagnostics.ambr @@ -590,7 +590,6 @@ 'config': dict({ 'fields': dict({ }), - 'prefer_typed': None, }), }), }), diff --git a/tests/components/teslemetry/test_init.py b/tests/components/teslemetry/test_init.py index 9160faaff4cf..f01ed390d93b 100644 --- a/tests/components/teslemetry/test_init.py +++ b/tests/components/teslemetry/test_init.py @@ -25,6 +25,7 @@ from tesla_fleet_api.exceptions import ( ) from tesla_fleet_api.tesla import EnergySiteRouter from tesla_fleet_api.teslemetry import EnergySite +from teslemetry_stream import TeslemetryStreamAuthenticationError from homeassistant.components.teslemetry import ( STREAM_TOPICS, @@ -1241,6 +1242,23 @@ async def test_get_access_token_rate_limited_after_setup_is_not_fatal( assert not hass.config_entries.flow.async_progress() +async def test_stream_rejected_token_starts_reauth( + hass: HomeAssistant, + mock_stream_listen: AsyncMock, +) -> None: + """Test the stream listener starts reauth when the token is rejected.""" + mock_stream_listen.side_effect = TeslemetryStreamAuthenticationError + + await setup_platform(hass) + await hass.async_block_till_done() + + flows = hass.config_entries.flow.async_progress() + assert any( + flow["handler"] == DOMAIN and flow["context"].get("source") == "reauth" + for flow in flows + ) + + SITE_ID = 123456 HOST = "192.168.91.1" PASSWORD = "abcde" diff --git a/tests/components/teslemetry/test_sensor.py b/tests/components/teslemetry/test_sensor.py index eb0245c16145..bb2c23fefe33 100644 --- a/tests/components/teslemetry/test_sensor.py +++ b/tests/components/teslemetry/test_sensor.py @@ -176,10 +176,15 @@ async def test_sensors_streaming( ) await hass.async_block_till_done() - # Balance-only credit events should not clear quota usage. + # A credit event without quota data should not clear quota usage. mock_add_listener.send( { - "credits": {"balance": 1980}, + "credits": { + "type": "wake_up", + "cost": 0, + "name": "wake_up", + "balance": 1980, + }, "createdAt": "2024-10-04T10:45:18.537Z", } )