mirror of
https://github.com/home-assistant/core.git
synced 2025-09-08 06:11:31 +02:00
Add binary sensors to Volvo integration (#150127)
This commit is contained in:
@@ -25,6 +25,7 @@ from .api import VolvoAuth
|
||||
from .const import CONF_VIN, DOMAIN, PLATFORMS
|
||||
from .coordinator import (
|
||||
VolvoConfigEntry,
|
||||
VolvoFastIntervalCoordinator,
|
||||
VolvoMediumIntervalCoordinator,
|
||||
VolvoSlowIntervalCoordinator,
|
||||
VolvoVerySlowIntervalCoordinator,
|
||||
@@ -38,7 +39,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: VolvoConfigEntry) -> boo
|
||||
vehicle = await _async_load_vehicle(api)
|
||||
|
||||
# Order is important! Faster intervals must come first.
|
||||
# Different interval coordinators are in place to keep the number
|
||||
# of requests under 5000 per day. This lets users use the same
|
||||
# API key for two vehicles (as the limit is 10000 per day).
|
||||
coordinators = (
|
||||
VolvoFastIntervalCoordinator(hass, entry, api, vehicle),
|
||||
VolvoMediumIntervalCoordinator(hass, entry, api, vehicle),
|
||||
VolvoSlowIntervalCoordinator(hass, entry, api, vehicle),
|
||||
VolvoVerySlowIntervalCoordinator(hass, entry, api, vehicle),
|
||||
|
408
homeassistant/components/volvo/binary_sensor.py
Normal file
408
homeassistant/components/volvo/binary_sensor.py
Normal file
@@ -0,0 +1,408 @@
|
||||
"""Volvo binary sensors."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from volvocarsapi.models import VolvoCarsApiBaseModel, VolvoCarsValue
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
BinarySensorDeviceClass,
|
||||
BinarySensorEntity,
|
||||
BinarySensorEntityDescription,
|
||||
)
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .const import API_NONE_VALUE
|
||||
from .coordinator import VolvoBaseCoordinator, VolvoConfigEntry
|
||||
from .entity import VolvoEntity, VolvoEntityDescription
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class VolvoBinarySensorDescription(
|
||||
BinarySensorEntityDescription, VolvoEntityDescription
|
||||
):
|
||||
"""Describes a Volvo binary sensor entity."""
|
||||
|
||||
on_values: tuple[str, ...]
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class VolvoCarsDoorDescription(VolvoBinarySensorDescription):
|
||||
"""Describes a Volvo door entity."""
|
||||
|
||||
device_class: BinarySensorDeviceClass = BinarySensorDeviceClass.DOOR
|
||||
on_values: tuple[str, ...] = field(default=("OPEN", "AJAR"), init=False)
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class VolvoCarsTireDescription(VolvoBinarySensorDescription):
|
||||
"""Describes a Volvo tire entity."""
|
||||
|
||||
device_class: BinarySensorDeviceClass = BinarySensorDeviceClass.PROBLEM
|
||||
on_values: tuple[str, ...] = field(
|
||||
default=("VERY_LOW_PRESSURE", "LOW_PRESSURE", "HIGH_PRESSURE"), init=False
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class VolvoCarsWindowDescription(VolvoBinarySensorDescription):
|
||||
"""Describes a Volvo window entity."""
|
||||
|
||||
device_class: BinarySensorDeviceClass = BinarySensorDeviceClass.WINDOW
|
||||
on_values: tuple[str, ...] = field(default=("OPEN", "AJAR"), init=False)
|
||||
|
||||
|
||||
_DESCRIPTIONS: tuple[VolvoBinarySensorDescription, ...] = (
|
||||
# brakes endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="brake_fluid_level_warning",
|
||||
api_field="brakeFluidLevelWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("TOO_LOW",),
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="brake_light_center_warning",
|
||||
api_field="brakeLightCenterWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="brake_light_left_warning",
|
||||
api_field="brakeLightLeftWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="brake_light_right_warning",
|
||||
api_field="brakeLightRightWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# engine endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="coolant_level_warning",
|
||||
api_field="engineCoolantLevelWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("TOO_LOW",),
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="daytime_running_light_left_warning",
|
||||
api_field="daytimeRunningLightLeftWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="daytime_running_light_right_warning",
|
||||
api_field="daytimeRunningLightRightWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# doors endpoint
|
||||
VolvoCarsDoorDescription(
|
||||
key="door_front_left",
|
||||
api_field="frontLeftDoor",
|
||||
),
|
||||
# doors endpoint
|
||||
VolvoCarsDoorDescription(
|
||||
key="door_front_right",
|
||||
api_field="frontRightDoor",
|
||||
),
|
||||
# doors endpoint
|
||||
VolvoCarsDoorDescription(
|
||||
key="door_rear_left",
|
||||
api_field="rearLeftDoor",
|
||||
),
|
||||
# doors endpoint
|
||||
VolvoCarsDoorDescription(
|
||||
key="door_rear_right",
|
||||
api_field="rearRightDoor",
|
||||
),
|
||||
# engine-status endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="engine_status",
|
||||
api_field="engineStatus",
|
||||
device_class=BinarySensorDeviceClass.RUNNING,
|
||||
on_values=("RUNNING",),
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="fog_light_front_warning",
|
||||
api_field="fogLightFrontWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="fog_light_rear_warning",
|
||||
api_field="fogLightRearWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="hazard_lights_warning",
|
||||
api_field="hazardLightsWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="high_beam_left_warning",
|
||||
api_field="highBeamLeftWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="high_beam_right_warning",
|
||||
api_field="highBeamRightWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# doors endpoint
|
||||
VolvoCarsDoorDescription(
|
||||
key="hood",
|
||||
api_field="hood",
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="low_beam_left_warning",
|
||||
api_field="lowBeamLeftWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="low_beam_right_warning",
|
||||
api_field="lowBeamRightWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# engine endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="oil_level_warning",
|
||||
api_field="oilLevelWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("SERVICE_REQUIRED", "TOO_LOW", "TOO_HIGH"),
|
||||
),
|
||||
# position lights
|
||||
VolvoBinarySensorDescription(
|
||||
key="position_light_front_left_warning",
|
||||
api_field="positionLightFrontLeftWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# position lights
|
||||
VolvoBinarySensorDescription(
|
||||
key="position_light_front_right_warning",
|
||||
api_field="positionLightFrontRightWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# position lights
|
||||
VolvoBinarySensorDescription(
|
||||
key="position_light_rear_left_warning",
|
||||
api_field="positionLightRearLeftWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# position lights
|
||||
VolvoBinarySensorDescription(
|
||||
key="position_light_rear_right_warning",
|
||||
api_field="positionLightRearRightWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# registration plate light
|
||||
VolvoBinarySensorDescription(
|
||||
key="registration_plate_light_warning",
|
||||
api_field="registrationPlateLightWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# reverse lights
|
||||
VolvoBinarySensorDescription(
|
||||
key="reverse_lights_warning",
|
||||
api_field="reverseLightsWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="side_mark_lights_warning",
|
||||
api_field="sideMarkLightsWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# windows endpoint
|
||||
VolvoCarsWindowDescription(
|
||||
key="sunroof",
|
||||
api_field="sunroof",
|
||||
),
|
||||
# tyres endpoint
|
||||
VolvoCarsTireDescription(
|
||||
key="tire_front_left",
|
||||
api_field="frontLeft",
|
||||
),
|
||||
# tyres endpoint
|
||||
VolvoCarsTireDescription(
|
||||
key="tire_front_right",
|
||||
api_field="frontRight",
|
||||
),
|
||||
# tyres endpoint
|
||||
VolvoCarsTireDescription(
|
||||
key="tire_rear_left",
|
||||
api_field="rearLeft",
|
||||
),
|
||||
# tyres endpoint
|
||||
VolvoCarsTireDescription(
|
||||
key="tire_rear_right",
|
||||
api_field="rearRight",
|
||||
),
|
||||
# doors endpoint
|
||||
VolvoCarsDoorDescription(
|
||||
key="tailgate",
|
||||
api_field="tailgate",
|
||||
),
|
||||
# doors endpoint
|
||||
VolvoCarsDoorDescription(
|
||||
key="tank_lid",
|
||||
api_field="tankLid",
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="turn_indication_front_left_warning",
|
||||
api_field="turnIndicationFrontLeftWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="turn_indication_front_right_warning",
|
||||
api_field="turnIndicationFrontRightWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="turn_indication_rear_left_warning",
|
||||
api_field="turnIndicationRearLeftWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# warnings endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="turn_indication_rear_right_warning",
|
||||
api_field="turnIndicationRearRightWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("FAILURE",),
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
# diagnostics endpoint
|
||||
VolvoBinarySensorDescription(
|
||||
key="washer_fluid_level_warning",
|
||||
api_field="washerFluidLevelWarning",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
on_values=("TOO_LOW",),
|
||||
),
|
||||
# windows endpoint
|
||||
VolvoCarsWindowDescription(
|
||||
key="window_front_left",
|
||||
api_field="frontLeftWindow",
|
||||
),
|
||||
# windows endpoint
|
||||
VolvoCarsWindowDescription(
|
||||
key="window_front_right",
|
||||
api_field="frontRightWindow",
|
||||
),
|
||||
# windows endpoint
|
||||
VolvoCarsWindowDescription(
|
||||
key="window_rear_left",
|
||||
api_field="rearLeftWindow",
|
||||
),
|
||||
# windows endpoint
|
||||
VolvoCarsWindowDescription(
|
||||
key="window_rear_right",
|
||||
api_field="rearRightWindow",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: VolvoConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up binary sensors."""
|
||||
coordinators = entry.runtime_data
|
||||
async_add_entities(
|
||||
VolvoBinarySensor(coordinator, description)
|
||||
for coordinator in coordinators
|
||||
for description in _DESCRIPTIONS
|
||||
if description.api_field in coordinator.data
|
||||
)
|
||||
|
||||
|
||||
class VolvoBinarySensor(VolvoEntity, BinarySensorEntity):
|
||||
"""Volvo binary sensor."""
|
||||
|
||||
entity_description: VolvoBinarySensorDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: VolvoBaseCoordinator,
|
||||
description: VolvoBinarySensorDescription,
|
||||
) -> None:
|
||||
"""Initialize entity."""
|
||||
self._attr_extra_state_attributes = {}
|
||||
|
||||
super().__init__(coordinator, description)
|
||||
|
||||
def _update_state(self, api_field: VolvoCarsApiBaseModel | None) -> None:
|
||||
"""Update the state of the entity."""
|
||||
if api_field is None:
|
||||
self._attr_is_on = None
|
||||
return
|
||||
|
||||
assert isinstance(api_field, VolvoCarsValue)
|
||||
assert isinstance(api_field.value, str)
|
||||
|
||||
value = api_field.value
|
||||
|
||||
self._attr_is_on = (
|
||||
value in self.entity_description.on_values
|
||||
if value.upper() != API_NONE_VALUE
|
||||
else None
|
||||
)
|
@@ -3,12 +3,9 @@
|
||||
from homeassistant.const import Platform
|
||||
|
||||
DOMAIN = "volvo"
|
||||
PLATFORMS: list[Platform] = [Platform.SENSOR]
|
||||
|
||||
ATTR_API_TIMESTAMP = "api_timestamp"
|
||||
PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR]
|
||||
|
||||
API_NONE_VALUE = "UNSPECIFIED"
|
||||
CONF_VIN = "vin"
|
||||
|
||||
DATA_BATTERY_CAPACITY = "battery_capacity_kwh"
|
||||
|
||||
MANUFACTURER = "Volvo"
|
||||
|
@@ -29,6 +29,7 @@ from .const import DATA_BATTERY_CAPACITY, DOMAIN
|
||||
VERY_SLOW_INTERVAL = 60
|
||||
SLOW_INTERVAL = 15
|
||||
MEDIUM_INTERVAL = 2
|
||||
FAST_INTERVAL = 1
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -187,9 +188,13 @@ class VolvoVerySlowIntervalCoordinator(VolvoBaseCoordinator):
|
||||
self,
|
||||
) -> list[Callable[[], Coroutine[Any, Any, Any]]]:
|
||||
return [
|
||||
self.api.async_get_brakes_status,
|
||||
self.api.async_get_diagnostics,
|
||||
self.api.async_get_engine_warnings,
|
||||
self.api.async_get_odometer,
|
||||
self.api.async_get_statistics,
|
||||
self.api.async_get_tyre_states,
|
||||
self.api.async_get_warnings,
|
||||
]
|
||||
|
||||
async def _async_update_data(self) -> CoordinatorData:
|
||||
@@ -265,6 +270,8 @@ class VolvoMediumIntervalCoordinator(VolvoBaseCoordinator):
|
||||
async def _async_determine_api_calls(
|
||||
self,
|
||||
) -> list[Callable[[], Coroutine[Any, Any, Any]]]:
|
||||
api_calls: list[Any] = []
|
||||
|
||||
if self.vehicle.has_battery_engine():
|
||||
capabilities = await self.api.async_get_energy_capabilities()
|
||||
|
||||
@@ -279,9 +286,12 @@ class VolvoMediumIntervalCoordinator(VolvoBaseCoordinator):
|
||||
if isinstance(value, dict) and value.get("isSupported", False)
|
||||
]
|
||||
|
||||
return [self._async_get_energy_state]
|
||||
api_calls.append(self._async_get_energy_state)
|
||||
|
||||
return []
|
||||
if self.vehicle.has_combustion_engine():
|
||||
api_calls.append(self.api.async_get_engine_status)
|
||||
|
||||
return api_calls
|
||||
|
||||
async def _async_get_energy_state(
|
||||
self,
|
||||
@@ -301,3 +311,33 @@ class VolvoMediumIntervalCoordinator(VolvoBaseCoordinator):
|
||||
for key, value in energy_state.items()
|
||||
if key in self._supported_capabilities
|
||||
}
|
||||
|
||||
|
||||
class VolvoFastIntervalCoordinator(VolvoBaseCoordinator):
|
||||
"""Volvo coordinator with fast update rate."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
entry: VolvoConfigEntry,
|
||||
api: VolvoCarsApi,
|
||||
vehicle: VolvoCarsVehicle,
|
||||
) -> None:
|
||||
"""Initialize the coordinator."""
|
||||
|
||||
super().__init__(
|
||||
hass,
|
||||
entry,
|
||||
api,
|
||||
vehicle,
|
||||
timedelta(minutes=FAST_INTERVAL),
|
||||
"Volvo fast interval coordinator",
|
||||
)
|
||||
|
||||
async def _async_determine_api_calls(
|
||||
self,
|
||||
) -> list[Callable[[], Coroutine[Any, Any, Any]]]:
|
||||
return [
|
||||
self.api.async_get_doors_status,
|
||||
self.api.async_get_window_states,
|
||||
]
|
||||
|
@@ -1,5 +1,265 @@
|
||||
{
|
||||
"entity": {
|
||||
"binary_sensor": {
|
||||
"brake_fluid_level_warning": {
|
||||
"default": "mdi:car-brake-fluid-level",
|
||||
"state": {
|
||||
"on": "mdi:car-brake-alert"
|
||||
}
|
||||
},
|
||||
"brake_light_center_warning": {
|
||||
"default": "mdi:car-light-dimmed",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"brake_light_left_warning": {
|
||||
"default": "mdi:car-light-dimmed",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"brake_light_right_warning": {
|
||||
"default": "mdi:car-light-dimmed",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"coolant_level_warning": {
|
||||
"default": "mdi:car-coolant-level"
|
||||
},
|
||||
"daytime_running_light_left_warning": {
|
||||
"default": "mdi:car-light-dimmed",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"daytime_running_light_right_warning": {
|
||||
"default": "mdi:car-light-dimmed",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"door_front_left": {
|
||||
"default": "mdi:car-door-lock",
|
||||
"state": {
|
||||
"on": "mdi:car-door-lock-open"
|
||||
}
|
||||
},
|
||||
"door_front_right": {
|
||||
"default": "mdi:car-door-lock",
|
||||
"state": {
|
||||
"on": "mdi:car-door-lock-open"
|
||||
}
|
||||
},
|
||||
"door_rear_left": {
|
||||
"default": "mdi:car-door-lock",
|
||||
"state": {
|
||||
"on": "mdi:car-door-lock-open"
|
||||
}
|
||||
},
|
||||
"door_rear_right": {
|
||||
"default": "mdi:car-door-lock",
|
||||
"state": {
|
||||
"on": "mdi:car-door-lock-open"
|
||||
}
|
||||
},
|
||||
"engine_status": {
|
||||
"default": "mdi:engine-off",
|
||||
"state": {
|
||||
"on": "mdi:engine"
|
||||
}
|
||||
},
|
||||
"fog_light_front_warning": {
|
||||
"default": "mdi:car-light-fog",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"fog_light_rear_warning": {
|
||||
"default": "mdi:car-light-fog",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"hazard_lights_warning": {
|
||||
"default": "mdi:hazard-lights",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"high_beam_left_warning": {
|
||||
"default": "mdi:car-light-high",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"high_beam_right_warning": {
|
||||
"default": "mdi:car-light-high",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"hood": {
|
||||
"default": "mdi:car-door-lock",
|
||||
"state": {
|
||||
"on": "mdi:car-door-lock-open"
|
||||
}
|
||||
},
|
||||
"low_beam_left_warning": {
|
||||
"default": "mdi:car-light-dimmed",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"low_beam_right_warning": {
|
||||
"default": "mdi:car-light-dimmed",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"oil_level_warning": {
|
||||
"default": "mdi:oil-level"
|
||||
},
|
||||
"position_light_front_left_warning": {
|
||||
"default": "mdi:car-parking-lights",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"position_light_front_right_warning": {
|
||||
"default": "mdi:car-parking-lights",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"position_light_rear_left_warning": {
|
||||
"default": "mdi:car-parking-lights",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"position_light_rear_right_warning": {
|
||||
"default": "mdi:car-parking-lights",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"registration_plate_light_warning": {
|
||||
"default": "mdi:lightbulb-outline",
|
||||
"state": {
|
||||
"on": "mdi:lightbulb-off-outline"
|
||||
}
|
||||
},
|
||||
"reverse_lights_warning": {
|
||||
"default": "mdi:car-light-dimmed",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"side_mark_lights_warning": {
|
||||
"default": "mdi:wall-sconce-round",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"sunroof": {
|
||||
"default": "mdi:car-door-lock",
|
||||
"state": {
|
||||
"on": "mdi:car-door-lock-open"
|
||||
}
|
||||
},
|
||||
"tailgate": {
|
||||
"default": "mdi:car-door-lock",
|
||||
"state": {
|
||||
"on": "mdi:car-door-lock-open"
|
||||
}
|
||||
},
|
||||
"tank_lid": {
|
||||
"default": "mdi:car-door-lock",
|
||||
"state": {
|
||||
"on": "mdi:car-door-lock-open"
|
||||
}
|
||||
},
|
||||
"turn_indication_front_left_warning": {
|
||||
"default": "mdi:arrow-left-top",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"turn_indication_front_right_warning": {
|
||||
"default": "mdi:arrow-right-top",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"turn_indication_rear_left_warning": {
|
||||
"default": "mdi:arrow-left-top",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"turn_indication_rear_right_warning": {
|
||||
"default": "mdi:arrow-right-top",
|
||||
"state": {
|
||||
"on": "mdi:car-light-alert"
|
||||
}
|
||||
},
|
||||
"tire_front_left": {
|
||||
"default": "mdi:tire",
|
||||
"state": {
|
||||
"on": "mdi:car-tire-alert"
|
||||
}
|
||||
},
|
||||
"tire_front_right": {
|
||||
"default": "mdi:tire",
|
||||
"state": {
|
||||
"on": "mdi:car-tire-alert"
|
||||
}
|
||||
},
|
||||
"tire_rear_left": {
|
||||
"default": "mdi:tire",
|
||||
"state": {
|
||||
"on": "mdi:car-tire-alert"
|
||||
}
|
||||
},
|
||||
"tire_rear_right": {
|
||||
"default": "mdi:tire",
|
||||
"state": {
|
||||
"on": "mdi:car-tire-alert"
|
||||
}
|
||||
},
|
||||
"washer_fluid_level_warning": {
|
||||
"default": "mdi:wiper-wash",
|
||||
"state": {
|
||||
"on": "mdi:wiper-wash-alert"
|
||||
}
|
||||
},
|
||||
"window_front_left": {
|
||||
"default": "mdi:car-door-lock",
|
||||
"state": {
|
||||
"on": "mdi:car-door-lock-open"
|
||||
}
|
||||
},
|
||||
"window_front_right": {
|
||||
"default": "mdi:car-door-lock",
|
||||
"state": {
|
||||
"on": "mdi:car-door-lock-open"
|
||||
}
|
||||
},
|
||||
"window_rear_left": {
|
||||
"default": "mdi:car-door-lock",
|
||||
"state": {
|
||||
"on": "mdi:car-door-lock-open"
|
||||
}
|
||||
},
|
||||
"window_rear_right": {
|
||||
"default": "mdi:car-door-lock",
|
||||
"state": {
|
||||
"on": "mdi:car-door-lock-open"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
"availability": {
|
||||
"default": "mdi:car-connected"
|
||||
|
@@ -35,8 +35,8 @@ from homeassistant.const import (
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .const import DATA_BATTERY_CAPACITY
|
||||
from .coordinator import VolvoBaseCoordinator, VolvoConfigEntry
|
||||
from .const import API_NONE_VALUE, DATA_BATTERY_CAPACITY
|
||||
from .coordinator import VolvoConfigEntry
|
||||
from .entity import VolvoEntity, VolvoEntityDescription, value_to_translation_key
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
@@ -248,7 +248,7 @@ _DESCRIPTIONS: tuple[VolvoSensorDescription, ...] = (
|
||||
# statistics endpoint
|
||||
# We're not using `electricRange` from the energy state endpoint because
|
||||
# the official app seems to use `distanceToEmptyBattery`.
|
||||
# In issue #150213, a user described to behavior as follows:
|
||||
# In issue #150213, a user described the behavior as follows:
|
||||
# - For a `distanceToEmptyBattery` of 250km, the `electricRange` was 150mi
|
||||
# - For a `distanceToEmptyBattery` of 260km, the `electricRange` was 160mi
|
||||
VolvoSensorDescription(
|
||||
@@ -354,27 +354,13 @@ async def async_setup_entry(
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up sensors."""
|
||||
|
||||
entities: list[VolvoSensor] = []
|
||||
added_keys: set[str] = set()
|
||||
|
||||
def _add_entity(
|
||||
coordinator: VolvoBaseCoordinator, description: VolvoSensorDescription
|
||||
) -> None:
|
||||
entities.append(VolvoSensor(coordinator, description))
|
||||
added_keys.add(description.key)
|
||||
|
||||
coordinators = entry.runtime_data
|
||||
|
||||
for coordinator in coordinators:
|
||||
for description in _DESCRIPTIONS:
|
||||
if description.key in added_keys:
|
||||
continue
|
||||
|
||||
if description.api_field in coordinator.data:
|
||||
_add_entity(coordinator, description)
|
||||
|
||||
async_add_entities(entities)
|
||||
async_add_entities(
|
||||
VolvoSensor(coordinator, description)
|
||||
for coordinator in coordinators
|
||||
for description in _DESCRIPTIONS
|
||||
if description.api_field in coordinator.data
|
||||
)
|
||||
|
||||
|
||||
class VolvoSensor(VolvoEntity, SensorEntity):
|
||||
@@ -401,7 +387,7 @@ class VolvoSensor(VolvoEntity, SensorEntity):
|
||||
native_value = str(native_value)
|
||||
native_value = (
|
||||
value_to_translation_key(native_value)
|
||||
if native_value.upper() != "UNSPECIFIED"
|
||||
if native_value.upper() != API_NONE_VALUE
|
||||
else None
|
||||
)
|
||||
|
||||
|
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"common": {
|
||||
"pressure": "Pressure"
|
||||
},
|
||||
"config": {
|
||||
"step": {
|
||||
"pick_implementation": {
|
||||
@@ -50,6 +53,140 @@
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"binary_sensor": {
|
||||
"brake_fluid_level_warning": {
|
||||
"name": "Brake fluid"
|
||||
},
|
||||
"brake_light_center_warning": {
|
||||
"name": "Brake light center"
|
||||
},
|
||||
"brake_light_left_warning": {
|
||||
"name": "Brake light left"
|
||||
},
|
||||
"brake_light_right_warning": {
|
||||
"name": "Brake light right"
|
||||
},
|
||||
"coolant_level_warning": {
|
||||
"name": "Coolant level"
|
||||
},
|
||||
"daytime_running_light_left_warning": {
|
||||
"name": "Daytime running light left"
|
||||
},
|
||||
"daytime_running_light_right_warning": {
|
||||
"name": "Daytime running light right"
|
||||
},
|
||||
"door_front_left": {
|
||||
"name": "Door front left"
|
||||
},
|
||||
"door_front_right": {
|
||||
"name": "Door front right"
|
||||
},
|
||||
"door_rear_left": {
|
||||
"name": "Door rear left"
|
||||
},
|
||||
"door_rear_right": {
|
||||
"name": "Door rear right"
|
||||
},
|
||||
"engine_status": {
|
||||
"name": "Engine status"
|
||||
},
|
||||
"fog_light_front_warning": {
|
||||
"name": "Fog light front"
|
||||
},
|
||||
"fog_light_rear_warning": {
|
||||
"name": "Fog light rear"
|
||||
},
|
||||
"hazard_lights_warning": {
|
||||
"name": "Hazard lights"
|
||||
},
|
||||
"high_beam_left_warning": {
|
||||
"name": "High beam left"
|
||||
},
|
||||
"high_beam_right_warning": {
|
||||
"name": "High beam right"
|
||||
},
|
||||
"hood": {
|
||||
"name": "Hood"
|
||||
},
|
||||
"low_beam_left_warning": {
|
||||
"name": "Low beam left"
|
||||
},
|
||||
"low_beam_right_warning": {
|
||||
"name": "Low beam right"
|
||||
},
|
||||
"oil_level_warning": {
|
||||
"name": "Oil level"
|
||||
},
|
||||
"position_light_front_left_warning": {
|
||||
"name": "Position light front left"
|
||||
},
|
||||
"position_light_front_right_warning": {
|
||||
"name": "Position light front right"
|
||||
},
|
||||
"position_light_rear_left_warning": {
|
||||
"name": "Position light rear left"
|
||||
},
|
||||
"position_light_rear_right_warning": {
|
||||
"name": "Position light rear right"
|
||||
},
|
||||
"registration_plate_light_warning": {
|
||||
"name": "Registration plate light"
|
||||
},
|
||||
"reverse_lights_warning": {
|
||||
"name": "Reverse lights"
|
||||
},
|
||||
"side_mark_lights_warning": {
|
||||
"name": "Side mark lights"
|
||||
},
|
||||
"sunroof": {
|
||||
"name": "Sunroof"
|
||||
},
|
||||
"tailgate": {
|
||||
"name": "Tailgate"
|
||||
},
|
||||
"tank_lid": {
|
||||
"name": "Tank lid"
|
||||
},
|
||||
"turn_indication_front_left_warning": {
|
||||
"name": "Turn indication front left"
|
||||
},
|
||||
"turn_indication_front_right_warning": {
|
||||
"name": "Turn indication front right"
|
||||
},
|
||||
"turn_indication_rear_left_warning": {
|
||||
"name": "Turn indication rear left"
|
||||
},
|
||||
"turn_indication_rear_right_warning": {
|
||||
"name": "Turn indication rear right"
|
||||
},
|
||||
"tire_front_left": {
|
||||
"name": "Tire front left"
|
||||
},
|
||||
"tire_front_right": {
|
||||
"name": "Tire front right"
|
||||
},
|
||||
"tire_rear_left": {
|
||||
"name": "Tire rear left"
|
||||
},
|
||||
"tire_rear_right": {
|
||||
"name": "Tire rear right"
|
||||
},
|
||||
"washer_fluid_level_warning": {
|
||||
"name": "Washer fluid"
|
||||
},
|
||||
"window_front_left": {
|
||||
"name": "Window front left"
|
||||
},
|
||||
"window_front_right": {
|
||||
"name": "Window front right"
|
||||
},
|
||||
"window_rear_left": {
|
||||
"name": "Window rear left"
|
||||
},
|
||||
"window_rear_right": {
|
||||
"name": "Window rear right"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
"availability": {
|
||||
"name": "Car connection",
|
||||
|
8527
tests/components/volvo/snapshots/test_binary_sensor.ambr
Normal file
8527
tests/components/volvo/snapshots/test_binary_sensor.ambr
Normal file
File diff suppressed because it is too large
Load Diff
32
tests/components/volvo/test_binary_sensor.py
Normal file
32
tests/components/volvo/test_binary_sensor.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""Test Volvo binary sensors."""
|
||||
|
||||
from collections.abc import Awaitable, Callable
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"full_model",
|
||||
["ex30_2024", "s90_diesel_2018", "xc40_electric_2024", "xc90_petrol_2019"],
|
||||
)
|
||||
async def test_binary_sensor(
|
||||
hass: HomeAssistant,
|
||||
setup_integration: Callable[[], Awaitable[bool]],
|
||||
entity_registry: er.EntityRegistry,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test binary sensor."""
|
||||
|
||||
with patch("homeassistant.components.volvo.PLATFORMS", [Platform.BINARY_SENSOR]):
|
||||
assert await setup_integration()
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
Reference in New Issue
Block a user