Compare commits

...

30 Commits

Author SHA1 Message Date
ce06f109fe Beacon use wrong coordinator 2022-03-04 19:07:54 +01:00
e9262ff3d4 Fix coordinator device name, await on add entity 2022-03-04 19:01:22 +01:00
f36a3093bf Fix missing import beacon 2022-03-04 18:55:12 +01:00
73d15f8c9a Fix mist spelling of get_tracker_beacons 2022-03-04 18:49:55 +01:00
d326726138 Fix invalid sintax 2022-03-04 18:45:58 +01:00
3000d5588b Fix support multiple tracker beacon 2022-03-04 18:42:13 +01:00
a3c84c63fd Fix missing tracker in list 2022-03-04 18:18:46 +01:00
a37cca7902 Fix missing get_tracker_beacon_by_tracker_id 2022-03-04 18:11:28 +01:00
32db0ec42e Fix "NameError: name 'new_georide_tracker' is not defined" 2022-03-04 18:07:37 +01:00
1250dda047 Fix "list' object has no attribute 'tracker_id' " 2022-03-04 18:04:10 +01:00
759fe2d257 Fix "local variable 'tracker' referenced before assignment" 2022-03-04 18:00:03 +01:00
9e2e6e8d53 remove await on force_refresh_trackers_beacon 2022-03-04 17:56:29 +01:00
4dc091525e Fix force_refresh_trackers_beacon 2022-03-04 17:53:51 +01:00
e92ac1825d Fix siren and device unique id 2022-03-04 17:28:10 +01:00
fd10326489 Revert change on device id format 2022-03-04 17:18:08 +01:00
4dcf642260 Fix unique id format 2022-03-04 17:08:24 +01:00
80de671649 Small import fixes 2022-03-04 16:59:28 +01:00
9f5b09dc4c Add entity category on All entities 2022-03-04 16:50:34 +01:00
09231c4fc0 First steps of entity category 2022-03-04 16:15:42 +01:00
0555c63b7d Bump version to 0.9.0 2022-03-04 15:52:47 +01:00
adb6cef3c7 Add suport for new device beacon, siren control, eco_mode control, better device event 2022-03-04 15:47:19 +01:00
af12cd70e4 Add cloud and issue info 2022-03-03 20:30:24 +01:00
b17f38ee66 Fix #4 jwt decode afater update of hA to pyjwt 2.1.0 2021-10-10 13:06:26 +02:00
fe073cff55 Merge PR #3 2021-08-30 20:09:10 +02:00
a3c5d2db6e Fix data.name unsted of data['name'] 2021-07-13 20:36:19 +02:00
c295c8848c Change version 2021-07-05 18:41:22 +02:00
29f42a75c9 Fix alarm event trigger 2021-07-05 18:39:07 +02:00
54b7e9b5d6 Setup ne device event on georide Ha 2021-07-01 11:54:03 +02:00
af0a4a37aa Bump georideapilib min version to v0.6.1 2021-05-05 22:53:52 +02:00
c229ca4b6e Fix lock change 2021-04-11 18:00:54 +02:00
11 changed files with 852 additions and 75 deletions

View File

@@ -10,6 +10,86 @@ Official GeoRide website: https://georide.fr/
## Description ## Description
This component add some sensor for GeoRide Tracker This component add some sensor for GeoRide Tracker
### What's entity is available :
Get GeoRide position
Get GeoRide lock status
Change GeoRide lock status
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)
you can display your tracker name by by data.device_name
event;
georide_position_event
georide_lock_event
georide_device_event
georide_alarm_event
you can filter with data.type == 'alarm_vibration' to filter by vibration
here is the alarm type available: (listen the georide_alarm_event)
alarm_vibration
alarm_exitZone
alarm_crash
alarm_crashParking
alarm_deviceOffline
alarm_deviceOnline
alarm_powerCut
alarm_powerUncut
alarm_batteryWarning
alarm_temperatureWarning
alarm_magnetOn
alarm_magnetOff
alarm_sonorAlarmOn
## Question:
### 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)
```yaml
sensor:
- platform: template # Conversion georide de m en km
sensors:
odometer_XX_km:
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:
Simply made a automation like this:
```yaml
alias: '[TEST] Send notification'
description: ''
trigger:
- platform: event
event_type: georide_lock_event
condition: []
action:
- service: notify.mobile_app_oneplus_a3003
data:
message: 'The device {{ data.device_name }} have recieved a lock event'
mode: single
```
## Options ## Options

View File

@@ -32,7 +32,7 @@ from homeassistant.helpers.update_coordinator import (
) )
from .device import Device from .device import Device, DeviceBeacon
from .const import ( from .const import (
CONF_EMAIL, CONF_EMAIL,
CONF_PASSWORD, CONF_PASSWORD,
@@ -40,7 +40,8 @@ from .const import (
TRACKER_ID, TRACKER_ID,
TOKEN_SAFE_DAY, TOKEN_SAFE_DAY,
MIN_UNTIL_REFRESH, 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.config_entries.async_forward_entry_setup(entry, "sensor"))
hass.async_create_task( hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, "binary_sensor")) 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 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, "switch")
await hass.config_entries.async_forward_entry_unload(entry, "sensor") 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, "binary_sensor")
await hass.config_entries.async_forward_entry_unload(entry, "siren")
context = hass.data[DOMAIN]["context"] context = hass.data[DOMAIN]["context"]
@@ -133,6 +137,8 @@ class GeoRideContext:
self._email = email self._email = email
self._password = password self._password = password
self._georide_trackers_coordoned = [] self._georide_trackers_coordoned = []
self._georide_trackers_beacon_coordoned = []
self._georide_trackers_beacon = []
self._georide_trackers = [] self._georide_trackers = []
self._token = token self._token = token
self._socket = None self._socket = None
@@ -176,7 +182,6 @@ class GeoRideContext:
socket.subscribe_device(self.on_device_callback) socket.subscribe_device(self.on_device_callback)
socket.subscribe_position(self.on_position_callback) socket.subscribe_position(self.on_position_callback)
socket.subscribe_alarm(self.on_alarm_callback) socket.subscribe_alarm(self.on_alarm_callback)
self._socket = socket self._socket = socket
socket.init() socket.init()
@@ -184,7 +189,7 @@ class GeoRideContext:
async def get_token(self): async def get_token(self):
""" here we return the current valid tocken """ """ 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'] exp_timestamp = jwt_data['exp']
epoch = math.ceil(time.time()) epoch = math.ceil(time.time())
@@ -208,17 +213,32 @@ class GeoRideContext:
return tracker return tracker
return {} 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_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:
filtered_beacon.append(tracker_beacon)
return filtered_beacon
async def refresh_trackers(self): async def refresh_trackers(self):
""" here we return last tracker by id""" """ here we return last tracker by id"""
_LOGGER.debug("Call refresh tracker") _LOGGER.debug("Call refresh tracker")
epoch_min = math.floor(time.time()/60) epoch_min = math.floor(time.time()/60)
#if (epoch_min % MIN_UNTIL_REFRESH) == 0:
if epoch_min != self._previous_refresh: if epoch_min != self._previous_refresh:
self._previous_refresh = epoch_min self._previous_refresh = epoch_min
await self.force_refresh_trackers() await self.force_refresh_trackers()
#else: for tracker in self._georide_trackers:
# _LOGGER.debug("We wil dont refresh the tracker list") 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): async def force_refresh_trackers(self):
"""Used to refresh the tracker list""" """Used to refresh the tracker list"""
@@ -230,16 +250,37 @@ class GeoRideContext:
for tracker in self._georide_trackers: for tracker in self._georide_trackers:
if tracker.tracker_id == refreshed_tracker.tracker_id: if tracker.tracker_id == refreshed_tracker.tracker_id:
tracker.update_all_data(refreshed_tracker) tracker.update_all_data(refreshed_tracker)
if tracker.version > 2:
await self.force_refresh_trackers_beacon(tracker.tracker_id)
found = True found = True
if not found: if not found:
self._georide_trackers.append(refreshed_tracker) self._georide_trackers.append(refreshed_tracker)
if refreshed_tracker.version > 2:
await self.force_refresh_trackers_beacon(refreshed_tracker.tracker_id)
if not self._thread_started: if not self._thread_started:
_LOGGER.info("Start the thread") _LOGGER.info("Start the thread")
# We refresh the tracker list each hours # We refresh the tracker list each hours
self._thread_started = True self._thread_started = True
await self.connect_socket() 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_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
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): async def init_context(self, hass):
"""Used to refresh the tracker list""" """Used to refresh the tracker list"""
@@ -255,17 +296,39 @@ class GeoRideContext:
update_method=self.refresh_trackers, update_method=self.refresh_trackers,
update_interval=update_interval update_interval=update_interval
) )
self._georide_trackers_coordoned.append({
coordoned_tracker = {
"tracker_device": Device(tracker), "tracker_device": Device(tracker),
"coordinator": coordinator "coordinator": coordinator
}) }
if tracker.version > 2:
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,
_LOGGER,
name= tracker_beacon.name
)
coordoned_beacon = {
"tracker_beacon": DeviceBeacon(tracker_beacon),
"coordinator": beacon_coordinator
}
self._georide_trackers_beacon_coordoned.append(coordoned_beacon)
self._georide_trackers_coordoned.append(coordoned_tracker)
def get_coordoned_trackers(self): @property
def georide_trackers_coordoned(self):
"""Return coordoned trackers""" """Return coordoned trackers"""
return self._georide_trackers_coordoned return self._georide_trackers_coordoned
@property
def georide_trackers_beacon_coordoned(self):
"""Return coordoned trackers"""
return self._georide_trackers_beacon_coordoned
@property @property
def socket(self): def socket(self):
""" hold the GeoRide socket """ """ hold the GeoRide socket """
@@ -281,7 +344,8 @@ class GeoRideContext:
"""on lock callback""" """on lock callback"""
_LOGGER.info("On lock received") _LOGGER.info("On lock received")
for coordoned_tracker in self._georide_trackers_coordoned: 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'] coordinator = coordoned_tracker['coordinator']
if tracker.tracker_id == data['trackerId']: if tracker.tracker_id == data['trackerId']:
tracker.locked_latitude = data['lockedLatitude'] tracker.locked_latitude = data['lockedLatitude']
@@ -289,33 +353,31 @@ class GeoRideContext:
tracker.is_locked = data['isLocked'] tracker.is_locked = data['isLocked']
event_data = { event_data = {
"device_id": tracker.tracker_id, "device_id": tracker_device.unique_id,
"type": "on_lock", "device_name": tracker_device.name,
} }
self._hass.bus.async_fire(f"{DOMAIN}_event", event_data) self._hass.bus.async_fire(f"{DOMAIN}_lock_event", event_data)
asyncio.run_coroutine_threadsafe( asyncio.run_coroutine_threadsafe(
coordinator.async_request_refresh(), self._hass.loop coordinator.async_request_refresh(), self._hass.loop
).result() ).result()
break break
@callback @callback
def on_device_callback(self, data): def on_device_callback(self, data):
"""on device callback""" """on device callback"""
_LOGGER.info("On device received") _LOGGER.info("On device received")
for coordoned_tracker in self._georide_trackers_coordoned: 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'] coordinator = coordoned_tracker['coordinator']
if tracker.tracker_id == data['trackerId']: if tracker.tracker_id == data['trackerId']:
tracker.status = data['status'] tracker.status = data['status']
event_data = { event_data = {
"device_id": tracker.tracker_id, "device_id": tracker_device.unique_id,
"type": "on_device", "device_name": tracker_device.name,
} }
self._hass.bus.async_fire(f"{DOMAIN}_event", event_data) self._hass.bus.async_fire(f"{DOMAIN}_device_event", event_data)
asyncio.run_coroutine_threadsafe( asyncio.run_coroutine_threadsafe(
coordinator.async_request_refresh(), self._hass.loop coordinator.async_request_refresh(), self._hass.loop
).result() ).result()
@@ -326,31 +388,47 @@ class GeoRideContext:
"""on device callback""" """on device callback"""
_LOGGER.info("On alarm received") _LOGGER.info("On alarm received")
for coordoned_tracker in self._georide_trackers_coordoned: 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'] coordinator = coordoned_tracker['coordinator']
if tracker.tracker_id == data['trackerId']: if tracker.tracker_id == data['trackerId']:
if data.name == 'vibration': if data['name'] == 'vibration':
_LOGGER.info("Vibration detected") _LOGGER.info("Vibration detected")
elif data.name == 'exitZone': elif data['name'] == 'exitZone':
_LOGGER.info("Exit zone detected") _LOGGER.info("Exit zone detected")
elif data.name == 'crash': elif data['name'] == 'crash':
_LOGGER.info("Crash detected") _LOGGER.info("Crash detected")
elif data.name == 'crashParking': elif data['name'] == 'crashParking':
_LOGGER.info("Crash parking detected") _LOGGER.info("Crash parking detected")
elif data.name == 'deviceOffline': elif data['name'] == 'deviceOffline':
_LOGGER.info("Device offline detected") _LOGGER.info("Device offline detected")
elif data.name == 'deviceOnline': elif data['name'] == 'deviceOnline':
_LOGGER.info("Device online detected") _LOGGER.info("Device online detected")
elif data.name == 'powerCut': elif data['name'] == 'powerCut':
_LOGGER.info("powerCut detected") _LOGGER.info("powerCut detected")
elif data['name'] == 'powerUncut':
_LOGGER.info("powerUncut detected")
elif data['name'] == 'batteryWarning':
_LOGGER.info("batteryWarning detected")
elif data['name'] == 'temperatureWarning':
_LOGGER.info("temperatureWarning detected")
elif data['name'] == 'magnetOn':
_LOGGER.info("magnetOn detected")
elif data['name'] == 'magnetOff':
_LOGGER.info("magnetOff detected")
elif data['name'] == 'sonorAlarmOn':
_LOGGER.info("sonorAlarmOn detected")
tracker.is_siren_on = True
else: else:
_LOGGER.warning("Unamanged alarm: %s", data.name) _LOGGER.warning("Unmanaged alarm: %s", data["name"])
event_data = { event_data = {
"device_id": tracker.tracker_id, "device_id": tracker_device.unique_id,
"type": f"alarm_{data.name}", "device_name": tracker_device.name,
"type": f"alarm_{data['name']}"
} }
self._hass.bus.async_fire(f"{DOMAIN}_event", event_data) self._hass.bus.async_fire(f"{DOMAIN}_alarm_event", event_data)
asyncio.run_coroutine_threadsafe( asyncio.run_coroutine_threadsafe(
coordinator.async_request_refresh(), self._hass.loop coordinator.async_request_refresh(), self._hass.loop
).result() ).result()
@@ -371,10 +449,10 @@ class GeoRideContext:
tracker.fixtime = data['fixtime'] tracker.fixtime = data['fixtime']
event_data = { event_data = {
"device_id": tracker.tracker_id, "device_id": tracker_device.unique_id,
"type": "position", "device_name": tracker_device.name,
} }
self._hass.bus.async_fire(f"{DOMAIN}_event", event_data) self._hass.bus.async_fire(f"{DOMAIN}_position_event", event_data)
asyncio.run_coroutine_threadsafe( asyncio.run_coroutine_threadsafe(
coordinator.async_request_refresh(), self._hass.loop coordinator.async_request_refresh(), self._hass.loop
).result() ).result()

View File

@@ -5,6 +5,7 @@ import logging
from typing import Any, Mapping from typing import Any, Mapping
from homeassistant.core import callback 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 BinarySensorEntity
from homeassistant.components.binary_sensor import ENTITY_ID_FORMAT from homeassistant.components.binary_sensor import ENTITY_ID_FORMAT
from homeassistant.helpers.update_coordinator import ( from homeassistant.helpers.update_coordinator import (
@@ -14,14 +15,14 @@ from homeassistant.helpers.update_coordinator import (
from .const import DOMAIN as GEORIDE_DOMAIN from .const import DOMAIN as GEORIDE_DOMAIN
from .device import Device from .device import Device, DeviceBeacon
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: disable=W0613 async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: disable=W0613
"""Set up GeoRide tracker based off an entry.""" """Set up GeoRide tracker based off an entry."""
georide_context = hass.data[GEORIDE_DOMAIN]["context"] georide_context = hass.data[GEORIDE_DOMAIN]["context"]
entities = [] entities = []
coordoned_trackers = georide_context.get_coordoned_trackers() coordoned_trackers = georide_context.georide_trackers_coordoned
for coordoned_tracker in coordoned_trackers: for coordoned_tracker in coordoned_trackers:
tracker_device = coordoned_tracker['tracker_device'] tracker_device = coordoned_tracker['tracker_device']
coordinator = coordoned_tracker['coordinator'] coordinator = coordoned_tracker['coordinator']
@@ -30,9 +31,19 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: d
entities.append(GeoRideCrashedBinarySensorEntity(coordinator, tracker_device)) entities.append(GeoRideCrashedBinarySensorEntity(coordinator, tracker_device))
entities.append(GeoRideOwnerBinarySensorEntity(coordinator, tracker_device)) entities.append(GeoRideOwnerBinarySensorEntity(coordinator, tracker_device))
entities.append(GeoRideActiveSubscriptionBinarySensorEntity(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 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_beacon['tracker_beacon']
coordinator = coordoned_beacon['coordinator']
entities.append(GeoRideBeaconUpdatedBinarySensorEntity(coordinator, tracker_beacon))
hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.beacon.beacon_id] = coordinator
async_add_entities(entities, True) async_add_entities(entities, True)
return True return True
@@ -55,6 +66,26 @@ class GeoRideBinarySensorEntity(CoordinatorEntity, BinarySensorEntity):
"""Return the device info.""" """Return the device info."""
return self._tracker_device.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 entity_category(self):
return None
@property
def device_info(self):
"""Return the device info."""
return self._tracker_device.device_info
class GeoRideStolenBinarySensorEntity(GeoRideBinarySensorEntity): class GeoRideStolenBinarySensorEntity(GeoRideBinarySensorEntity):
"""Represent a tracked device.""" """Represent a tracked device."""
def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]], def __init__(self, coordinator: DataUpdateCoordinator[Mapping[str, Any]],
@@ -68,6 +99,11 @@ class GeoRideStolenBinarySensorEntity(GeoRideBinarySensorEntity):
"""Return the unique ID.""" """Return the unique ID."""
return f"is_stolen_{self._tracker_device.tracker.tracker_id}" return f"is_stolen_{self._tracker_device.tracker.tracker_id}"
@property
def device_class(self):
"""Return the device class."""
return "problem"
@property @property
def is_on(self): def is_on(self):
"""state value property""" """state value property"""
@@ -76,7 +112,7 @@ class GeoRideStolenBinarySensorEntity(GeoRideBinarySensorEntity):
@property @property
def name(self): def name(self):
""" GeoRide odometer name """ """ GeoRide odometer name """
return f"{self._name} is stolen" return f"{self._name} is not stolen"
class GeoRideCrashedBinarySensorEntity(GeoRideBinarySensorEntity): class GeoRideCrashedBinarySensorEntity(GeoRideBinarySensorEntity):
@@ -93,6 +129,11 @@ class GeoRideCrashedBinarySensorEntity(GeoRideBinarySensorEntity):
"""Return the unique ID.""" """Return the unique ID."""
return f"is_crashed_{self._tracker_device.tracker.tracker_id}" return f"is_crashed_{self._tracker_device.tracker.tracker_id}"
@property
def device_class(self):
"""Return the device class."""
return "problem"
@property @property
def is_on(self): def is_on(self):
"""state value property""" """state value property"""
@@ -101,7 +142,7 @@ class GeoRideCrashedBinarySensorEntity(GeoRideBinarySensorEntity):
@property @property
def name(self): def name(self):
""" GeoRide odometer name """ """ GeoRide odometer name """
return f"{self._name} is crashed" return f"{self._name} is not crashed"
class GeoRideActiveSubscriptionBinarySensorEntity(GeoRideBinarySensorEntity): class GeoRideActiveSubscriptionBinarySensorEntity(GeoRideBinarySensorEntity):
"""Represent a tracked device.""" """Represent a tracked device."""
@@ -112,6 +153,10 @@ class GeoRideActiveSubscriptionBinarySensorEntity(GeoRideBinarySensorEntity):
super().__init__(coordinator, tracker_device) super().__init__(coordinator, tracker_device)
self.entity_id = f"{ENTITY_ID_FORMAT.format('is_active_subscription_')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 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 @property
def unique_id(self): def unique_id(self):
"""Return the unique ID.""" """Return the unique ID."""
@@ -120,7 +165,13 @@ class GeoRideActiveSubscriptionBinarySensorEntity(GeoRideBinarySensorEntity):
@property @property
def is_on(self): def is_on(self):
"""state value property""" """state value property"""
if self._tracker_device.tracker.subscription_id is not None: 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 True
return False return False
@@ -155,3 +206,98 @@ class GeoRideOwnerBinarySensorEntity(GeoRideBinarySensorEntity):
""" GeoRide odometer name """ """ GeoRide odometer name """
return f"{self._name} is own tracker" return f"{self._name} is own tracker"
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 entity_category(self):
return EntityCategory.DIAGNOSTIC
@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"
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):
"""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"

View File

@@ -10,4 +10,6 @@ TRACKER_ID = "trackerId"
MIN_UNTIL_REFRESH = 10 MIN_UNTIL_REFRESH = 10
SIREN_ACTIVATION_DELAY = 30
TOKEN_SAFE_DAY = 432000 # five days TOKEN_SAFE_DAY = 432000 # five days

View File

@@ -1,5 +1,5 @@
"""Home Assistant representation of an GeoRide Tracker device.""" """Home Assistant representation of an GeoRide Tracker device."""
import georideapilib.objects as GeoRideTracker from georideapilib.objects import GeoRideTracker, GeoRideTrackerBeacon
from .const import DOMAIN as GEORIDE_DOMAIN from .const import DOMAIN as GEORIDE_DOMAIN
@@ -28,11 +28,15 @@ class Device:
@property @property
def model_name(self) -> str: def model_name(self) -> str:
"""Get the model name.""" """Get the model name."""
name = None
if self._tracker.version == 1:
name = "GeoRide 1" name = "GeoRide 1"
if self._tracker.is_old_tracker: elif self._tracker.version == 2:
name = "Prototype / GeoRide 1" name = "GeoRide 2"
elif self._tracker.is_second_gen: elif self._tracker.version == 3:
name = "GeoRide 2 / GeoRide 3" name = "GeoRide 3"
else:
name = "Prototype / Unknown"
return name return name
@property @property
@@ -40,7 +44,7 @@ class Device:
"""Return the device info.""" """Return the device info."""
return { return {
"name": self.name, "name": self.name,
"identifiers": {(GEORIDE_DOMAIN, self._tracker.tracker_id)}, "identifiers": self.unique_id,
"manufacturer": "GeoRide", "manufacturer": "GeoRide",
"model": self.model_name, "model": self.model_name,
"suggested_area": "Garage" "suggested_area": "Garage"
@@ -54,4 +58,53 @@ class Device:
def __str__(self) -> str: def __str__(self) -> str:
"""Get string representation.""" """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": 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, self._beacon.beacon_id)}
def __str__(self) -> str:
"""Get string representation."""
return f"GeoRide Device: {self.name}::{self.model_name}::{self.unique_id}"

View File

@@ -20,7 +20,7 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: disable=W0613 async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: disable=W0613
"""Set up Georide tracker based off an entry.""" """Set up Georide tracker based off an entry."""
georide_context = hass.data[GEORIDE_DOMAIN]["context"] georide_context = hass.data[GEORIDE_DOMAIN]["context"]
coordoned_trackers = georide_context.get_coordoned_trackers() coordoned_trackers = georide_context.georide_trackers_coordoned
entities = [] entities = []
for coordoned_tracker in coordoned_trackers: for coordoned_tracker in coordoned_trackers:
@@ -47,6 +47,10 @@ class GeoRideTrackerEntity(CoordinatorEntity, TrackerEntity):
self.entity_id = DOMAIN + ".{}".format(tracker_device.tracker.tracker_id) self.entity_id = DOMAIN + ".{}".format(tracker_device.tracker.tracker_id)
self._hass = hass self._hass = hass
@property
def entity_category(self):
return None
@property @property
def unique_id(self): def unique_id(self):
"""Return the unique ID.""" """Return the unique ID."""

View File

@@ -3,11 +3,13 @@
"name": "GeoRide", "name": "GeoRide",
"config_flow": true, "config_flow": true,
"documentation": "https://github.com/ptimatth/GeorideHA", "documentation": "https://github.com/ptimatth/GeorideHA",
"issue_tracker": "https://github.com/ptimatth/GeorideHA/issues",
"iot_class": "cloud_polling",
"requirements": [ "requirements": [
"georideapilib>=0.6.0", "georideapilib>=0.8.2",
"pyjwt>=1.7.1" "pyjwt==2.1.0"
], ],
"dependencies": [], "dependencies": [],
"codeowners": ["ptimatth"], "codeowners": ["ptimatth"],
"version": "0.6.0" "version": "0.9.0"
} }

View File

@@ -4,6 +4,7 @@ import logging
from typing import Any, Mapping from typing import Any, Mapping
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.entity import DeviceInfo, EntityCategory
from homeassistant.components.sensor import SensorEntity from homeassistant.components.sensor import SensorEntity
from homeassistant.components.sensor import ENTITY_ID_FORMAT from homeassistant.components.sensor import ENTITY_ID_FORMAT
from homeassistant.helpers.update_coordinator import ( from homeassistant.helpers.update_coordinator import (
@@ -12,7 +13,7 @@ from homeassistant.helpers.update_coordinator import (
) )
from .const import DOMAIN as GEORIDE_DOMAIN from .const import DOMAIN as GEORIDE_DOMAIN
from .device import Device from .device import Device, DeviceBeacon
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -21,15 +22,26 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: disable=W0613 async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: disable=W0613
"""Set up GeoRide tracker based off an entry.""" """Set up GeoRide tracker based off an entry."""
georide_context = hass.data[GEORIDE_DOMAIN]["context"] georide_context = hass.data[GEORIDE_DOMAIN]["context"]
coordoned_trackers = georide_context.get_coordoned_trackers() coordoned_trackers = georide_context.georide_trackers_coordoned
entities = [] entities = []
for coordoned_tracker in coordoned_trackers: for coordoned_tracker in coordoned_trackers:
tracker_device = coordoned_tracker['tracker_device'] tracker_device = coordoned_tracker['tracker_device']
coordinator = coordoned_tracker['coordinator'] coordinator = coordoned_tracker['coordinator']
entity = GeoRideOdometerSensorEntity(coordinator, tracker_device, hass)
hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator 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(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_beacon['tracker_beacon']
coordinator = coordoned_beacon['coordinator']
entities.append(GeoRideBeaconUpdatedBinarySensorEntity(coordinator, tracker_beacon))
hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.beacon.beacon_id] = coordinator
async_add_entities(entities) async_add_entities(entities)
@@ -50,6 +62,10 @@ class GeoRideOdometerSensorEntity(CoordinatorEntity, SensorEntity):
self._state = 0 self._state = 0
self._hass = hass self._hass = hass
@property
def entity_category(self):
return None
@property @property
def unique_id(self): def unique_id(self):
"""Return the unique ID.""" """Return the unique ID."""
@@ -58,7 +74,8 @@ class GeoRideOdometerSensorEntity(CoordinatorEntity, SensorEntity):
@property @property
def state(self): def state(self):
"""state property""" """state property"""
return self._tracker_device.tracker.odometer odometer = self._tracker_device.tracker.odometer
return odometer
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
@@ -76,6 +93,237 @@ class GeoRideOdometerSensorEntity(CoordinatorEntity, SensorEntity):
return "mdi:counter" return "mdi:counter"
@property @property
def device_info(self): def device_info(self) -> DeviceInfo:
"""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) -> 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):
"""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 entity_category(self):
return EntityCategory.DIAGNOSTIC
@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) -> DeviceInfo:
"""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 entity_category(self):
return EntityCategory.DIAGNOSTIC
@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) -> DeviceInfo:
"""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 entity_category(self):
return EntityCategory.DIAGNOSTIC
@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) -> DeviceInfo:
"""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 entity_category(self):
return EntityCategory.DIAGNOSTIC
@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) -> DeviceInfo:
"""Return the device info.""" """Return the device info."""
return self._tracker_device.device_info return self._tracker_device.device_info

View File

@@ -0,0 +1,96 @@
""" device tracker for GeoRide object """
import logging
from typing import Any, Mapping
from homeassistant.components.siren import SirenEntity
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
)
import georideapilib.api as GeoRideApi
from .const import DOMAIN as GEORIDE_DOMAIN
from .device import Device
ENTITY_ID_FORMAT = GEORIDE_DOMAIN + ".{}"
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: disable=W0613
"""Set up GeoRide tracker based off an entry."""
georide_context = hass.data[GEORIDE_DOMAIN]["context"]
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
if tracker_device.tracker.version > 2:
entities.append(GeoRideSirenEntity(coordinator, tracker_device, hass))
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
@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)
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

View File

@@ -24,17 +24,18 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: disable=W0613 async def async_setup_entry(hass, config_entry, async_add_entities): # pylint: disable=W0613
"""Set up GeoRide tracker based off an entry.""" """Set up GeoRide tracker based off an entry."""
georide_context = hass.data[GEORIDE_DOMAIN]["context"] 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: for coordoned_tracker in coordoned_trackers:
tracker_device = coordoned_tracker['tracker_device'] tracker_device = coordoned_tracker['tracker_device']
coordinator = coordoned_tracker['coordinator'] coordinator = coordoned_tracker['coordinator']
entity = GeoRideLockSwitchEntity(coordinator, tracker_device, hass)
hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator hass.data[GEORIDE_DOMAIN]["devices"][tracker_device.tracker.tracker_id] = coordinator
lock_switch_entities.append(entity) 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 return True
@@ -50,6 +51,10 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity):
self.entity_id = f"{ENTITY_ID_FORMAT.format('lock')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301 self.entity_id = f"{ENTITY_ID_FORMAT.format('lock')}.{tracker_device.tracker.tracker_id}"# pylint: disable=C0301
self._hass = hass self._hass = hass
@property
def entity_category(self):
return None
async def async_turn_on(self, **kwargs): async def async_turn_on(self, **kwargs):
""" lock the GeoRide tracker """ """ lock the GeoRide tracker """
_LOGGER.info('async_turn_on %s', kwargs) _LOGGER.info('async_turn_on %s', kwargs)
@@ -58,7 +63,7 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity):
success = await self._hass.async_add_executor_job(GeoRideApi.lock_tracker, success = await self._hass.async_add_executor_job(GeoRideApi.lock_tracker,
token, self._tracker_device.tracker.tracker_id) token, self._tracker_device.tracker.tracker_id)
if success: if success:
self._tracker.is_locked = True self._tracker_device.tracker.is_locked = True
async def async_turn_off(self, **kwargs): async def async_turn_off(self, **kwargs):
""" unlock the GeoRide tracker """ """ unlock the GeoRide tracker """
@@ -68,7 +73,7 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity):
success = await self._hass.async_add_executor_job(GeoRideApi.unlock_tracker, success = await self._hass.async_add_executor_job(GeoRideApi.unlock_tracker,
token, self._tracker_device.tracker.tracker_id) token, self._tracker_device.tracker.tracker_id)
if success: if success:
self._tracker.is_locked = False self._tracker_device.tracker.is_locked = False
async def async_toggle(self, **kwargs): async def async_toggle(self, **kwargs):
""" toggle lock the georide tracker """ """ toggle lock the georide tracker """
@@ -77,7 +82,7 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity):
token = await georide_context.get_token() token = await georide_context.get_token()
result = await self._hass.async_add_executor_job(GeoRideApi.toogle_lock_tracker, result = await self._hass.async_add_executor_job(GeoRideApi.toogle_lock_tracker,
token, self._tracker_device.tracker.tracker_id) token, self._tracker_device.tracker.tracker_id)
self._tracker.is_locked = result self._tracker_device.tracker.is_locked = result
@property @property
def unique_id(self): def unique_id(self):
@@ -105,3 +110,66 @@ class GeoRideLockSwitchEntity(CoordinatorEntity, SwitchEntity):
def device_info(self): def device_info(self):
"""Return the device info.""" """Return the device info."""
return self._tracker_device.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
@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)
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

View File

@@ -4,5 +4,5 @@
"render_readme": true, "render_readme": true,
"domains": ["devices_tracker", "sensor"], "domains": ["devices_tracker", "sensor"],
"country": ["FR"], "country": ["FR"],
"homeassistant": "2021.4.0" "homeassistant": "2022.2.0"
} }