Coverage for custom_components/bouncie/device_tracker.py: 100%
43 statements
« prev ^ index » next coverage.py v7.2.4, created at 2026-06-18 16:22 +0000
« prev ^ index » next coverage.py v7.2.4, created at 2026-06-18 16:22 +0000
1"""Support for Bouncie device tracker."""
3from homeassistant.components.device_tracker import SourceType
4from homeassistant.components.device_tracker.config_entry import TrackerEntity
5from homeassistant.core import HomeAssistant, callback
6from homeassistant.helpers.entity import DeviceInfo
7from homeassistant.helpers.update_coordinator import CoordinatorEntity
8from homeassistant.util import slugify
10from . import BouncieDataUpdateCoordinator, const
12ATTRIBUTION = "Data provided by Bouncie"
15def _get_vehicle_name(vehicle_info: dict) -> str:
16 """Return a display name for a vehicle."""
17 return vehicle_info.get("nickName") or vehicle_info["vin"]
20async def async_setup_entry(hass: HomeAssistant, config_entry, async_add_entities):
21 """Set up the Bouncie vehicle trackers by config_entry."""
22 coordinator = hass.data[const.DOMAIN][config_entry.entry_id]
23 async_add_entities(
24 [
25 BouncieVehicleTracker(coordinator, vehicle_info)
26 for vehicle_info in coordinator.data["vehicles"]
27 ],
28 True,
29 )
32class BouncieVehicleTracker(
33 CoordinatorEntity[BouncieDataUpdateCoordinator], TrackerEntity
34):
35 """Representation of a Tesla car location device tracker."""
37 _attr_attribution = ATTRIBUTION
39 def __init__(
40 self,
41 coordinator: BouncieDataUpdateCoordinator,
42 vehicle_info: dict,
43 ) -> None:
44 """Initialize car location entity."""
45 self._vehicle_info = vehicle_info
46 vehicle_name = _get_vehicle_name(self._vehicle_info)
47 self._attr_has_entity_name = True
48 self._attr_name = None
49 self._attr_unique_id = slugify(f"{vehicle_name} tracker")
50 self._attr_device_info = DeviceInfo(
51 identifiers={(const.DOMAIN, self._vehicle_info["vin"])},
52 manufacturer=self._vehicle_info[const.VEHICLE_MODEL_KEY]["make"],
53 model=self._vehicle_info[const.VEHICLE_MODEL_KEY]["name"],
54 name=vehicle_name,
55 hw_version=self._vehicle_info[const.VEHICLE_MODEL_KEY]["year"],
56 )
57 super().__init__(coordinator)
59 @property
60 def source_type(self):
61 """Return device tracker source type."""
62 return SourceType.GPS
64 @property
65 def longitude(self):
66 """Return longitude."""
67 return self._vehicle_info["stats"]["location"]["lon"]
69 @property
70 def latitude(self):
71 """Return latitude."""
72 return self._vehicle_info["stats"]["location"]["lat"]
74 @property
75 def extra_state_attributes(self):
76 """Return device state attributes."""
77 return {
78 "heading": self._vehicle_info["stats"]["location"]["heading"],
79 "speed": self._vehicle_info["stats"]["speed"],
80 }
82 @property
83 def force_update(self):
84 """Disable forced updated since we are polling via the coordinator updates."""
85 return False
87 @callback
88 def _handle_coordinator_update(self) -> None:
89 self._vehicle_info = [
90 vehicle
91 for vehicle in self.coordinator.data["vehicles"]
92 if vehicle["vin"] == self._vehicle_info["vin"]
93 ][0] or self._vehicle_info
94 self.async_write_ha_state()
95 return super()._handle_coordinator_update()