mirror of
https://github.com/home-assistant/core.git
synced 2026-10-07 14:58:11 -04:00
Require the location scope for Teslemetry location sensors (#183467)
This commit is contained in:
@@ -5,6 +5,7 @@ from dataclasses import dataclass
|
||||
from typing import cast, override
|
||||
|
||||
from tesla_fleet_api import firmware_at_least
|
||||
from tesla_fleet_api.const import Scope
|
||||
from teslemetry_stream.vehicle import TeslemetryStreamVehicle
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
@@ -52,6 +53,7 @@ class TeslemetryBinarySensorEntityDescription(BinarySensorEntityDescription):
|
||||
| None
|
||||
) = None
|
||||
streaming_firmware: str = "2024.26"
|
||||
requires_location_scope: bool = False
|
||||
|
||||
|
||||
VEHICLE_DESCRIPTIONS: tuple[TeslemetryBinarySensorEntityDescription, ...] = (
|
||||
@@ -351,6 +353,7 @@ VEHICLE_DESCRIPTIONS: tuple[TeslemetryBinarySensorEntityDescription, ...] = (
|
||||
),
|
||||
TeslemetryBinarySensorEntityDescription(
|
||||
key="gps_state",
|
||||
requires_location_scope=True,
|
||||
streaming_listener=lambda vehicle, callback: vehicle.listen_GpsState(callback),
|
||||
entity_registry_enabled_default=False,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
@@ -556,9 +559,12 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the Teslemetry binary sensor platform from a config entry."""
|
||||
|
||||
location_scope = Scope.VEHICLE_LOCATION in entry.runtime_data.scopes
|
||||
entities: list[BinarySensorEntity] = []
|
||||
for vehicle in entry.runtime_data.vehicles:
|
||||
for description in VEHICLE_DESCRIPTIONS:
|
||||
if description.requires_location_scope and not location_scope:
|
||||
continue
|
||||
if (
|
||||
not vehicle.poll
|
||||
and description.streaming_listener
|
||||
|
||||
@@ -6,6 +6,7 @@ from datetime import datetime, timedelta
|
||||
from typing import override
|
||||
|
||||
from tesla_fleet_api import firmware_at_least
|
||||
from tesla_fleet_api.const import Scope
|
||||
from teslemetry_stream import TeslemetryStream, TeslemetryStreamVehicle
|
||||
from teslemetry_stream.const import CreditsEvent
|
||||
|
||||
@@ -215,6 +216,7 @@ class TeslemetryVehicleSensorEntityDescription(SensorEntityDescription):
|
||||
) = None
|
||||
streaming_firmware: str = "2024.26"
|
||||
requires_hw4: bool = False
|
||||
requires_location_scope: bool = False
|
||||
|
||||
|
||||
VEHICLE_DESCRIPTIONS: tuple[TeslemetryVehicleSensorEntityDescription, ...] = (
|
||||
@@ -548,6 +550,7 @@ VEHICLE_DESCRIPTIONS: tuple[TeslemetryVehicleSensorEntityDescription, ...] = (
|
||||
),
|
||||
TeslemetryVehicleSensorEntityDescription(
|
||||
key="drive_state_active_route_destination",
|
||||
requires_location_scope=True,
|
||||
polling=True,
|
||||
streaming_listener=lambda vehicle, callback: vehicle.listen_DestinationName(
|
||||
callback
|
||||
@@ -1097,6 +1100,7 @@ VEHICLE_DESCRIPTIONS: tuple[TeslemetryVehicleSensorEntityDescription, ...] = (
|
||||
),
|
||||
TeslemetryVehicleSensorEntityDescription(
|
||||
key="gps_heading",
|
||||
requires_location_scope=True,
|
||||
streaming_listener=lambda vehicle, callback: vehicle.listen_GpsHeading(
|
||||
callback
|
||||
),
|
||||
@@ -1674,9 +1678,12 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the Teslemetry sensor platform from a config entry."""
|
||||
|
||||
location_scope = Scope.VEHICLE_LOCATION in entry.runtime_data.scopes
|
||||
entities: list[SensorEntity] = []
|
||||
for vehicle in entry.runtime_data.vehicles:
|
||||
for description in VEHICLE_DESCRIPTIONS:
|
||||
if description.requires_location_scope and not location_scope:
|
||||
continue
|
||||
if (
|
||||
not vehicle.poll
|
||||
and description.streaming_listener
|
||||
|
||||
@@ -7,13 +7,14 @@ import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from teslemetry_stream import Signal
|
||||
|
||||
from homeassistant.components.teslemetry.const import DOMAIN
|
||||
from homeassistant.components.teslemetry.coordinator import VEHICLE_INTERVAL
|
||||
from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN, Platform
|
||||
from homeassistant.core import HomeAssistant, State
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import assert_entities, assert_entities_alt, setup_platform
|
||||
from .const import VEHICLE_DATA_ALT
|
||||
from .const import METADATA, VEHICLE_DATA_ALT
|
||||
|
||||
from tests.common import async_fire_time_changed, mock_restore_cache
|
||||
|
||||
@@ -162,3 +163,35 @@ async def test_binary_sensors_connectivity(
|
||||
# Assert the entities have correct state with concrete assertions
|
||||
assert hass.states.get("binary_sensor.test_cellular").state == "on"
|
||||
assert hass.states.get("binary_sensor.test_wi_fi").state == "off"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("scopes", "expected"),
|
||||
[
|
||||
pytest.param(METADATA["scopes"], True, id="location_scope"),
|
||||
pytest.param(
|
||||
[scope for scope in METADATA["scopes"] if scope != "vehicle_location"],
|
||||
False,
|
||||
id="no_location_scope",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_gps_state_requires_location_scope(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_metadata: AsyncMock,
|
||||
scopes: list[str],
|
||||
expected: bool,
|
||||
) -> None:
|
||||
"""Test the GPS state binary sensor is only created with the location scope."""
|
||||
|
||||
mock_metadata.return_value = {**METADATA, "scopes": scopes}
|
||||
|
||||
await setup_platform(hass, [Platform.BINARY_SENSOR])
|
||||
|
||||
assert (
|
||||
entity_registry.async_get_entity_id(
|
||||
Platform.BINARY_SENSOR, DOMAIN, "LRW3F7EK4NC700000-gps_state"
|
||||
)
|
||||
is not None
|
||||
) is expected
|
||||
|
||||
@@ -745,3 +745,36 @@ async def test_energy_history_unavailable_while_stream_disconnected(
|
||||
mock_energy_totals_stream.send(is_cache=True)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(ENERGY_HISTORY_ENTITY).state == "0.036"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("scopes", "expected"),
|
||||
[
|
||||
pytest.param(METADATA["scopes"], True, id="location_scope"),
|
||||
pytest.param(
|
||||
[scope for scope in METADATA["scopes"] if scope != "vehicle_location"],
|
||||
False,
|
||||
id="no_location_scope",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_location_sensors_require_location_scope(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_metadata: AsyncMock,
|
||||
scopes: list[str],
|
||||
expected: bool,
|
||||
) -> None:
|
||||
"""Test location sensors are only created with the vehicle location scope."""
|
||||
|
||||
mock_metadata.return_value = {**METADATA, "scopes": scopes}
|
||||
|
||||
await setup_platform(hass, [Platform.SENSOR])
|
||||
|
||||
for key in ("gps_heading", "drive_state_active_route_destination"):
|
||||
assert (
|
||||
entity_registry.async_get_entity_id(
|
||||
Platform.SENSOR, DOMAIN, f"{VEHICLE_VIN}-{key}"
|
||||
)
|
||||
is not None
|
||||
) is expected
|
||||
|
||||
Reference in New Issue
Block a user