diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index b133c76..255ae0f 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -88,7 +88,7 @@ async def async_setup_entry(hass, entry): hass.data[DOMAIN]["context"] = context # We add trackers to the context - await context.refresh_trackers() + await context.force_refresh_trackers() hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, "device_tracker")) @@ -127,7 +127,7 @@ class GeoRideContext: self._hass = hass self._email = email self._password = password - self._georide_trackers = defaultdict(set) + self._georide_trackers = [] self._token = token self._socket = None self._thread_started = False @@ -196,11 +196,20 @@ class GeoRideContext: async def get_tracker(self, tracker_id): """ here we return last tracker by id""" + await self.refresh_trackers() + for tracker in self._georide_trackers: + if tracker.tracker_id == tracker_id: + return tracker + return {} + + async def refresh_trackers(self): + """ here we return last tracker by id""" + _LOGGER.info("Call refresh tracker") epoch_min = math.floor(time.time()/60) if (epoch_min % MIN_UNTIL_REFRESH) == 0: if epoch_min != self._previous_refresh: self._previous_refresh = epoch_min - await self.refresh_trackers() + await self.force_refresh_trackers() if not self._thread_started: _LOGGER.info("Start the thread") @@ -208,21 +217,22 @@ class GeoRideContext: self._thread_started = True await self.connect_socket() - for tracker in self._georide_trackers: - if tracker.tracker_id == tracker_id: - return tracker - return None - async def refresh_trackers(self): + + async def force_refresh_trackers(self): """Used to refresh the tracker list""" _LOGGER.info("Tracker list refresh") new_georide_trackers = await self._hass.async_add_executor_job(GeoRideApi.get_trackers, await self.get_token()) - for tracker in self._georide_trackers: - for refreshed_tracker in new_georide_trackers: + for refreshed_tracker in new_georide_trackers: + found = False + for tracker in self._georide_trackers: if tracker.tracker_id == refreshed_tracker.tracker_id: tracker.update_all_data(refreshed_tracker) + found = True + if not found: + self._georide_trackers.append(refreshed_tracker) @property diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 4cad045..d54d9a0 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -1,15 +1,24 @@ -""" odometter sensor for GeoRide object """ +""" binary_sensor for GeoRide object """ import logging +from datetime import timedelta +from typing import Any, Mapping + from homeassistant.core import callback from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.components.binary_sensor import ENTITY_ID_FORMAT +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, + DataUpdateCoordinator, +) + import georideapilib.api as GeoRideApi import georideapilib.objects as GeoRideTracker from .const import DOMAIN as GEORIDE_DOMAIN +from .const import MIN_UNTIL_REFRESH _LOGGER = logging.getLogger(__name__) @@ -20,6 +29,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d if token is None: return False + update_interval = timedelta(seconds=1) trackers = await hass.async_add_executor_job(GeoRideApi.get_trackers,token) entities = [] for tracker in trackers: @@ -27,13 +37,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d hass, _LOGGER, name=tracker.tracker_name, - update_method=georide_context.get_tracker, - update_interval=update_interval, + update_method=georide_context.refresh_trackers, + update_interval=update_interval ) - stolen_entity = GeoRideStolenBinarySensorEntity(coordinator, - coordinator) - crashed_entity = GeoRideCrashedBinarySensorEntity(hass, - tracker) + stolen_entity = GeoRideStolenBinarySensorEntity(coordinator, tracker) + crashed_entity = GeoRideCrashedBinarySensorEntity(coordinator, tracker) entities.append(stolen_entity) entities.append(crashed_entity) hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = coordinator @@ -43,23 +51,22 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d return True -class GeoRideBinarySensorEntity( CoordinatorEntity,B inarySensorEntity): +class GeoRideBinarySensorEntity(CoordinatorEntity, BinarySensorEntity): """Represent a tracked device.""" - def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker: GeoRideTracker, get_token_callback, get_tracker_callback): + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker: GeoRideTracker): """Set up Georide entity.""" super().__init__(coordinator) self._tracker = tracker - self._get_token_callback = get_token_callback - self._get_tracker_callback = get_tracker_callback self._name = tracker.tracker_name self.entity_id = ENTITY_ID_FORMAT.format("is_stolen") + "." + str(tracker.tracker_id) - self._state = 0 + self._state = None + self._data = False @property def unique_id(self): """Return the unique ID.""" - return self._tracker_id + return self._tracker.tracker_id @property def name(self): @@ -67,26 +74,16 @@ class GeoRideBinarySensorEntity( CoordinatorEntity,B inarySensorEntity): return self._name @property - def state(self): - return self._state - - @property - def get_token_callback(self): - """ GeoRide switch token callback method """ - return self._get_token_callback - - @property - def get_tracker_callback(self): - """ GeoRide switch token callback method """ - return self._get_tracker_callback - + def is_on(self): + """state value property""" + return self._data @property def device_info(self): """Return the device info.""" return { "name": self.name, - "identifiers": {(GEORIDE_DOMAIN, self._tracker_id)}, + "identifiers": {(GEORIDE_DOMAIN, self._tracker.tracker_id)}, "manufacturer": "GeoRide" } @@ -95,20 +92,22 @@ class GeoRideStolenBinarySensorEntity(GeoRideBinarySensorEntity): def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker: GeoRideTracker): """Set up Georide entity.""" - super().__init__(coordinator, tracker, hass, get_tracker_callback,get_tracker_callback) - - self.entity_id = ENTITY_ID_FORMAT.format("is_stolen") + "." + str(tracker_id) + super().__init__(coordinator, tracker) + self.entity_id = ENTITY_ID_FORMAT.format("is_stolen") + "." + str(tracker.tracker_id) - async def async_update(self): + async def async_update(self): """ update the current tracker""" - _LOGGER.info('update') + _LOGGER.debug('update') self._name = self._tracker.tracker_name - self._state = self._tracker.is_stolen + self._data = self._tracker.is_stolen @property def unique_id(self): """Return the unique ID.""" - return f"is_stolen_{self._tracker_id}" + return f"is_stolen_{self._tracker.tracker_id}" + + + class GeoRideCrashedBinarySensorEntity(GeoRideBinarySensorEntity): @@ -117,15 +116,15 @@ class GeoRideCrashedBinarySensorEntity(GeoRideBinarySensorEntity): def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker: GeoRideTracker): """Set up Georide entity.""" super().__init__(coordinator, tracker) - self.entity_id = ENTITY_ID_FORMAT.format("is_crashed") + "." + str(tracker_id) + self.entity_id = ENTITY_ID_FORMAT.format("is_crashed") + "." + str(tracker.tracker_id) async def async_update(self): """ update the current tracker""" - _LOGGER.info('update') + _LOGGER.debug('update') self._name = self._tracker.tracker_name - self._state = self._tracker.is_crashed + self._data = self._tracker.is_crashed @property def unique_id(self): """Return the unique ID.""" - return f"is_crashed_{self._tracker_id}" + return f"is_crashed_{self._tracker.tracker_id}" diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index da296cd..f0467d7 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -15,17 +15,8 @@ _LOGGER = logging.getLogger(__name__) async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: disable=W0613 """Set up Georide tracker based off an entry.""" - georide_context = hass.data[GEORIDE_DOMAIN]["context"] - token = await georide_context.get_token() - if token is None: - return False - - _LOGGER.debug('Current GeoRide token: %s', token) - - - trackers = await hass.async_add_executor_job(GeoRideApi.get_trackers, token) - - + georide_context = hass.data[GEORIDE_DOMAIN]["context"] + trackers = georide_context.get_trackers() tracker_entities = [] for tracker in trackers: entity = GeoRideTrackerEntity(hass, tracker.tracker_id, georide_context.get_token, @@ -49,7 +40,7 @@ class GeoRideTrackerEntity(TrackerEntity): self._get_token_callback = get_token_callback self._get_tracker_callback = get_tracker_callback self._name = tracker.tracker_name - self._data = tracker or {} + self._tracker = tracker self.entity_id = DOMAIN + ".{}".format(tracker_id) self._hass = hass @@ -100,7 +91,7 @@ class GeoRideTrackerEntity(TrackerEntity): "name": self.name, "identifiers": {(GEORIDE_DOMAIN, self._tracker_id)}, "manufacturer": "GeoRide", - "odometer": "{} km".format(self._data.odometer) + "odometer": "{} km".format(self.tracker.odometer) } @property @@ -121,7 +112,7 @@ class GeoRideTrackerEntity(TrackerEntity): async def async_update(self): """ update the current tracker""" - _LOGGER.info('update') + _LOGGER.debug('update') self._data = await self._get_tracker_callback(self._tracker_id) - self._name = self._data.tracker_name + self._name = self.tracker.tracker_name diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index c13914c..d34d18b 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -53,7 +53,7 @@ class GeoRideOdometerSensorEntity(SwitchEntity): async def async_update(self): """ update the current tracker""" - _LOGGER.info('update') + _LOGGER.debug('update') self._data = await self._get_tracker_callback(self._tracker_id) self._name = self._data.tracker_name self._state = self._data.odometer diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index 1f83bd8..c03c3bb 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -2,10 +2,19 @@ import logging + +from datetime import timedelta +from typing import Any, Mapping + from homeassistant.core import callback from homeassistant.components.switch import SwitchEntity from homeassistant.components.switch import ENTITY_ID_FORMAT +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, + DataUpdateCoordinator, +) + import georideapilib.api as GeoRideApi from .const import DOMAIN as GEORIDE_DOMAIN @@ -16,19 +25,21 @@ _LOGGER = logging.getLogger(__name__) async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: disable=W0613 """Set up GeoRide tracker based off an entry.""" - georide_context = hass.data[GEORIDE_DOMAIN]["context"] - token = await georide_context.get_token() - if token is None: - return False - - - _LOGGER.info('Current georide token: %s', token) - trackers = await hass.async_add_executor_job(GeoRideApi.get_trackers, token) + georide_context = hass.data[GEORIDE_DOMAIN]["context"] + trackers = georide_context.get_trackers() + update_interval = timedelta(seconds=1) lock_switch_entities = [] for tracker in trackers: - entity = GeoRideLockSwitchEntity(hass, tracker.tracker_id, georide_context.get_token, - georide_context.get_tracker, data=tracker) + coordinator = DataUpdateCoordinator[Mapping[str, Any]]( + hass, + _LOGGER, + name=tracker.tracker_name, + update_method=georide_context.refresh_trackers, + update_interval=update_interval + ) + + entity = GeoRideLockSwitchEntity(coordinator, tracker, hass) hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = entity lock_switch_entities.append(entity) @@ -38,65 +49,61 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d -class GeoRideLockSwitchEntity(SwitchEntity): +class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): """Represent a tracked device.""" - def __init__(self, hass, tracker_id, get_token_callback, get_tracker_callback, data): + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker, hass): """Set up GeoRide entity.""" - self._tracker_id = tracker_id - self._data = data or {} - self._get_token_callback = get_token_callback - self._get_tracker_callback = get_tracker_callback - self._name = data.tracker_name - self._is_on = data.is_locked - self.entity_id = ENTITY_ID_FORMAT.format("lock") +"." + str(tracker_id) - self._state = {} + super().__init__(coordinator) + self._tracker = tracker + self._name = tracker.tracker_name + self._is_on = tracker.is_locked + self.entity_id = ENTITY_ID_FORMAT.format("lock") +"." + str(tracker.tracker_id) self._hass = hass async def async_turn_on(self, **kwargs): """ lock the GeoRide tracker """ _LOGGER.info('async_turn_on %s', kwargs) - token = await self._get_token_callback() + georide_context = self._hass.data[GEORIDE_DOMAIN]["context"] + token = await georide_context.get_token() success = await self._hass.async_add_executor_job(GeoRideApi.lock_tracker, - token, self._tracker_id) + token, self._tracker_id) if success: - self._data.is_locked = True + self._tracker.is_locked = True self._is_on = True async def async_turn_off(self, **kwargs): """ unlock the GeoRide tracker """ _LOGGER.info('async_turn_off %s', kwargs) - token = await self._get_token_callback() + georide_context = self._hass.data[GEORIDE_DOMAIN]["context"] + token = await georide_context.get_token() success = await self._hass.async_add_executor_job(GeoRideApi.unlock_tracker, token, self._tracker_id) if success: - self._data.is_locked = False + self._tracker.is_locked = False self._is_on = False async def async_toggle(self, **kwargs): """ toggle lock the georide tracker """ _LOGGER.info('async_toggle %s', kwargs) - token = await self._get_token_callback() + georide_context = self._hass.data[GEORIDE_DOMAIN]["context"] + token = await georide_context.get_token() result = await self._hass.async_add_executor_job(GeoRideApi.toogle_lock_tracker, token, self._tracker_id) - self._data.is_locked = result + self._tracker.is_locked = result self._is_on = result - async def async_update(self): """ update the current tracker""" - _LOGGER.info('update %s', self._tracker_id) - self._data = await self._get_tracker_callback(self._tracker_id) - _LOGGER.debug('data %s', self._data.is_locked) - - self._name = self._data.tracker_name - self._is_on = self._data.is_locked + _LOGGER.debug('update') + self._name = self._tracker.tracker_name + self._is_on = self._tracker.is_lockedtracker @property def unique_id(self): """Return the unique ID.""" - return self._tracker_id + return self._tracker.tracker_id @property def name(self): @@ -107,16 +114,6 @@ class GeoRideLockSwitchEntity(SwitchEntity): def is_on(self): """ GeoRide switch status """ return self._is_on - - @property - def get_token_callback(self): - """ GeoRide switch token callback method """ - return self._get_token_callback - - @property - def get_tracker_callback(self): - """ GeoRide switch token callback method """ - return self._get_tracker_callback @property def icon(self): @@ -131,7 +128,7 @@ class GeoRideLockSwitchEntity(SwitchEntity): """Return the device info.""" return { "name": self.name, - "identifiers": {(GEORIDE_DOMAIN, self._tracker_id)}, + "identifiers": {(GEORIDE_DOMAIN, self._tracker.tracker_id)}, "manufacturer": "GeoRide" }