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