From 3c6f39f7ba8f24cd7f5652d7779886da40e0f6fd Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 10 Apr 2021 11:34:39 +0200 Subject: [PATCH 01/20] Add async for refresh_tken --- custom_components/georide/__init__.py | 31 ++++- custom_components/georide/binary_sensor.py | 151 +++++++++++++++++++++ 2 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 custom_components/georide/binary_sensor.py diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 1e6e968..0f6457f 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -118,6 +118,7 @@ def connect_socket(context): socket.subscribe_locked(context.on_lock_callback) socket.subscribe_device(context.on_device_callback) socket.subscribe_position(context.on_position_callback) + socket.subscribe_alarm(context.on_alarm_callback) context.socket = socket @@ -176,7 +177,8 @@ class GeoRideContext: epoch = math.ceil(time.time()) if (exp_timestamp - TOKEN_SAFE_DAY) < epoch: _LOGGER.info("Time reached, renew token") - account = GeoRideApi.get_authorisation_token(self._email, self._password) + + account = await self._hass.async_add_executor_job(GeoRideApi.get_authorisation_token, [self._email, self._password]) config = self._hass.data[DOMAIN]["config"] config[CONF_TOKEN] = account.auth_token self._token = account.auth_token @@ -209,7 +211,6 @@ class GeoRideContext: _LOGGER.info("Tracker list refresh") self._georide_trackers = GeoRideApi.get_trackers(self.get_token()) - @property def socket(self): """ hold the GeoRide socket """ @@ -239,6 +240,30 @@ class GeoRideContext: if tracker.tracker_id == data['trackerId']: tracker.status = data['status'] return + @callback + def on_alarm_callback(self, data): + """on device callback""" + _LOGGER.info("On alarm received") + for tracker in self._georide_trackers: + if tracker.tracker_id == data['trackerId']: + if data.name == 'vibration': + _LOGGER.info("Vibration detected") + elif data.name == 'exitZone': + _LOGGER.info("Exit zone detected") + elif data.name == 'crash': + _LOGGER.info("Crash detected") + elif data.name == 'crashParking': + _LOGGER.info("Crash parking detected") + elif data.name == 'deviceOffline': + _LOGGER.info("Device offline detected") + elif data.name == 'deviceOnline': + _LOGGER.info("Device online detected") + elif data.name == 'powerCut': + _LOGGER.info("powerCut detected") + else: + _LOGGER.warning("Unamanged alarm: ", data.name) + + return @callback def on_position_callback(self, data): @@ -253,5 +278,3 @@ class GeoRideContext: tracker.fixtime = data['fixtime'] return - - diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py new file mode 100644 index 0000000..58032d5 --- /dev/null +++ b/custom_components/georide/binary_sensor.py @@ -0,0 +1,151 @@ +""" odometter sensor for GeoRide object """ + +import logging + +from homeassistant.core import callback +from homeassistant.components.binary_sensor import BinarySensorEntity +from homeassistant.components.binary_sensor import ENTITY_ID_FORMAT + +import georideapilib.api as GeoRideApi + +from .const import DOMAIN as GEORIDE_DOMAIN + + +_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"] + + if georide_context.get_token() is None: + return False + + trackers = GeoRideApi.get_trackers(georide_context.get_token()) + + binary_sensor_entities = [] + for tracker in trackers: + stolen_entity = GeoRideStolenBinarySensorEntity(tracker.tracker_id, georide_context.get_token, + georide_context.get_tracker, data=tracker) + hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = stolen_entity + crashed_entity = GeoRideCrashedBinarySensorEntity(tracker.tracker_id, georide_context.get_token, + georide_context.get_tracker, data=tracker) + hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = crashed_entity + binary_sensor_entities.append(stolen_entity) + binary_sensor_entities.append(crashed_entity) + async_add_entities(binary_sensor_entities) + + return True + +class GeoRideStolenBinarySensorEntity(BinarySensorEntity): + """Represent a tracked device.""" + + def __init__(self, tracker_id, get_token_callback, get_tracker_callback, data): + """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.entity_id = ENTITY_ID_FORMAT.format("is_stolen") + "." + str(tracker_id) + self._state = 0 + + + def update(self): + """ update the current tracker""" + _LOGGER.info('update') + self._data = self._get_tracker_callback(self._tracker_id) + self._name = self._data.tracker_name + self._state = self._data.is_stolen + + @property + def unique_id(self): + """Return the unique ID.""" + return self._tracker_id + + @property + def name(self): + """ GeoRide odometer name """ + 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 + + + @property + def device_info(self): + """Return the device info.""" + return { + "name": self.name, + "identifiers": {(GEORIDE_DOMAIN, self._tracker_id)}, + "manufacturer": "GeoRide" + } + + +class GeoRideCrashedBinarySensorEntity(BinarySensorEntity): + """Represent a tracked device.""" + + def __init__(self, tracker_id, get_token_callback, get_tracker_callback, data): + """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.entity_id = ENTITY_ID_FORMAT.format("is_crashed") + "." + str(tracker_id) + self._state = 0 + + + def update(self): + """ update the current tracker""" + _LOGGER.info('update') + self._data = self._get_tracker_callback(self._tracker_id) + self._name = self._data.tracker_name + self._state = self._data.is_crashed + + @property + def unique_id(self): + """Return the unique ID.""" + return self._tracker_id + + @property + def name(self): + """ GeoRide odometer name """ + 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 + + + @property + def device_info(self): + """Return the device info.""" + return { + "name": self.name, + "identifiers": {(GEORIDE_DOMAIN, self._tracker_id)}, + "manufacturer": "GeoRide" + } + + From 1e21de655f963117d5b5fe207b2a0f22c1613021 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 10 Apr 2021 11:58:58 +0200 Subject: [PATCH 02/20] Move all external call to asyn/await --- custom_components/georide/__init__.py | 6 +++--- custom_components/georide/binary_sensor.py | 14 +++++++------- custom_components/georide/device_tracker.py | 12 ++++++------ custom_components/georide/sensor.py | 10 +++++----- custom_components/georide/switch.py | 18 +++++++++--------- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 0f6457f..dcb5acb 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -111,7 +111,7 @@ async def async_unload_entry(hass, entry): return True -def connect_socket(context): +async def connect_socket(context): """subscribe to GeoRide socket""" _LOGGER.info("GeoRide socket connexion") socket = GeoRideSocket() @@ -123,7 +123,7 @@ def connect_socket(context): context.socket = socket socket.init() - socket.connect(context.get_token()) + socket.connect(await context.get_token()) class GeoRideContext: @@ -169,7 +169,7 @@ class GeoRideContext: """ GeoRide tracker list """ self._georide_trackers = trackers - def get_token(self): + async def get_token(self): """ here we return the current valid tocken """ jwt_data = jwt.decode(self._token, verify=False) exp_timestamp = jwt_data['exp'] diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 58032d5..fa6b025 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -15,11 +15,11 @@ _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"] - - if georide_context.get_token() is None: + token = await georide_context.get_token() + if token is None: return False - trackers = GeoRideApi.get_trackers(georide_context.get_token()) + trackers = GeoRideApi.get_trackers(token) binary_sensor_entities = [] for tracker in trackers: @@ -50,10 +50,10 @@ class GeoRideStolenBinarySensorEntity(BinarySensorEntity): self._state = 0 - def update(self): + async def async_update(self): """ update the current tracker""" _LOGGER.info('update') - self._data = self._get_tracker_callback(self._tracker_id) + self._data = await self._get_tracker_callback(self._tracker_id) self._name = self._data.tracker_name self._state = self._data.is_stolen @@ -107,10 +107,10 @@ class GeoRideCrashedBinarySensorEntity(BinarySensorEntity): self._state = 0 - def update(self): + async def async_update(self): """ update the current tracker""" _LOGGER.info('update') - self._data = self._get_tracker_callback(self._tracker_id) + self._data = await self._get_tracker_callback(self._tracker_id) self._name = self._data.tracker_name self._state = self._data.is_crashed diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index f7e80a9..edbd38c 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -16,14 +16,14 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d """Set up Georide tracker based off an entry.""" georide_context = hass.data[GEORIDE_DOMAIN]["context"] - - if georide_context.get_token() is None: + token = await georide_context.get_token() + if token is None: return False - _LOGGER.debug('Current GeoRide token: %s', georide_context.get_token()) + _LOGGER.debug('Current GeoRide token: %s', token) - trackers = GeoRideApi.get_trackers(georide_context.get_token()) + trackers = GeoRideApi.get_trackers(token) tracker_entities = [] @@ -118,9 +118,9 @@ class GeoRideTrackerEntity(TrackerEntity): """No polling needed.""" return True - def update(self): + async def async_update(self): """ update the current tracker""" _LOGGER.info('update') - self._data = self._get_tracker_callback(self._tracker_id) + self._data = await self._get_tracker_callback(self._tracker_id) self._name = self._data.tracker_name diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 52c1a49..ffb4344 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -17,11 +17,11 @@ _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"] - - if georide_context.get_token() is None: + token = await georide_context.get_token() + if token is None: return False - trackers = GeoRideApi.get_trackers(georide_context.get_token()) + trackers = GeoRideApi.get_trackers(token) odometer_switch_entities = [] for tracker in trackers: @@ -50,10 +50,10 @@ class GeoRideOdometerSensorEntity(SwitchEntity): self._state = 0 - def update(self): + async def async_update(self): """ update the current tracker""" _LOGGER.info('update') - self._data = self._get_tracker_callback(self._tracker_id) + 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 6997798..b72d1e4 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -17,13 +17,13 @@ _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"] - - if georide_context.get_token() is None: + token = await georide_context.get_token() + if token is None: return False - _LOGGER.info('Current georide token: %s', georide_context.get_token()) - trackers = GeoRideApi.get_trackers(georide_context.get_token()) + _LOGGER.info('Current georide token: %s', token) + trackers = await GeoRideApi.get_trackers(token) lock_switch_entities = [] for tracker in trackers: @@ -56,7 +56,7 @@ class GeoRideLockSwitchEntity(SwitchEntity): def turn_on(self, **kwargs): """ lock the GeoRide tracker """ _LOGGER.info('async_turn_on %s', kwargs) - success = GeoRideApi.lock_tracker(self._get_token_callback(), self._tracker_id) + success = GeoRideApi.lock_tracker(await self._get_token_callback(), self._tracker_id) if success: self._data.is_locked = True self._is_on = True @@ -64,7 +64,7 @@ class GeoRideLockSwitchEntity(SwitchEntity): def turn_off(self, **kwargs): """ unlock the GeoRide tracker """ _LOGGER.info('async_turn_off %s', kwargs) - success = GeoRideApi.unlock_tracker(self._get_token_callback(), self._tracker_id) + success = GeoRideApi.unlock_tracker(await self._get_token_callback(), self._tracker_id) if success: self._data.is_locked = False self._is_on = False @@ -72,16 +72,16 @@ class GeoRideLockSwitchEntity(SwitchEntity): async def async_toggle(self, **kwargs): """ toggle lock the georide tracker """ _LOGGER.info('async_toggle %s', kwargs) - result = GeoRideApi.toogle_lock_tracker(self._get_token_callback(), + result = await GeoRideApi.toogle_lock_tracker(await self._get_token_callback(), self._tracker_id) self._data.is_locked = result self._is_on = result - def update(self): + async def async_update(self): """ update the current tracker""" _LOGGER.info('update') - self._data = self._get_tracker_callback(self._tracker_id) + self._data = await self._get_tracker_callback(self._tracker_id) self._name = self._data.tracker_name self._is_on = self._data.is_locked From f72481236dd5981cfb9654534a63cabd78a9a701 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 10 Apr 2021 12:05:38 +0200 Subject: [PATCH 03/20] Add get_tracker to await --- custom_components/georide/__init__.py | 10 +++++----- custom_components/georide/binary_sensor.py | 2 +- custom_components/georide/device_tracker.py | 2 +- custom_components/georide/sensor.py | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index dcb5acb..2de6c79 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -85,7 +85,7 @@ async def async_setup_entry(hass, entry): hass.data[DOMAIN]["context"] = context # We add trackers to the context - context.refresh_trackers() + await context.refresh_trackers() hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, "device_tracker")) @@ -187,13 +187,13 @@ class GeoRideContext: _LOGGER.info("Token exp data: %s", exp_timestamp) return self._token - def get_tracker(self, tracker_id): + async def get_tracker(self, tracker_id): """ here we return last tracker by id""" 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 - self.refresh_trackers() + await self.refresh_trackers() if not self._thread_started: _LOGGER.info("Start the thread") @@ -206,10 +206,10 @@ class GeoRideContext: return tracker return None - def refresh_trackers(self): + async def refresh_trackers(self): """Used to refresh the tracker list""" _LOGGER.info("Tracker list refresh") - self._georide_trackers = GeoRideApi.get_trackers(self.get_token()) + self._georide_trackers = await GeoRideApi.get_trackers(await self.get_token()) @property def socket(self): diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index fa6b025..e4977ad 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -19,7 +19,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d if token is None: return False - trackers = GeoRideApi.get_trackers(token) + trackers = await GeoRideApi.get_trackers(token) binary_sensor_entities = [] for tracker in trackers: diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index edbd38c..e3590e9 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -23,7 +23,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d _LOGGER.debug('Current GeoRide token: %s', token) - trackers = GeoRideApi.get_trackers(token) + trackers = await GeoRideApi.get_trackers(token) tracker_entities = [] diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index ffb4344..dce133e 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -21,7 +21,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d if token is None: return False - trackers = GeoRideApi.get_trackers(token) + trackers = await GeoRideApi.get_trackers(token) odometer_switch_entities = [] for tracker in trackers: From b4871b9374344f920a4cd67f5ac767172d01d1d2 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 10 Apr 2021 12:09:49 +0200 Subject: [PATCH 04/20] Fix param gived to async_add_executor_job --- custom_components/georide/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 2de6c79..576633d 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -178,7 +178,7 @@ class GeoRideContext: if (exp_timestamp - TOKEN_SAFE_DAY) < epoch: _LOGGER.info("Time reached, renew token") - account = await self._hass.async_add_executor_job(GeoRideApi.get_authorisation_token, [self._email, self._password]) + account = await self._hass.async_add_executor_job(GeoRideApi.get_authorisation_token, self._email, self._password) config = self._hass.data[DOMAIN]["config"] config[CONF_TOKEN] = account.auth_token self._token = account.auth_token From af1df1cd844311febc68f7f6da1a80a2b17808d9 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 10 Apr 2021 12:25:47 +0200 Subject: [PATCH 05/20] Fix tracker retrivial --- custom_components/georide/binary_sensor.py | 2 +- custom_components/georide/device_tracker.py | 2 +- custom_components/georide/sensor.py | 2 +- custom_components/georide/switch.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index e4977ad..1ffe9c7 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -19,7 +19,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d if token is None: return False - trackers = await GeoRideApi.get_trackers(token) + trackers = await hass.async_add_executor_job(GeoRideApi.get_trackers,token) binary_sensor_entities = [] for tracker in trackers: diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index e3590e9..5537fea 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -23,7 +23,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d _LOGGER.debug('Current GeoRide token: %s', token) - trackers = await GeoRideApi.get_trackers(token) + trackers = await hass.async_add_executor_job(GeoRideApi.get_trackers, token) tracker_entities = [] diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index dce133e..4909f6c 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -21,7 +21,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d if token is None: return False - trackers = await GeoRideApi.get_trackers(token) + trackers = await hass.async_add_executor_job(GeoRideApi.get_trackers,token) odometer_switch_entities = [] for tracker in trackers: diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index b72d1e4..cccd1ec 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -23,7 +23,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d _LOGGER.info('Current georide token: %s', token) - trackers = await GeoRideApi.get_trackers(token) + trackers = await hass.async_add_executor_job(GeoRideApi.get_trackers, token) lock_switch_entities = [] for tracker in trackers: From bcaa4bf957d637a06307977300c1a22672e422c4 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 10 Apr 2021 12:43:43 +0200 Subject: [PATCH 06/20] Add hass object on entity items --- custom_components/georide/__init__.py | 2 +- custom_components/georide/binary_sensor.py | 18 ++++++++++------ custom_components/georide/device_tracker.py | 5 +++-- custom_components/georide/sensor.py | 5 +++-- custom_components/georide/switch.py | 24 +++++++++++++-------- 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 576633d..9f6eac4 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -209,7 +209,7 @@ class GeoRideContext: async def refresh_trackers(self): """Used to refresh the tracker list""" _LOGGER.info("Tracker list refresh") - self._georide_trackers = await GeoRideApi.get_trackers(await self.get_token()) + self._georide_trackers = await self._hass.async_add_executor_job(GeoRideApi.get_trackers, await self.get_token) @property def socket(self): diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 1ffe9c7..55b9e92 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -23,11 +23,15 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d binary_sensor_entities = [] for tracker in trackers: - stolen_entity = GeoRideStolenBinarySensorEntity(tracker.tracker_id, georide_context.get_token, - georide_context.get_tracker, data=tracker) + stolen_entity = GeoRideStolenBinarySensorEntity(hass, tracker.tracker_id, + georide_context.get_token, + georide_context.get_tracker, + data=tracker) hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = stolen_entity - crashed_entity = GeoRideCrashedBinarySensorEntity(tracker.tracker_id, georide_context.get_token, - georide_context.get_tracker, data=tracker) + crashed_entity = GeoRideCrashedBinarySensorEntity(hass, tracker.tracker_id, + georide_context.get_token, + georide_context.get_tracker, + data=tracker) hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = crashed_entity binary_sensor_entities.append(stolen_entity) binary_sensor_entities.append(crashed_entity) @@ -38,7 +42,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d class GeoRideStolenBinarySensorEntity(BinarySensorEntity): """Represent a tracked device.""" - def __init__(self, tracker_id, get_token_callback, get_tracker_callback, data): + def __init__(self, hass, tracker_id, get_token_callback, get_tracker_callback, data): """Set up Georide entity.""" self._tracker_id = tracker_id self._data = data or {} @@ -48,6 +52,7 @@ class GeoRideStolenBinarySensorEntity(BinarySensorEntity): self.entity_id = ENTITY_ID_FORMAT.format("is_stolen") + "." + str(tracker_id) self._state = 0 + self._hass = hass async def async_update(self): @@ -95,7 +100,7 @@ class GeoRideStolenBinarySensorEntity(BinarySensorEntity): class GeoRideCrashedBinarySensorEntity(BinarySensorEntity): """Represent a tracked device.""" - def __init__(self, tracker_id, get_token_callback, get_tracker_callback, data): + def __init__(self, hass, tracker_id, get_token_callback, get_tracker_callback, data): """Set up Georide entity.""" self._tracker_id = tracker_id self._data = data or {} @@ -105,6 +110,7 @@ class GeoRideCrashedBinarySensorEntity(BinarySensorEntity): self.entity_id = ENTITY_ID_FORMAT.format("is_crashed") + "." + str(tracker_id) self._state = 0 + self._hass = hass async def async_update(self): diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index 5537fea..da296cd 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -28,7 +28,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d tracker_entities = [] for tracker in trackers: - entity = GeoRideTrackerEntity(tracker.tracker_id, georide_context.get_token, + entity = GeoRideTrackerEntity(hass, tracker.tracker_id, georide_context.get_token, georide_context.get_tracker, tracker) @@ -43,7 +43,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d class GeoRideTrackerEntity(TrackerEntity): """Represent a tracked device.""" - def __init__(self, tracker_id, get_token_callback, get_tracker_callback, tracker): + def __init__(self, hass, tracker_id, get_token_callback, get_tracker_callback, tracker): """Set up GeoRide entity.""" self._tracker_id = tracker_id self._get_token_callback = get_token_callback @@ -51,6 +51,7 @@ class GeoRideTrackerEntity(TrackerEntity): self._name = tracker.tracker_name self._data = tracker or {} self.entity_id = DOMAIN + ".{}".format(tracker_id) + self._hass = hass @property def unique_id(self): diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 4909f6c..c13914c 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -25,7 +25,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d odometer_switch_entities = [] for tracker in trackers: - entity = GeoRideOdometerSensorEntity(tracker.tracker_id, georide_context.get_token, + entity = GeoRideOdometerSensorEntity(hass, tracker.tracker_id, georide_context.get_token, georide_context.get_tracker, data=tracker) hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = entity odometer_switch_entities.append(entity) @@ -37,7 +37,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d class GeoRideOdometerSensorEntity(SwitchEntity): """Represent a tracked device.""" - def __init__(self, tracker_id, get_token_callback, get_tracker_callback, data): + def __init__(self, hass, tracker_id, get_token_callback, get_tracker_callback, data): """Set up Georide entity.""" self._tracker_id = tracker_id self._data = data or {} @@ -48,6 +48,7 @@ class GeoRideOdometerSensorEntity(SwitchEntity): self.entity_id = ENTITY_ID_FORMAT.format("odometer") + "." + str(tracker_id) self._state = 0 + self._hass = hass async def async_update(self): diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index cccd1ec..9fc8615 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -27,7 +27,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d lock_switch_entities = [] for tracker in trackers: - entity = GeoRideLockSwitchEntity(tracker.tracker_id, georide_context.get_token, + entity = GeoRideLockSwitchEntity(hass, tracker.tracker_id, georide_context.get_token, georide_context.get_tracker, data=tracker) hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = entity lock_switch_entities.append(entity) @@ -41,7 +41,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d class GeoRideLockSwitchEntity(SwitchEntity): """Represent a tracked device.""" - def __init__(self, tracker_id, get_token_callback, get_tracker_callback, data): + def __init__(self, hass, tracker_id, get_token_callback, get_tracker_callback, data): """Set up GeoRide entity.""" self._tracker_id = tracker_id self._data = data or {} @@ -51,20 +51,25 @@ class GeoRideLockSwitchEntity(SwitchEntity): self._is_on = data.is_locked self.entity_id = ENTITY_ID_FORMAT.format("lock") +"." + str(tracker_id) self._state = {} + self._hass = hass + - - def turn_on(self, **kwargs): + async def async_turn_on(self, **kwargs): """ lock the GeoRide tracker """ _LOGGER.info('async_turn_on %s', kwargs) - success = GeoRideApi.lock_tracker(await self._get_token_callback(), self._tracker_id) + token = await self._get_token_callback() + success = await self._hass.async_add_executor_job(GeoRideApi.lock_tracker, + token, self._tracker_id) if success: self._data.is_locked = True self._is_on = True - def turn_off(self, **kwargs): + async def async_turn_off(self, **kwargs): """ unlock the GeoRide tracker """ _LOGGER.info('async_turn_off %s', kwargs) - success = GeoRideApi.unlock_tracker(await self._get_token_callback(), self._tracker_id) + token = await self._get_token_callback() + success = await self._hass.async_add_executor_job(GeoRideApi.unlock_tracker, + token, self._tracker_id) if success: self._data.is_locked = False self._is_on = False @@ -72,8 +77,9 @@ class GeoRideLockSwitchEntity(SwitchEntity): async def async_toggle(self, **kwargs): """ toggle lock the georide tracker """ _LOGGER.info('async_toggle %s', kwargs) - result = await GeoRideApi.toogle_lock_tracker(await self._get_token_callback(), - self._tracker_id) + token = await self._get_token_callback() + result = await self._hass.async_add_executor_job(GeoRideApi.toogle_lock_tracker, + token, self._tracker_id) self._data.is_locked = result self._is_on = result From be4e68e15282f83810b2805b60d4fbdffbe8efd0 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 10 Apr 2021 12:54:42 +0200 Subject: [PATCH 07/20] Add version in manifet, and add_executor_job on config_flow --- custom_components/georide/__init__.py | 2 +- custom_components/georide/config_flow.py | 6 +++--- custom_components/georide/manifest.json | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 9f6eac4..e0e9ad9 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -209,7 +209,7 @@ class GeoRideContext: async def refresh_trackers(self): """Used to refresh the tracker list""" _LOGGER.info("Tracker list refresh") - self._georide_trackers = await self._hass.async_add_executor_job(GeoRideApi.get_trackers, await self.get_token) + self._georide_trackers = await self._hass.async_add_executor_job(GeoRideApi.get_trackers, await self.get_token()) @property def socket(self): diff --git a/custom_components/georide/config_flow.py b/custom_components/georide/config_flow.py index 52361bc..b8d5cc5 100644 --- a/custom_components/georide/config_flow.py +++ b/custom_components/georide/config_flow.py @@ -7,13 +7,13 @@ import georideapilib.api as GeoRideApi import georideapilib.exception as GeoRideException -from .const import CONF_EMAIL, CONF_PASSWORD, CONF_TOKEN +from .const import CONF_EMAIL, CONF_PASSWORD, CONF_TOKEN, DOMAIN _LOGGER = logging.getLogger(__name__) @config_entries.HANDLERS.register("georide") -class GeoRideConfigFlow(config_entries.ConfigFlow): +class GeoRideConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """GeoRide config flow """ async def async_step_user(self, user_input=None): #pylint: disable=W0613 @@ -54,7 +54,7 @@ class GeoRideConfigFlow(config_entries.ConfigFlow): password = user_input[CONF_PASSWORD] try: - account = GeoRideApi.get_authorisation_token(email, password) + account = await self.hass.async_add_executor_job(GeoRideApi.get_authorisation_token, email, password) data = { CONF_EMAIL: email, CONF_PASSWORD: password, diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 0cad021..b3209e6 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -8,5 +8,6 @@ "pyjwt>=1.7.1" ], "dependencies": [], - "codeowners": ["ptimatth"] + "codeowners": ["ptimatth"], + "version": "0.6.0" } \ No newline at end of file From e09f8eb7e7b9f0747ce9ee033d584433d83350cb Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 10 Apr 2021 13:10:30 +0200 Subject: [PATCH 08/20] Add new sensor --- custom_components/georide/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index e0e9ad9..9b2ee42 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -93,7 +93,8 @@ async def async_setup_entry(hass, entry): hass.config_entries.async_forward_entry_setup(entry, "switch")) hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, "sensor")) - + hass.async_create_task( + hass.config_entries.async_forward_entry_setup(entry, "binary_sensor")) return True @@ -103,6 +104,8 @@ async def async_unload_entry(hass, entry): await hass.config_entries.async_forward_entry_unload(entry, "device_tracker") await hass.config_entries.async_forward_entry_unload(entry, "switch") await hass.config_entries.async_forward_entry_unload(entry, "sensor") + await hass.config_entries.async_forward_entry_unload(entry, "binary_sensor") + context = hass.data[DOMAIN]["context"] context.socket.disconnect() From 5cab811c85ff3fba1915d3d7f26950ff06665092 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 10 Apr 2021 13:48:31 +0200 Subject: [PATCH 09/20] Fix binnary sensors --- custom_components/georide/binary_sensor.py | 14 +++++++++----- custom_components/georide/switch.py | 2 ++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 55b9e92..b997a0f 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -20,22 +20,27 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d return False trackers = await hass.async_add_executor_job(GeoRideApi.get_trackers,token) + - binary_sensor_entities = [] + stolen_entities = [] for tracker in trackers: stolen_entity = GeoRideStolenBinarySensorEntity(hass, tracker.tracker_id, georide_context.get_token, georide_context.get_tracker, data=tracker) hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = stolen_entity + stolen_entities.append(stolen_entity) + async_add_entities(stolen_entities) + + crashed_entities = [] + for tracker in trackers: crashed_entity = GeoRideCrashedBinarySensorEntity(hass, tracker.tracker_id, georide_context.get_token, georide_context.get_tracker, data=tracker) hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = crashed_entity - binary_sensor_entities.append(stolen_entity) - binary_sensor_entities.append(crashed_entity) - async_add_entities(binary_sensor_entities) + crashed_entities.append(crashed_entity) + async_add_entities(crashed_entities) return True @@ -112,7 +117,6 @@ class GeoRideCrashedBinarySensorEntity(BinarySensorEntity): self._state = 0 self._hass = hass - async def async_update(self): """ update the current tracker""" _LOGGER.info('update') diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index 9fc8615..686a32f 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -88,6 +88,8 @@ class GeoRideLockSwitchEntity(SwitchEntity): """ update the current tracker""" _LOGGER.info('update') self._data = await self._get_tracker_callback(self._tracker_id) + _LOGGER.debug('data %s', self._data) + self._name = self._data.tracker_name self._is_on = self._data.is_locked From 283a1074e1f551b336dc21a893327e78195c7520 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 10 Apr 2021 16:01:32 +0200 Subject: [PATCH 10/20] Move connect_socket into the context --- custom_components/georide/__init__.py | 38 ++++++++++++++------------- custom_components/georide/switch.py | 4 +-- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 9b2ee42..7422a44 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -114,19 +114,6 @@ async def async_unload_entry(hass, entry): return True -async def connect_socket(context): - """subscribe to GeoRide socket""" - _LOGGER.info("GeoRide socket connexion") - socket = GeoRideSocket() - socket.subscribe_locked(context.on_lock_callback) - socket.subscribe_device(context.on_device_callback) - socket.subscribe_position(context.on_position_callback) - socket.subscribe_alarm(context.on_alarm_callback) - - context.socket = socket - - socket.init() - socket.connect(await context.get_token()) class GeoRideContext: @@ -170,7 +157,21 @@ class GeoRideContext: @georide_trackers.setter def georide_trackers(self, trackers): """ GeoRide tracker list """ - self._georide_trackers = trackers + self._georide_trackers = trackers + + async def connect_socket(self): + """subscribe to GeoRide socket""" + _LOGGER.info("GeoRide socket connexion") + socket = GeoRideSocket() + socket.subscribe_locked(self.on_lock_callback) + socket.subscribe_device(self.on_device_callback) + socket.subscribe_position(self.on_position_callback) + socket.subscribe_alarm(self.on_alarm_callback) + + self._socket = socket + + socket.init() + socket.connect(await self.get_token()) async def get_token(self): """ here we return the current valid tocken """ @@ -180,8 +181,8 @@ class GeoRideContext: epoch = math.ceil(time.time()) if (exp_timestamp - TOKEN_SAFE_DAY) < epoch: _LOGGER.info("Time reached, renew token") - - account = await self._hass.async_add_executor_job(GeoRideApi.get_authorisation_token, self._email, self._password) + account = await self._hass.async_add_executor_job(GeoRideApi.get_authorisation_token, + self._email, self._password) config = self._hass.data[DOMAIN]["config"] config[CONF_TOKEN] = account.auth_token self._token = account.auth_token @@ -200,7 +201,7 @@ class GeoRideContext: if not self._thread_started: _LOGGER.info("Start the thread") - self._hass.async_add_executor_job(connect_socket, self) + await self.connect_socket() # We refresh the tracker list each hours self._thread_started = True @@ -212,7 +213,8 @@ class GeoRideContext: async def refresh_trackers(self): """Used to refresh the tracker list""" _LOGGER.info("Tracker list refresh") - self._georide_trackers = await self._hass.async_add_executor_job(GeoRideApi.get_trackers, await self.get_token()) + self._georide_trackers = await self._hass.async_add_executor_job(GeoRideApi.get_trackers, + await self.get_token()) @property def socket(self): diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index 686a32f..1f83bd8 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -86,9 +86,9 @@ class GeoRideLockSwitchEntity(SwitchEntity): async def async_update(self): """ update the current tracker""" - _LOGGER.info('update') + _LOGGER.info('update %s', self._tracker_id) self._data = await self._get_tracker_callback(self._tracker_id) - _LOGGER.debug('data %s', self._data) + _LOGGER.debug('data %s', self._data.is_locked) self._name = self._data.tracker_name self._is_on = self._data.is_locked From ec63a36c812eba3e97e856fd4e7b112f1d3f6276 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 10 Apr 2021 20:13:49 +0200 Subject: [PATCH 11/20] Change tracker update mangment --- custom_components/georide/__init__.py | 17 ++- custom_components/georide/binary_sensor.py | 126 ++++++++------------- custom_components/georide/manifest.json | 2 +- 3 files changed, 62 insertions(+), 83 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 7422a44..b133c76 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -23,6 +23,8 @@ import homeassistant.helpers.config_validation as cv import homeassistant.helpers.event as ha_event from homeassistant.setup import async_when_setup +from homeassistant.helpers.typing import HomeAssistantType + from .const import ( CONF_EMAIL, @@ -35,6 +37,7 @@ from .const import ( ) + _LOGGER = logging.getLogger(__name__) @@ -171,7 +174,7 @@ class GeoRideContext: self._socket = socket socket.init() - socket.connect(await self.get_token()) + self._hass.async_add_executor_job(socket.connect, await self.get_token()) async def get_token(self): """ here we return the current valid tocken """ @@ -201,9 +204,9 @@ class GeoRideContext: if not self._thread_started: _LOGGER.info("Start the thread") - await self.connect_socket() # We refresh the tracker list each hours self._thread_started = True + await self.connect_socket() for tracker in self._georide_trackers: if tracker.tracker_id == tracker_id: @@ -213,8 +216,14 @@ class GeoRideContext: async def refresh_trackers(self): """Used to refresh the tracker list""" _LOGGER.info("Tracker list refresh") - self._georide_trackers = await self._hass.async_add_executor_job(GeoRideApi.get_trackers, - await self.get_token()) + 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: + if tracker.tracker_id == refreshed_tracker.tracker_id: + tracker.update_all_data(refreshed_tracker) + @property def socket(self): diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index b997a0f..4cad045 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -7,6 +7,7 @@ from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.components.binary_sensor import ENTITY_ID_FORMAT import georideapilib.api as GeoRideApi +import georideapilib.objects as GeoRideTracker from .const import DOMAIN as GEORIDE_DOMAIN @@ -20,52 +21,40 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d return False trackers = await hass.async_add_executor_job(GeoRideApi.get_trackers,token) - - - stolen_entities = [] + entities = [] for tracker in trackers: - stolen_entity = GeoRideStolenBinarySensorEntity(hass, tracker.tracker_id, - georide_context.get_token, - georide_context.get_tracker, - data=tracker) - hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = stolen_entity - stolen_entities.append(stolen_entity) - async_add_entities(stolen_entities) - - crashed_entities = [] - for tracker in trackers: - crashed_entity = GeoRideCrashedBinarySensorEntity(hass, tracker.tracker_id, - georide_context.get_token, - georide_context.get_tracker, - data=tracker) - hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = crashed_entity - crashed_entities.append(crashed_entity) - async_add_entities(crashed_entities) + coordinator = DataUpdateCoordinator[Mapping[str, Any]]( + hass, + _LOGGER, + name=tracker.tracker_name, + update_method=georide_context.get_tracker, + update_interval=update_interval, + ) + stolen_entity = GeoRideStolenBinarySensorEntity(coordinator, + coordinator) + crashed_entity = GeoRideCrashedBinarySensorEntity(hass, + tracker) + entities.append(stolen_entity) + entities.append(crashed_entity) + hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = coordinator + + async_add_entities(entities, True) return True -class GeoRideStolenBinarySensorEntity(BinarySensorEntity): - """Represent a tracked device.""" - def __init__(self, hass, tracker_id, get_token_callback, get_tracker_callback, data): +class GeoRideBinarySensorEntity( CoordinatorEntity,B inarySensorEntity): + """Represent a tracked device.""" + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker: GeoRideTracker, get_token_callback, get_tracker_callback): """Set up Georide entity.""" - self._tracker_id = tracker_id - self._data = data or {} + super().__init__(coordinator) + self._tracker = tracker self._get_token_callback = get_token_callback self._get_tracker_callback = get_tracker_callback - self._name = data.tracker_name + self._name = tracker.tracker_name - self.entity_id = ENTITY_ID_FORMAT.format("is_stolen") + "." + str(tracker_id) + self.entity_id = ENTITY_ID_FORMAT.format("is_stolen") + "." + str(tracker.tracker_id) self._state = 0 - self._hass = hass - - - async def async_update(self): - """ update the current tracker""" - _LOGGER.info('update') - self._data = await self._get_tracker_callback(self._tracker_id) - self._name = self._data.tracker_name - self._state = self._data.is_stolen @property def unique_id(self): @@ -101,61 +90,42 @@ class GeoRideStolenBinarySensorEntity(BinarySensorEntity): "manufacturer": "GeoRide" } - -class GeoRideCrashedBinarySensorEntity(BinarySensorEntity): +class GeoRideStolenBinarySensorEntity(GeoRideBinarySensorEntity): """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: GeoRideTracker): """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 + super().__init__(coordinator, tracker, hass, get_tracker_callback,get_tracker_callback) - self.entity_id = ENTITY_ID_FORMAT.format("is_crashed") + "." + str(tracker_id) - self._state = 0 - self._hass = hass + self.entity_id = ENTITY_ID_FORMAT.format("is_stolen") + "." + str(tracker_id) - async def async_update(self): + async def async_update(self): """ update the current tracker""" _LOGGER.info('update') - self._data = await self._get_tracker_callback(self._tracker_id) - self._name = self._data.tracker_name - self._state = self._data.is_crashed + self._name = self._tracker.tracker_name + self._state = self._tracker.is_stolen @property def unique_id(self): """Return the unique ID.""" - return self._tracker_id + return f"is_stolen_{self._tracker_id}" - @property - def name(self): - """ GeoRide odometer name """ - 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 - +class GeoRideCrashedBinarySensorEntity(GeoRideBinarySensorEntity): + """Represent a tracked device.""" - @property - def device_info(self): - """Return the device info.""" - return { - "name": self.name, - "identifiers": {(GEORIDE_DOMAIN, self._tracker_id)}, - "manufacturer": "GeoRide" - } + 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) + async def async_update(self): + """ update the current tracker""" + _LOGGER.info('update') + self._name = self._tracker.tracker_name + self._state = self._tracker.is_crashed + @property + def unique_id(self): + """Return the unique ID.""" + return f"is_crashed_{self._tracker_id}" diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index b3209e6..854832a 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "documentation": "https://github.com/ptimatth/GeorideHA", "requirements": [ - "georideapilib>=0.4.4", + "georideapilib>=0.5.0", "pyjwt>=1.7.1" ], "dependencies": [], From 093bebc3919f78cea854aaa4e2db916ed131c0aa Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 10 Apr 2021 22:47:32 +0200 Subject: [PATCH 12/20] Trying to refactor the tracker entity_status --- custom_components/georide/__init__.py | 30 ++++--- custom_components/georide/binary_sensor.py | 75 +++++++++-------- custom_components/georide/device_tracker.py | 21 ++--- custom_components/georide/sensor.py | 2 +- custom_components/georide/switch.py | 89 ++++++++++----------- 5 files changed, 107 insertions(+), 110 deletions(-) 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" } From 0113102a7f909dff5a751d859449b41751b7441f Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 10 Apr 2021 23:48:29 +0200 Subject: [PATCH 13/20] Centralize update loop --- custom_components/georide/__init__.py | 38 ++++++++++++-- custom_components/georide/binary_sensor.py | 35 +++++-------- custom_components/georide/device_tracker.py | 51 +++++++++--------- custom_components/georide/sensor.py | 58 ++++++++++----------- custom_components/georide/switch.py | 17 ++---- 5 files changed, 106 insertions(+), 93 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 255ae0f..5a3b930 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -2,6 +2,7 @@ from collections import defaultdict import logging +from typing import Any, Mapping from datetime import timedelta import math import time @@ -24,7 +25,10 @@ import homeassistant.helpers.event as ha_event from homeassistant.setup import async_when_setup from homeassistant.helpers.typing import HomeAssistantType - +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, + DataUpdateCoordinator, +) from .const import ( CONF_EMAIL, @@ -88,7 +92,7 @@ async def async_setup_entry(hass, entry): hass.data[DOMAIN]["context"] = context # We add trackers to the context - await context.force_refresh_trackers() + await context.init_context(hass) hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, "device_tracker")) @@ -127,6 +131,7 @@ class GeoRideContext: self._hass = hass self._email = email self._password = password + self._georide_trackers_coordoned = [] self._georide_trackers = [] self._token = token self._socket = None @@ -204,12 +209,14 @@ class GeoRideContext: async def refresh_trackers(self): """ here we return last tracker by id""" - _LOGGER.info("Call refresh tracker") + _LOGGER.debug("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.force_refresh_trackers() + else: + _LOGGER.debug("We wil dont refresh the tracker list") if not self._thread_started: _LOGGER.info("Start the thread") @@ -235,6 +242,31 @@ class GeoRideContext: self._georide_trackers.append(refreshed_tracker) + async def init_context(self, hass): + """Used to refresh the tracker list""" + _LOGGER.info("Init_context") + await self.force_refresh_trackers() + update_interval = timedelta(seconds=10) + + for tracker in self._georide_trackers: + coordinator = DataUpdateCoordinator[Mapping[str, Any]]( + hass, + _LOGGER, + name=tracker.tracker_name, + update_method=self.refresh_trackers, + update_interval=update_interval + ) + self._georide_trackers_coordoned.append({ + "tracker": tracker, + "coordinator": coordinator + }) + + + def get_coordoned_trackers(self): + """Return coordoned trackers""" + + return self._georide_trackers_coordoned + @property def socket(self): """ hold the GeoRide socket """ diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index d54d9a0..ad7b1ef 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -8,38 +8,27 @@ 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, + 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__) 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 - - update_interval = timedelta(seconds=1) - trackers = await hass.async_add_executor_job(GeoRideApi.get_trackers,token) + georide_context = hass.data[GEORIDE_DOMAIN]["context"] entities = [] - for tracker in trackers: - coordinator = DataUpdateCoordinator[Mapping[str, Any]]( - hass, - _LOGGER, - name=tracker.tracker_name, - update_method=georide_context.refresh_trackers, - update_interval=update_interval - ) + coordoned_trackers = georide_context.get_coordoned_trackers() + for coordoned_tracker in coordoned_trackers: + tracker = coordoned_tracker['tracker'] + coordinator = coordoned_tracker['coordinator'] + stolen_entity = GeoRideStolenBinarySensorEntity(coordinator, tracker) crashed_entity = GeoRideCrashedBinarySensorEntity(coordinator, tracker) entities.append(stolen_entity) @@ -53,7 +42,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d class GeoRideBinarySensorEntity(CoordinatorEntity, BinarySensorEntity): """Represent a tracked device.""" - def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker: GeoRideTracker): + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker: GeoRideTracker): """Set up Georide entity.""" super().__init__(coordinator) self._tracker = tracker @@ -89,8 +79,8 @@ class GeoRideBinarySensorEntity(CoordinatorEntity, BinarySensorEntity): class GeoRideStolenBinarySensorEntity(GeoRideBinarySensorEntity): """Represent a tracked device.""" - - def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker: GeoRideTracker): + 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_stolen") + "." + str(tracker.tracker_id) @@ -113,7 +103,8 @@ class GeoRideStolenBinarySensorEntity(GeoRideBinarySensorEntity): class GeoRideCrashedBinarySensorEntity(GeoRideBinarySensorEntity): """Represent a tracked device.""" - def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker: GeoRideTracker): + 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.tracker_id) diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index f0467d7..dc1feb3 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -1,9 +1,14 @@ """ device tracker for GeoRide object """ import logging +from typing import Any, Mapping from homeassistant.components.device_tracker.const import DOMAIN, SOURCE_TYPE_GPS from homeassistant.components.device_tracker.config_entry import TrackerEntity +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, + DataUpdateCoordinator, +) import georideapilib.api as GeoRideApi @@ -14,34 +19,31 @@ _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"] + coordoned_trackers = georide_context.get_coordoned_trackers() - 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, - georide_context.get_tracker, tracker) + entities = [] + for coordoned_tracker in coordoned_trackers: + tracker = coordoned_tracker['tracker'] + coordinator = coordoned_tracker['coordinator'] + entity = GeoRideTrackerEntity(coordinator, tracker, hass) + hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = coordinator + entities.append(entity) - - hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = entity - tracker_entities.append(entity) - - async_add_entities(tracker_entities) + async_add_entities(entities) return True -class GeoRideTrackerEntity(TrackerEntity): +class GeoRideTrackerEntity(CoordinatorEntity, TrackerEntity): """Represent a tracked device.""" - def __init__(self, hass, tracker_id, get_token_callback, get_tracker_callback, tracker): + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker, hass): """Set up GeoRide entity.""" - self._tracker_id = tracker_id - self._get_token_callback = get_token_callback - self._get_tracker_callback = get_tracker_callback + super().__init__(coordinator) self._name = tracker.tracker_name self._tracker = tracker - self.entity_id = DOMAIN + ".{}".format(tracker_id) + self.entity_id = DOMAIN + ".{}".format(tracker.tracker_id) self._hass = hass @property @@ -51,20 +53,21 @@ class GeoRideTrackerEntity(TrackerEntity): @property def name(self): + """ame property""" return self._name @property def latitude(self): """Return latitude value of the device.""" if self._data.latitude: - return self._data.latitude + return self._tracker.latitude return None @property def longitude(self): """Return longitude value of the device.""" if self._data.longitude: - return self._data.longitude + return self._tracker.longitude return None @@ -89,9 +92,9 @@ class GeoRideTrackerEntity(TrackerEntity): """Return the device info.""" return { "name": self.name, - "identifiers": {(GEORIDE_DOMAIN, self._tracker_id)}, + "identifiers": {(GEORIDE_DOMAIN, self._tracker.tracker_id)}, "manufacturer": "GeoRide", - "odometer": "{} km".format(self.tracker.odometer) + "odometer": "{} km".format(self._tracker.odometer) } @property @@ -109,10 +112,4 @@ class GeoRideTrackerEntity(TrackerEntity): def should_poll(self): """No polling needed.""" return True - - async def async_update(self): - """ update the current tracker""" - _LOGGER.debug('update') - self._data = await self._get_tracker_callback(self._tracker_id) - self._name = self.tracker.tracker_name diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index d34d18b..44369cc 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -1,10 +1,15 @@ """ odometter sensor for GeoRide object """ import logging +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 @@ -16,37 +21,31 @@ _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 + georide_context = hass.data[GEORIDE_DOMAIN]["context"] + coordoned_trackers = georide_context.get_coordoned_trackers() - trackers = await hass.async_add_executor_job(GeoRideApi.get_trackers,token) + entities = [] + for coordoned_tracker in coordoned_trackers: + tracker = coordoned_tracker['tracker'] + coordinator = coordoned_tracker['coordinator'] + entity = GeoRideOdometerSensorEntity(coordinator, tracker, hass) + hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = coordinator + entities.append(entity) - odometer_switch_entities = [] - for tracker in trackers: - entity = GeoRideOdometerSensorEntity(hass, tracker.tracker_id, georide_context.get_token, - georide_context.get_tracker, data=tracker) - hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = entity - odometer_switch_entities.append(entity) - - async_add_entities(odometer_switch_entities) + async_add_entities(entities) return True -class GeoRideOdometerSensorEntity(SwitchEntity): +class GeoRideOdometerSensorEntity(CoordinatorEntity, SwitchEntity): """Represent a tracked device.""" - def __init__(self, hass, tracker_id, get_token_callback, get_tracker_callback, data): - """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 + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker, hass): + """Set up GeoRide entity.""" + super().__init__(coordinator) + self._tracker = tracker + self._name = tracker.tracker_name self._unit_of_measurement = "m" - - self.entity_id = ENTITY_ID_FORMAT.format("odometer") + "." + str(tracker_id) + self.entity_id = ENTITY_ID_FORMAT.format("odometer") + "." + str(tracker.tracker_id) self._state = 0 self._hass = hass @@ -54,14 +53,13 @@ class GeoRideOdometerSensorEntity(SwitchEntity): async def async_update(self): """ update the current tracker""" _LOGGER.debug('update') - self._data = await self._get_tracker_callback(self._tracker_id) - self._name = self._data.tracker_name - self._state = self._data.odometer + self._name = self._tracker.tracker_name + self._state = self._tracker.odometer @property def unique_id(self): """Return the unique ID.""" - return self._tracker_id + return self._tracker.tracker_id @property def name(self): @@ -70,10 +68,12 @@ class GeoRideOdometerSensorEntity(SwitchEntity): @property def state(self): + """state property""" return self._state @property def unit_of_measurement(self): + """unit of mesurment property""" return self._unit_of_measurement @property @@ -88,15 +88,15 @@ class GeoRideOdometerSensorEntity(SwitchEntity): @property def icon(self): + """icon getter""" return "mdi:counter" - @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" } diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index c03c3bb..f972f12 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -26,21 +26,14 @@ _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"] - trackers = georide_context.get_trackers() - update_interval = timedelta(seconds=1) + coordoned_trackers = georide_context.get_coordoned_trackers() lock_switch_entities = [] - for tracker in trackers: - coordinator = DataUpdateCoordinator[Mapping[str, Any]]( - hass, - _LOGGER, - name=tracker.tracker_name, - update_method=georide_context.refresh_trackers, - update_interval=update_interval - ) - + for coordoned_tracker in coordoned_trackers: + tracker = coordoned_tracker['tracker'] + coordinator = coordoned_tracker['coordinator'] entity = GeoRideLockSwitchEntity(coordinator, tracker, hass) - hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = entity + hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = coordinator lock_switch_entities.append(entity) async_add_entities(lock_switch_entities) From 660aaa018024522d24fada61ff4d146aba534647 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 11 Apr 2021 00:05:52 +0200 Subject: [PATCH 14/20] Fix switch response --- custom_components/georide/device_tracker.py | 9 ++++++--- custom_components/georide/switch.py | 14 ++------------ 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index dc1feb3..c016696 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -49,7 +49,7 @@ class GeoRideTrackerEntity(CoordinatorEntity, TrackerEntity): @property def unique_id(self): """Return the unique ID.""" - return self._tracker_id + return self._tracker.tracker_id @property def name(self): @@ -59,14 +59,14 @@ class GeoRideTrackerEntity(CoordinatorEntity, TrackerEntity): @property def latitude(self): """Return latitude value of the device.""" - if self._data.latitude: + if self._tracker.latitude: return self._tracker.latitude return None @property def longitude(self): """Return longitude value of the device.""" - if self._data.longitude: + if self._tracker.longitude: return self._tracker.longitude return None @@ -86,6 +86,9 @@ class GeoRideTrackerEntity(CoordinatorEntity, TrackerEntity): """return the entity icon""" return "mdi:map-marker" + async def async_update(self): + """ update the current tracker""" + _LOGGER.debug('update') @property def device_info(self): diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index f972f12..26c24f7 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -50,7 +50,6 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): 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 @@ -64,7 +63,6 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): token, self._tracker_id) if success: self._tracker.is_locked = True - self._is_on = True async def async_turn_off(self, **kwargs): """ unlock the GeoRide tracker """ @@ -75,7 +73,6 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): token, self._tracker_id) if success: self._tracker.is_locked = False - self._is_on = False async def async_toggle(self, **kwargs): """ toggle lock the georide tracker """ @@ -85,13 +82,6 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): result = await self._hass.async_add_executor_job(GeoRideApi.toogle_lock_tracker, token, self._tracker_id) self._tracker.is_locked = result - self._is_on = result - - async def async_update(self): - """ update the current tracker""" - _LOGGER.debug('update') - self._name = self._tracker.tracker_name - self._is_on = self._tracker.is_lockedtracker @property def unique_id(self): @@ -106,12 +96,12 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): @property def is_on(self): """ GeoRide switch status """ - return self._is_on + return self._tracker.is_locked @property def icon(self): """return the entity icon""" - if self._is_on: + if self._tracker.tracker_id: return "mdi:lock" return "mdi:lock-open" From dbbe1f33b98f7a80cea43b8bb4ea137545182227 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 11 Apr 2021 00:14:21 +0200 Subject: [PATCH 15/20] Add space betteween useless refresh --- custom_components/georide/__init__.py | 42 ++++++++++++++------------- custom_components/georide/switch.py | 6 ++-- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 5a3b930..0df6823 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -211,42 +211,39 @@ class GeoRideContext: """ here we return last tracker by id""" _LOGGER.debug("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.force_refresh_trackers() + if epoch_min != self._previous_refresh: + self._previous_refresh = epoch_min + await self.force_refresh_trackers() else: _LOGGER.debug("We wil dont refresh the tracker list") - if not self._thread_started: - _LOGGER.info("Start the thread") - # We refresh the tracker list each hours - self._thread_started = True - await self.connect_socket() - - 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 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) + if not found: + self._georide_trackers.append(refreshed_tracker) + if not self._thread_started: + _LOGGER.info("Start the thread") + # We refresh the tracker list each hours + self._thread_started = True + await self.connect_socket() + async def init_context(self, hass): """Used to refresh the tracker list""" _LOGGER.info("Init_context") await self.force_refresh_trackers() - update_interval = timedelta(seconds=10) + update_interval = timedelta(minutes=MIN_UNTIL_REFRESH) for tracker in self._georide_trackers: coordinator = DataUpdateCoordinator[Mapping[str, Any]]( @@ -286,7 +283,9 @@ class GeoRideContext: tracker.locked_latitude = data['lockedLatitude'] tracker.locked_longitude = data['lockedLongitude'] tracker.is_locked = data['isLocked'] - return + break + self.force_refresh_trackers() + @callback def on_device_callback(self, data): @@ -295,7 +294,8 @@ class GeoRideContext: for tracker in self._georide_trackers: if tracker.tracker_id == data['trackerId']: tracker.status = data['status'] - return + self.force_refresh_trackers() + @callback def on_alarm_callback(self, data): """on device callback""" @@ -318,8 +318,8 @@ class GeoRideContext: _LOGGER.info("powerCut detected") else: _LOGGER.warning("Unamanged alarm: ", data.name) - - return + break + self.force_refresh_trackers() @callback def on_position_callback(self, data): @@ -332,5 +332,7 @@ class GeoRideContext: tracker.moving = data['moving'] tracker.speed = data['speed'] tracker.fixtime = data['fixtime'] - return + break + self.force_refresh_trackers() + diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index 26c24f7..f33b7a3 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -60,7 +60,7 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): 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.tracker_id) if success: self._tracker.is_locked = True @@ -70,7 +70,7 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): 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) + token, self._tracker.tracker_id) if success: self._tracker.is_locked = False @@ -80,7 +80,7 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): 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) + token, self._tracker.tracker_id) self._tracker.is_locked = result @property From 7d25405c2f792e3247a57fdf698e81adedacaf69 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 11 Apr 2021 01:07:31 +0200 Subject: [PATCH 16/20] Use coordinator to imporoo reactivituy --- custom_components/georide/__init__.py | 59 ++++++++++++++++++--------- custom_components/georide/sensor.py | 10 ----- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 0df6823..96ac7dd 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -1,6 +1,7 @@ """ georide custom conpennt """ from collections import defaultdict +import asyncio import logging from typing import Any, Mapping from datetime import timedelta @@ -12,10 +13,10 @@ import voluptuous as vol import jwt from aiohttp.web import json_response -from georideapilib.objects import GeorideAccount as GeoRideAccount +from georideapilib.objects import GeoRideAccount import georideapilib.api as GeoRideApi -from georideapilib.socket import GeorideSocket as GeoRideSocket +from georideapilib.socket import GeoRideSocket from homeassistant import config_entries from homeassistant.const import CONF_WEBHOOK_ID @@ -211,11 +212,12 @@ class GeoRideContext: """ here we return last tracker by id""" _LOGGER.debug("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.force_refresh_trackers() - else: - _LOGGER.debug("We wil dont refresh the tracker list") + #else: + # _LOGGER.debug("We wil dont refresh the tracker list") async def force_refresh_trackers(self): @@ -229,13 +231,13 @@ class GeoRideContext: 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) - if not self._thread_started: - _LOGGER.info("Start the thread") - # We refresh the tracker list each hours - self._thread_started = True - await self.connect_socket() + if not found: + self._georide_trackers.append(refreshed_tracker) + if not self._thread_started: + _LOGGER.info("Start the thread") + # We refresh the tracker list each hours + self._thread_started = True + await self.connect_socket() @@ -278,29 +280,40 @@ class GeoRideContext: def on_lock_callback(self, data): """on lock callback""" _LOGGER.info("On lock received") - for tracker in self._georide_trackers: + for coordoned_tracker in self._georide_trackers_coordoned: + tracker = coordoned_tracker['tracker'] + coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: tracker.locked_latitude = data['lockedLatitude'] tracker.locked_longitude = data['lockedLongitude'] tracker.is_locked = data['isLocked'] + asyncio.run_coroutine_threadsafe( + coordinator.async_request_refresh(), self._hass.loop + ).result() break - self.force_refresh_trackers() @callback def on_device_callback(self, data): """on device callback""" _LOGGER.info("On device received") - for tracker in self._georide_trackers: + for coordoned_tracker in self._georide_trackers_coordoned: + tracker = coordoned_tracker['tracker'] + coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: tracker.status = data['status'] - self.force_refresh_trackers() + asyncio.run_coroutine_threadsafe( + coordinator.async_request_refresh(), self._hass.loop + ).result() + break @callback def on_alarm_callback(self, data): """on device callback""" _LOGGER.info("On alarm received") - for tracker in self._georide_trackers: + for coordoned_tracker in self._georide_trackers_coordoned: + tracker = coordoned_tracker['tracker'] + coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: if data.name == 'vibration': _LOGGER.info("Vibration detected") @@ -318,21 +331,27 @@ class GeoRideContext: _LOGGER.info("powerCut detected") else: _LOGGER.warning("Unamanged alarm: ", data.name) + asyncio.run_coroutine_threadsafe( + coordinator.async_request_refresh(), self._hass.loop + ).result() break - self.force_refresh_trackers() - @callback + @callback def on_position_callback(self, data): """on position callback""" _LOGGER.info("On position received") - for tracker in self._georide_trackers: + for coordoned_tracker in self._georide_trackers_coordoned: + tracker = coordoned_tracker['tracker'] + coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: tracker.latitude = data['latitude'] tracker.longitude = data['longitude'] tracker.moving = data['moving'] tracker.speed = data['speed'] tracker.fixtime = data['fixtime'] + asyncio.run_coroutine_threadsafe( + coordinator.async_request_refresh(), self._hass.loop + ).result() break - self.force_refresh_trackers() diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 44369cc..4e2234a 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -76,16 +76,6 @@ class GeoRideOdometerSensorEntity(CoordinatorEntity, SwitchEntity): """unit of mesurment property""" return self._unit_of_measurement - @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): """icon getter""" From 56a8a3547967371ad0017db4e584f4feed5d39c5 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 11 Apr 2021 01:31:00 +0200 Subject: [PATCH 17/20] Fix old Swirhc entity to odometer --- custom_components/georide/binary_sensor.py | 32 ++++++++------------- custom_components/georide/device_tracker.py | 6 +--- custom_components/georide/sensor.py | 17 ++++------- 3 files changed, 18 insertions(+), 37 deletions(-) diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index ad7b1ef..4128747 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -50,8 +50,7 @@ class GeoRideBinarySensorEntity(CoordinatorEntity, BinarySensorEntity): self._name = tracker.tracker_name self.entity_id = ENTITY_ID_FORMAT.format("is_stolen") + "." + str(tracker.tracker_id) - self._state = None - self._data = False + self._is_on = False @property def unique_id(self): @@ -63,11 +62,6 @@ class GeoRideBinarySensorEntity(CoordinatorEntity, BinarySensorEntity): """ GeoRide odometer name """ return self._name - @property - def is_on(self): - """state value property""" - return self._data - @property def device_info(self): """Return the device info.""" @@ -85,17 +79,15 @@ class GeoRideStolenBinarySensorEntity(GeoRideBinarySensorEntity): super().__init__(coordinator, tracker) self.entity_id = ENTITY_ID_FORMAT.format("is_stolen") + "." + str(tracker.tracker_id) - async def async_update(self): - """ update the current tracker""" - _LOGGER.debug('update') - self._name = self._tracker.tracker_name - self._data = self._tracker.is_stolen - @property def unique_id(self): """Return the unique ID.""" return f"is_stolen_{self._tracker.tracker_id}" - + + @property + def is_on(self): + """state value property""" + return self._tracker.is_stolen @@ -109,13 +101,13 @@ class GeoRideCrashedBinarySensorEntity(GeoRideBinarySensorEntity): super().__init__(coordinator, tracker) self.entity_id = ENTITY_ID_FORMAT.format("is_crashed") + "." + str(tracker.tracker_id) - async def async_update(self): - """ update the current tracker""" - _LOGGER.debug('update') - self._name = self._tracker.tracker_name - self._data = self._tracker.is_crashed - @property def unique_id(self): """Return the unique ID.""" return f"is_crashed_{self._tracker.tracker_id}" + + @property + def is_on(self): + """state value property""" + return self._tracker.is_crashed + diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index c016696..faf1cea 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -49,7 +49,7 @@ class GeoRideTrackerEntity(CoordinatorEntity, TrackerEntity): @property def unique_id(self): """Return the unique ID.""" - return self._tracker.tracker_id + return f"georide_tracker_{self._tracker.tracker_id}" @property def name(self): @@ -85,10 +85,6 @@ class GeoRideTrackerEntity(CoordinatorEntity, TrackerEntity): def icon(self): """return the entity icon""" return "mdi:map-marker" - - async def async_update(self): - """ update the current tracker""" - _LOGGER.debug('update') @property def device_info(self): diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 4e2234a..5426262 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -4,8 +4,8 @@ import logging 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.components.sensor import SensorEntity +from homeassistant.components.sensor import ENTITY_ID_FORMAT from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, DataUpdateCoordinator, @@ -36,7 +36,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d return True -class GeoRideOdometerSensorEntity(CoordinatorEntity, SwitchEntity): +class GeoRideOdometerSensorEntity(CoordinatorEntity, SensorEntity): """Represent a tracked device.""" def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker, hass): @@ -49,13 +49,6 @@ class GeoRideOdometerSensorEntity(CoordinatorEntity, SwitchEntity): self._state = 0 self._hass = hass - - async def async_update(self): - """ update the current tracker""" - _LOGGER.debug('update') - self._name = self._tracker.tracker_name - self._state = self._tracker.odometer - @property def unique_id(self): """Return the unique ID.""" @@ -64,12 +57,12 @@ class GeoRideOdometerSensorEntity(CoordinatorEntity, SwitchEntity): @property def name(self): """ GeoRide odometer name """ - return self._name + return self._tracker.tracker_name @property def state(self): """state property""" - return self._state + return self._tracker.odometer @property def unit_of_measurement(self): From 8a44d22d41789341f6d1d832b294e93b0caf1e60 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 11 Apr 2021 13:38:15 +0200 Subject: [PATCH 18/20] Migreate to 0.6.0 and new device architecture --- custom_components/georide/__init__.py | 33 +++-- custom_components/georide/binary_sensor.py | 126 +++++++++++++------- custom_components/georide/device.py | 52 ++++++++ custom_components/georide/device_tracker.py | 60 +++------- custom_components/georide/manifest.json | 2 +- custom_components/georide/sensor.py | 45 ++++--- custom_components/georide/switch.py | 49 +++----- hacs.json | 2 +- 8 files changed, 217 insertions(+), 152 deletions(-) create mode 100644 custom_components/georide/device.py diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 96ac7dd..9ef15d6 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -31,6 +31,8 @@ from homeassistant.helpers.update_coordinator import ( DataUpdateCoordinator, ) + +from .device import Device from .const import ( CONF_EMAIL, CONF_PASSWORD, @@ -62,7 +64,7 @@ async def async_setup(hass, config): hass.data[DOMAIN] = {"config": config[DOMAIN], "devices": {}, "unsub": None} hass.async_create_task( hass.config_entries.flow.async_init( - DOMAIN, + DOMAIN, context={ "source": config_entries.SOURCE_IMPORT }, @@ -86,7 +88,7 @@ async def async_setup_entry(hass, entry): password, token ) - + _LOGGER.info("Context-setup and start the thread") _LOGGER.info("Thread started") @@ -147,7 +149,7 @@ class GeoRideContext: def email(self): """ current email """ return self._email - + @property def password(self): """ password """ @@ -224,9 +226,9 @@ class GeoRideContext: """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()) + await self.get_token()) for refreshed_tracker in new_georide_trackers: - found = False + found = False for tracker in self._georide_trackers: if tracker.tracker_id == refreshed_tracker.tracker_id: tracker.update_all_data(refreshed_tracker) @@ -256,7 +258,7 @@ class GeoRideContext: update_interval=update_interval ) self._georide_trackers_coordoned.append({ - "tracker": tracker, + "tracker_device": Device(tracker), "coordinator": coordinator }) @@ -270,7 +272,7 @@ class GeoRideContext: def socket(self): """ hold the GeoRide socket """ return self._socket - + @socket.setter def socket(self, socket): """set the GeoRide socket""" @@ -281,7 +283,7 @@ class GeoRideContext: """on lock callback""" _LOGGER.info("On lock received") for coordoned_tracker in self._georide_trackers_coordoned: - tracker = coordoned_tracker['tracker'] + tracker = coordoned_tracker['tracker_device'].tracker coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: tracker.locked_latitude = data['lockedLatitude'] @@ -298,7 +300,7 @@ class GeoRideContext: """on device callback""" _LOGGER.info("On device received") for coordoned_tracker in self._georide_trackers_coordoned: - tracker = coordoned_tracker['tracker'] + tracker = coordoned_tracker['tracker_device'].tracker coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: tracker.status = data['status'] @@ -312,7 +314,7 @@ class GeoRideContext: """on device callback""" _LOGGER.info("On alarm received") for coordoned_tracker in self._georide_trackers_coordoned: - tracker = coordoned_tracker['tracker'] + tracker = coordoned_tracker['tracker_device'].tracker coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: if data.name == 'vibration': @@ -330,7 +332,13 @@ class GeoRideContext: elif data.name == 'powerCut': _LOGGER.info("powerCut detected") else: - _LOGGER.warning("Unamanged alarm: ", data.name) + _LOGGER.warning("Unamanged alarm: %s", data.name) + + event_data = { + "device_id": tracker.tracker_id, + "type": data.name, + } + self._hass.bus.async_fire(f"{DOMAIN}_event", event_data) asyncio.run_coroutine_threadsafe( coordinator.async_request_refresh(), self._hass.loop ).result() @@ -341,7 +349,7 @@ class GeoRideContext: """on position callback""" _LOGGER.info("On position received") for coordoned_tracker in self._georide_trackers_coordoned: - tracker = coordoned_tracker['tracker'] + tracker = coordoned_tracker['tracker_device'].tracker coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: tracker.latitude = data['latitude'] @@ -354,4 +362,3 @@ class GeoRideContext: ).result() break - diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 4128747..4c5a777 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -2,7 +2,6 @@ import logging -from datetime import timedelta from typing import Any, Mapping from homeassistant.core import callback @@ -13,27 +12,26 @@ from homeassistant.helpers.update_coordinator import ( DataUpdateCoordinator ) -import georideapilib.api as GeoRideApi -import georideapilib.objects as GeoRideTracker from .const import DOMAIN as GEORIDE_DOMAIN +from .device import Device - -_LOGGER = logging.getLogger(__name__) +_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"] entities = [] coordoned_trackers = georide_context.get_coordoned_trackers() for coordoned_tracker in coordoned_trackers: - tracker = coordoned_tracker['tracker'] + tracker_device = coordoned_tracker['tracker_device'] coordinator = coordoned_tracker['coordinator'] - 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 + entities.append(GeoRideStolenBinarySensorEntity(coordinator, tracker_device)) + entities.append(GeoRideCrashedBinarySensorEntity(coordinator, tracker_device)) + entities.append(GeoRideOwnerBinarySensorEntity(coordinator, tracker_device)) + entities.append(GeoRideActiveSubscriptionBinarySensorEntity(coordinator, tracker_device)) + + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator async_add_entities(entities, True) @@ -43,71 +41,117 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d class GeoRideBinarySensorEntity(CoordinatorEntity, BinarySensorEntity): """Represent a tracked device.""" def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], - tracker: GeoRideTracker): + tracker_device: Device): """Set up Georide entity.""" super().__init__(coordinator) - self._tracker = tracker - self._name = tracker.tracker_name + self._tracker_device = tracker_device + self._name = tracker_device.tracker.tracker_name - self.entity_id = ENTITY_ID_FORMAT.format("is_stolen") + "." + str(tracker.tracker_id) + self.entity_id = f"{ENTITY_ID_FORMAT.format('binary_sensor')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 self._is_on = False + @property + def device_info(self): + """Return the device info.""" + return self._tracker_device.device_info + +class GeoRideStolenBinarySensorEntity(GeoRideBinarySensorEntity): + """Represent a tracked device.""" + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_device: Device): + """Set up Georide entity.""" + super().__init__(coordinator, tracker_device) + self.entity_id = f"{ENTITY_ID_FORMAT.format('is_stolen')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + @property def unique_id(self): """Return the unique ID.""" - return self._tracker.tracker_id + return f"is_stolen_{self._tracker_device.tracker.tracker_id}" + + @property + def is_on(self): + """state value property""" + return self._tracker_device.is_stolen @property def name(self): """ GeoRide odometer name """ - return self._name + return f"{self._name} is stolen" - @property - def device_info(self): - """Return the device info.""" - return { - "name": self.name, - "identifiers": {(GEORIDE_DOMAIN, self._tracker.tracker_id)}, - "manufacturer": "GeoRide" - } -class GeoRideStolenBinarySensorEntity(GeoRideBinarySensorEntity): +class GeoRideCrashedBinarySensorEntity(GeoRideBinarySensorEntity): """Represent a tracked device.""" + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], - tracker: GeoRideTracker): + tracker_device: Device): """Set up Georide entity.""" - super().__init__(coordinator, tracker) - self.entity_id = ENTITY_ID_FORMAT.format("is_stolen") + "." + str(tracker.tracker_id) + super().__init__(coordinator, tracker_device) + self.entity_id = f"{ENTITY_ID_FORMAT.format('is_crashed')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 @property def unique_id(self): """Return the unique ID.""" - return f"is_stolen_{self._tracker.tracker_id}" - + return f"is_crashed_{self._tracker_device.tracker.tracker_id}" + @property def is_on(self): """state value property""" - return self._tracker.is_stolen - + return self._tracker_device.tracker.is_crashed + @property + def name(self): + """ GeoRide odometer name """ + return f"{self._name} is crashed" +class GeoRideActiveSubscriptionBinarySensorEntity(GeoRideBinarySensorEntity): + """Represent a tracked device.""" -class GeoRideCrashedBinarySensorEntity(GeoRideBinarySensorEntity): + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_device: Device): + """Set up Georide entity.""" + super().__init__(coordinator, tracker_device) + self.entity_id = f"{ENTITY_ID_FORMAT.format('is_active_subscription_')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + + @property + def unique_id(self): + """Return the unique ID.""" + return f"is_active_subscription_{self._tracker_device.tracker.tracker_id}" + + @property + def is_on(self): + """state value property""" + if self._tracker.subscription_id is not None: + return True + return False + + @property + def name(self): + """ GeoRide odometer name """ + return f"{self._name} has an active subscription" + +class GeoRideOwnerBinarySensorEntity(GeoRideBinarySensorEntity): """Represent a tracked device.""" def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], - tracker: GeoRideTracker): + tracker_device: Device): """Set up Georide entity.""" - super().__init__(coordinator, tracker) - self.entity_id = ENTITY_ID_FORMAT.format("is_crashed") + "." + str(tracker.tracker_id) + super().__init__(coordinator, tracker_device) + self.entity_id = f"{ENTITY_ID_FORMAT.format('is_owner')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 @property def unique_id(self): """Return the unique ID.""" - return f"is_crashed_{self._tracker.tracker_id}" - + return f"is_owner_{self._tracker_device.tracker.tracker_id}" + @property def is_on(self): """state value property""" - return self._tracker.is_crashed - + if self._tracker_device.tracker.role == "owner": + return True + return False + + @property + def name(self): + """ GeoRide odometer name """ + return f"{self._name} is own tracker" + \ No newline at end of file diff --git a/custom_components/georide/device.py b/custom_components/georide/device.py new file mode 100644 index 0000000..d89f905 --- /dev/null +++ b/custom_components/georide/device.py @@ -0,0 +1,52 @@ +"""Home Assistant representation of an GeoRide Tracker device.""" +import georideapilib.objects as GeoRideTracker +from .const import DOMAIN as GEORIDE_DOMAIN + + +class Device: + """Home Assistant representation of a GeoRide Tracker device.""" + + def __init__(self, tracker): + """Initialize GeoRideTracker device.""" + self._tracker: GeoRideTracker = tracker + + @property + def name(self) -> str: + """Get the name.""" + return self._tracker.name + + @property + def manufacturer(self) -> str: + """Get the manufacturer.""" + return "GeoRide" + + @property + def model_name(self) -> str: + """Get the model name.""" + name = "GeoRide 1" + if self._tracker.is_old_tracker: + name = "Prototype / GeoRide 1" + elif self._tracker.is_second_gen: + name = "GeoRide 2 / GeoRide 3" + return name + + @property + def device_info(self): + """Return the device info.""" + return { + "name": self.name, + "identifiers": {(GEORIDE_DOMAIN, self._tracker.tracker_id)}, + "manufacturer": "GeoRide", + "model": self.model_name, + "suggested_area": "Garage" + } + + + @property + def unique_id(self) -> str: + """Get the unique id.""" + return {(GEORIDE_DOMAIN, self._tracker.tracker_id)} + + def __str__(self) -> str: + """Get string representation.""" + return f"GeoRide Device: {self.name}::{self.model_name}::self.unique_id" diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index faf1cea..ce57d8a 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -5,13 +5,13 @@ from typing import Any, Mapping from homeassistant.components.device_tracker.const import DOMAIN, SOURCE_TYPE_GPS from homeassistant.components.device_tracker.config_entry import TrackerEntity + from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, DataUpdateCoordinator, ) -import georideapilib.api as GeoRideApi - +from .device import Device from .const import DOMAIN as GEORIDE_DOMAIN @@ -24,10 +24,10 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d entities = [] for coordoned_tracker in coordoned_trackers: - tracker = coordoned_tracker['tracker'] + tracker_device = coordoned_tracker['tracker_device'] coordinator = coordoned_tracker['coordinator'] - entity = GeoRideTrackerEntity(coordinator, tracker, hass) - hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = coordinator + entity = GeoRideTrackerEntity(coordinator, tracker_device, hass) + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator entities.append(entity) async_add_entities(entities) @@ -38,12 +38,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d class GeoRideTrackerEntity(CoordinatorEntity, TrackerEntity): """Represent a tracked device.""" - def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker, hass): + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_device: Device, hass): """Set up GeoRide entity.""" super().__init__(coordinator) - self._name = tracker.tracker_name - self._tracker = tracker - self.entity_id = DOMAIN + ".{}".format(tracker.tracker_id) + self._name = tracker_device.tracker.tracker_name + self._tracker_device = tracker_device + self.entity_id = DOMAIN + ".{}".format(tracker_device.tracker.tracker_id) self._hass = hass @property @@ -53,29 +54,28 @@ class GeoRideTrackerEntity(CoordinatorEntity, TrackerEntity): @property def name(self): - """ame property""" - return self._name - + """ GeoRide odometer name """ + return f"{self._name} position" + @property def latitude(self): """Return latitude value of the device.""" - if self._tracker.latitude: - return self._tracker.latitude + if self._tracker_device.tracker.latitude: + return self._tracker_device.tracker.latitude return None @property def longitude(self): """Return longitude value of the device.""" - if self._tracker.longitude: - return self._tracker.longitude - + if self._tracker_device.tracker.longitude: + return self._tracker_device.tracker.longitude return None @property def source_type(self): """Return the source type, eg gps or router, of the device.""" return SOURCE_TYPE_GPS - + @property def location_accuracy(self): """ return the gps accuracy of georide (could not be aquired, then 10) """ @@ -89,26 +89,4 @@ class GeoRideTrackerEntity(CoordinatorEntity, TrackerEntity): @property def device_info(self): """Return the device info.""" - return { - "name": self.name, - "identifiers": {(GEORIDE_DOMAIN, self._tracker.tracker_id)}, - "manufacturer": "GeoRide", - "odometer": "{} km".format(self._tracker.odometer) - } - - @property - def get_tracker_callback(self): - """ get tracker callaback""" - return self._get_tracker_callback - - @property - def get_token_callback(self): - """ get token callaback""" - return self._get_token_callback - - - @property - def should_poll(self): - """No polling needed.""" - return True - + return self._tracker_device.device_info diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 854832a..0ab5500 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "documentation": "https://github.com/ptimatth/GeorideHA", "requirements": [ - "georideapilib>=0.5.0", + "georideapilib>=0.6.0", "pyjwt>=1.7.1" ], "dependencies": [], diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 5426262..b870e42 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -11,9 +11,8 @@ from homeassistant.helpers.update_coordinator import ( DataUpdateCoordinator, ) -import georideapilib.api as GeoRideApi - from .const import DOMAIN as GEORIDE_DOMAIN +from .device import Device _LOGGER = logging.getLogger(__name__) @@ -26,10 +25,10 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d entities = [] for coordoned_tracker in coordoned_trackers: - tracker = coordoned_tracker['tracker'] + tracker_device = coordoned_tracker['tracker_device'] coordinator = coordoned_tracker['coordinator'] - entity = GeoRideOdometerSensorEntity(coordinator, tracker, hass) - hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = coordinator + entity = GeoRideOdometerSensorEntity(coordinator, tracker_device, hass) + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator entities.append(entity) async_add_entities(entities) @@ -39,48 +38,44 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d class GeoRideOdometerSensorEntity(CoordinatorEntity, SensorEntity): """Represent a tracked device.""" - def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker, hass): + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_device:Device, hass): """Set up GeoRide entity.""" super().__init__(coordinator) - self._tracker = tracker - self._name = tracker.tracker_name + self._tracker_device = tracker_device + self._name = tracker_device.tracker.tracker_name self._unit_of_measurement = "m" - self.entity_id = ENTITY_ID_FORMAT.format("odometer") + "." + str(tracker.tracker_id) + self.entity_id = f"{ENTITY_ID_FORMAT.format('odometer')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + self._state = 0 self._hass = hass @property def unique_id(self): """Return the unique ID.""" - return self._tracker.tracker_id - - @property - def name(self): - """ GeoRide odometer name """ - return self._tracker.tracker_name + return self._tracker_device.tracker.tracker_id @property def state(self): """state property""" - return self._tracker.odometer + return self._tracker_device.tracker.odometer @property def unit_of_measurement(self): """unit of mesurment property""" return self._unit_of_measurement - + + @property + def name(self): + """ GeoRide odometer name """ + return f"{self._name} odometer" + @property def icon(self): """icon getter""" return "mdi:counter" - + @property def device_info(self): """Return the device info.""" - return { - "name": self.name, - "identifiers": {(GEORIDE_DOMAIN, self._tracker.tracker_id)}, - "manufacturer": "GeoRide" - } - - + return self._tracker_device.device_info() diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index f33b7a3..7158b32 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -3,10 +3,8 @@ 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 @@ -18,7 +16,7 @@ from homeassistant.helpers.update_coordinator import ( import georideapilib.api as GeoRideApi from .const import DOMAIN as GEORIDE_DOMAIN - +from .device import Device _LOGGER = logging.getLogger(__name__) @@ -30,29 +28,27 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d lock_switch_entities = [] for coordoned_tracker in coordoned_trackers: - tracker = coordoned_tracker['tracker'] + tracker_device = coordoned_tracker['tracker_device'] coordinator = coordoned_tracker['coordinator'] - entity = GeoRideLockSwitchEntity(coordinator, tracker, hass) - hass.data[GEORIDE_DOMAIN]["devices"][tracker.tracker_id] = coordinator + entity = GeoRideLockSwitchEntity(coordinator, tracker_device, hass) + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator lock_switch_entities.append(entity) async_add_entities(lock_switch_entities) return True - - class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): """Represent a tracked device.""" - def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker, hass): + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_device:Device, hass): """Set up GeoRide entity.""" super().__init__(coordinator) - self._tracker = tracker - self._name = tracker.tracker_name - self.entity_id = ENTITY_ID_FORMAT.format("lock") +"." + str(tracker.tracker_id) + self._tracker_device = tracker_device + self._name = tracker_device.tracker.tracker_name + self.entity_id = f"{ENTITY_ID_FORMAT.format('lock')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 self._hass = hass - async def async_turn_on(self, **kwargs): """ lock the GeoRide tracker """ @@ -60,17 +56,17 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): 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.tracker_id) + token, self._tracker_device.tracker.tracker_id) if success: self._tracker.is_locked = True - + async def async_turn_off(self, **kwargs): """ unlock the GeoRide tracker """ _LOGGER.info('async_turn_off %s', kwargs) 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.tracker_id) + token, self._tracker_device.tracker.tracker_id) if success: self._tracker.is_locked = False @@ -80,7 +76,7 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): 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.tracker_id) + token, self._tracker_device.tracker.tracker_id) self._tracker.is_locked = result @property @@ -90,29 +86,22 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): @property def name(self): - """ GeoRide switch name """ - return self._name - + """ GeoRide odometer name """ + return f"{self._name} lock" + @property def is_on(self): """ GeoRide switch status """ - return self._tracker.is_locked + return self._tracker_device.tracker.is_locked @property def icon(self): """return the entity icon""" - if self._tracker.tracker_id: + if self._tracker_device.tracker.is_locked: return "mdi:lock" return "mdi:lock-open" - @property def device_info(self): """Return the device info.""" - return { - "name": self.name, - "identifiers": {(GEORIDE_DOMAIN, self._tracker.tracker_id)}, - "manufacturer": "GeoRide" - } - - + return self._tracker_device.device_info() diff --git a/hacs.json b/hacs.json index 0c2b63c..33f17e1 100644 --- a/hacs.json +++ b/hacs.json @@ -4,5 +4,5 @@ "render_readme": true, "domains": ["devices_tracker", "sensor"], "country": ["FR"], - "homeassistant": "0.110.0" + "homeassistant": "2021.4.0" } \ No newline at end of file From 5e83ed1c680a278a98ad9d5a7e2b935ffae31a40 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 11 Apr 2021 17:00:33 +0200 Subject: [PATCH 19/20] Fix small mistakes --- custom_components/georide/__init__.py | 2 -- custom_components/georide/binary_sensor.py | 4 ++-- custom_components/georide/device.py | 7 ++++++- custom_components/georide/device_tracker.py | 2 +- custom_components/georide/sensor.py | 4 ++-- custom_components/georide/switch.py | 4 ++-- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 9ef15d6..55f926e 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -120,8 +120,6 @@ async def async_unload_entry(hass, entry): context = hass.data[DOMAIN]["context"] context.socket.disconnect() - hass.data[DOMAIN]["unsub"]() - return True diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 4c5a777..ac3ddff 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -71,7 +71,7 @@ class GeoRideStolenBinarySensorEntity(GeoRideBinarySensorEntity): @property def is_on(self): """state value property""" - return self._tracker_device.is_stolen + return self._tracker_device.tracker.is_stolen @property def name(self): @@ -120,7 +120,7 @@ class GeoRideActiveSubscriptionBinarySensorEntity(GeoRideBinarySensorEntity): @property def is_on(self): """state value property""" - if self._tracker.subscription_id is not None: + if self._tracker_device.tracker.subscription_id is not None: return True return False diff --git a/custom_components/georide/device.py b/custom_components/georide/device.py index d89f905..b3137e9 100644 --- a/custom_components/georide/device.py +++ b/custom_components/georide/device.py @@ -10,10 +10,15 @@ class Device: """Initialize GeoRideTracker device.""" self._tracker: GeoRideTracker = tracker + @property + def tracker(self): + """return the tracker""" + return self._tracker + @property def name(self) -> str: """Get the name.""" - return self._tracker.name + return self._tracker.tracker_name @property def manufacturer(self) -> str: diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index ce57d8a..8a5fc03 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -50,7 +50,7 @@ class GeoRideTrackerEntity(CoordinatorEntity, TrackerEntity): @property def unique_id(self): """Return the unique ID.""" - return f"georide_tracker_{self._tracker.tracker_id}" + return f"georide_tracker_{self._tracker_device.tracker.tracker_id}" @property def name(self): diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index b870e42..52d190d 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -53,7 +53,7 @@ class GeoRideOdometerSensorEntity(CoordinatorEntity, SensorEntity): @property def unique_id(self): """Return the unique ID.""" - return self._tracker_device.tracker.tracker_id + return f"odometer_{self._tracker_device.tracker.tracker_id}" @property def state(self): @@ -78,4 +78,4 @@ class GeoRideOdometerSensorEntity(CoordinatorEntity, SensorEntity): @property def device_info(self): """Return the device info.""" - return self._tracker_device.device_info() + return self._tracker_device.device_info diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index 7158b32..57f44be 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -82,7 +82,7 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): @property def unique_id(self): """Return the unique ID.""" - return self._tracker.tracker_id + return f"lock_{self._tracker_device.tracker_id}" @property def name(self): @@ -104,4 +104,4 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): @property def device_info(self): """Return the device info.""" - return self._tracker_device.device_info() + return self._tracker_device.device_info From 5c77acbdb714f87c1960e85c0f9c7b960bedc720 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 11 Apr 2021 17:14:40 +0200 Subject: [PATCH 20/20] Fire more home assistant event --- custom_components/georide/__init__.py | 22 +++++++++++++++++++++- custom_components/georide/switch.py | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 55f926e..69f5713 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -287,6 +287,13 @@ class GeoRideContext: tracker.locked_latitude = data['lockedLatitude'] tracker.locked_longitude = data['lockedLongitude'] tracker.is_locked = data['isLocked'] + + event_data = { + "device_id": tracker.tracker_id, + "type": "on_lock", + } + self._hass.bus.async_fire(f"{DOMAIN}_event", event_data) + asyncio.run_coroutine_threadsafe( coordinator.async_request_refresh(), self._hass.loop ).result() @@ -302,6 +309,13 @@ class GeoRideContext: coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: tracker.status = data['status'] + + event_data = { + "device_id": tracker.tracker_id, + "type": "on_device", + } + self._hass.bus.async_fire(f"{DOMAIN}_event", event_data) + asyncio.run_coroutine_threadsafe( coordinator.async_request_refresh(), self._hass.loop ).result() @@ -334,7 +348,7 @@ class GeoRideContext: event_data = { "device_id": tracker.tracker_id, - "type": data.name, + "type": f"alarm_{data.name}", } self._hass.bus.async_fire(f"{DOMAIN}_event", event_data) asyncio.run_coroutine_threadsafe( @@ -355,6 +369,12 @@ class GeoRideContext: tracker.moving = data['moving'] tracker.speed = data['speed'] tracker.fixtime = data['fixtime'] + + event_data = { + "device_id": tracker.tracker_id, + "type": "position", + } + self._hass.bus.async_fire(f"{DOMAIN}_event", event_data) asyncio.run_coroutine_threadsafe( coordinator.async_request_refresh(), self._hass.loop ).result() diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index 57f44be..71c3f11 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -82,7 +82,7 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity): @property def unique_id(self): """Return the unique ID.""" - return f"lock_{self._tracker_device.tracker_id}" + return f"lock_{self._tracker_device.tracker.tracker_id}" @property def name(self):