Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add device tracker platform to Renault integration #54745

Merged
merged 15 commits into from
Sep 1, 2021
2 changes: 2 additions & 0 deletions homeassistant/components/renault/const.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Constants for the Renault component."""
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
from homeassistant.components.device_tracker import DOMAIN as DEVICE_TRACKER_DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN

DOMAIN = "renault"
Expand All @@ -11,6 +12,7 @@

PLATFORMS = [
BINARY_SENSOR_DOMAIN,
DEVICE_TRACKER_DOMAIN,
SENSOR_DOMAIN,
]

Expand Down
61 changes: 61 additions & 0 deletions homeassistant/components/renault/device_tracker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""Support for Renault device trackers."""
from __future__ import annotations

from renault_api.kamereon.models import KamereonVehicleLocationData

from homeassistant.components.device_tracker import SOURCE_TYPE_GPS
from homeassistant.components.device_tracker.config_entry import TrackerEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .const import DOMAIN
from .renault_entities import RenaultDataEntity, RenaultEntityDescription
from .renault_hub import RenaultHub


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Renault entities from config entry."""
proxy: RenaultHub = hass.data[DOMAIN][config_entry.entry_id]
entities: list[RenaultDeviceTracker] = [
RenaultDeviceTracker(vehicle, description)
for vehicle in proxy.vehicles.values()
for description in DEVICE_TRACKER_TYPES
if description.coordinator in vehicle.coordinators
]
async_add_entities(entities)


class RenaultDeviceTracker(
RenaultDataEntity[KamereonVehicleLocationData], TrackerEntity
):
"""Mixin for device tracker specific attributes."""

@property
def latitude(self) -> float | None:
"""Return latitude value of the device."""
return self.coordinator.data.gpsLatitude if self.coordinator.data else None

@property
def longitude(self) -> float | None:
"""Return longitude value of the device."""
return self.coordinator.data.gpsLongitude if self.coordinator.data else None

@property
def source_type(self) -> str:
"""Return the source type of the device."""
return SOURCE_TYPE_GPS


DEVICE_TRACKER_TYPES: tuple[RenaultEntityDescription, ...] = (
RenaultEntityDescription(
key="location",
coordinator="location",
icon="mdi:car",
name="Location",
),
)
4 changes: 4 additions & 0 deletions homeassistant/components/renault/renault_entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,8 @@ def extra_state_attributes(self) -> Mapping[str, Any] | None:
last_update = self._get_data_attr("timestamp")
if last_update:
return {ATTR_LAST_UPDATE: last_update}
if self.entity_description.coordinator == "location":
last_update = self._get_data_attr("lastUpdateTime")
if last_update:
return {ATTR_LAST_UPDATE: last_update}
return None
5 changes: 5 additions & 0 deletions homeassistant/components/renault/renault_vehicle.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ async def async_initialise(self) -> None:
key="hvac_status",
update_method=lambda x: x.get_hvac_status,
),
RenaultCoordinatorDescription(
endpoint="location",
key="location",
update_method=lambda x: x.get_location,
),
RenaultCoordinatorDescription(
endpoint="battery-status",
key="battery",
Expand Down
14 changes: 14 additions & 0 deletions tests/components/renault/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ def get_fixtures(vehicle_type: str) -> dict[str, Any]:
if "hvac_status" in mock_vehicle["endpoints"]
else load_fixture("renault/no_data.json")
).get_attributes(schemas.KamereonVehicleHvacStatusDataSchema),
"location": schemas.KamereonVehicleDataResponseSchema.loads(
load_fixture(f"renault/{mock_vehicle['endpoints']['location']}")
if "location" in mock_vehicle["endpoints"]
else load_fixture("renault/no_data.json")
).get_attributes(schemas.KamereonVehicleLocationDataSchema),
}


Expand Down Expand Up @@ -132,6 +137,9 @@ async def setup_renault_integration_vehicle(hass: HomeAssistant, vehicle_type: s
), patch(
"renault_api.renault_vehicle.RenaultVehicle.get_hvac_status",
return_value=mock_fixtures["hvac_status"],
), patch(
"renault_api.renault_vehicle.RenaultVehicle.get_location",
return_value=mock_fixtures["location"],
):
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
Expand Down Expand Up @@ -181,6 +189,9 @@ async def setup_renault_integration_vehicle_with_no_data(
), patch(
"renault_api.renault_vehicle.RenaultVehicle.get_hvac_status",
return_value=mock_fixtures["hvac_status"],
), patch(
"renault_api.renault_vehicle.RenaultVehicle.get_location",
return_value=mock_fixtures["location"],
):
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
Expand Down Expand Up @@ -229,6 +240,9 @@ async def setup_renault_integration_vehicle_with_side_effect(
), patch(
"renault_api.renault_vehicle.RenaultVehicle.get_hvac_status",
side_effect=side_effect,
), patch(
"renault_api.renault_vehicle.RenaultVehicle.get_location",
side_effect=side_effect,
):
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
Expand Down
41 changes: 40 additions & 1 deletion tests/components/renault/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
DEVICE_CLASS_PLUG,
DOMAIN as BINARY_SENSOR_DOMAIN,
)
from homeassistant.components.device_tracker import DOMAIN as DEVICE_TRACKER_DOMAIN
from homeassistant.components.renault.const import (
CONF_KAMEREON_ACCOUNT_ID,
CONF_LOCALE,
Expand Down Expand Up @@ -33,6 +34,7 @@
LENGTH_KILOMETERS,
PERCENTAGE,
POWER_KILO_WATT,
STATE_NOT_HOME,
STATE_OFF,
STATE_ON,
STATE_UNKNOWN,
Expand Down Expand Up @@ -77,6 +79,7 @@
"endpoints_available": [
True, # cockpit
True, # hvac-status
False, # location
True, # battery-status
True, # charge-mode
],
Expand All @@ -102,6 +105,7 @@
ATTR_LAST_UPDATE: "2020-01-12T21:40:16Z",
},
],
DEVICE_TRACKER_DOMAIN: [],
SENSOR_DOMAIN: [
{
"entity_id": "sensor.battery_autonomy",
Expand Down Expand Up @@ -209,13 +213,15 @@
"endpoints_available": [
True, # cockpit
False, # hvac-status
True, # location
True, # battery-status
True, # charge-mode
],
"endpoints": {
"battery_status": "battery_status_not_charging.json",
"charge_mode": "charge_mode_schedule.json",
"cockpit": "cockpit_ev.json",
"location": "location.json",
},
BINARY_SENSOR_DOMAIN: [
{
Expand All @@ -233,6 +239,15 @@
ATTR_LAST_UPDATE: "2020-11-17T09:06:48+01:00",
},
],
DEVICE_TRACKER_DOMAIN: [
{
"entity_id": "device_tracker.location",
"unique_id": "vf1aaaaa555777999_location",
"result": STATE_NOT_HOME,
ATTR_ICON: "mdi:car",
ATTR_LAST_UPDATE: "2020-02-18T16:58:38Z",
}
],
SENSOR_DOMAIN: [
{
"entity_id": "sensor.battery_autonomy",
Expand Down Expand Up @@ -332,13 +347,15 @@
"endpoints_available": [
True, # cockpit
False, # hvac-status
True, # location
True, # battery-status
True, # charge-mode
],
"endpoints": {
"battery_status": "battery_status_charging.json",
"charge_mode": "charge_mode_always.json",
"cockpit": "cockpit_fuel.json",
"location": "location.json",
},
BINARY_SENSOR_DOMAIN: [
{
Expand All @@ -356,6 +373,15 @@
ATTR_LAST_UPDATE: "2020-01-12T21:40:16Z",
},
],
DEVICE_TRACKER_DOMAIN: [
{
"entity_id": "device_tracker.location",
"unique_id": "vf1aaaaa555777123_location",
"result": STATE_NOT_HOME,
ATTR_ICON: "mdi:car",
ATTR_LAST_UPDATE: "2020-02-18T16:58:38Z",
}
],
SENSOR_DOMAIN: [
{
"entity_id": "sensor.battery_autonomy",
Expand Down Expand Up @@ -471,11 +497,24 @@
"endpoints_available": [
True, # cockpit
False, # hvac-status
True, # location
# Ignore, # battery-status
# Ignore, # charge-mode
],
"endpoints": {"cockpit": "cockpit_fuel.json"},
"endpoints": {
"cockpit": "cockpit_fuel.json",
"location": "location.json",
},
BINARY_SENSOR_DOMAIN: [],
DEVICE_TRACKER_DOMAIN: [
{
"entity_id": "device_tracker.location",
"unique_id": "vf1aaaaa555777123_location",
"result": STATE_NOT_HOME,
ATTR_ICON: "mdi:car",
ATTR_LAST_UPDATE: "2020-02-18T16:58:38Z",
}
],
SENSOR_DOMAIN: [
{
"entity_id": "sensor.fuel_autonomy",
Expand Down
Loading