Add streaming connectivity binary sensors to Teslemetry (#143443)

* Add connectivity entities

* Add connectivity entities

* Fix Wi-Fi spelling in Teslemetry component
This commit is contained in:
Brett Adams 2025-04-28 20:58:40 +10:00 committed by GitHub
parent 1f047807a4
commit c6ebba8843
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 217 additions and 4 deletions

View File

@ -59,8 +59,21 @@ VEHICLE_DESCRIPTIONS: tuple[TeslemetryBinarySensorEntityDescription, ...] = (
key="state",
polling=True,
polling_value_fn=lambda x: x == TeslemetryState.ONLINE,
streaming_listener=lambda x, y: x.listen_State(y),
device_class=BinarySensorDeviceClass.CONNECTIVITY,
),
TeslemetryBinarySensorEntityDescription(
key="cellular",
streaming_listener=lambda x, y: x.listen_Cellular(y),
device_class=BinarySensorDeviceClass.CONNECTIVITY,
entity_category=EntityCategory.DIAGNOSTIC,
),
TeslemetryBinarySensorEntityDescription(
key="wifi",
streaming_listener=lambda x, y: x.listen_Wifi(y),
device_class=BinarySensorDeviceClass.CONNECTIVITY,
entity_category=EntityCategory.DIAGNOSTIC,
),
TeslemetryBinarySensorEntityDescription(
key="charge_state_battery_heater_on",
polling=True,

View File

@ -1,6 +1,24 @@
{
"entity": {
"binary_sensor": {
"state": {
"state": {
"off": "mdi:sleep",
"on": "mdi:car-connected"
}
},
"cellular": {
"state": {
"off": "mdi:signal-cellular-outline",
"on": "mdi:signal-cellular-3"
}
},
"wifi": {
"state": {
"off": "mdi:wifi-off",
"on": "mdi:wifi"
}
},
"climate_state_is_preconditioning": {
"state": {
"off": "mdi:hvac-off",

View File

@ -65,6 +65,12 @@
"state": {
"name": "Status"
},
"cellular": {
"name": "Cellular"
},
"wifi": {
"name": "Wi-Fi"
},
"storm_mode_active": {
"name": "Storm watch active"
},

View File

@ -518,6 +518,54 @@
'state': 'off',
})
# ---
# name: test_binary_sensor[binary_sensor.test_cellular-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.test_cellular',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.CONNECTIVITY: 'connectivity'>,
'original_icon': None,
'original_name': 'Cellular',
'platform': 'teslemetry',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'cellular',
'unique_id': 'LRW3F7EK4NC700000-cellular',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor[binary_sensor.test_cellular-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'connectivity',
'friendly_name': 'Test Cellular',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.test_cellular',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_binary_sensor[binary_sensor.test_charge_cable-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@ -2549,7 +2597,7 @@
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
'state': 'unknown',
})
# ---
# name: test_binary_sensor[binary_sensor.test_supercharger_session_trip_planner-entry]
@ -2886,6 +2934,54 @@
'state': 'off',
})
# ---
# name: test_binary_sensor[binary_sensor.test_wi_fi-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.test_wi_fi',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.CONNECTIVITY: 'connectivity'>,
'original_icon': None,
'original_name': 'Wi-Fi',
'platform': 'teslemetry',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'wifi',
'unique_id': 'LRW3F7EK4NC700000-wifi',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor[binary_sensor.test_wi_fi-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'connectivity',
'friendly_name': 'Test Wi-Fi',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.test_wi_fi',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_binary_sensor[binary_sensor.test_wiper_heat-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@ -3078,6 +3174,20 @@
'state': 'off',
})
# ---
# name: test_binary_sensor_refresh[binary_sensor.test_cellular-statealt]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'connectivity',
'friendly_name': 'Test Cellular',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.test_cellular',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_binary_sensor_refresh[binary_sensor.test_charge_cable-statealt]
StateSnapshot({
'attributes': ReadOnlyDict({
@ -3647,7 +3757,7 @@
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
'state': 'unknown',
})
# ---
# name: test_binary_sensor_refresh[binary_sensor.test_supercharger_session_trip_planner-statealt]
@ -3746,6 +3856,20 @@
'state': 'on',
})
# ---
# name: test_binary_sensor_refresh[binary_sensor.test_wi_fi-statealt]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'connectivity',
'friendly_name': 'Test Wi-Fi',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.test_wi_fi',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_binary_sensor_refresh[binary_sensor.test_wiper_heat-statealt]
StateSnapshot({
'attributes': ReadOnlyDict({
@ -3759,6 +3883,12 @@
'state': 'unknown',
})
# ---
# name: test_binary_sensors_connectivity[binary_sensor.test_cellular-state]
'on'
# ---
# name: test_binary_sensors_connectivity[binary_sensor.test_wi_fi-state]
'off'
# ---
# name: test_binary_sensors_streaming[binary_sensor.test_driver_seat_belt-state]
'off'
# ---

View File

@ -108,3 +108,45 @@ async def test_binary_sensors_streaming(
):
state = hass.states.get(entity_id)
assert state.state == snapshot(name=f"{entity_id}-state")
async def test_binary_sensors_connectivity(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
entity_registry: er.EntityRegistry,
freezer: FrozenDateTimeFactory,
mock_vehicle_data: AsyncMock,
mock_add_listener: AsyncMock,
) -> None:
"""Tests that the binary sensor entities with streaming are correct."""
freezer.move_to("2024-01-01 00:00:00+00:00")
await setup_platform(hass, [Platform.BINARY_SENSOR])
# Stream update
mock_add_listener.send(
{
"vin": VEHICLE_DATA_ALT["response"]["vin"],
"status": "CONNECTED",
"networkInterface": "cellular",
"createdAt": "2024-10-04T10:45:17.537Z",
}
)
mock_add_listener.send(
{
"vin": VEHICLE_DATA_ALT["response"]["vin"],
"status": "DISCONNECTED",
"networkInterface": "wifi",
"createdAt": "2024-10-04T10:45:17.537Z",
}
)
await hass.async_block_till_done()
# Assert the entities restored their values
for entity_id in (
"binary_sensor.test_cellular",
"binary_sensor.test_wi_fi",
):
state = hass.states.get(entity_id)
assert state.state == snapshot(name=f"{entity_id}-state")

View File

@ -14,7 +14,7 @@ from tesla_fleet_api.exceptions import (
from homeassistant.components.teslemetry.coordinator import VEHICLE_INTERVAL
from homeassistant.components.teslemetry.models import TeslemetryData
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import STATE_OFF, STATE_ON, Platform
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNKNOWN, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
@ -132,7 +132,7 @@ async def test_vehicle_stream(
mock_add_listener.assert_called()
state = hass.states.get("binary_sensor.test_status")
assert state.state == STATE_ON
assert state.state == STATE_UNKNOWN
state = hass.states.get("binary_sensor.test_user_present")
assert state.state == STATE_OFF
@ -141,11 +141,15 @@ async def test_vehicle_stream(
{
"vin": VEHICLE_DATA_ALT["response"]["vin"],
"vehicle_data": VEHICLE_DATA_ALT["response"],
"state": "online",
"createdAt": "2024-10-04T10:45:17.537Z",
}
)
await hass.async_block_till_done()
state = hass.states.get("binary_sensor.test_status")
assert state.state == STATE_ON
state = hass.states.get("binary_sensor.test_user_present")
assert state.state == STATE_ON