Split attributes into sensors for here_travel_time (#72405)

pull/74222/head
Kevin Stillhammer 2022-06-30 07:09:52 +02:00 committed by GitHub
parent 555e9c6762
commit bef512c425
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 187 additions and 120 deletions

View File

@ -187,8 +187,8 @@ class HereTravelTimeDataUpdateCoordinator(DataUpdateCoordinator):
return HERERoutingData( return HERERoutingData(
{ {
ATTR_ATTRIBUTION: attribution, ATTR_ATTRIBUTION: attribution,
ATTR_DURATION: summary["baseTime"] / 60, # type: ignore[misc] ATTR_DURATION: round(summary["baseTime"] / 60), # type: ignore[misc]
ATTR_DURATION_IN_TRAFFIC: traffic_time / 60, ATTR_DURATION_IN_TRAFFIC: round(traffic_time / 60),
ATTR_DISTANCE: distance, ATTR_DISTANCE: distance,
ATTR_ROUTE: response.route_short, ATTR_ROUTE: response.route_short,
ATTR_ORIGIN: ",".join(origin), ATTR_ORIGIN: ",".join(origin),

View File

@ -24,8 +24,6 @@ CONF_DEPARTURE_TIME = "departure_time"
DEFAULT_NAME = "HERE Travel Time" DEFAULT_NAME = "HERE Travel Time"
TRACKABLE_DOMAINS = ["device_tracker", "sensor", "zone", "person"]
TRAVEL_MODE_BICYCLE = "bicycle" TRAVEL_MODE_BICYCLE = "bicycle"
TRAVEL_MODE_CAR = "car" TRAVEL_MODE_CAR = "car"
TRAVEL_MODE_PEDESTRIAN = "pedestrian" TRAVEL_MODE_PEDESTRIAN = "pedestrian"
@ -41,7 +39,6 @@ TRAVEL_MODES = [
TRAVEL_MODE_TRUCK, TRAVEL_MODE_TRUCK,
] ]
TRAVEL_MODES_PUBLIC = [TRAVEL_MODE_PUBLIC, TRAVEL_MODE_PUBLIC_TIME_TABLE]
TRAVEL_MODES_VEHICLE = [TRAVEL_MODE_CAR, TRAVEL_MODE_TRUCK] TRAVEL_MODES_VEHICLE = [TRAVEL_MODE_CAR, TRAVEL_MODE_TRUCK]
TRAFFIC_MODE_ENABLED = "traffic_enabled" TRAFFIC_MODE_ENABLED = "traffic_enabled"
@ -58,6 +55,14 @@ ICON_PEDESTRIAN = "mdi:walk"
ICON_PUBLIC = "mdi:bus" ICON_PUBLIC = "mdi:bus"
ICON_TRUCK = "mdi:truck" ICON_TRUCK = "mdi:truck"
ICONS = {
TRAVEL_MODE_BICYCLE: ICON_BICYCLE,
TRAVEL_MODE_PEDESTRIAN: ICON_PEDESTRIAN,
TRAVEL_MODE_PUBLIC: ICON_PUBLIC,
TRAVEL_MODE_PUBLIC_TIME_TABLE: ICON_PUBLIC,
TRAVEL_MODE_TRUCK: ICON_TRUCK,
}
UNITS = [CONF_UNIT_SYSTEM_METRIC, CONF_UNIT_SYSTEM_IMPERIAL] UNITS = [CONF_UNIT_SYSTEM_METRIC, CONF_UNIT_SYSTEM_IMPERIAL]
ATTR_DURATION = "duration" ATTR_DURATION = "duration"

View File

@ -1,16 +1,24 @@
"""Support for HERE travel time sensors.""" """Support for HERE travel time sensors."""
from __future__ import annotations from __future__ import annotations
from collections.abc import Mapping
from datetime import timedelta from datetime import timedelta
import logging import logging
from typing import Any
import voluptuous as vol import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity from homeassistant.components.sensor import (
PLATFORM_SCHEMA,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
ATTR_ATTRIBUTION, ATTR_ATTRIBUTION,
ATTR_MODE, ATTR_LATITUDE,
ATTR_LONGITUDE,
CONF_API_KEY, CONF_API_KEY,
CONF_MODE, CONF_MODE,
CONF_NAME, CONF_NAME,
@ -28,10 +36,14 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import HereTravelTimeDataUpdateCoordinator from . import HereTravelTimeDataUpdateCoordinator
from .const import ( from .const import (
ATTR_DESTINATION,
ATTR_DESTINATION_NAME,
ATTR_DISTANCE,
ATTR_DURATION, ATTR_DURATION,
ATTR_DURATION_IN_TRAFFIC, ATTR_DURATION_IN_TRAFFIC,
ATTR_TRAFFIC_MODE, ATTR_ORIGIN,
ATTR_UNIT_SYSTEM, ATTR_ORIGIN_NAME,
ATTR_ROUTE,
CONF_ARRIVAL, CONF_ARRIVAL,
CONF_DEPARTURE, CONF_DEPARTURE,
CONF_DESTINATION_ENTITY_ID, CONF_DESTINATION_ENTITY_ID,
@ -44,14 +56,10 @@ from .const import (
CONF_TRAFFIC_MODE, CONF_TRAFFIC_MODE,
DEFAULT_NAME, DEFAULT_NAME,
DOMAIN, DOMAIN,
ICON_BICYCLE,
ICON_CAR, ICON_CAR,
ICON_PEDESTRIAN, ICONS,
ICON_PUBLIC,
ICON_TRUCK,
ROUTE_MODE_FASTEST, ROUTE_MODE_FASTEST,
ROUTE_MODES, ROUTE_MODES,
TRAFFIC_MODE_ENABLED,
TRAVEL_MODE_BICYCLE, TRAVEL_MODE_BICYCLE,
TRAVEL_MODE_CAR, TRAVEL_MODE_CAR,
TRAVEL_MODE_PEDESTRIAN, TRAVEL_MODE_PEDESTRIAN,
@ -59,7 +67,6 @@ from .const import (
TRAVEL_MODE_PUBLIC_TIME_TABLE, TRAVEL_MODE_PUBLIC_TIME_TABLE,
TRAVEL_MODE_TRUCK, TRAVEL_MODE_TRUCK,
TRAVEL_MODES, TRAVEL_MODES,
TRAVEL_MODES_PUBLIC,
UNITS, UNITS,
) )
@ -115,6 +122,69 @@ PLATFORM_SCHEMA = vol.All(
) )
def sensor_descriptions(travel_mode: str) -> tuple[SensorEntityDescription, ...]:
"""Construct SensorEntityDescriptions."""
return (
SensorEntityDescription(
name="Duration",
icon=ICONS.get(travel_mode, ICON_CAR),
key=ATTR_DURATION,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=TIME_MINUTES,
),
SensorEntityDescription(
name="Duration in Traffic",
icon=ICONS.get(travel_mode, ICON_CAR),
key=ATTR_DURATION_IN_TRAFFIC,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=TIME_MINUTES,
),
SensorEntityDescription(
name="Distance",
icon=ICONS.get(travel_mode, ICON_CAR),
key=ATTR_DISTANCE,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
name="Route",
icon="mdi:directions",
key=ATTR_ROUTE,
),
)
def create_origin_sensor(
config_entry: ConfigEntry, hass: HomeAssistant
) -> OriginSensor:
"""Create a origin sensor."""
return OriginSensor(
config_entry.entry_id,
config_entry.data[CONF_NAME],
SensorEntityDescription(
name="Origin",
icon="mdi:store-marker",
key=ATTR_ORIGIN_NAME,
),
hass.data[DOMAIN][config_entry.entry_id],
)
def create_destination_sensor(
config_entry: ConfigEntry, hass: HomeAssistant
) -> DestinationSensor:
"""Create a destination sensor."""
return DestinationSensor(
config_entry.entry_id,
config_entry.data[CONF_NAME],
SensorEntityDescription(
name="Destination",
icon="mdi:store-marker",
key=ATTR_DESTINATION_NAME,
),
hass.data[DOMAIN][config_entry.entry_id],
)
async def async_setup_platform( async def async_setup_platform(
hass: HomeAssistant, hass: HomeAssistant,
config: ConfigType, config: ConfigType,
@ -143,16 +213,20 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Add HERE travel time entities from a config_entry.""" """Add HERE travel time entities from a config_entry."""
async_add_entities(
[ sensors: list[HERETravelTimeSensor] = []
for sensor_description in sensor_descriptions(config_entry.data[CONF_MODE]):
sensors.append(
HERETravelTimeSensor( HERETravelTimeSensor(
config_entry.entry_id, config_entry.entry_id,
config_entry.data[CONF_NAME], config_entry.data[CONF_NAME],
config_entry.options[CONF_TRAFFIC_MODE], sensor_description,
hass.data[DOMAIN][config_entry.entry_id], hass.data[DOMAIN][config_entry.entry_id],
) )
], )
) sensors.append(create_origin_sensor(config_entry, hass))
sensors.append(create_destination_sensor(config_entry, hass))
async_add_entities(sensors)
class HERETravelTimeSensor(SensorEntity, CoordinatorEntity): class HERETravelTimeSensor(SensorEntity, CoordinatorEntity):
@ -162,15 +236,14 @@ class HERETravelTimeSensor(SensorEntity, CoordinatorEntity):
self, self,
unique_id_prefix: str, unique_id_prefix: str,
name: str, name: str,
traffic_mode: str, sensor_description: SensorEntityDescription,
coordinator: HereTravelTimeDataUpdateCoordinator, coordinator: HereTravelTimeDataUpdateCoordinator,
) -> None: ) -> None:
"""Initialize the sensor.""" """Initialize the sensor."""
super().__init__(coordinator) super().__init__(coordinator)
self._traffic_mode = traffic_mode == TRAFFIC_MODE_ENABLED self.entity_description = sensor_description
self._attr_native_unit_of_measurement = TIME_MINUTES self._attr_name = f"{name} {sensor_description.name}"
self._attr_name = name self._attr_unique_id = f"{unique_id_prefix}_{sensor_description.key}"
self._attr_unique_id = unique_id_prefix
self._attr_device_info = DeviceInfo( self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, unique_id_prefix)}, identifiers={(DOMAIN, unique_id_prefix)},
entry_type=DeviceEntryType.SERVICE, entry_type=DeviceEntryType.SERVICE,
@ -188,34 +261,10 @@ class HERETravelTimeSensor(SensorEntity, CoordinatorEntity):
self.async_on_remove(async_at_start(self.hass, _update_at_start)) self.async_on_remove(async_at_start(self.hass, _update_at_start))
@property @property
def native_value(self) -> str | None: def native_value(self) -> str | float | None:
"""Return the state of the sensor.""" """Return the state of the sensor."""
if self.coordinator.data is not None: if self.coordinator.data is not None:
return str( return self.coordinator.data.get(self.entity_description.key)
round(
self.coordinator.data.get(
ATTR_DURATION_IN_TRAFFIC
if self._traffic_mode
else ATTR_DURATION
)
)
)
return None
@property
def extra_state_attributes(
self,
) -> dict[str, None | float | str | bool] | None:
"""Return the state attributes."""
if self.coordinator.data is not None:
res = {
ATTR_UNIT_SYSTEM: self.coordinator.config.units,
ATTR_MODE: self.coordinator.config.travel_mode,
ATTR_TRAFFIC_MODE: self._traffic_mode,
**self.coordinator.data,
}
res.pop(ATTR_ATTRIBUTION)
return res
return None return None
@property @property
@ -225,15 +274,30 @@ class HERETravelTimeSensor(SensorEntity, CoordinatorEntity):
return self.coordinator.data.get(ATTR_ATTRIBUTION) return self.coordinator.data.get(ATTR_ATTRIBUTION)
return None return None
class OriginSensor(HERETravelTimeSensor):
"""Sensor holding information about the route origin."""
@property @property
def icon(self) -> str: def extra_state_attributes(self) -> Mapping[str, Any] | None:
"""Icon to use in the frontend depending on travel_mode.""" """GPS coordinates."""
if self.coordinator.config.travel_mode == TRAVEL_MODE_BICYCLE: if self.coordinator.data is not None:
return ICON_BICYCLE return {
if self.coordinator.config.travel_mode == TRAVEL_MODE_PEDESTRIAN: ATTR_LATITUDE: self.coordinator.data[ATTR_ORIGIN].split(",")[0],
return ICON_PEDESTRIAN ATTR_LONGITUDE: self.coordinator.data[ATTR_ORIGIN].split(",")[1],
if self.coordinator.config.travel_mode in TRAVEL_MODES_PUBLIC: }
return ICON_PUBLIC return None
if self.coordinator.config.travel_mode == TRAVEL_MODE_TRUCK:
return ICON_TRUCK
return ICON_CAR class DestinationSensor(HERETravelTimeSensor):
"""Sensor holding information about the route destination."""
@property
def extra_state_attributes(self) -> Mapping[str, Any] | None:
"""GPS coordinates."""
if self.coordinator.data is not None:
return {
ATTR_LATITUDE: self.coordinator.data[ATTR_DESTINATION].split(",")[0],
ATTR_LONGITUDE: self.coordinator.data[ATTR_DESTINATION].split(",")[1],
}
return None

View File

@ -7,14 +7,6 @@ import pytest
from homeassistant.components.here_travel_time.config_flow import default_options from homeassistant.components.here_travel_time.config_flow import default_options
from homeassistant.components.here_travel_time.const import ( from homeassistant.components.here_travel_time.const import (
ATTR_DESTINATION,
ATTR_DESTINATION_NAME,
ATTR_DISTANCE,
ATTR_DURATION,
ATTR_DURATION_IN_TRAFFIC,
ATTR_ORIGIN,
ATTR_ORIGIN_NAME,
ATTR_ROUTE,
CONF_ARRIVAL_TIME, CONF_ARRIVAL_TIME,
CONF_DEPARTURE_TIME, CONF_DEPARTURE_TIME,
CONF_DESTINATION_ENTITY_ID, CONF_DESTINATION_ENTITY_ID,
@ -24,7 +16,6 @@ from homeassistant.components.here_travel_time.const import (
CONF_ORIGIN_LATITUDE, CONF_ORIGIN_LATITUDE,
CONF_ORIGIN_LONGITUDE, CONF_ORIGIN_LONGITUDE,
CONF_ROUTE_MODE, CONF_ROUTE_MODE,
CONF_TRAFFIC_MODE,
CONF_UNIT_SYSTEM, CONF_UNIT_SYSTEM,
DOMAIN, DOMAIN,
ICON_BICYCLE, ICON_BICYCLE,
@ -34,18 +25,18 @@ from homeassistant.components.here_travel_time.const import (
ICON_TRUCK, ICON_TRUCK,
NO_ROUTE_ERROR_MESSAGE, NO_ROUTE_ERROR_MESSAGE,
ROUTE_MODE_FASTEST, ROUTE_MODE_FASTEST,
TRAFFIC_MODE_DISABLED,
TRAFFIC_MODE_ENABLED, TRAFFIC_MODE_ENABLED,
TRAVEL_MODE_BICYCLE, TRAVEL_MODE_BICYCLE,
TRAVEL_MODE_CAR, TRAVEL_MODE_CAR,
TRAVEL_MODE_PEDESTRIAN, TRAVEL_MODE_PEDESTRIAN,
TRAVEL_MODE_PUBLIC_TIME_TABLE, TRAVEL_MODE_PUBLIC_TIME_TABLE,
TRAVEL_MODE_TRUCK, TRAVEL_MODE_TRUCK,
TRAVEL_MODES_VEHICLE,
) )
from homeassistant.const import ( from homeassistant.const import (
ATTR_ATTRIBUTION, ATTR_ATTRIBUTION,
ATTR_ICON, ATTR_ICON,
ATTR_LATITUDE,
ATTR_LONGITUDE,
CONF_API_KEY, CONF_API_KEY,
CONF_MODE, CONF_MODE,
CONF_NAME, CONF_NAME,
@ -67,62 +58,57 @@ from tests.common import MockConfigEntry
@pytest.mark.parametrize( @pytest.mark.parametrize(
"mode,icon,traffic_mode,unit_system,arrival_time,departure_time,expected_state,expected_distance,expected_duration_in_traffic", "mode,icon,unit_system,arrival_time,departure_time,expected_duration,expected_distance,expected_duration_in_traffic",
[ [
( (
TRAVEL_MODE_CAR, TRAVEL_MODE_CAR,
ICON_CAR, ICON_CAR,
TRAFFIC_MODE_ENABLED,
"metric", "metric",
None, None,
None, None,
"30",
"23.903",
"31", "31",
23.903,
31.016666666666666,
), ),
( (
TRAVEL_MODE_BICYCLE, TRAVEL_MODE_BICYCLE,
ICON_BICYCLE, ICON_BICYCLE,
TRAFFIC_MODE_DISABLED,
"metric", "metric",
None, None,
None, None,
"30", "30",
23.903, "23.903",
30.05, "30",
), ),
( (
TRAVEL_MODE_PEDESTRIAN, TRAVEL_MODE_PEDESTRIAN,
ICON_PEDESTRIAN, ICON_PEDESTRIAN,
TRAFFIC_MODE_DISABLED,
"imperial", "imperial",
None, None,
None, None,
"30", "30",
14.852631013, "14.852631013",
30.05, "30",
), ),
( (
TRAVEL_MODE_PUBLIC_TIME_TABLE, TRAVEL_MODE_PUBLIC_TIME_TABLE,
ICON_PUBLIC, ICON_PUBLIC,
TRAFFIC_MODE_DISABLED,
"imperial", "imperial",
"08:00:00", "08:00:00",
None, None,
"30", "30",
14.852631013, "14.852631013",
30.05, "30",
), ),
( (
TRAVEL_MODE_TRUCK, TRAVEL_MODE_TRUCK,
ICON_TRUCK, ICON_TRUCK,
TRAFFIC_MODE_ENABLED,
"metric", "metric",
None, None,
"08:00:00", "08:00:00",
"30",
"23.903",
"31", "31",
23.903,
31.016666666666666,
), ),
], ],
) )
@ -131,11 +117,10 @@ async def test_sensor(
hass: HomeAssistant, hass: HomeAssistant,
mode, mode,
icon, icon,
traffic_mode,
unit_system, unit_system,
arrival_time, arrival_time,
departure_time, departure_time,
expected_state, expected_duration,
expected_distance, expected_distance,
expected_duration_in_traffic, expected_duration_in_traffic,
): ):
@ -153,7 +138,6 @@ async def test_sensor(
CONF_NAME: "test", CONF_NAME: "test",
}, },
options={ options={
CONF_TRAFFIC_MODE: traffic_mode,
CONF_ROUTE_MODE: ROUTE_MODE_FASTEST, CONF_ROUTE_MODE: ROUTE_MODE_FASTEST,
CONF_ARRIVAL_TIME: arrival_time, CONF_ARRIVAL_TIME: arrival_time,
CONF_DEPARTURE_TIME: departure_time, CONF_DEPARTURE_TIME: departure_time,
@ -166,44 +150,57 @@ async def test_sensor(
hass.bus.async_fire(EVENT_HOMEASSISTANT_START) hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
await hass.async_block_till_done() await hass.async_block_till_done()
sensor = hass.states.get("sensor.test") duration = hass.states.get("sensor.test_duration")
assert sensor.attributes.get("unit_of_measurement") == TIME_MINUTES assert duration.attributes.get("unit_of_measurement") == TIME_MINUTES
assert ( assert (
sensor.attributes.get(ATTR_ATTRIBUTION) duration.attributes.get(ATTR_ATTRIBUTION)
== "With the support of HERE Technologies. All information is provided without warranty of any kind." == "With the support of HERE Technologies. All information is provided without warranty of any kind."
) )
assert sensor.state == expected_state assert duration.attributes.get(ATTR_ICON) == icon
assert duration.state == expected_duration
assert sensor.attributes.get(ATTR_DURATION) == 30.05 assert (
assert sensor.attributes.get(ATTR_DISTANCE) == expected_distance hass.states.get("sensor.test_duration_in_traffic").state
assert sensor.attributes.get(ATTR_ROUTE) == ( == expected_duration_in_traffic
)
assert hass.states.get("sensor.test_distance").state == expected_distance
assert hass.states.get("sensor.test_route").state == (
"US-29 - K St NW; US-29 - Whitehurst Fwy; " "US-29 - K St NW; US-29 - Whitehurst Fwy; "
"I-495 N - Capital Beltway; MD-187 S - Old Georgetown Rd" "I-495 N - Capital Beltway; MD-187 S - Old Georgetown Rd"
) )
assert sensor.attributes.get(CONF_UNIT_SYSTEM) == unit_system
assert ( assert (
sensor.attributes.get(ATTR_DURATION_IN_TRAFFIC) == expected_duration_in_traffic hass.states.get("sensor.test_duration_in_traffic").state
== expected_duration_in_traffic
) )
assert sensor.attributes.get(ATTR_ORIGIN) == ",".join( assert hass.states.get("sensor.test_origin").state == "22nd St NW"
[CAR_ORIGIN_LATITUDE, CAR_ORIGIN_LONGITUDE] assert (
hass.states.get("sensor.test_origin").attributes.get(ATTR_LATITUDE)
== CAR_ORIGIN_LATITUDE
) )
assert sensor.attributes.get(ATTR_DESTINATION) == ",".join( assert (
[CAR_DESTINATION_LATITUDE, CAR_DESTINATION_LONGITUDE] hass.states.get("sensor.test_origin").attributes.get(ATTR_LONGITUDE)
) == CAR_ORIGIN_LONGITUDE
assert sensor.attributes.get(ATTR_ORIGIN_NAME) == "22nd St NW"
assert sensor.attributes.get(ATTR_DESTINATION_NAME) == "Service Rd S"
assert sensor.attributes.get(CONF_MODE) == mode
assert sensor.attributes.get(CONF_TRAFFIC_MODE) is (
traffic_mode == TRAFFIC_MODE_ENABLED
) )
assert sensor.attributes.get(ATTR_ICON) == icon assert hass.states.get("sensor.test_origin").state == "22nd St NW"
assert (
hass.states.get("sensor.test_origin").attributes.get(ATTR_LATITUDE)
== CAR_ORIGIN_LATITUDE
)
assert (
hass.states.get("sensor.test_origin").attributes.get(ATTR_LONGITUDE)
== CAR_ORIGIN_LONGITUDE
)
# Test traffic mode disabled for vehicles assert hass.states.get("sensor.test_destination").state == "Service Rd S"
if mode in TRAVEL_MODES_VEHICLE: assert (
assert sensor.attributes.get(ATTR_DURATION) != sensor.attributes.get( hass.states.get("sensor.test_destination").attributes.get(ATTR_LATITUDE)
ATTR_DURATION_IN_TRAFFIC == CAR_DESTINATION_LATITUDE
) )
assert (
hass.states.get("sensor.test_destination").attributes.get(ATTR_LONGITUDE)
== CAR_DESTINATION_LONGITUDE
)
@pytest.mark.usefixtures("valid_response") @pytest.mark.usefixtures("valid_response")
@ -261,7 +258,9 @@ async def test_no_attribution(hass: HomeAssistant):
hass.bus.async_fire(EVENT_HOMEASSISTANT_START) hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get("sensor.test").attributes.get(ATTR_ATTRIBUTION) is None assert (
hass.states.get("sensor.test_duration").attributes.get(ATTR_ATTRIBUTION) is None
)
async def test_entity_ids(hass: HomeAssistant, valid_response: MagicMock): async def test_entity_ids(hass: HomeAssistant, valid_response: MagicMock):
@ -305,8 +304,7 @@ async def test_entity_ids(hass: HomeAssistant, valid_response: MagicMock):
hass.bus.async_fire(EVENT_HOMEASSISTANT_START) hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
await hass.async_block_till_done() await hass.async_block_till_done()
sensor = hass.states.get("sensor.test") assert hass.states.get("sensor.test_distance").state == "23.903"
assert sensor.attributes.get(ATTR_DISTANCE) == 23.903
valid_response.assert_called_with( valid_response.assert_called_with(
[CAR_ORIGIN_LATITUDE, CAR_ORIGIN_LONGITUDE], [CAR_ORIGIN_LATITUDE, CAR_ORIGIN_LONGITUDE],