From fe073cff558a8af58f73a172a5cfe4cc3d40bb74 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Mon, 30 Aug 2021 19:42:22 +0200 Subject: [PATCH 01/51] Merge PR #3 --- README.md | 11 +- custom_components/georide/binary_sensor.py | 73 +++++++- custom_components/georide/manifest.json | 2 +- custom_components/georide/sensor.py | 183 ++++++++++++++++++++- 4 files changed, 259 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 37d8c04..f2fa0c2 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,15 @@ This component add some sensor for GeoRide Tracker Get GeoRide position Get GeoRide lock status Change GeoRide lock status - Add GeoRide from configuration.yml - Add GeoRide from interface Get stollen status Get crashed status Get is owner status Get subsription status + Get odomoter to km an m (2 entities) + Internal battery (of georide 3) (not work on GR1) + External battery (of the bike) (not work on GR1) + Fixtime (last registered positition of the georide) + ### What's events are available: you can filter by data.device_id == XX (XX is your tracker id) @@ -53,7 +56,7 @@ here is the alarm type available: (listen the georide_alarm_event) ## Question: -### How to have the odometer in Km ? +### How to have the odometer in Km ? (Deprecated, now you have an entity - thx @Inervo) Simply add a sensor like this in configuration.yaml (Replace XX by your tracker id) @@ -66,8 +69,6 @@ sensor: friendly_name: "Odometter - Km" value_template: "{{ states.sensor.odometer_XX.state | multiply(0.001) | round(3, 'flour') }}" unit_of_measurement: 'Km' - - ``` ### How to use the event: diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index ac3ddff..a733420 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -30,6 +30,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d entities.append(GeoRideCrashedBinarySensorEntity(coordinator, tracker_device)) entities.append(GeoRideOwnerBinarySensorEntity(coordinator, tracker_device)) entities.append(GeoRideActiveSubscriptionBinarySensorEntity(coordinator, tracker_device)) + entities.append(GeoRideNetworkBinarySensorEntity(coordinator, tracker_device)) + entities.append(GeoRideMovingBinarySensorEntity(coordinator, tracker_device)) hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator @@ -68,6 +70,11 @@ def unique_id(self): """Return the unique ID.""" return f"is_stolen_{self._tracker_device.tracker.tracker_id}" + @property + def device_class(self): + """Return the device class.""" + return "problem" + @property def is_on(self): """state value property""" @@ -93,6 +100,11 @@ def unique_id(self): """Return the unique ID.""" return f"is_crashed_{self._tracker_device.tracker.tracker_id}" + @property + def device_class(self): + """Return the device class.""" + return "problem" + @property def is_on(self): """state value property""" @@ -154,4 +166,63 @@ def is_on(self): def name(self): """ GeoRide odometer name """ return f"{self._name} is own tracker" - \ No newline at end of file + +class GeoRideNetworkBinarySensorEntity(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('have_network')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + + @property + def unique_id(self): + """Return the unique ID.""" + return f"have_network_{self._tracker_device.tracker.tracker_id}" + + @property + def device_class(self): + """Return the device class.""" + return "connectivity" + + @property + def is_on(self): + """state value property""" + if self._tracker_device.tracker.status == "online": + return True + return False + + @property + def name(self): + """ GeoRide name """ + return f"{self._name} have network" + +class GeoRideMovingBinarySensorEntity(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('moving')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + + @property + def unique_id(self): + """Return the unique ID.""" + return f"moving_{self._tracker_device.tracker.tracker_id}" + + @property + def device_class(self): + """Return the device class.""" + return "moving" + + @property + def is_on(self): + """state value property""" + return self._tracker_device.tracker.moving + + @property + def name(self): + """ GeoRide name """ + return f"{self._name} is moving" diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index af72fb5..69a2a00 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -9,5 +9,5 @@ ], "dependencies": [], "codeowners": ["ptimatth"], - "version": "0.7.2" + "version": "0.8.0" } \ No newline at end of file diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 52d190d..d02f732 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -27,9 +27,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d for coordoned_tracker in coordoned_trackers: tracker_device = coordoned_tracker['tracker_device'] coordinator = coordoned_tracker['coordinator'] - entity = GeoRideOdometerSensorEntity(coordinator, tracker_device, hass) hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator - entities.append(entity) + entities.append(GeoRideOdometerSensorEntity(coordinator, tracker_device, hass)) + entities.append(GeoRideOdometerKmSensorEntity(coordinator, tracker_device, hass)) + entities.append(GeoRideInternalBatterySensorEntity(coordinator, tracker_device)) + entities.append(GeoRideExternalBatterySensorEntity(coordinator, tracker_device)) + entities.append(GeoRideFixtimeSensorEntity(coordinator, tracker_device)) async_add_entities(entities) @@ -58,7 +61,8 @@ def unique_id(self): @property def state(self): """state property""" - return self._tracker_device.tracker.odometer + odometer = self._tracker_device.tracker.odometer + return odometer @property def unit_of_measurement(self): @@ -79,3 +83,176 @@ def icon(self): def device_info(self): """Return the device info.""" return self._tracker_device.device_info + +class GeoRideOdometerKmSensorEntity(CoordinatorEntity, SensorEntity): + """Represent a tracked device.""" + + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_device:Device, hass): + """Set up GeoRide entity.""" + super().__init__(coordinator) + self._tracker_device = tracker_device + self._name = tracker_device.tracker.tracker_name + self._unit_of_measurement = "km" + self.entity_id = f"{ENTITY_ID_FORMAT.format('odometer_km')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + + self._state = 0 + self._hass = hass + + @property + def unique_id(self): + """Return the unique ID.""" + return f"odometer_km_{self._tracker_device.tracker.tracker_id}" + + @property + def state(self): + """state property""" + odometer = self._tracker_device.tracker.odometer // 1000 + return 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 km" + + @property + def icon(self): + """icon getter""" + return "mdi:counter" + + @property + def device_info(self): + """Return the device info.""" + return self._tracker_device.device_info + +class GeoRideInternalBatterySensorEntity(CoordinatorEntity, SensorEntity): + """Represent a tracked device.""" + + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_device:Device): + """Set up GeoRide entity.""" + super().__init__(coordinator) + self._tracker_device = tracker_device + self._name = tracker_device.tracker.tracker_name + self._unit_of_measurement = "V" + self.entity_id = f"{ENTITY_ID_FORMAT.format('internal_battery_voltage')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + + self._state = 0 + + @property + def unique_id(self): + """Return the unique ID.""" + return f"internal_battery_voltage_{self._tracker_device.tracker.tracker_id}" + + @property + def state(self): + """state property""" + return self._tracker_device.tracker.internal_battery_voltage + + @property + def unit_of_measurement(self): + """unit of mesurment property""" + return self._unit_of_measurement + + @property + def name(self): + """ GeoRide internal_battery_voltage name """ + return f"{self._name} internal_battery_voltage" + + @property + def icon(self): + """icon getter""" + return "mdi:battery" + + @property + def device_info(self): + """Return the device info.""" + return self._tracker_device.device_info + +class GeoRideExternalBatterySensorEntity(CoordinatorEntity, SensorEntity): + """Represent a tracked device.""" + + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_device:Device): + """Set up GeoRide entity.""" + super().__init__(coordinator) + self._tracker_device = tracker_device + self._name = tracker_device.tracker.tracker_name + self._unit_of_measurement = "V" + self.entity_id = f"{ENTITY_ID_FORMAT.format('external_battery_voltage')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + + self._state = 0 + + @property + def unique_id(self): + """Return the unique ID.""" + return f"external_battery_voltage_{self._tracker_device.tracker.tracker_id}" + + @property + def state(self): + """state property""" + return self._tracker_device.tracker.external_battery_voltage + + @property + def unit_of_measurement(self): + """unit of mesurment property""" + return self._unit_of_measurement + + @property + def name(self): + """ GeoRide internal_battery_voltage name """ + return f"{self._name} external_battery_voltage" + + @property + def icon(self): + """icon getter""" + return "mdi:battery" + + @property + def device_info(self): + """Return the device info.""" + return self._tracker_device.device_info + +class GeoRideFixtimeSensorEntity(CoordinatorEntity, SensorEntity): + """Represent a tracked device.""" + + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_device:Device): + """Set up GeoRide entity.""" + super().__init__(coordinator) + self._tracker_device = tracker_device + self._name = tracker_device.tracker.tracker_name + self.entity_id = f"{ENTITY_ID_FORMAT.format('fixtime')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + + self._state = 0 + self._device_class = "timestamp" + + @property + def unique_id(self): + """Return the unique ID.""" + return f"fixtime_{self._tracker_device.tracker.tracker_id}" + + @property + def state(self): + """state property""" + return self._tracker_device.tracker.fixtime + + @property + def name(self): + """ GeoRide fixtime name """ + return f"{self._name} last fixed position" + + @property + def icon(self): + """icon getter""" + return "mdi:map-clock" + + @property + def device_info(self): + """Return the device info.""" + return self._tracker_device.device_info From b17f38ee660ccb1c4372ab027b2dcb188ceb7d81 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 10 Oct 2021 12:59:12 +0200 Subject: [PATCH 02/51] Fix #4 jwt decode afater update of hA to pyjwt 2.1.0 --- custom_components/georide/__init__.py | 2 +- custom_components/georide/manifest.json | 4 ++-- hacs.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 88f3081..0a830e4 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -184,7 +184,7 @@ async def connect_socket(self): async def get_token(self): """ here we return the current valid tocken """ - jwt_data = jwt.decode(self._token, verify=False) + jwt_data = jwt.decode(self._token, options={"verify_signature": False}) exp_timestamp = jwt_data['exp'] epoch = math.ceil(time.time()) diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 69a2a00..a3793e2 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -5,9 +5,9 @@ "documentation": "https://github.com/ptimatth/GeorideHA", "requirements": [ "georideapilib>=0.6.1", - "pyjwt>=1.7.1" + "pyjwt==2.1.0" ], "dependencies": [], "codeowners": ["ptimatth"], - "version": "0.8.0" + "version": "0.8.1" } \ No newline at end of file diff --git a/hacs.json b/hacs.json index 79d0e21..cec66f3 100644 --- a/hacs.json +++ b/hacs.json @@ -4,5 +4,5 @@ "render_readme": true, "domains": ["devices_tracker", "sensor"], "country": ["FR"], - "homeassistant": "2021.6.0" + "homeassistant": "2021.10.0" } \ No newline at end of file From af12cd70e45cb3cd2329d6873e4aea49d06231b9 Mon Sep 17 00:00:00 2001 From: Matthieu DUVAL Date: Mon, 24 Jan 2022 10:48:22 +0100 Subject: [PATCH 03/51] Add cloud and issue info --- custom_components/georide/manifest.json | 6 ++++-- hacs.json | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index a3793e2..800ea0d 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -3,11 +3,13 @@ "name": "GeoRide", "config_flow": true, "documentation": "https://github.com/ptimatth/GeorideHA", + "issue_tracker": "https://github.com/ptimatth/GeorideHA/issues", + "iot_class": "cloud_polling", "requirements": [ - "georideapilib>=0.6.1", + "georideapilib>=0.7.0", "pyjwt==2.1.0" ], "dependencies": [], "codeowners": ["ptimatth"], - "version": "0.8.1" + "version": "0.8.2" } \ No newline at end of file diff --git a/hacs.json b/hacs.json index cec66f3..d8e4f24 100644 --- a/hacs.json +++ b/hacs.json @@ -4,5 +4,5 @@ "render_readme": true, "domains": ["devices_tracker", "sensor"], "country": ["FR"], - "homeassistant": "2021.10.0" + "homeassistant": "2022.2.0" } \ No newline at end of file From adb6cef3c74f7f31dc7e0aeb2ef08d4b864efb3a Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 15:47:19 +0100 Subject: [PATCH 04/51] Add suport for new device beacon, siren control, eco_mode control, better device event --- custom_components/georide/__init__.py | 113 +++++++++++++++----- custom_components/georide/binary_sensor.py | 73 +++++++++++-- custom_components/georide/const.py | 2 + custom_components/georide/device.py | 67 ++++++++++-- custom_components/georide/device_tracker.py | 4 +- custom_components/georide/manifest.json | 2 +- custom_components/georide/sensor.py | 62 +++++++++-- custom_components/georide/siren.py | 91 ++++++++++++++++ custom_components/georide/switch.py | 72 +++++++++++-- 9 files changed, 432 insertions(+), 54 deletions(-) create mode 100644 custom_components/georide/siren.py diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 0a830e4..d6d0190 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -40,7 +40,8 @@ TRACKER_ID, TOKEN_SAFE_DAY, MIN_UNTIL_REFRESH, - DOMAIN + DOMAIN, + SIREN_ACTIVATION_DELAY ) @@ -105,6 +106,8 @@ async def async_setup_entry(hass, entry): hass.config_entries.async_forward_entry_setup(entry, "sensor")) hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, "binary_sensor")) + hass.async_create_task( + hass.config_entries.async_forward_entry_setup(entry, "siren")) return True @@ -115,6 +118,7 @@ async def async_unload_entry(hass, entry): 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") + await hass.config_entries.async_forward_entry_unload(entry, "siren") context = hass.data[DOMAIN]["context"] @@ -133,6 +137,8 @@ def __init__(self, hass, email, password, token): self._email = email self._password = password self._georide_trackers_coordoned = [] + self._georide_trackers_beacon_coordoned = [] + self._georide_trackers_beacon = [] self._georide_trackers = [] self._token = token self._socket = None @@ -176,7 +182,6 @@ async def connect_socket(self): 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() @@ -208,17 +213,31 @@ async def get_tracker(self, tracker_id): return tracker return {} + async def get_tracker_beacon(self, beacon_id): + """ here we return last tracker_beacon by id""" + for tracker_beacon in self._georide_trackers_beacon: + if tracker_beacon.beacon_id == beacon_id: + return tracker_beacon + return {} + + async def get_tracker_beacon_by_tracker_id(self, tracker_id): + """ here we return last tracker_beacon by id""" + for tracker_beacon in self._georide_trackers_beacon: + if tracker_beacon.linked_tracker_id == tracker_id: + return tracker_beacon + return {} + async def refresh_trackers(self): """ 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") - + for tracker in self._georide_trackers: + if tracker.is_siren_on: + if time.time() - SIREN_ACTIVATION_DELAY > tracker.siren_last_on_date: + tracker.is_siren_on = False async def force_refresh_trackers(self): """Used to refresh the tracker list""" @@ -230,16 +249,37 @@ async def force_refresh_trackers(self): for tracker in self._georide_trackers: if tracker.tracker_id == refreshed_tracker.tracker_id: tracker.update_all_data(refreshed_tracker) + if tracker.version > 2: + await force_refresh_trackers_beacon(tracker.tracker_id) found = True if not found: self._georide_trackers.append(refreshed_tracker) + if refreshed_tracker.version > 2: + await force_refresh_trackers_beacon(tracker.tracker_id) + 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_beacon(self, tracker_id): + """Used to refresh the tracker list""" + _LOGGER.info("Tracker beacon refresh") + new_georide_tracker_beacon = await self._hass.async_add_executor_job(GeoRideApi.get_tracker_beacon, + await self.get_token(), tracker_id) + found = False + for tracker_beacon in self._georide_trackers_beacon: + if tracker_beacon.tracker_id == new_georide_tracker_beacon.beacon_id: + tracker_beacon.update_all_data(new_georide_tracker_beacon) + found = True + if not found: + self._georide_trackers_beacon.append(new_georide_tracker_beacon) + 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""" @@ -255,16 +295,37 @@ async def init_context(self, hass): update_method=self.refresh_trackers, update_interval=update_interval ) - self._georide_trackers_coordoned.append({ - "tracker_device": Device(tracker), + + coordoned_tracker = { + "tracker_device": Device(tracker), + "coordinator": coordinator + } + if tracker.version > 2: + tracker_beacon = await get_tracker_beacon_by_tracker_id(tracker.tracker_id) + beacon_coordinator = DataUpdateCoordinator[Mapping[str, Any]]( + hass, + _LOGGER, + name=tracker_beacon.name + ) + coordoned_beacon = { + "beacon_device": DeviceBeacon(tracker_beacon), "coordinator": coordinator - }) + } + self._georide_trackers_beacon_coordoned(coordoned_beacon) + self._georide_trackers_coordoned.append(coordoned_tracker) - def get_coordoned_trackers(self): + @property + def georide_trackers_coordoned(self): """Return coordoned trackers""" return self._georide_trackers_coordoned + + @property + def georide_trackers_beacon_coordoned(self): + """Return coordoned trackers""" + + return self._georide_trackers_beacon_coordoned @property def socket(self): @@ -281,7 +342,8 @@ def on_lock_callback(self, data): """on lock callback""" _LOGGER.info("On lock received") for coordoned_tracker in self._georide_trackers_coordoned: - tracker = coordoned_tracker['tracker_device'].tracker + tracker_device = coordoned_tracker['tracker_device'] + tracker = tracker_device.tracker coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: tracker.locked_latitude = data['lockedLatitude'] @@ -289,8 +351,8 @@ def on_lock_callback(self, data): tracker.is_locked = data['isLocked'] event_data = { - "device_id": tracker.tracker_id, - "device_name": tracker.tracker_name + "device_id": tracker_device.unique_id, + "device_name": tracker_device.name, } self._hass.bus.async_fire(f"{DOMAIN}_lock_event", event_data) @@ -299,23 +361,21 @@ def on_lock_callback(self, data): ).result() break - @callback def on_device_callback(self, data): """on device callback""" _LOGGER.info("On device received") for coordoned_tracker in self._georide_trackers_coordoned: - tracker = coordoned_tracker['tracker_device'].tracker + tracker_device = coordoned_tracker['tracker_device'] + tracker = tracker_device.tracker coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: tracker.status = data['status'] - event_data = { - "device_id": tracker.tracker_id, - "device_name": tracker.tracker_name, + "device_id": tracker_device.unique_id, + "device_name": tracker_device.name, } self._hass.bus.async_fire(f"{DOMAIN}_device_event", event_data) - asyncio.run_coroutine_threadsafe( coordinator.async_request_refresh(), self._hass.loop ).result() @@ -326,7 +386,9 @@ def on_alarm_callback(self, data): """on device callback""" _LOGGER.info("On alarm received") for coordoned_tracker in self._georide_trackers_coordoned: - tracker = coordoned_tracker['tracker_device'].tracker + tracker_device = coordoned_tracker['tracker_device'] + tracker = tracker_device.tracker + coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: if data['name'] == 'vibration': @@ -355,12 +417,13 @@ def on_alarm_callback(self, data): _LOGGER.info("magnetOff detected") elif data['name'] == 'sonorAlarmOn': _LOGGER.info("sonorAlarmOn detected") + tracker.is_siren_on = True else: _LOGGER.warning("Unmanaged alarm: %s", data["name"]) event_data = { - "device_id": tracker.tracker_id, - "device_name": tracker.tracker_name, + "device_id": tracker_device.unique_id, + "device_name": tracker_device.name, "type": f"alarm_{data['name']}" } self._hass.bus.async_fire(f"{DOMAIN}_alarm_event", event_data) @@ -384,8 +447,8 @@ def on_position_callback(self, data): tracker.fixtime = data['fixtime'] event_data = { - "device_id": tracker.tracker_id, - "device_name": tracker.tracker_name + "device_id": tracker_device.unique_id, + "device_name": tracker_device.name, } self._hass.bus.async_fire(f"{DOMAIN}_position_event", event_data) asyncio.run_coroutine_threadsafe( diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index a733420..623bd4c 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -14,14 +14,14 @@ from .const import DOMAIN as GEORIDE_DOMAIN -from .device import Device +from .device import Device, DeviceBeacon _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() + coordoned_trackers = georide_context.georide_trackers_coordoned for coordoned_tracker in coordoned_trackers: tracker_device = coordoned_tracker['tracker_device'] coordinator = coordoned_tracker['coordinator'] @@ -33,7 +33,15 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d entities.append(GeoRideNetworkBinarySensorEntity(coordinator, tracker_device)) entities.append(GeoRideMovingBinarySensorEntity(coordinator, tracker_device)) - hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.unique_id] = coordinator + + coordoned_beacons = georide_context.georide_trackers_beacon_coordoned + for coordoned_beacon in coordoned_beacons: + tracker_beacon = coordoned_tracker['tracker_beacon'] + coordinator = coordoned_tracker['coordinator'] + entities.append(GeoRideBeaconUpdatedBinarySensorEntity(coordinator, tracker_beacon)) + hass.data[GEORIDE_DOMAIN]["devices"][tracker_beacon.unique_id] = coordinator + async_add_entities(entities, True) @@ -57,6 +65,22 @@ def device_info(self): """Return the device info.""" return self._tracker_device.device_info +class GeoRideBeaconBinarySensorEntity(CoordinatorEntity, BinarySensorEntity): + """Represent a tracked device.""" + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_device_beacon: DeviceBeacon): + """Set up Georide entity.""" + super().__init__(coordinator) + self._tracker_device_beacon = tracker_device_beacon + self._name = tracker_device_beacon.beacon.name + self.entity_id = f"{ENTITY_ID_FORMAT.format('binary_sensor')}.{tracker_device.beacon.beacon_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]], @@ -83,7 +107,7 @@ def is_on(self): @property def name(self): """ GeoRide odometer name """ - return f"{self._name} is stolen" + return f"{self._name} is not stolen" class GeoRideCrashedBinarySensorEntity(GeoRideBinarySensorEntity): @@ -132,9 +156,15 @@ def unique_id(self): @property def is_on(self): """state value property""" - if self._tracker_device.tracker.subscription_id is not None: - return True - return False + tracker = self._tracker_device.tracker + if tracker.is_oldsubscription: + if .tracker.subscription_id is not None: + return True + return False + else: + if tracker.subscription is not None and tracker.subscription.subscription_id is not None: + return True + return False @property def name(self): @@ -226,3 +256,32 @@ def is_on(self): def name(self): """ GeoRide name """ return f"{self._name} is moving" + +class GeoRideBeaconUpdatedBinarySensorEntity(GeoRideBeaconBinarySensorEntity): + """Represent a tracked device.""" + + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_beacon_device: DeviceBeacon): + """Set up Georide entity.""" + super().__init__(coordinator, tracker_device) + self.entity_id = f"{ENTITY_ID_FORMAT.format('update')}.{tracker_beacon_device.tracker_beacon.beacon_id}"# pylint: disable=C0301 + + @property + def unique_id(self): + """Return the unique ID.""" + return f"update_{self._tracker_beacon_device.beacon.beacon_id}" + + @property + def device_class(self): + """Return the device class.""" + return "update" + + @property + def is_on(self): + """state value property""" + return not self._tracker_beacon_device.beacon.is_updated + + @property + def name(self): + """ GeoRide name """ + return f"{self._name} have an update" \ No newline at end of file diff --git a/custom_components/georide/const.py b/custom_components/georide/const.py index abe697b..03e11ee 100644 --- a/custom_components/georide/const.py +++ b/custom_components/georide/const.py @@ -10,4 +10,6 @@ MIN_UNTIL_REFRESH = 10 +SIREN_ACTIVATION_DELAY = 30 + TOKEN_SAFE_DAY = 432000 # five days diff --git a/custom_components/georide/device.py b/custom_components/georide/device.py index b3137e9..cc3821b 100644 --- a/custom_components/georide/device.py +++ b/custom_components/georide/device.py @@ -1,5 +1,5 @@ """Home Assistant representation of an GeoRide Tracker device.""" -import georideapilib.objects as GeoRideTracker +import georideapilib.objects as GeoRideTracker, GeoRideTrackerBeacon from .const import DOMAIN as GEORIDE_DOMAIN @@ -28,11 +28,15 @@ def manufacturer(self) -> str: @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" + name = None + if self._tracker.version == 1: + name = "GeoRide 1" + elif self._tracker.version == 2: + name = "GeoRide 2" + elif self._tracker.version == 3: + name = "GeoRide 3" + else: + name = "Prototype / Unknown" return name @property @@ -54,4 +58,53 @@ def unique_id(self) -> str: def __str__(self) -> str: """Get string representation.""" - return f"GeoRide Device: {self.name}::{self.model_name}::self.unique_id" + return f"GeoRide Device: {self.name}::{self.model_name}::{self.unique_id}" + +class DeviceBeacon: + """Home Assistant representation of a GeoRide Tracker device.""" + + def __init__(self, beacon): + """Initialize GeoRideTracker device.""" + self._beacon: GeoRideTrackerBeacon = beacon + + @property + def beacon(self): + """return the tracker beacon""" + return self._beacon + + @property + def name(self) -> str: + """Get the name.""" + return self._beacon.name + + @property + def manufacturer(self) -> str: + """Get the manufacturer.""" + return "GeoRide" + + @property + def model_name(self) -> str: + """Get the model name.""" + name = "GeoRide Beacon" + return name + + @property + def device_info(self): + """Return the device info.""" + return { + "name": self.name, + "identifiers": {(GEORIDE_DOMAIN, self._beacon.beacon_id)}, + "manufacturer": "GeoRide", + "model": self.model_name, + "suggested_area": "Garage" + } + + + @property + def unique_id(self) -> str: + """Get the unique id.""" + return {(GEORIDE_DOMAIN, "beacon", self._beacon.beacon_id)} + + def __str__(self) -> str: + """Get string representation.""" + return f"GeoRide Device: {self.name}::{self.model_name}::{self.unique_id}" \ No newline at end of file diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index 8a5fc03..73ac313 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -20,14 +20,14 @@ 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() + coordoned_trackers = georide_context.georide_trackers_coordoned entities = [] for coordoned_tracker in coordoned_trackers: tracker_device = coordoned_tracker['tracker_device'] coordinator = coordoned_tracker['coordinator'] entity = GeoRideTrackerEntity(coordinator, tracker_device, hass) - hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.unique_id] = coordinator entities.append(entity) async_add_entities(entities) diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 800ea0d..0c3bf1d 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -6,7 +6,7 @@ "issue_tracker": "https://github.com/ptimatth/GeorideHA/issues", "iot_class": "cloud_polling", "requirements": [ - "georideapilib>=0.7.0", + "georideapilib>=0.8.0", "pyjwt==2.1.0" ], "dependencies": [], diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index d02f732..818ef46 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -21,20 +21,28 @@ 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() + coordoned_trackers = georide_context.georide_trackers_coordoned entities = [] for coordoned_tracker in coordoned_trackers: tracker_device = coordoned_tracker['tracker_device'] coordinator = coordoned_tracker['coordinator'] - hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.unique_id] = coordinator entities.append(GeoRideOdometerSensorEntity(coordinator, tracker_device, hass)) entities.append(GeoRideOdometerKmSensorEntity(coordinator, tracker_device, hass)) - entities.append(GeoRideInternalBatterySensorEntity(coordinator, tracker_device)) - entities.append(GeoRideExternalBatterySensorEntity(coordinator, tracker_device)) entities.append(GeoRideFixtimeSensorEntity(coordinator, tracker_device)) + if tracker_device.tracker.version > 2: + entities.append(GeoRideInternalBatterySensorEntity(coordinator, tracker_device)) + entities.append(GeoRideExternalBatterySensorEntity(coordinator, tracker_device)) + + coordoned_beacons = georide_context.georide_trackers_beacon_coordoned + for coordoned_beacon in coordoned_beacons: + tracker_beacon = coordoned_tracker['tracker_beacon'] + coordinator = coordoned_tracker['coordinator'] + entities.append(GeoRideBeaconUpdatedBinarySensorEntity(coordinator, tracker_beacon)) + hass.data[GEORIDE_DOMAIN]["devices"][tracker_beacon.unique_id] = coordinator - async_add_entities(entities) + await async_add_entities(entities) return True @@ -185,7 +193,6 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self._name = tracker_device.tracker.tracker_name self._unit_of_measurement = "V" self.entity_id = f"{ENTITY_ID_FORMAT.format('external_battery_voltage')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 - self._state = 0 @property @@ -256,3 +263,46 @@ def icon(self): def device_info(self): """Return the device info.""" return self._tracker_device.device_info + +class GeoRideBeaconBatterySensorEntity(CoordinatorEntity, SensorEntity): + """Represent a tracked device.""" + + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_beacon:DeviceBeacon): + """Set up GeoRide entity.""" + super().__init__(coordinator) + self._tracker_device = tracker_device + self._name = tracker_device.tracker.tracker_name + self._unit_of_measurement = "%" + self.entity_id = f"{ENTITY_ID_FORMAT.format('battery_percent')}.{tracker_beacon.beacon.beacon_id}"# pylint: disable=C0301 + self._state = 0 + + @property + def unique_id(self): + """Return the unique ID.""" + return f"battery_percent_{self._tracker_device.beacon.beacon_id}" + + @property + def state(self): + """state property""" + return self._tracker_device.beacon.battery_level + + @property + def unit_of_measurement(self): + """unit of mesurment property""" + return self._unit_of_measurement + + @property + def name(self): + """ GeoRide internal_battery_voltage name """ + return f"{self._name} battery percent" + + @property + def icon(self): + """icon getter""" + return "mdi:battery" + + @property + def device_info(self): + """Return the device info.""" + return self._tracker_device.device_info \ No newline at end of file diff --git a/custom_components/georide/siren.py b/custom_components/georide/siren.py new file mode 100644 index 0000000..16c23fd --- /dev/null +++ b/custom_components/georide/siren.py @@ -0,0 +1,91 @@ +""" device tracker for GeoRide object """ + +import logging + + +from typing import Any, Mapping + +from homeassistant.components.siren import SirenEntity +from homeassistant.components.siren import ENTITY_ID_FORMAT + +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, + DataUpdateCoordinator, +) + +import georideapilib.api as GeoRideApi + +from .const import DOMAIN as GEORIDE_DOMAIN +from .device import Device + +_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.georide_trackers_coordoned + + entities = [] + for coordoned_tracker in coordoned_trackers: + tracker_device = coordoned_tracker['tracker_device'] + coordinator = coordoned_tracker['coordinator'] + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.unique_id] = coordinator + if tracker_device.tracker.version > 2: + entities.append(GeoRideSirenEntity(coordinator, tracker_device, hass)) + + await async_add_entities(entities) + + return True + +class GeoRideSirenEntity(CoordinatorEntity, SirenEntity): + """Represent a tracked device.""" + + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_device:Device, hass): + """Set up GeoRide entity.""" + super().__init__(coordinator) + self._tracker_device = tracker_device + self._name = tracker_device.tracker.tracker_name + self.entity_id = f"{ENTITY_ID_FORMAT.format('eco_mode')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + self._hass = hass + + async def async_turn_on(self, **kwargs): + """ lock the GeoRide tracker """ + _LOGGER.info('async_turn_on eco %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.change_tracker_siren_state, + token, self._tracker_device.tracker.tracker_id, True) + if success: + self._tracker_device.tracker.is_siren_on = True + + async def async_turn_off(self, **kwargs): + """ unlock the GeoRide tracker """ + _LOGGER.info('async_turn_off eco %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.change_tracker_siren_state, + token, self._tracker_device.tracker.tracker_id, False) + if success: + self._tracker_device.tracker.is_siren_on = False + + @property + def unique_id(self): + """Return the unique ID.""" + return f"siren_{self._tracker_device.tracker.tracker_id}" + + @property + def name(self): + """ GeoRide odometer name """ + return f"{self._name} siren" + + @property + def is_on(self): + """ GeoRide switch status """ + return self._tracker_device.tracker.is_siren_on + + @property + def device_info(self): + """Return the device info.""" + return self._tracker_device.device_info \ No newline at end of file diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index 79f0a0b..191cafd 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -24,17 +24,18 @@ 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() + coordoned_trackers = georide_context.georide_trackers_coordoned - lock_switch_entities = [] + entities = [] for coordoned_tracker in coordoned_trackers: tracker_device = coordoned_tracker['tracker_device'] coordinator = coordoned_tracker['coordinator'] - entity = GeoRideLockSwitchEntity(coordinator, tracker_device, hass) - hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator - lock_switch_entities.append(entity) + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.unique_id] = coordinator + entities.append(GeoRideLockSwitchEntity(coordinator, tracker_device, hass)) + if tracker_device.tracker.version > 2: + entities.append(GeoRideEcoModeSwitchEntity(coordinator, tracker_device, hass)) - async_add_entities(lock_switch_entities) + async_add_entities(entities) return True @@ -105,3 +106,62 @@ def icon(self): def device_info(self): """Return the device info.""" return self._tracker_device.device_info + +class GeoRideEcoModeSwitchEntity(CoordinatorEntity, SwitchEntity): + """Represent a tracked device.""" + + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_device:Device, hass): + """Set up GeoRide entity.""" + super().__init__(coordinator) + self._tracker_device = tracker_device + self._name = tracker_device.tracker.tracker_name + self.entity_id = f"{ENTITY_ID_FORMAT.format('eco_mode')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + self._hass = hass + + async def async_turn_on(self, **kwargs): + """ lock the GeoRide tracker """ + _LOGGER.info('async_turn_on eco %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.change_tracker_eco_mode_state, + token, self._tracker_device.tracker.tracker_id, True) + if success: + self._tracker_device.tracker.is_in_eco = True + + async def async_turn_off(self, **kwargs): + """ unlock the GeoRide tracker """ + _LOGGER.info('async_turn_off eco %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.change_tracker_eco_mode_state, + token, self._tracker_device.tracker.tracker_id, False) + if success: + self._tracker_device.tracker.is_in_eco = False + + @property + def unique_id(self): + """Return the unique ID.""" + return f"eco_mode_{self._tracker_device.tracker.tracker_id}" + + @property + def name(self): + """ GeoRide odometer name """ + return f"{self._name} eco mode" + + @property + def is_on(self): + """ GeoRide switch status """ + return self._tracker_device.tracker.is_in_eco + + @property + def icon(self): + """return the entity icon""" + if self._tracker_device.tracker.is_in_eco: + return "mdi:battery-heart-variant" + return "mdi:battery" + + @property + def device_info(self): + """Return the device info.""" + return self._tracker_device.device_info \ No newline at end of file From 0555c63b7d2e414129392602a0dd322ce2b6890a Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 15:52:47 +0100 Subject: [PATCH 05/51] Bump version to 0.9.0 --- custom_components/georide/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 0c3bf1d..1d6addd 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -11,5 +11,5 @@ ], "dependencies": [], "codeowners": ["ptimatth"], - "version": "0.8.2" + "version": "0.9.0" } \ No newline at end of file From 09231c4fc07335e1632335915ebb7b3802f0bb3d Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 16:15:42 +0100 Subject: [PATCH 06/51] First steps of entity category --- custom_components/georide/manifest.json | 2 +- custom_components/georide/sensor.py | 38 +++++++++++++++++++++---- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 1d6addd..999d7f7 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -6,7 +6,7 @@ "issue_tracker": "https://github.com/ptimatth/GeorideHA/issues", "iot_class": "cloud_polling", "requirements": [ - "georideapilib>=0.8.0", + "georideapilib>=0.8.1", "pyjwt==2.1.0" ], "dependencies": [], diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 818ef46..5ea412c 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -4,6 +4,7 @@ from typing import Any, Mapping from homeassistant.core import callback +from homeassistant.helpers.entity import DeviceInfo, EntityCategory from homeassistant.components.sensor import SensorEntity from homeassistant.components.sensor import ENTITY_ID_FORMAT from homeassistant.helpers.update_coordinator import ( @@ -61,6 +62,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self._state = 0 self._hass = hass + @property + def entity_category(self): + return None + @property def unique_id(self): """Return the unique ID.""" @@ -88,7 +93,7 @@ def icon(self): return "mdi:counter" @property - def device_info(self): + def device_info(self) -> DeviceInfo: """Return the device info.""" return self._tracker_device.device_info @@ -107,6 +112,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self._state = 0 self._hass = hass + @property + def entity_category(self): + return EntityCategory.DIAGNOSTIC + @property def unique_id(self): """Return the unique ID.""" @@ -134,12 +143,13 @@ def icon(self): return "mdi:counter" @property - def device_info(self): + def device_info(self) -> DeviceInfo: """Return the device info.""" return self._tracker_device.device_info class GeoRideInternalBatterySensorEntity(CoordinatorEntity, SensorEntity): """Represent a tracked device.""" + entity_category = EntityCategory.DIAGNOSTIC def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker_device:Device): @@ -152,6 +162,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self._state = 0 + @property + def entity_category(self): + return EntityCategory.DIAGNOSTIC + @property def unique_id(self): """Return the unique ID.""" @@ -178,7 +192,7 @@ def icon(self): return "mdi:battery" @property - def device_info(self): + def device_info(self) -> DeviceInfo: """Return the device info.""" return self._tracker_device.device_info @@ -195,6 +209,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self.entity_id = f"{ENTITY_ID_FORMAT.format('external_battery_voltage')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 self._state = 0 + @property + def entity_category(self): + return EntityCategory.DIAGNOSTIC + @property def unique_id(self): """Return the unique ID.""" @@ -221,7 +239,7 @@ def icon(self): return "mdi:battery" @property - def device_info(self): + def device_info(self) -> DeviceInfo: """Return the device info.""" return self._tracker_device.device_info @@ -239,6 +257,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self._state = 0 self._device_class = "timestamp" + @property + def entity_category(self): + return EntityCategory.DIAGNOSTIC + @property def unique_id(self): """Return the unique ID.""" @@ -260,7 +282,7 @@ def icon(self): return "mdi:map-clock" @property - def device_info(self): + def device_info(self) -> DeviceInfo: """Return the device info.""" return self._tracker_device.device_info @@ -277,6 +299,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self.entity_id = f"{ENTITY_ID_FORMAT.format('battery_percent')}.{tracker_beacon.beacon.beacon_id}"# pylint: disable=C0301 self._state = 0 + @property + def entity_category(self): + return EntityCategory.DIAGNOSTIC + @property def unique_id(self): """Return the unique ID.""" @@ -303,6 +329,6 @@ def icon(self): return "mdi:battery" @property - def device_info(self): + def device_info(self) -> DeviceInfo: """Return the device info.""" return self._tracker_device.device_info \ No newline at end of file From 9f5b09dc4c7016615fda960ba914cec58754ba6a Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 16:50:34 +0100 Subject: [PATCH 07/51] Add entity category on All entities --- custom_components/georide/binary_sensor.py | 16 ++++++++++++++++ custom_components/georide/device.py | 2 +- custom_components/georide/device_tracker.py | 4 ++++ custom_components/georide/manifest.json | 2 +- custom_components/georide/siren.py | 4 ++++ custom_components/georide/switch.py | 8 ++++++++ 6 files changed, 34 insertions(+), 2 deletions(-) diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 623bd4c..2bdf912 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -5,6 +5,7 @@ from typing import Any, Mapping from homeassistant.core import callback +from homeassistant.helpers.entity import DeviceInfo, EntityCategory from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.components.binary_sensor import ENTITY_ID_FORMAT from homeassistant.helpers.update_coordinator import ( @@ -76,6 +77,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self.entity_id = f"{ENTITY_ID_FORMAT.format('binary_sensor')}.{tracker_device.beacon.beacon_id}"# pylint: disable=C0301 self._is_on = False + @property + def entity_category(self): + return None + @property def device_info(self): """Return the device info.""" @@ -148,6 +153,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], 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 entity_category(self): + return EntityCategory.DIAGNOSTIC + @property def unique_id(self): """Return the unique ID.""" @@ -206,6 +215,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], super().__init__(coordinator, tracker_device) self.entity_id = f"{ENTITY_ID_FORMAT.format('have_network')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + @property + def entity_category(self): + return EntityCategory.DIAGNOSTIC + @property def unique_id(self): """Return the unique ID.""" @@ -259,6 +272,9 @@ def name(self): class GeoRideBeaconUpdatedBinarySensorEntity(GeoRideBeaconBinarySensorEntity): """Represent a tracked device.""" + @property + def entity_category(self): + return EntityCategory.DIAGNOSTIC def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker_beacon_device: DeviceBeacon): diff --git a/custom_components/georide/device.py b/custom_components/georide/device.py index cc3821b..67110f1 100644 --- a/custom_components/georide/device.py +++ b/custom_components/georide/device.py @@ -1,5 +1,5 @@ """Home Assistant representation of an GeoRide Tracker device.""" -import georideapilib.objects as GeoRideTracker, GeoRideTrackerBeacon +from georideapilib.objects import GeoRideTracker, GeoRideTrackerBeacon from .const import DOMAIN as GEORIDE_DOMAIN diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index 73ac313..8bfb1b6 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -47,6 +47,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self.entity_id = DOMAIN + ".{}".format(tracker_device.tracker.tracker_id) self._hass = hass + @property + def entity_category(self): + return None + @property def unique_id(self): """Return the unique ID.""" diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 999d7f7..9a8d45a 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -6,7 +6,7 @@ "issue_tracker": "https://github.com/ptimatth/GeorideHA/issues", "iot_class": "cloud_polling", "requirements": [ - "georideapilib>=0.8.1", + "georideapilib==0.8.1", "pyjwt==2.1.0" ], "dependencies": [], diff --git a/custom_components/georide/siren.py b/custom_components/georide/siren.py index 16c23fd..7ef489f 100644 --- a/custom_components/georide/siren.py +++ b/custom_components/georide/siren.py @@ -50,6 +50,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self.entity_id = f"{ENTITY_ID_FORMAT.format('eco_mode')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 self._hass = hass + @property + def entity_category(self): + return None + async def async_turn_on(self, **kwargs): """ lock the GeoRide tracker """ _LOGGER.info('async_turn_on eco %s', kwargs) diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index 191cafd..01a5329 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -51,6 +51,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self.entity_id = f"{ENTITY_ID_FORMAT.format('lock')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 self._hass = hass + @property + def entity_category(self): + return None + async def async_turn_on(self, **kwargs): """ lock the GeoRide tracker """ _LOGGER.info('async_turn_on %s', kwargs) @@ -119,6 +123,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self.entity_id = f"{ENTITY_ID_FORMAT.format('eco_mode')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 self._hass = hass + @property + def entity_category(self): + return None + async def async_turn_on(self, **kwargs): """ lock the GeoRide tracker """ _LOGGER.info('async_turn_on eco %s', kwargs) From 80de6716497a14ccc42245442caeb59e4368c346 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 16:59:28 +0100 Subject: [PATCH 08/51] Small import fixes --- custom_components/georide/binary_sensor.py | 2 +- custom_components/georide/sensor.py | 2 +- custom_components/georide/siren.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 2bdf912..194a280 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -167,7 +167,7 @@ def is_on(self): """state value property""" tracker = self._tracker_device.tracker if tracker.is_oldsubscription: - if .tracker.subscription_id is not None: + if tracker.subscription_id is not None: return True return False else: diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 5ea412c..c2a89b2 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -13,7 +13,7 @@ ) from .const import DOMAIN as GEORIDE_DOMAIN -from .device import Device +from .device import Device, DeviceBeacon _LOGGER = logging.getLogger(__name__) diff --git a/custom_components/georide/siren.py b/custom_components/georide/siren.py index 7ef489f..2eb675f 100644 --- a/custom_components/georide/siren.py +++ b/custom_components/georide/siren.py @@ -6,7 +6,6 @@ from typing import Any, Mapping from homeassistant.components.siren import SirenEntity -from homeassistant.components.siren import ENTITY_ID_FORMAT from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, @@ -17,6 +16,7 @@ from .const import DOMAIN as GEORIDE_DOMAIN from .device import Device +ENTITY_ID_FORMAT: Final = DOMAIN + ".{}" _LOGGER = logging.getLogger(__name__) From 4dcf642260450240344b97552bd67e6d6484641c Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 17:08:24 +0100 Subject: [PATCH 09/51] Fix unique id format --- custom_components/georide/device.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/custom_components/georide/device.py b/custom_components/georide/device.py index 67110f1..0bf04fb 100644 --- a/custom_components/georide/device.py +++ b/custom_components/georide/device.py @@ -44,7 +44,7 @@ def device_info(self): """Return the device info.""" return { "name": self.name, - "identifiers": {(GEORIDE_DOMAIN, self._tracker.tracker_id)}, + "identifiers": self.unique_id, "manufacturer": "GeoRide", "model": self.model_name, "suggested_area": "Garage" @@ -54,7 +54,7 @@ def device_info(self): @property def unique_id(self) -> str: """Get the unique id.""" - return {(GEORIDE_DOMAIN, self._tracker.tracker_id)} + return f"{GEORIDE_DOMAIN}_{self._tracker.tracker_id}" def __str__(self) -> str: """Get string representation.""" @@ -93,17 +93,17 @@ def device_info(self): """Return the device info.""" return { "name": self.name, - "identifiers": {(GEORIDE_DOMAIN, self._beacon.beacon_id)}, + "identifiers": self.unique_id, "manufacturer": "GeoRide", "model": self.model_name, "suggested_area": "Garage" } - @property def unique_id(self) -> str: """Get the unique id.""" - return {(GEORIDE_DOMAIN, "beacon", self._beacon.beacon_id)} + + return f"{GEORIDE_DOMAIN}_beacon_{self._tracker.tracker_id}" def __str__(self) -> str: """Get string representation.""" From fd1032648978cd92b1ca9cdb9dd9d4850ec83854 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 17:17:56 +0100 Subject: [PATCH 10/51] Revert change on device id format --- custom_components/georide/binary_sensor.py | 4 ++-- custom_components/georide/device_tracker.py | 2 +- custom_components/georide/sensor.py | 6 +++--- custom_components/georide/siren.py | 3 ++- custom_components/georide/switch.py | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 194a280..71716fd 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -34,14 +34,14 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d entities.append(GeoRideNetworkBinarySensorEntity(coordinator, tracker_device)) entities.append(GeoRideMovingBinarySensorEntity(coordinator, tracker_device)) - hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.unique_id] = coordinator + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator coordoned_beacons = georide_context.georide_trackers_beacon_coordoned for coordoned_beacon in coordoned_beacons: tracker_beacon = coordoned_tracker['tracker_beacon'] coordinator = coordoned_tracker['coordinator'] entities.append(GeoRideBeaconUpdatedBinarySensorEntity(coordinator, tracker_beacon)) - hass.data[GEORIDE_DOMAIN]["devices"][tracker_beacon.unique_id] = coordinator + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.beacon.beacon_id] = coordinator async_add_entities(entities, True) diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index 8bfb1b6..e945043 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -27,7 +27,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d tracker_device = coordoned_tracker['tracker_device'] coordinator = coordoned_tracker['coordinator'] entity = GeoRideTrackerEntity(coordinator, tracker_device, hass) - hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.unique_id] = coordinator + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator entities.append(entity) async_add_entities(entities) diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index c2a89b2..0be66db 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -28,7 +28,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d for coordoned_tracker in coordoned_trackers: tracker_device = coordoned_tracker['tracker_device'] coordinator = coordoned_tracker['coordinator'] - hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.unique_id] = coordinator + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator entities.append(GeoRideOdometerSensorEntity(coordinator, tracker_device, hass)) entities.append(GeoRideOdometerKmSensorEntity(coordinator, tracker_device, hass)) entities.append(GeoRideFixtimeSensorEntity(coordinator, tracker_device)) @@ -41,9 +41,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d tracker_beacon = coordoned_tracker['tracker_beacon'] coordinator = coordoned_tracker['coordinator'] entities.append(GeoRideBeaconUpdatedBinarySensorEntity(coordinator, tracker_beacon)) - hass.data[GEORIDE_DOMAIN]["devices"][tracker_beacon.unique_id] = coordinator + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.beacon.beacon_id] = coordinator - await async_add_entities(entities) + async_add_entities(entities) return True diff --git a/custom_components/georide/siren.py b/custom_components/georide/siren.py index 2eb675f..dd72704 100644 --- a/custom_components/georide/siren.py +++ b/custom_components/georide/siren.py @@ -16,7 +16,8 @@ from .const import DOMAIN as GEORIDE_DOMAIN from .device import Device -ENTITY_ID_FORMAT: Final = DOMAIN + ".{}" + +ENTITY_ID_FORMAT: Final = GEORIDE_DOMAIN + ".{}" _LOGGER = logging.getLogger(__name__) diff --git a/custom_components/georide/switch.py b/custom_components/georide/switch.py index 01a5329..0559264 100644 --- a/custom_components/georide/switch.py +++ b/custom_components/georide/switch.py @@ -30,7 +30,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d for coordoned_tracker in coordoned_trackers: tracker_device = coordoned_tracker['tracker_device'] coordinator = coordoned_tracker['coordinator'] - hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.unique_id] = coordinator + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator entities.append(GeoRideLockSwitchEntity(coordinator, tracker_device, hass)) if tracker_device.tracker.version > 2: entities.append(GeoRideEcoModeSwitchEntity(coordinator, tracker_device, hass)) From e92ac1825d7f15e624e964b0913d388b599fe946 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 17:28:10 +0100 Subject: [PATCH 11/51] Fix siren and device unique id --- custom_components/georide/device.py | 4 ++-- custom_components/georide/siren.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_components/georide/device.py b/custom_components/georide/device.py index 0bf04fb..a7276c4 100644 --- a/custom_components/georide/device.py +++ b/custom_components/georide/device.py @@ -54,7 +54,7 @@ def device_info(self): @property def unique_id(self) -> str: """Get the unique id.""" - return f"{GEORIDE_DOMAIN}_{self._tracker.tracker_id}" + return {(GEORIDE_DOMAIN, self._tracker.tracker_id)} def __str__(self) -> str: """Get string representation.""" @@ -103,7 +103,7 @@ def device_info(self): def unique_id(self) -> str: """Get the unique id.""" - return f"{GEORIDE_DOMAIN}_beacon_{self._tracker.tracker_id}" + return {(GEORIDE_DOMAIN, self._beacon.beacon_id)} def __str__(self) -> str: """Get string representation.""" diff --git a/custom_components/georide/siren.py b/custom_components/georide/siren.py index dd72704..d507210 100644 --- a/custom_components/georide/siren.py +++ b/custom_components/georide/siren.py @@ -17,7 +17,7 @@ from .const import DOMAIN as GEORIDE_DOMAIN from .device import Device -ENTITY_ID_FORMAT: Final = GEORIDE_DOMAIN + ".{}" +ENTITY_ID_FORMAT = GEORIDE_DOMAIN + ".{}" _LOGGER = logging.getLogger(__name__) @@ -31,7 +31,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d for coordoned_tracker in coordoned_trackers: tracker_device = coordoned_tracker['tracker_device'] coordinator = coordoned_tracker['coordinator'] - hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.unique_id] = coordinator + hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator if tracker_device.tracker.version > 2: entities.append(GeoRideSirenEntity(coordinator, tracker_device, hass)) From 4dc091525ea9205a0780631910406ddfb4c973c9 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 17:53:51 +0100 Subject: [PATCH 12/51] Fix force_refresh_trackers_beacon --- custom_components/georide/__init__.py | 6 +++--- custom_components/georide/sensor.py | 6 +----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index d6d0190..da92000 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -250,12 +250,12 @@ async def force_refresh_trackers(self): if tracker.tracker_id == refreshed_tracker.tracker_id: tracker.update_all_data(refreshed_tracker) if tracker.version > 2: - await force_refresh_trackers_beacon(tracker.tracker_id) + await self.force_refresh_trackers_beacon(tracker.tracker_id) found = True if not found: self._georide_trackers.append(refreshed_tracker) if refreshed_tracker.version > 2: - await force_refresh_trackers_beacon(tracker.tracker_id) + await self.force_refresh_trackers_beacon(tracker.tracker_id) if not self._thread_started: _LOGGER.info("Start the thread") @@ -320,7 +320,7 @@ def georide_trackers_coordoned(self): """Return coordoned trackers""" return self._georide_trackers_coordoned - + @property def georide_trackers_beacon_coordoned(self): """Return coordoned trackers""" diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 0be66db..c8ba6d1 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -111,11 +111,7 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self._state = 0 self._hass = hass - - @property - def entity_category(self): - return EntityCategory.DIAGNOSTIC - + @property def unique_id(self): """Return the unique ID.""" From 9e2e6e8d5348cd9146a3997612f6cfc72dde0902 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 17:56:29 +0100 Subject: [PATCH 13/51] remove await on force_refresh_trackers_beacon --- custom_components/georide/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index da92000..89f535d 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -250,13 +250,12 @@ async def force_refresh_trackers(self): if tracker.tracker_id == refreshed_tracker.tracker_id: tracker.update_all_data(refreshed_tracker) if tracker.version > 2: - await self.force_refresh_trackers_beacon(tracker.tracker_id) + self.force_refresh_trackers_beacon(tracker.tracker_id) found = True if not found: self._georide_trackers.append(refreshed_tracker) if refreshed_tracker.version > 2: - await self.force_refresh_trackers_beacon(tracker.tracker_id) - + self.force_refresh_trackers_beacon(tracker.tracker_id) if not self._thread_started: _LOGGER.info("Start the thread") # We refresh the tracker list each hours From 759fe2d25775e7ea8ac1f6b14d407cf0a8d9a321 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 18:00:03 +0100 Subject: [PATCH 14/51] Fix "local variable 'tracker' referenced before assignment" --- 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 89f535d..d995ccf 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -255,7 +255,7 @@ async def force_refresh_trackers(self): if not found: self._georide_trackers.append(refreshed_tracker) if refreshed_tracker.version > 2: - self.force_refresh_trackers_beacon(tracker.tracker_id) + self.force_refresh_trackers_beacon(new_georide_trackers.tracker_id) if not self._thread_started: _LOGGER.info("Start the thread") # We refresh the tracker list each hours From 1250dda0477e66532289df8f4967634e30902c14 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 18:04:10 +0100 Subject: [PATCH 15/51] Fix "list' object has no attribute 'tracker_id' " --- 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 d995ccf..0124b12 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -255,7 +255,7 @@ async def force_refresh_trackers(self): if not found: self._georide_trackers.append(refreshed_tracker) if refreshed_tracker.version > 2: - self.force_refresh_trackers_beacon(new_georide_trackers.tracker_id) + self.force_refresh_trackers_beacon(new_georide_tracker.tracker_id) if not self._thread_started: _LOGGER.info("Start the thread") # We refresh the tracker list each hours From 32db0ec42e4713d4a1bb1d01a36b3cc70ed38850 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 18:07:37 +0100 Subject: [PATCH 16/51] Fix "NameError: name 'new_georide_tracker' is not defined" --- 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 0124b12..874d653 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -255,7 +255,7 @@ async def force_refresh_trackers(self): if not found: self._georide_trackers.append(refreshed_tracker) if refreshed_tracker.version > 2: - self.force_refresh_trackers_beacon(new_georide_tracker.tracker_id) + self.force_refresh_trackers_beacon(refreshed_tracker.tracker_id) if not self._thread_started: _LOGGER.info("Start the thread") # We refresh the tracker list each hours From a37cca790228a2c210fb0fc9e883f964bc792553 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 18:11:28 +0100 Subject: [PATCH 17/51] Fix missing get_tracker_beacon_by_tracker_id --- 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 874d653..9c06002 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -300,7 +300,7 @@ async def init_context(self, hass): "coordinator": coordinator } if tracker.version > 2: - tracker_beacon = await get_tracker_beacon_by_tracker_id(tracker.tracker_id) + tracker_beacon = await self.get_tracker_beacon_by_tracker_id(tracker.tracker_id) beacon_coordinator = DataUpdateCoordinator[Mapping[str, Any]]( hass, _LOGGER, From a3c84c63fd50bf6d01d4468b0400129164b50135 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 18:18:46 +0100 Subject: [PATCH 18/51] Fix missing tracker in list --- custom_components/georide/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 9c06002..c8bd2a0 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -250,12 +250,12 @@ async def force_refresh_trackers(self): if tracker.tracker_id == refreshed_tracker.tracker_id: tracker.update_all_data(refreshed_tracker) if tracker.version > 2: - self.force_refresh_trackers_beacon(tracker.tracker_id) + await self.force_refresh_trackers_beacon(tracker.tracker_id) found = True if not found: self._georide_trackers.append(refreshed_tracker) if refreshed_tracker.version > 2: - self.force_refresh_trackers_beacon(refreshed_tracker.tracker_id) + await self.force_refresh_trackers_beacon(refreshed_tracker.tracker_id) if not self._thread_started: _LOGGER.info("Start the thread") # We refresh the tracker list each hours @@ -304,7 +304,7 @@ async def init_context(self, hass): beacon_coordinator = DataUpdateCoordinator[Mapping[str, Any]]( hass, _LOGGER, - name=tracker_beacon.name + name= tracker_beacon.name ) coordoned_beacon = { "beacon_device": DeviceBeacon(tracker_beacon), From 3000d5588be67413ee0629477207b46a14e05dfe Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 18:42:07 +0100 Subject: [PATCH 19/51] Fix support multiple tracker beacon --- custom_components/georide/__init__.py | 48 +++++++++++++------------ custom_components/georide/manifest.json | 2 +- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index c8bd2a0..745d863 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -220,12 +220,13 @@ async def get_tracker_beacon(self, beacon_id): return tracker_beacon return {} - async def get_tracker_beacon_by_tracker_id(self, tracker_id): + async def get_tracker_beacons_by_tracker_id(self, tracker_id): """ here we return last tracker_beacon by id""" + filtered_beacon = [] for tracker_beacon in self._georide_trackers_beacon: if tracker_beacon.linked_tracker_id == tracker_id: - return tracker_beacon - return {} + filtered_beacon.append(tracker_beacon) + return filtered_beacon async def refresh_trackers(self): """ here we return last tracker by id""" @@ -265,15 +266,17 @@ async def force_refresh_trackers(self): async def force_refresh_trackers_beacon(self, tracker_id): """Used to refresh the tracker list""" _LOGGER.info("Tracker beacon refresh") - new_georide_tracker_beacon = await self._hass.async_add_executor_job(GeoRideApi.get_tracker_beacon, + new_georide_tracker_beacons = await self._hass.async_add_executor_job(GeoRideApi.get_tracker_beacon, await self.get_token(), tracker_id) - found = False - for tracker_beacon in self._georide_trackers_beacon: - if tracker_beacon.tracker_id == new_georide_tracker_beacon.beacon_id: - tracker_beacon.update_all_data(new_georide_tracker_beacon) - found = True - if not found: - self._georide_trackers_beacon.append(new_georide_tracker_beacon) + + for new_georide_tracker_beacon in new_georide_tracker_beacons: + found = False + for tracker_beacon in self._georide_trackers_beacon: + if tracker_beacon.tracker_id == new_georide_tracker_beacon.beacon_id: + tracker_beacon.update_all_data(new_georide_tracker_beacon) + found = True + if not found: + self._georide_trackers_beacon.append(new_georide_tracker_beacon) if not self._thread_started: _LOGGER.info("Start the thread") # We refresh the tracker list each hours @@ -300,17 +303,18 @@ async def init_context(self, hass): "coordinator": coordinator } if tracker.version > 2: - tracker_beacon = await self.get_tracker_beacon_by_tracker_id(tracker.tracker_id) - beacon_coordinator = DataUpdateCoordinator[Mapping[str, Any]]( - hass, - _LOGGER, - name= tracker_beacon.name - ) - coordoned_beacon = { - "beacon_device": DeviceBeacon(tracker_beacon), - "coordinator": coordinator - } - self._georide_trackers_beacon_coordoned(coordoned_beacon) + tracker_beacons = await self.get_tracker_beacon_by_tracker_id(tracker.tracker_id) + for tracker_beacon in tracker_beacons + beacon_coordinator = DataUpdateCoordinator[Mapping[str, Any]]( + hass, + _LOGGER, + name= tracker_beacon.name + ) + coordoned_beacon = { + "beacon_device": DeviceBeacon(tracker_beacon), + "coordinator": coordinator + } + self._georide_trackers_beacon_coordoned.append(coordoned_beacon) self._georide_trackers_coordoned.append(coordoned_tracker) diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 9a8d45a..6f680c7 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -6,7 +6,7 @@ "issue_tracker": "https://github.com/ptimatth/GeorideHA/issues", "iot_class": "cloud_polling", "requirements": [ - "georideapilib==0.8.1", + "georideapilib>=0.8.2", "pyjwt==2.1.0" ], "dependencies": [], From d326726138ad9673ed056659890c41fa1ec1f0de Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 18:45:58 +0100 Subject: [PATCH 20/51] Fix invalid sintax --- custom_components/georide/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 745d863..f59106a 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -268,7 +268,6 @@ async def force_refresh_trackers_beacon(self, tracker_id): _LOGGER.info("Tracker beacon refresh") new_georide_tracker_beacons = await self._hass.async_add_executor_job(GeoRideApi.get_tracker_beacon, await self.get_token(), tracker_id) - for new_georide_tracker_beacon in new_georide_tracker_beacons: found = False for tracker_beacon in self._georide_trackers_beacon: @@ -304,7 +303,7 @@ async def init_context(self, hass): } if tracker.version > 2: tracker_beacons = await self.get_tracker_beacon_by_tracker_id(tracker.tracker_id) - for tracker_beacon in tracker_beacons + for tracker_beacon in tracker_beacons: beacon_coordinator = DataUpdateCoordinator[Mapping[str, Any]]( hass, _LOGGER, From 73d15f8c9aa381853b7e1f6f7e2ada96ca34371f Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 18:49:55 +0100 Subject: [PATCH 21/51] Fix mist spelling of get_tracker_beacons --- custom_components/georide/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index f59106a..2053a9c 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -266,7 +266,7 @@ async def force_refresh_trackers(self): async def force_refresh_trackers_beacon(self, tracker_id): """Used to refresh the tracker list""" _LOGGER.info("Tracker beacon refresh") - new_georide_tracker_beacons = await self._hass.async_add_executor_job(GeoRideApi.get_tracker_beacon, + new_georide_tracker_beacons = await self._hass.async_add_executor_job(GeoRideApi.get_tracker_beacons, await self.get_token(), tracker_id) for new_georide_tracker_beacon in new_georide_tracker_beacons: found = False @@ -302,7 +302,7 @@ async def init_context(self, hass): "coordinator": coordinator } if tracker.version > 2: - tracker_beacons = await self.get_tracker_beacon_by_tracker_id(tracker.tracker_id) + tracker_beacons = await self.get_tracker_beacons_by_tracker_id(tracker.tracker_id) for tracker_beacon in tracker_beacons: beacon_coordinator = DataUpdateCoordinator[Mapping[str, Any]]( hass, From f36a3093bf1335c6c8c6633d38e1574d1c764e5f Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 18:55:12 +0100 Subject: [PATCH 22/51] Fix missing import beacon --- custom_components/georide/__init__.py | 2 +- custom_components/georide/binary_sensor.py | 2 +- custom_components/georide/sensor.py | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 2053a9c..c5978a6 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -32,7 +32,7 @@ ) -from .device import Device +from .device import Device, DeviceBeacon from .const import ( CONF_EMAIL, CONF_PASSWORD, diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 71716fd..b631e31 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -142,7 +142,7 @@ def is_on(self): @property def name(self): """ GeoRide odometer name """ - return f"{self._name} is crashed" + return f"{self._name} is not crashed" class GeoRideActiveSubscriptionBinarySensorEntity(GeoRideBinarySensorEntity): """Represent a tracked device.""" diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index c8ba6d1..9e457b3 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -108,10 +108,9 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self._name = tracker_device.tracker.tracker_name self._unit_of_measurement = "km" self.entity_id = f"{ENTITY_ID_FORMAT.format('odometer_km')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 - self._state = 0 self._hass = hass - + @property def unique_id(self): """Return the unique ID.""" From e9262ff3d458d692f626288df73e287be5664c77 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 19:01:22 +0100 Subject: [PATCH 23/51] Fix coordinator device name, await on add entity --- custom_components/georide/__init__.py | 2 +- custom_components/georide/siren.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index c5978a6..06cf152 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -310,7 +310,7 @@ async def init_context(self, hass): name= tracker_beacon.name ) coordoned_beacon = { - "beacon_device": DeviceBeacon(tracker_beacon), + "tracker_beacon": DeviceBeacon(tracker_beacon), "coordinator": coordinator } self._georide_trackers_beacon_coordoned.append(coordoned_beacon) diff --git a/custom_components/georide/siren.py b/custom_components/georide/siren.py index d507210..748f4fd 100644 --- a/custom_components/georide/siren.py +++ b/custom_components/georide/siren.py @@ -35,7 +35,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d if tracker_device.tracker.version > 2: entities.append(GeoRideSirenEntity(coordinator, tracker_device, hass)) - await async_add_entities(entities) + async_add_entities(entities) return True From ce06f109fef34e2d42d04faea415059f08dbbaf1 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 19:07:54 +0100 Subject: [PATCH 24/51] Beacon use wrong coordinator --- custom_components/georide/__init__.py | 2 +- custom_components/georide/binary_sensor.py | 4 ++-- custom_components/georide/sensor.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 06cf152..849c48b 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -311,7 +311,7 @@ async def init_context(self, hass): ) coordoned_beacon = { "tracker_beacon": DeviceBeacon(tracker_beacon), - "coordinator": coordinator + "coordinator": beacon_coordinator } self._georide_trackers_beacon_coordoned.append(coordoned_beacon) self._georide_trackers_coordoned.append(coordoned_tracker) diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index b631e31..346717c 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -38,8 +38,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d coordoned_beacons = georide_context.georide_trackers_beacon_coordoned for coordoned_beacon in coordoned_beacons: - tracker_beacon = coordoned_tracker['tracker_beacon'] - coordinator = coordoned_tracker['coordinator'] + tracker_beacon = coordoned_beacon['tracker_beacon'] + coordinator = coordoned_beacon['coordinator'] entities.append(GeoRideBeaconUpdatedBinarySensorEntity(coordinator, tracker_beacon)) hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.beacon.beacon_id] = coordinator diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 9e457b3..c787639 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -38,8 +38,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d coordoned_beacons = georide_context.georide_trackers_beacon_coordoned for coordoned_beacon in coordoned_beacons: - tracker_beacon = coordoned_tracker['tracker_beacon'] - coordinator = coordoned_tracker['coordinator'] + tracker_beacon = coordoned_beacon['tracker_beacon'] + coordinator = coordoned_beacon['coordinator'] entities.append(GeoRideBeaconUpdatedBinarySensorEntity(coordinator, tracker_beacon)) hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.beacon.beacon_id] = coordinator From bf1e138c0549576ad47525d740a0ac9cd0354dac Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 19:12:55 +0100 Subject: [PATCH 25/51] Fix wrong sensor setup --- custom_components/georide/binary_sensor.py | 2 +- custom_components/georide/sensor.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 346717c..8bef3dd 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -279,7 +279,7 @@ def entity_category(self): def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker_beacon_device: DeviceBeacon): """Set up Georide entity.""" - super().__init__(coordinator, tracker_device) + super().__init__(coordinator, tracker_beacon_device) self.entity_id = f"{ENTITY_ID_FORMAT.format('update')}.{tracker_beacon_device.tracker_beacon.beacon_id}"# pylint: disable=C0301 @property diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index c787639..4653637 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -40,7 +40,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d for coordoned_beacon in coordoned_beacons: tracker_beacon = coordoned_beacon['tracker_beacon'] coordinator = coordoned_beacon['coordinator'] - entities.append(GeoRideBeaconUpdatedBinarySensorEntity(coordinator, tracker_beacon)) + entities.append(GeoRideBeaconBatterySensorEntity(coordinator, tracker_beacon)) hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.beacon.beacon_id] = coordinator async_add_entities(entities) From 7f3d5d7ec773fb315060770ad8822f89843c9328 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 19:17:20 +0100 Subject: [PATCH 26/51] Fix tracker device not exist --- custom_components/georide/binary_sensor.py | 2 +- custom_components/georide/sensor.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 8bef3dd..e1cca3e 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -74,7 +74,7 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], super().__init__(coordinator) self._tracker_device_beacon = tracker_device_beacon self._name = tracker_device_beacon.beacon.name - self.entity_id = f"{ENTITY_ID_FORMAT.format('binary_sensor')}.{tracker_device.beacon.beacon_id}"# pylint: disable=C0301 + self.entity_id = f"{ENTITY_ID_FORMAT.format('binary_sensor')}.{tracker_device_beacon.beacon.beacon_id}"# pylint: disable=C0301 self._is_on = False @property diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 4653637..88929d4 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -285,11 +285,11 @@ class GeoRideBeaconBatterySensorEntity(CoordinatorEntity, SensorEntity): """Represent a tracked device.""" def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], - tracker_beacon:DeviceBeacon): + tracker_beacon: DeviceBeacon): """Set up GeoRide entity.""" super().__init__(coordinator) - self._tracker_device = tracker_device - self._name = tracker_device.tracker.tracker_name + self._tracker_device = tracker_beacon + self._name = tracker_beacon.beacon.name self._unit_of_measurement = "%" self.entity_id = f"{ENTITY_ID_FORMAT.format('battery_percent')}.{tracker_beacon.beacon.beacon_id}"# pylint: disable=C0301 self._state = 0 From 7a8702d57ce558eb184cc52cd6f91263ea5f0957 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 19:21:59 +0100 Subject: [PATCH 27/51] Fix 'DeviceBeacon' object has no attribute 'tracker_beacon' --- custom_components/georide/binary_sensor.py | 2 +- custom_components/georide/sensor.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index e1cca3e..0db7c6b 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -280,7 +280,7 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], tracker_beacon_device: DeviceBeacon): """Set up Georide entity.""" super().__init__(coordinator, tracker_beacon_device) - self.entity_id = f"{ENTITY_ID_FORMAT.format('update')}.{tracker_beacon_device.tracker_beacon.beacon_id}"# pylint: disable=C0301 + self.entity_id = f"{ENTITY_ID_FORMAT.format('update')}.{tracker_beacon_device.beacon.beacon_id}"# pylint: disable=C0301 @property def unique_id(self): diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 88929d4..3f447d5 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -41,7 +41,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d tracker_beacon = coordoned_beacon['tracker_beacon'] coordinator = coordoned_beacon['coordinator'] entities.append(GeoRideBeaconBatterySensorEntity(coordinator, tracker_beacon)) - hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.beacon.beacon_id] = coordinator + hass.data[GEORIDE_DOMAIN]["devices"][tracker_beacon.beacon.beacon_id] = coordinator async_add_entities(entities) From 9f70dc220fb76462e7c853de1fdca4ff12210e01 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 19:24:47 +0100 Subject: [PATCH 28/51] Fix 'Device' object has no attribute 'beacon' --- custom_components/georide/binary_sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 0db7c6b..8d6f6d5 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -41,7 +41,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d tracker_beacon = coordoned_beacon['tracker_beacon'] coordinator = coordoned_beacon['coordinator'] entities.append(GeoRideBeaconUpdatedBinarySensorEntity(coordinator, tracker_beacon)) - hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.beacon.beacon_id] = coordinator + hass.data[GEORIDE_DOMAIN]["devices"][tracker_beacon.beacon.beacon_id] = coordinator async_add_entities(entities, True) From 112cf68542003b3793d6f87a88a49cc885d5b739 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 19:34:00 +0100 Subject: [PATCH 29/51] Fix update method on coordinator --- custom_components/georide/__init__.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 849c48b..c188e4a 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -239,6 +239,10 @@ async def refresh_trackers(self): if tracker.is_siren_on: if time.time() - SIREN_ACTIVATION_DELAY > tracker.siren_last_on_date: tracker.is_siren_on = False + + async def refresh_trackers_beacon(self): + """ here we return last tracker by id""" + _LOGGER.debug("Do nothing, updated by another way") async def force_refresh_trackers(self): """Used to refresh the tracker list""" @@ -282,6 +286,8 @@ async def force_refresh_trackers_beacon(self, tracker_id): self._thread_started = True await self.connect_socket() + + async def init_context(self, hass): """Used to refresh the tracker list""" _LOGGER.info("Init_context") @@ -307,7 +313,9 @@ async def init_context(self, hass): beacon_coordinator = DataUpdateCoordinator[Mapping[str, Any]]( hass, _LOGGER, - name= tracker_beacon.name + name=tracker_beacon.name + update_method=self.refresh_trackers_beacon, + update_interval=update_interval ) coordoned_beacon = { "tracker_beacon": DeviceBeacon(tracker_beacon), From 1b2776f6465c3e89b35afa2c20fe7f8def818608 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 19:37:06 +0100 Subject: [PATCH 30/51] Fix update method on coordinator coma --- 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 c188e4a..8e67154 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -313,7 +313,7 @@ async def init_context(self, hass): beacon_coordinator = DataUpdateCoordinator[Mapping[str, Any]]( hass, _LOGGER, - name=tracker_beacon.name + name=tracker_beacon.name, update_method=self.refresh_trackers_beacon, update_interval=update_interval ) From e9da051fc139b0f25fa168f8f3b9543ddd4c8ae8 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 19:43:05 +0100 Subject: [PATCH 31/51] Fix attribute missing _tracker_device_beacon --- custom_components/georide/binary_sensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 8d6f6d5..148ae66 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -285,7 +285,7 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], @property def unique_id(self): """Return the unique ID.""" - return f"update_{self._tracker_beacon_device.beacon.beacon_id}" + return f"update_{self._tracker_device_beacon.beacon.beacon_id}" @property def device_class(self): @@ -295,7 +295,7 @@ def device_class(self): @property def is_on(self): """state value property""" - return not self._tracker_beacon_device.beacon.is_updated + return not self._tracker_device_beacon.beacon.is_updated @property def name(self): From 0ee5a9ad12b6721764b7aeb3bd6e81bc632201f8 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 4 Mar 2022 19:46:09 +0100 Subject: [PATCH 32/51] Fix tracker device not exti --- custom_components/georide/binary_sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 148ae66..5e1b806 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -84,7 +84,7 @@ def entity_category(self): @property def device_info(self): """Return the device info.""" - return self._tracker_device.device_info + return self._tracker_device_beacon.device_info class GeoRideStolenBinarySensorEntity(GeoRideBinarySensorEntity): """Represent a tracked device.""" From 9719f26631a5c0b634c46efc66a77a588b6c71df Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 6 Mar 2022 12:46:50 +0100 Subject: [PATCH 33/51] Fix update beacon, Add speedometer, Add update on tracker properties change --- custom_components/georide/__init__.py | 22 ++++++++++- custom_components/georide/binary_sensor.py | 4 ++ custom_components/georide/sensor.py | 44 ++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 8e67154..cb348f0 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -182,6 +182,7 @@ async def connect_socket(self): socket.subscribe_device(self.on_device_callback) socket.subscribe_position(self.on_position_callback) socket.subscribe_alarm(self.on_alarm_callback) + socker.subscribe_refresh_tracker(self.on_refresh_tracker_callback) self._socket = socket socket.init() @@ -275,7 +276,7 @@ async def force_refresh_trackers_beacon(self, tracker_id): for new_georide_tracker_beacon in new_georide_tracker_beacons: found = False for tracker_beacon in self._georide_trackers_beacon: - if tracker_beacon.tracker_id == new_georide_tracker_beacon.beacon_id: + if tracker_beacon.beacon_id == new_georide_tracker_beacon.beacon_id: tracker_beacon.update_all_data(new_georide_tracker_beacon) found = True if not found: @@ -390,6 +391,25 @@ def on_device_callback(self, data): coordinator.async_request_refresh(), self._hass.loop ).result() break + @callback + def on_refresh_tracker_callback(self): + """on device callback""" + _LOGGER.info("On refresh tracker received") + self._previous_refresh = math.floor(time.time()/60) + await self.force_refresh_trackers() + + for coordoned_tracker in self._georide_trackers_coordoned: + tracker_device = coordoned_tracker['tracker_device'] + tracker = tracker_device.tracker + coordinator = coordoned_tracker['coordinator'] + event_data = { + "device_id": tracker_device.unique_id, + "device_name": tracker_device.name, + } + self._hass.bus.async_fire(f"{DOMAIN}_refresh_tracker_event", event_data) + asyncio.run_coroutine_threadsafe( + coordinator.async_request_refresh(), self._hass.loop + ).result() @callback def on_alarm_callback(self, data): diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index 5e1b806..da6660d 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -250,6 +250,10 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], super().__init__(coordinator, tracker_device) self.entity_id = f"{ENTITY_ID_FORMAT.format('moving')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + @property + def entity_category(self): + return EntityCategory.DIAGNOSTIC + @property def unique_id(self): """Return the unique ID.""" diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 3f447d5..a8b0824 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -142,6 +142,50 @@ def device_info(self) -> DeviceInfo: """Return the device info.""" return self._tracker_device.device_info +class GeoRideSpeedSensorEntity(CoordinatorEntity, SensorEntity): + """Represent a tracked device.""" + + def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], + tracker_device:Device, hass): + """Set up GeoRide entity.""" + super().__init__(coordinator) + self._tracker_device = tracker_device + self._name = tracker_device.tracker.tracker_name + self._unit_of_measurement = "km/h" + self.entity_id = f"{ENTITY_ID_FORMAT.format('speed')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + self._state = 0 + self._hass = hass + + @property + def unique_id(self): + """Return the unique ID.""" + return f"speed_{self._tracker_device.tracker.tracker_id}" + + @property + def state(self): + """state property""" + return self._tracker_device.tracker.speed + + @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} speed" + + @property + def icon(self): + """icon getter""" + return "mdi:speedometer" + + @property + def device_info(self) -> DeviceInfo: + """Return the device info.""" + return self._tracker_device.device_info + class GeoRideInternalBatterySensorEntity(CoordinatorEntity, SensorEntity): """Represent a tracked device.""" entity_category = EntityCategory.DIAGNOSTIC From 118911c3617032390922b57452c39fb4db1e069f Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 6 Mar 2022 13:16:44 +0100 Subject: [PATCH 34/51] Fix tracker position, add mesuremnt for longtherme statistics --- custom_components/georide/__init__.py | 4 ++-- custom_components/georide/sensor.py | 27 ++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index cb348f0..389bb1a 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -182,7 +182,7 @@ async def connect_socket(self): socket.subscribe_device(self.on_device_callback) socket.subscribe_position(self.on_position_callback) socket.subscribe_alarm(self.on_alarm_callback) - socker.subscribe_refresh_tracker(self.on_refresh_tracker_callback) + socket.subscribe_refresh_tracker(self.on_refresh_tracker_callback) self._socket = socket socket.init() @@ -396,7 +396,7 @@ def on_refresh_tracker_callback(self): """on device callback""" _LOGGER.info("On refresh tracker received") self._previous_refresh = math.floor(time.time()/60) - await self.force_refresh_trackers() + self.force_refresh_trackers() for coordoned_tracker in self._georide_trackers_coordoned: tracker_device = coordoned_tracker['tracker_device'] diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index a8b0824..2ed3032 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -32,6 +32,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d entities.append(GeoRideOdometerSensorEntity(coordinator, tracker_device, hass)) entities.append(GeoRideOdometerKmSensorEntity(coordinator, tracker_device, hass)) entities.append(GeoRideFixtimeSensorEntity(coordinator, tracker_device)) + entities.append(GeoRideSpeedSensorEntity(coordinator, tracker_device)) if tracker_device.tracker.version > 2: entities.append(GeoRideInternalBatterySensorEntity(coordinator, tracker_device)) entities.append(GeoRideExternalBatterySensorEntity(coordinator, tracker_device)) @@ -155,6 +156,7 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self.entity_id = f"{ENTITY_ID_FORMAT.format('speed')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 self._state = 0 self._hass = hass + self._state_class = "measurement" @property def unique_id(self): @@ -166,6 +168,10 @@ def state(self): """state property""" return self._tracker_device.tracker.speed + @property + def state_class(self): + return self._state_class + @property def unit_of_measurement(self): """unit of mesurment property""" @@ -198,8 +204,17 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self._name = tracker_device.tracker.tracker_name self._unit_of_measurement = "V" self.entity_id = f"{ENTITY_ID_FORMAT.format('internal_battery_voltage')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 - self._state = 0 + self._state_class = "measurement" + self._device_class = "voltage" + + @property + def state_class(self): + return self._state_class + + @property + def device_class(self): + return self._device_class @property def entity_category(self): @@ -247,6 +262,16 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self._unit_of_measurement = "V" self.entity_id = f"{ENTITY_ID_FORMAT.format('external_battery_voltage')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 self._state = 0 + self._state_class = "measurement" + self._device_class = "voltage" + + @property + def state_class(self): + return self._state_class + + @property + def device_class(self): + return self._device_class @property def entity_category(self): From 2bc41f43c5af23f500590569d9f75815be78b5d9 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 6 Mar 2022 13:44:19 +0100 Subject: [PATCH 35/51] Fix sensor declaration --- custom_components/georide/sensor.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 2ed3032..1ad10a8 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -31,8 +31,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator entities.append(GeoRideOdometerSensorEntity(coordinator, tracker_device, hass)) entities.append(GeoRideOdometerKmSensorEntity(coordinator, tracker_device, hass)) + entities.append(GeoRideSpeedSensorEntity(coordinator, tracker_device,hass)) entities.append(GeoRideFixtimeSensorEntity(coordinator, tracker_device)) - entities.append(GeoRideSpeedSensorEntity(coordinator, tracker_device)) if tracker_device.tracker.version > 2: entities.append(GeoRideInternalBatterySensorEntity(coordinator, tracker_device)) entities.append(GeoRideExternalBatterySensorEntity(coordinator, tracker_device)) @@ -317,7 +317,6 @@ def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], self._tracker_device = tracker_device self._name = tracker_device.tracker.tracker_name self.entity_id = f"{ENTITY_ID_FORMAT.format('fixtime')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 - self._state = 0 self._device_class = "timestamp" From 4384526faeb8b65bd7bc8decff7e361ae9f388db Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 6 Mar 2022 19:38:51 +0100 Subject: [PATCH 36/51] Fix call on position_event --- custom_components/georide/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 389bb1a..7558e97 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -467,7 +467,8 @@ def on_position_callback(self, data): """on position callback""" _LOGGER.info("On position received") for coordoned_tracker in self._georide_trackers_coordoned: - tracker = coordoned_tracker['tracker_device'].tracker + tracker_device = coordoned_tracker['tracker_device'].tracker + tracker = tracker_device.tracker coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: tracker.latitude = data['latitude'] From cb5f069affcfa6844a2d17f37d62a78d68a16565 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Mon, 7 Mar 2022 12:12:03 +0100 Subject: [PATCH 37/51] Fix tracker asign to tracker_device --- 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 7558e97..9c09610 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -467,7 +467,7 @@ def on_position_callback(self, data): """on position callback""" _LOGGER.info("On position received") for coordoned_tracker in self._georide_trackers_coordoned: - tracker_device = coordoned_tracker['tracker_device'].tracker + tracker_device = coordoned_tracker['tracker_device'] tracker = tracker_device.tracker coordinator = coordoned_tracker['coordinator'] if tracker.tracker_id == data['trackerId']: From 6eebbebdfa5345823a5466cc66716e5525be7dd7 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sat, 19 Mar 2022 21:45:17 +0100 Subject: [PATCH 38/51] Update to georideapilib 0.8.3 --- custom_components/georide/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 6f680c7..d7c8ece 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -6,7 +6,7 @@ "issue_tracker": "https://github.com/ptimatth/GeorideHA/issues", "iot_class": "cloud_polling", "requirements": [ - "georideapilib>=0.8.2", + "georideapilib>=0.8.3", "pyjwt==2.1.0" ], "dependencies": [], From d27051702502ebccbc8b222a9d02293e41ba520a Mon Sep 17 00:00:00 2001 From: Matthieu Date: Sun, 20 Mar 2022 14:05:24 +0100 Subject: [PATCH 39/51] Update to georideapilib 0.8.4 --- custom_components/georide/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index d7c8ece..3fc7bf1 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -6,7 +6,7 @@ "issue_tracker": "https://github.com/ptimatth/GeorideHA/issues", "iot_class": "cloud_polling", "requirements": [ - "georideapilib>=0.8.3", + "georideapilib>=0.8.4", "pyjwt==2.1.0" ], "dependencies": [], From b8c8bcba14e0650cd817d5d94f2b8af1c151ff3f Mon Sep 17 00:00:00 2001 From: Matthieu DUVAL Date: Wed, 6 Apr 2022 17:24:18 +0200 Subject: [PATCH 40/51] Update pyjwt to match with the latest version --- custom_components/georide/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 3fc7bf1..f04ebf7 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -7,7 +7,7 @@ "iot_class": "cloud_polling", "requirements": [ "georideapilib>=0.8.4", - "pyjwt==2.1.0" + "pyjwt>=2.2.0" ], "dependencies": [], "codeowners": ["ptimatth"], From 7ea6c96331c03bf498c071877747ad248a1f82b9 Mon Sep 17 00:00:00 2001 From: Matthieu DUVAL Date: Mon, 27 Feb 2023 18:02:27 +0100 Subject: [PATCH 41/51] Update to to latest georideapilib --- custom_components/georide/__init__.py | 22 +++++-- custom_components/georide/config_flow.py | 4 +- custom_components/georide/device.py | 84 +++++++++++++++++++----- custom_components/georide/manifest.json | 4 +- hacs.json | 2 +- 5 files changed, 86 insertions(+), 30 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 9c09610..6d24751 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -44,11 +44,8 @@ SIREN_ACTIVATION_DELAY ) - - _LOGGER = logging.getLogger(__name__) - CONFIG_SCHEMA = vol.Schema( { vol.Required(DOMAIN, default={}): { @@ -59,7 +56,6 @@ extra=vol.ALLOW_EXTRA, ) - async def async_setup(hass, config): """Setup GeoRide component.""" hass.data[DOMAIN] = {"config": config[DOMAIN], "devices": {}, "unsub": None} @@ -76,7 +72,6 @@ async def async_setup(hass, config): # Return boolean to indicate that initialization was successful. return True - async def async_setup_entry(hass, entry): """Set up GeoRide entry.""" config = hass.data[DOMAIN]["config"] @@ -111,7 +106,7 @@ async def async_setup_entry(hass, entry): return True -async def async_unload_entry(hass, entry): +async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): """Unload an GeoRide config entry.""" await hass.config_entries.async_forward_entry_unload(entry, "device_tracker") @@ -120,9 +115,22 @@ async def async_unload_entry(hass, entry): await hass.config_entries.async_forward_entry_unload(entry, "binary_sensor") await hass.config_entries.async_forward_entry_unload(entry, "siren") + context = hass.data[DOMAIN]["context"] + context.socket.disconnect() // Disconnect only if all devices is disabled + + return True + +async def async_remove_config_entry_device(hass: HomeAssistant, config_entry: ConfigEntry, device_entry: DeviceEntry) -> bool: + """Remove an GeoRide device entry.""" + + await hass.config_entries.async_remove_config_entry_device(device_entry, "device_tracker") + await hass.config_entries.async_remove_config_entry_device(device_entry, "switch") + await hass.config_entries.async_remove_config_entry_device(device_entry, "sensor") + await hass.config_entries.async_remove_config_entry_device(device_entry, "binary_sensor") + await hass.config_entries.async_remove_config_entry_device(device_entry, "siren") context = hass.data[DOMAIN]["context"] - context.socket.disconnect() + # context.socket.disconnect() return True diff --git a/custom_components/georide/config_flow.py b/custom_components/georide/config_flow.py index b8d5cc5..5e324ca 100644 --- a/custom_components/georide/config_flow.py +++ b/custom_components/georide/config_flow.py @@ -12,7 +12,7 @@ _LOGGER = logging.getLogger(__name__) -@config_entries.HANDLERS.register("georide") +@config_entries.HANDLERS.register(DOMAIN) class GeoRideConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """GeoRide config flow """ @@ -37,8 +37,6 @@ async def async_step_import(self, user_input=None): #pylint: disable=W0613 vol.Required(CONF_PASSWORD): vol.All(str) })) - - async def async_step_georide_login(self, user_input): """ try to seupt GeoRide Account """ diff --git a/custom_components/georide/device.py b/custom_components/georide/device.py index a7276c4..0053076 100644 --- a/custom_components/georide/device.py +++ b/custom_components/georide/device.py @@ -9,6 +9,7 @@ class Device: def __init__(self, tracker): """Initialize GeoRideTracker device.""" self._tracker: GeoRideTracker = tracker + @property def tracker(self): @@ -20,11 +21,26 @@ def name(self) -> str: """Get the name.""" return self._tracker.tracker_name + @property + def default_manufacturer(self) -> str: + """Get the default_manufacturer.""" + return "GeoRide" + @property def manufacturer(self) -> str: """Get the manufacturer.""" return "GeoRide" + + @property + def default_model(self) -> str: + """Get the default model.""" + return "GeoRide 1" + @property + def suggested_area(self) -> str: + """Get the suggested_area.""" + return "Garage" + @property def model_name(self) -> str: """Get the model name.""" @@ -34,10 +50,28 @@ def model_name(self) -> str: elif self._tracker.version == 2: name = "GeoRide 2" elif self._tracker.version == 3: - name = "GeoRide 3" + if self._tracker.model == 'georide-3': + name = "GeoRide 3" + else: + name = "GeoRide Mini" else: name = "Prototype / Unknown" return name + + @property + def sw_version(self) -> str: + """Get the software version.""" + return str(self._tracker.software_version) + + @property + def hw_version(self) -> str: + """Get the hardware version.""" + return str(self._tracker.version) + + @property + def unique_id(self) -> str: + """Get the unique id.""" + return {(GEORIDE_DOMAIN, self._tracker.tracker_id)} @property def device_info(self): @@ -45,17 +79,13 @@ def device_info(self): return { "name": self.name, "identifiers": self.unique_id, - "manufacturer": "GeoRide", + "manufacturer": self.manufacturer, "model": self.model_name, - "suggested_area": "Garage" + "suggested_area": self.suggested_area, + "sw_version" : self.sw_version, + "hw_version": self.hw_version } - - @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}" @@ -77,10 +107,25 @@ def name(self) -> str: """Get the name.""" return self._beacon.name + @property + def default_manufacturer(self) -> str: + """Get the default_manufacturer.""" + return "GeoRide" + @property def manufacturer(self) -> str: """Get the manufacturer.""" return "GeoRide" + + @property + def default_model(self) -> str: + """Get the default model.""" + return "GeoRide Beacon" + + @property + def suggested_area(self) -> str: + """Get the suggested_area.""" + return "Garage" @property def model_name(self) -> str: @@ -88,23 +133,28 @@ def model_name(self) -> str: name = "GeoRide Beacon" return name + @property + def unique_id(self) -> str: + """Get the unique id.""" + return {(GEORIDE_DOMAIN, self._beacon.beacon_id)} + + @property + def via_device(self) -> str: + """Get the unique id.""" + return {(GEORIDE_DOMAIN, self._beacon.tracker_id)} + @property def device_info(self): """Return the device info.""" return { "name": self.name, "identifiers": self.unique_id, - "manufacturer": "GeoRide", + "manufacturer": self.manufacturer, "model": self.model_name, - "suggested_area": "Garage" + "suggested_area": self.suggested_area, + "via_device": self.via_device } - @property - def unique_id(self) -> str: - """Get the unique id.""" - - return {(GEORIDE_DOMAIN, self._beacon.beacon_id)} - def __str__(self) -> str: """Get string representation.""" return f"GeoRide Device: {self.name}::{self.model_name}::{self.unique_id}" \ No newline at end of file diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index f04ebf7..f95928c 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -6,10 +6,10 @@ "issue_tracker": "https://github.com/ptimatth/GeorideHA/issues", "iot_class": "cloud_polling", "requirements": [ - "georideapilib>=0.8.4", + "georideapilib>=0.9.0", "pyjwt>=2.2.0" ], "dependencies": [], "codeowners": ["ptimatth"], - "version": "0.9.0" + "version": "1.0.0" } \ No newline at end of file diff --git a/hacs.json b/hacs.json index d8e4f24..8c67814 100644 --- a/hacs.json +++ b/hacs.json @@ -4,5 +4,5 @@ "render_readme": true, "domains": ["devices_tracker", "sensor"], "country": ["FR"], - "homeassistant": "2022.2.0" + "homeassistant": "2023.2.0" } \ No newline at end of file From bdaccea1e1b89c0e2cd3a2b108cbb72a76f1f73a Mon Sep 17 00:00:00 2001 From: Matthieu DUVAL Date: Mon, 27 Feb 2023 21:31:37 +0100 Subject: [PATCH 42/51] Add devices class to better categorisation in HA --- custom_components/georide/__init__.py | 18 ++----- custom_components/georide/binary_sensor.py | 60 ++++++++++++++++++---- custom_components/georide/device.py | 2 +- custom_components/georide/manifest.json | 2 +- custom_components/georide/sensor.py | 18 ++++++- 5 files changed, 73 insertions(+), 27 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 6d24751..3bac8c4 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -106,7 +106,7 @@ async def async_setup_entry(hass, entry): return True -async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): +async def async_unload_entry(hass, entry): """Unload an GeoRide config entry.""" await hass.config_entries.async_forward_entry_unload(entry, "device_tracker") @@ -116,22 +116,12 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): await hass.config_entries.async_forward_entry_unload(entry, "siren") context = hass.data[DOMAIN]["context"] - context.socket.disconnect() // Disconnect only if all devices is disabled + context.socket.disconnect() # Disconnect only if all devices is disabled return True -async def async_remove_config_entry_device(hass: HomeAssistant, config_entry: ConfigEntry, device_entry: DeviceEntry) -> bool: - """Remove an GeoRide device entry.""" - - await hass.config_entries.async_remove_config_entry_device(device_entry, "device_tracker") - await hass.config_entries.async_remove_config_entry_device(device_entry, "switch") - await hass.config_entries.async_remove_config_entry_device(device_entry, "sensor") - await hass.config_entries.async_remove_config_entry_device(device_entry, "binary_sensor") - await hass.config_entries.async_remove_config_entry_device(device_entry, "siren") - - context = hass.data[DOMAIN]["context"] - # context.socket.disconnect() - +async def async_remove_config_entry_device(hass, config_entry, device_entry) -> bool: + """Remove an GeoRide device entry.""" return True diff --git a/custom_components/georide/binary_sensor.py b/custom_components/georide/binary_sensor.py index da6660d..911d1e5 100644 --- a/custom_components/georide/binary_sensor.py +++ b/custom_components/georide/binary_sensor.py @@ -6,8 +6,7 @@ from homeassistant.core import callback from homeassistant.helpers.entity import DeviceInfo, EntityCategory -from homeassistant.components.binary_sensor import BinarySensorEntity -from homeassistant.components.binary_sensor import ENTITY_ID_FORMAT +from homeassistant.components.binary_sensor import BinarySensorEntity, BinarySensorDeviceClass, ENTITY_ID_FORMAT from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, DataUpdateCoordinator @@ -33,6 +32,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d entities.append(GeoRideActiveSubscriptionBinarySensorEntity(coordinator, tracker_device)) entities.append(GeoRideNetworkBinarySensorEntity(coordinator, tracker_device)) entities.append(GeoRideMovingBinarySensorEntity(coordinator, tracker_device)) + entities.append(GeoRideUpdatedBinarySensorEntity(coordinator, tracker_device)) hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator @@ -102,7 +102,7 @@ def unique_id(self): @property def device_class(self): """Return the device class.""" - return "problem" + return BinarySensorDeviceClass.PROBLEM @property def is_on(self): @@ -132,7 +132,7 @@ def unique_id(self): @property def device_class(self): """Return the device class.""" - return "problem" + return BinarySensorDeviceClass.PROBLEM @property def is_on(self): @@ -236,6 +236,11 @@ def is_on(self): return True return False + @property + def device_class(self) -> str: + """device class""" + return BinarySensorDeviceClass.CONNECTIVITY + @property def name(self): """ GeoRide name """ @@ -268,12 +273,49 @@ def device_class(self): def is_on(self): """state value property""" return self._tracker_device.tracker.moving + + @property + def device_class(self) -> str: + """device class""" + return BinarySensorDeviceClass.MOVING @property def name(self): """ GeoRide name """ return f"{self._name} is moving" +class GeoRideUpdatedBinarySensorEntity(GeoRideBinarySensorEntity): + """Represent a tracked device.""" + @property + def entity_category(self): + return EntityCategory.DIAGNOSTIC + + 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('update')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 + + @property + def unique_id(self): + """Return the unique ID.""" + return f"update_{self._tracker_device.tracker.tracker_id}" + + @property + def is_on(self): + """state value property""" + return not self._tracker_device.tracker.is_up_to_date + + @property + def device_class(self) -> str: + """device class""" + return BinarySensorDeviceClass.UPDATE + + @property + def name(self): + """ GeoRide name """ + return f"{self._name} have an update" + class GeoRideBeaconUpdatedBinarySensorEntity(GeoRideBeaconBinarySensorEntity): """Represent a tracked device.""" @property @@ -291,15 +333,15 @@ def unique_id(self): """Return the unique ID.""" return f"update_{self._tracker_device_beacon.beacon.beacon_id}" - @property - def device_class(self): - """Return the device class.""" - return "update" - @property def is_on(self): """state value property""" return not self._tracker_device_beacon.beacon.is_updated + + @property + def device_class(self) -> str: + """device class""" + return BinarySensorDeviceClass.UPDATE @property def name(self): diff --git a/custom_components/georide/device.py b/custom_components/georide/device.py index 0053076..65fe47a 100644 --- a/custom_components/georide/device.py +++ b/custom_components/georide/device.py @@ -141,7 +141,7 @@ def unique_id(self) -> str: @property def via_device(self) -> str: """Get the unique id.""" - return {(GEORIDE_DOMAIN, self._beacon.tracker_id)} + return (GEORIDE_DOMAIN, self._beacon.linked_tracker_id ) @property def device_info(self): diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index f95928c..0cd1643 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -6,7 +6,7 @@ "issue_tracker": "https://github.com/ptimatth/GeorideHA/issues", "iot_class": "cloud_polling", "requirements": [ - "georideapilib>=0.9.0", + "georideapilib>=0.9.3", "pyjwt>=2.2.0" ], "dependencies": [], diff --git a/custom_components/georide/sensor.py b/custom_components/georide/sensor.py index 1ad10a8..62423bb 100644 --- a/custom_components/georide/sensor.py +++ b/custom_components/georide/sensor.py @@ -5,8 +5,7 @@ from homeassistant.core import callback from homeassistant.helpers.entity import DeviceInfo, EntityCategory -from homeassistant.components.sensor import SensorEntity -from homeassistant.components.sensor import ENTITY_ID_FORMAT +from homeassistant.components.sensor import SensorEntity, SensorDeviceClass, ENTITY_ID_FORMAT from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, DataUpdateCoordinator, @@ -245,6 +244,11 @@ def icon(self): """icon getter""" return "mdi:battery" + @property + def device_class(self) -> str: + """device class""" + return SensorDeviceClass.VOLTAGE + @property def device_info(self) -> DeviceInfo: """Return the device info.""" @@ -302,6 +306,11 @@ def icon(self): """icon getter""" return "mdi:battery" + @property + def device_class(self) -> str: + """device class""" + return SensorDeviceClass.VOLTAGE + @property def device_info(self) -> DeviceInfo: """Return the device info.""" @@ -391,6 +400,11 @@ def icon(self): """icon getter""" return "mdi:battery" + @property + def device_class(self) -> str: + """device class""" + return SensorDeviceClass.BATTERY + @property def device_info(self) -> DeviceInfo: """Return the device info.""" From fa0f67e6ec32fd8b0ff60a47ebf5166bc85f05b8 Mon Sep 17 00:00:00 2001 From: Matthieu DUVAL Date: Tue, 28 Feb 2023 19:23:10 +0100 Subject: [PATCH 43/51] Update to latest georidelib --- custom_components/georide/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 0cd1643..67eab13 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -6,7 +6,7 @@ "issue_tracker": "https://github.com/ptimatth/GeorideHA/issues", "iot_class": "cloud_polling", "requirements": [ - "georideapilib>=0.9.3", + "georideapilib>=0.9.4", "pyjwt>=2.2.0" ], "dependencies": [], From aa6cf7b515ea7ce13fe288610d8c9f236db18179 Mon Sep 17 00:00:00 2001 From: Matthieu DUVAL Date: Tue, 28 Feb 2023 19:34:56 +0100 Subject: [PATCH 44/51] Add beacon verification from the parametter has_beacon unsted of hw version --- 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 3bac8c4..77cac20 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -306,7 +306,7 @@ async def init_context(self, hass): "tracker_device": Device(tracker), "coordinator": coordinator } - if tracker.version > 2: + if tracker.has_beacon: tracker_beacons = await self.get_tracker_beacons_by_tracker_id(tracker.tracker_id) for tracker_beacon in tracker_beacons: beacon_coordinator = DataUpdateCoordinator[Mapping[str, Any]]( From be29b2d9bf08b71a0d7c1e4d84381d3e383d8d8b Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 24 Mar 2023 23:17:13 +0100 Subject: [PATCH 45/51] Update to georideapilib 0.9.6 --- custom_components/georide/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 67eab13..6ad3e09 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -6,7 +6,7 @@ "issue_tracker": "https://github.com/ptimatth/GeorideHA/issues", "iot_class": "cloud_polling", "requirements": [ - "georideapilib>=0.9.4", + "georideapilib>=0.9.6", "pyjwt>=2.2.0" ], "dependencies": [], From ad77edd1030f4ba79b6ad96b48522e281b4acd17 Mon Sep 17 00:00:00 2001 From: Matthieu DUVAL Date: Wed, 24 May 2023 12:46:26 +0200 Subject: [PATCH 46/51] Update badge and GeoRidelib version --- README.md | 1 + custom_components/georide/manifest.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f2fa0c2..d5ed2c1 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ ⚠️ This is not an official implementation [![hacs_badge](https://img.shields.io/badge/HACS-Default-orange.svg?style=for-the-badge)](https://github.com/custom-components/hacs) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg?style=for-the-badge)](https://www.gnu.org/licenses/gpl-3.0) +[![install_badge](https://img.shields.io/badge/dynamic/json?color=41BDF5&logo=home-assistant&label=integration%20usage&suffix=%20installs&cacheSeconds=15600&url=https://analytics.home-assistant.io/custom_integrations.json&query=$.georide.total)](https://analytics.home-assistant.io/) Official GeoRide website: https://georide.fr/ diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 6ad3e09..431d050 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -6,10 +6,10 @@ "issue_tracker": "https://github.com/ptimatth/GeorideHA/issues", "iot_class": "cloud_polling", "requirements": [ - "georideapilib>=0.9.6", + "georideapilib>=1.0.0", "pyjwt>=2.2.0" ], "dependencies": [], "codeowners": ["ptimatth"], - "version": "1.0.0" + "version": "1.1.0" } \ No newline at end of file From 33d8942e31be2e951a13d643f56afdfc9e387229 Mon Sep 17 00:00:00 2001 From: Sigri Date: Wed, 25 Oct 2023 20:39:23 +0200 Subject: [PATCH 47/51] Fix syntax --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d5ed2c1..bc7549c 100644 --- a/README.md +++ b/README.md @@ -102,12 +102,12 @@ mode: single ## Installation ### Option 1 -- Just folow the integration config steps. +- Just follow the integration config steps. ### Option 2 -- Add the folowing line in your configuration.yml +- Add the following line in your configuration.yml ```yaml georide: email: @exmple.com password: -``` \ No newline at end of file +``` From cbf81d7438fa421196f5b24058016c67ca2d5d6b Mon Sep 17 00:00:00 2001 From: Sigri Date: Wed, 25 Oct 2023 21:19:05 +0200 Subject: [PATCH 48/51] Add manual installation --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index bc7549c..75ebd07 100644 --- a/README.md +++ b/README.md @@ -111,3 +111,12 @@ mode: single email: @exmple.com password: ``` + +### Option 3 (manual) +- Download .zip git repo +- Go to /config (with File Editor or SSH) +- Unzip GeorideHA.zip +- Restart Home Assistant +- Go to "Integrations" +- If GeoRide not display, choose "add integration" +- Configure GeoRide add-on From f7d801e1f4a117ca983374bd3caf91d9cffe2e32 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Tue, 12 Nov 2024 19:33:43 +0100 Subject: [PATCH 49/51] Update deprecated methods and types --- custom_components/georide/__init__.py | 12 +----------- custom_components/georide/device_tracker.py | 4 ++-- hacs.json | 2 +- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/custom_components/georide/__init__.py b/custom_components/georide/__init__.py index 77cac20..03dee78 100644 --- a/custom_components/georide/__init__.py +++ b/custom_components/georide/__init__.py @@ -25,7 +25,6 @@ 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, @@ -93,16 +92,7 @@ async def async_setup_entry(hass, entry): # We add trackers to the context await context.init_context(hass) - hass.async_create_task( - hass.config_entries.async_forward_entry_setup(entry, "device_tracker")) - hass.async_create_task( - 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")) - hass.async_create_task( - hass.config_entries.async_forward_entry_setup(entry, "siren")) + await hass.config_entries.async_forward_entry_setups(entry, ["device_tracker", "switch", "sensor", "binary_sensor", "siren"]) return True diff --git a/custom_components/georide/device_tracker.py b/custom_components/georide/device_tracker.py index e945043..a97076f 100644 --- a/custom_components/georide/device_tracker.py +++ b/custom_components/georide/device_tracker.py @@ -3,7 +3,7 @@ import logging from typing import Any, Mapping -from homeassistant.components.device_tracker.const import DOMAIN, SOURCE_TYPE_GPS +from homeassistant.components.device_tracker.const import DOMAIN, SourceType from homeassistant.components.device_tracker.config_entry import TrackerEntity from homeassistant.helpers.update_coordinator import ( @@ -78,7 +78,7 @@ def longitude(self): @property def source_type(self): """Return the source type, eg gps or router, of the device.""" - return SOURCE_TYPE_GPS + return SourceType.GPS @property def location_accuracy(self): diff --git a/hacs.json b/hacs.json index 8c67814..4d3ee3d 100644 --- a/hacs.json +++ b/hacs.json @@ -4,5 +4,5 @@ "render_readme": true, "domains": ["devices_tracker", "sensor"], "country": ["FR"], - "homeassistant": "2023.2.0" + "homeassistant": "2024.11.0" } \ No newline at end of file From 43b578cd98033a5a678190dce6fedfebda28fafa Mon Sep 17 00:00:00 2001 From: Matthieu DUVAL Date: Sun, 29 Oct 2023 13:26:04 +0100 Subject: [PATCH 50/51] Merge pull request #9 from Sigri44/master Add manual installation --- README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d5ed2c1..75ebd07 100644 --- a/README.md +++ b/README.md @@ -102,12 +102,21 @@ mode: single ## Installation ### Option 1 -- Just folow the integration config steps. +- Just follow the integration config steps. ### Option 2 -- Add the folowing line in your configuration.yml +- Add the following line in your configuration.yml ```yaml georide: email: @exmple.com password: -``` \ No newline at end of file +``` + +### Option 3 (manual) +- Download .zip git repo +- Go to /config (with File Editor or SSH) +- Unzip GeorideHA.zip +- Restart Home Assistant +- Go to "Integrations" +- If GeoRide not display, choose "add integration" +- Configure GeoRide add-on From eea4e1bb6bc476a3ea93cb9f7ad1d9e402db2f7c Mon Sep 17 00:00:00 2001 From: Matthieu Date: Tue, 12 Nov 2024 20:11:16 +0100 Subject: [PATCH 51/51] update to vesion 1.1.1 --- custom_components/georide/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/georide/manifest.json b/custom_components/georide/manifest.json index 431d050..55ee38e 100644 --- a/custom_components/georide/manifest.json +++ b/custom_components/georide/manifest.json @@ -11,5 +11,5 @@ ], "dependencies": [], "codeowners": ["ptimatth"], - "version": "1.1.0" + "version": "1.1.1" } \ No newline at end of file