Coverage for custom_components/bouncie/device_tracker.py: 100%

40 statements  

« prev     ^ index     » next       coverage.py v7.2.4, created at 2025-01-04 23:39 +0000

1"""Support for Bouncie device tracker.""" 

2 

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 

9 

10from . import BouncieDataUpdateCoordinator, const 

11 

12ATTRIBUTION = "Data provided by Bouncie" 

13 

14 

15async def async_setup_entry(hass: HomeAssistant, config_entry, async_add_entities): 

16 """Set up the Bouncie vehicle trackers by config_entry.""" 

17 coordinator = hass.data[const.DOMAIN][config_entry.entry_id] 

18 async_add_entities( 

19 [ 

20 BouncieVehicleTracker(coordinator, vehicle_info) 

21 for vehicle_info in coordinator.data["vehicles"] 

22 ], 

23 True, 

24 ) 

25 

26 

27class BouncieVehicleTracker( 

28 CoordinatorEntity[BouncieDataUpdateCoordinator], TrackerEntity 

29): 

30 """Representation of a Tesla car location device tracker.""" 

31 

32 _attr_attribution = ATTRIBUTION 

33 

34 def __init__( 

35 self, 

36 coordinator: BouncieDataUpdateCoordinator, 

37 vehicle_info: dict, 

38 ) -> None: 

39 """Initialize car location entity.""" 

40 self._vehicle_info = vehicle_info 

41 self._attr_has_entity_name = True 

42 self._attr_name = None 

43 self._attr_unique_id = slugify(f'{self._vehicle_info["nickName"]} tracker') 

44 self._attr_device_info = DeviceInfo( 

45 identifiers={(const.DOMAIN, self._vehicle_info["vin"])}, 

46 manufacturer=self._vehicle_info[const.VEHICLE_MODEL_KEY]["make"], 

47 model=self._vehicle_info[const.VEHICLE_MODEL_KEY]["name"], 

48 name=self._vehicle_info["nickName"], 

49 hw_version=self._vehicle_info[const.VEHICLE_MODEL_KEY]["year"], 

50 ) 

51 super().__init__(coordinator) 

52 

53 @property 

54 def source_type(self): 

55 """Return device tracker source type.""" 

56 return SourceType.GPS 

57 

58 @property 

59 def longitude(self): 

60 """Return longitude.""" 

61 return self._vehicle_info["stats"]["location"]["lon"] 

62 

63 @property 

64 def latitude(self): 

65 """Return latitude.""" 

66 return self._vehicle_info["stats"]["location"]["lat"] 

67 

68 @property 

69 def extra_state_attributes(self): 

70 """Return device state attributes.""" 

71 return { 

72 "heading": self._vehicle_info["stats"]["location"]["heading"], 

73 "speed": self._vehicle_info["stats"]["speed"], 

74 } 

75 

76 @property 

77 def force_update(self): 

78 """Disable forced updated since we are polling via the coordinator updates.""" 

79 return False 

80 

81 @callback 

82 def _handle_coordinator_update(self) -> None: 

83 self._vehicle_info = [ 

84 vehicle 

85 for vehicle in self.coordinator.data["vehicles"] 

86 if vehicle["vin"] == self._vehicle_info["vin"] 

87 ][0] or self._vehicle_info 

88 self.async_write_ha_state() 

89 return super()._handle_coordinator_update()