commit cd5adffbd0b010f806f5d1749f5bf463a9bac8a2 Author: Matthieu Date: Fri Oct 25 00:40:15 2019 +0200 First commit with some GeorideApiLib items diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6f9cb1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +examples/__main__.py +__pycache__ +**/__pycache__ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..1bdfb08 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +language: python +python: + - "3.5" +cache: pip +install: + - pip install -r test_requirements.txt + - pip install . +script: + - py.test tests/*_test.py --cov=georideapilib + - pylint georideapilib + - coveralls \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..6e667ea --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# Georideapilib +![Logo Georide](georide-logo.png) + +⚠️ this is not an official implementation + +Official geroide website: https://georide.fr/ + +This library can control your georide tracker tracker + + +Some code have been taken from @alexmohr https://github.com/alexmohr/sonyapilib + +This library is used as communication interface in a home assistant component to control media players, which can be found here:(Not ready yes ;)) + +At the moment not all functions offered by the api are implemented. If you miss a function feel free to create a pull request or open a feature request. + +# Installation +To install simply run +``` +pip install georideapilib +``` + +This library has been tested with python 3.7 and above, functionality for older python version cannot be guaranteed. + diff --git a/examples/example.py b/examples/example.py new file mode 100644 index 0000000..7f45701 --- /dev/null +++ b/examples/example.py @@ -0,0 +1,63 @@ +import api as GeorideApi +from objects import GeorideAccount + +import datetime +import time + + +""" If ypu out to reuse account """ +""" +account = GeorideAccount(, , , ) +""" + +""" Get an acces token """ +account = GeorideApi.getAuthorisationToken("", "") +print("token 1: ", account.authToken) + + +""" do not abuse, renew when previous token have almost reached time """ +""" +account.authToken = GeorideApi.renewToken(account.authToken) +print("token 2: ", account.authToken) +""" + +user = GeorideApi.getUser(account.authToken) +print("User: ", user.firstName) + +trackers = GeorideApi.getTrackers(account.authToken) +tracker = trackers[0] +print("Tracker name: ", tracker.trackerName) + +trips = GeorideApi.getTrips(account.authToken, tracker.trackerId, "2019-10-10", "2019-10-24") +trip = trips[0]; +trip_date = datetime.datetime.strptime("2019-10-10T06:45:34.000Z", '%Y-%m-%dT%H:%M:%S.%fZ') +print("Trip date: {}, from: {}, to: {}".format(trip_date, trip.niceStartAddress, trip.niceEndAddress)) + +positions = GeorideApi.getPositions(account.authToken, tracker.trackerId, "2019-10-10", "2019-10-24") +position = positions[0]; +print("Position speed: {}, lon: {}, lat: {}".format(position.speed, position.longitude, position.latitude)) + + +tripShared = GeorideApi.shareATripByDate(account.authToken, tracker.trackerId, fromDate="2019-10-10", toDate="2019-10-24") +print("tripShared url: {}, id: {}".format(tripShared.url, tripShared.shareId)) + +time.sleep(30) +haveBeenLocked = GeorideApi.lockTracker(account.authToken, tracker.trackerId) +print("Tracker have been locked: ", haveBeenLocked) + +time.sleep(30) +haveBeenUnlocked = GeorideApi.lockTracker(account.authToken, tracker.trackerId) +print("Tracker have been unlocked: ", haveBeenUnlocked) + +time.sleep(30) +isLocked = GeorideApi.toogleLockTracker(account.authToken, tracker.trackerId) +print("Tracker is locked: ", haveBeenUnlocked) + +time.sleep(30) +trackers = GeorideApi.getTrackers(account.authToken) +tracker = trackers[0] +print("Tracker name: ", tracker.trackerName, " is locked: ", tracker.isLocked) + +""" +GeorideApi.revokeToken(account.authToken) +""" \ No newline at end of file diff --git a/georide-logo.png b/georide-logo.png new file mode 100644 index 0000000..b70f563 Binary files /dev/null and b/georide-logo.png differ diff --git a/georideapilib/api.py b/georideapilib/api.py new file mode 100644 index 0000000..cf04ebc --- /dev/null +++ b/georideapilib/api.py @@ -0,0 +1,192 @@ +""" +Georide api lib +@author Matthieu DUVAL +""" + +import urllib3 +import json + +from objects import GeorideTracker, GeorideAccount, GeorideUser, GeorideTrackerTrip, GeorideTrackerPosition, GeorideSharedTrip + +GEORIDE_API_HOST = "https://api.georide.fr" +GEORIDE_API_ENDPOINT_LOGIN = "/user/login" +GEORIDE_API_ENDPOINT_NEW_TOKEN = "/user/new-token" +GEORIDE_API_ENDPOINT_LOGOUT = "/user/logout" +GEORIDE_API_ENDPOINT_USER = "/user" +GEORIDE_API_ENDPOINT_TRAKERS = "/user/trackers" +GEORIDE_API_ENDPOINT_TRIPS = "/tracker/:trackerId/trips" +GEORIDE_API_ENDPOINT_LOCK = "/tracker/:trackerId/lock" +GEORIDE_API_ENDPOINT_UNLOCK = "/tracker/:trackerId/unlock" +GEORIDE_API_ENDPOINT_TOGGLE_LOCK = "/tracker/:trackerId/toggleLock" +GEORIDE_API_ENDPOINT_POSITIONS = "/tracker/:trackerId/trips/positions" +GEORIDE_API_ENDPOINT_TRIP_SHARE = "/tracker/:trackerId/share/trip" + + +def getAuthorisationToken(email, password): + http = urllib3.PoolManager() + data = {"email": email,"password": password} + encoded_data = json.dumps(data).encode('utf-8') + response = http.request( + 'POST', + GEORIDE_API_HOST + GEORIDE_API_ENDPOINT_LOGIN, + body=encoded_data, + headers={'Content-Type': 'application/json'}) + response_data = json.loads(response.data.decode('utf-8')) + account = GeorideAccount.fromJson(response_data) + return account + + +def renewToken(token): + http = urllib3.PoolManager() + headers = {"Authorization": "Bearer " + token} + response = http.request( + 'GET', + GEORIDE_API_HOST + GEORIDE_API_ENDPOINT_NEW_TOKEN, + headers=headers) + response_data = json.loads(response.data.decode('utf-8')) + newToken = response_data['authToken'] + return newToken + + +def revokeToken(token): + http = urllib3.PoolManager() + headers = {"Authorization": "Bearer " + token} + response = http.request( + 'POST', + GEORIDE_API_HOST + GEORIDE_API_ENDPOINT_LOGOUT, + headers=headers) + if response.status == 204: + return True + else: + return False + + +def getUser(token): + http = urllib3.PoolManager() + headers = {"Authorization": "Bearer " + token} + response = http.request( + 'GET', + GEORIDE_API_HOST + GEORIDE_API_ENDPOINT_USER, + headers=headers) + response_data = json.loads(response.data.decode('utf-8')) + account = GeorideUser.fromJson(response_data) + return account + +def getTrackers(token): + http = urllib3.PoolManager() + headers = {"Authorization": "Bearer " + token} + response = http.request( + 'GET', + GEORIDE_API_HOST + GEORIDE_API_ENDPOINT_TRAKERS, + headers=headers) + + response_data = json.loads(response.data.decode('utf-8')) + trackers = [] + for json_tracker in response_data: + trackers.append(GeorideTracker.fromJson(json_tracker)) + return trackers + + +def getTrips(token, trackerId, fromDate, toDate): + http = urllib3.PoolManager() + headers = {"Authorization": "Bearer " + token} + response = http.request( + 'GET', + GEORIDE_API_HOST + GEORIDE_API_ENDPOINT_TRIPS.replace(':trackerId', str(trackerId)), + fields={'from': fromDate, 'to': toDate}, + headers=headers) + + response_data = json.loads(response.data.decode('utf-8')) + trips = [] + for json_trip in response_data: + trips.append(GeorideTrackerTrip.fromJson(json_trip)) + return trips + +def getPositions(token, trackerId, fromDate, toDate): + http = urllib3.PoolManager() + headers = {"Authorization": "Bearer " + token} + response = http.request( + 'GET', + GEORIDE_API_HOST + GEORIDE_API_ENDPOINT_POSITIONS.replace(':trackerId', str(trackerId)), + fields={'from': fromDate, 'to': toDate}, + headers=headers) + + response_data = json.loads(response.data.decode('utf-8')) + positions = [] + for json_position in response_data: + positions.append(GeorideTrackerPosition.fromJson(json_position)) + return positions + +def shareATripByTripId(token, trackerId, tripId): + return _shareATrip(token, trackerId, tripId=tripId) + +def shareATripByDate(token, trackerId, fromDate, toDate): + return _shareATrip(token, trackerId, fromDate=fromDate, toDate=toDate) + +def shareATripByTripMergeId(token, trackerId, tripMergedId): + return _shareATrip(token, trackerId, tripMergedId=tripMergedId) + +def _shareATrip(token, trackerId, tripId=None, fromDate=None, toDate=None, tripMergedId=None): + data = None + if tripId != None: + data = {"tripId": tripId} + elif fromDate != None and toDate != None: + data = {"from": fromDate, "to": toDate} + elif tripMergedId != None: + data = {"tripMergedId": tripMergedId} + + encoded_data = json.dumps(data).encode('utf-8') + print("Trip data: ", encoded_data) + + http = urllib3.PoolManager() + headers = { + "Authorization": "Bearer " + token, + 'Content-Type': 'application/json' + } + response = http.request( + 'POST', + GEORIDE_API_HOST + GEORIDE_API_ENDPOINT_TRIP_SHARE.replace(':trackerId', str(trackerId)), + body=encoded_data, + headers=headers) + + response_data = json.loads(response.data.decode('utf-8')) + print("Trip data: ", response_data) + return GeorideSharedTrip.fromJson(response_data) + +def lockTracker(token, trackerId): + http = urllib3.PoolManager() + headers = {"Authorization": "Bearer " + token} + response = http.request( + 'POST', + GEORIDE_API_HOST + GEORIDE_API_ENDPOINT_LOCK.replace(':trackerId', str(trackerId)), + headers=headers) + if response.status == 204: + return True + else: + return False + +def unlockTracker(token, trackerId): + http = urllib3.PoolManager() + headers = {"Authorization": "Bearer " + token} + response = http.request( + 'POST', + GEORIDE_API_HOST + GEORIDE_API_ENDPOINT_UNCLOCK.replace(':trackerId', str(trackerId)), + headers=headers) + if response.status == 204: + return True + else: + return False + +def toogleLockTracker(token, trackerId): + http = urllib3.PoolManager() + headers = {"Authorization": "Bearer " + token} + response = http.request( + 'POST', + GEORIDE_API_HOST + GEORIDE_API_ENDPOINT_TOGGLE_LOCK.replace(':trackerId', str(trackerId)), + headers=headers) + response_data = json.loads(response.data.decode('utf-8')) + return response_data['locked'] + +if __name__ == '__main__': + print("Not a main module") + diff --git a/georideapilib/objects.py b/georideapilib/objects.py new file mode 100644 index 0000000..6b32f04 --- /dev/null +++ b/georideapilib/objects.py @@ -0,0 +1,504 @@ +""" +Georide objects implementation +@author Matthieu DUVAL +""" + +class GeorideSharedTrip: + def __init__(self, url, shareId): + self._url = url + self._shareId = shareId + + @property + def url(self): + return self._url + + @property + def shareId(self): + return self._shareId + + def fromJson(json): + return GeorideSharedTrip( + json['url'], + json['shareId'] + ) + +class GeorideTrackerTrip: + def __init__(self, tripId, trackerId, averageSpeed, maxSpeed, distance, duration, startAddress, niceStartAddress, startLat, + startLon, endAddress, niceEndAddress, endLat, endLon, startTime, endTime): + self._tripId = tripId + self._trackerId = trackerId + self._averageSpeed = averageSpeed + self._maxSpeed = maxSpeed + self._distance = distance + self._duration = duration + self._startAddress = startAddress + self._niceStartAddress = niceStartAddress + self._startLat = startLat + self._startLon = startLon + self._endAddress = endAddress + self._niceEndAddress = niceEndAddress + self._endLat = endLat + self._endLon = endLon + self._startTime = startTime + self._endTime = endTime + + @property + def tripId(self): + return self._tripId + + @property + def trackerId(self): + return self._trackerId + + @property + def averageSpeed(self): + return self._averageSpeed + + @property + def maxSpeed(self): + return self._maxSpeed + + @property + def distance(self): + return self._distance + + @property + def duration(self): + return self._duration + + @property + def startAddress(self): + return self._startAddress + + @property + def niceStartAddress(self): + return self._niceStartAddress + + @property + def startLat(self): + return self._startLat + + @property + def startLon(self): + return self._startLon + + @property + def endAddress(self): + return self._endAddress + + @property + def niceEndAddress(self): + return self._niceEndAddress + + @property + def endLat(self): + return self._endLat + + @property + def endLon(self): + return self._endLon + + @property + def startTime(self): + return self._startTime + + @property + def endTime(self): + return self._endTime + + def fromJson(json): + return GeorideTrackerTrip( + json['id'], + json['trackerId'], + json['averageSpeed'], + json['maxSpeed'], + json['distance'], + json['duration'], + json['startAddress'], + json['niceStartAddress'], + json['startLat'], + json['startLon'], + json['endAddress'], + json['niceEndAddress'], + json['endLat'], + json['endLon'], + json['startTime'], + json['endTime'] + ) + + +class GeorideTrackerPosition: + def __init__(self, fixtime, latitude, longitude, altitude, speed, address): + self._fixtime = fixtime + self._latitude = latitude + self._longitude = longitude + self._altitude = altitude + self._speed = speed + self._address = address + + @property + def fixtime(self): + return self._fixtime + + @property + def latitude(self): + return self._latitude + + @property + def longitude(self): + return self._longitude + + @property + def altitude(self): + return self._altitude + + @property + def speed(self): + return self._speed + + @property + def address(self): + return self._address + + def fromJson(json): + return GeorideTrackerPosition( + json['fixtime'], + json['latitude'], + json['longitude'], + json['altitude'], + json['speed'], + json['address'] + ) + + + + +class GeorideTracker: + def __init__(self, trackerId, trackerName, deviceButtonAction, deviceButtonDelay, vibrationLevel, isOldTracker, autoLockFreezedTo, + fixtime, role, lastPaymentDate, giftCardId, expires, activationDate, odometer, isStolen, isCrashed, crashDetectionDisabled, + speed, moving, positionId, latitude, longitude, altitude, lockedPositionId, lockedLatitude, lockedLongitude, isLocked, + canSeePosition, canLock, canUnlock, canShare, canUnshare, canCheckSpeed, canSeeStatistics, canSendBrokenDownSignal, + canSendStolenSignal, status): + self._trackerId = trackerId + self._trackerName = trackerName + self._deviceButtonAction = deviceButtonAction + self._deviceButtonDelay = deviceButtonDelay + self._vibrationLevel = vibrationLevel + self._isOldTracker = isOldTracker + self._autoLockFreezedTo = autoLockFreezedTo + self._fixtime = fixtime + self._role = role + self._lastPaymentDate = lastPaymentDate + self._giftCardId = giftCardId + self._expires = expires + self._activationDate = activationDate + self._odometer = odometer + self._isStolen = isStolen + self._isCrashed = isCrashed + self._crashDetectionDisabled = crashDetectionDisabled + self._speed = speed + self._moving = moving + self._positionId = positionId + self._latitude = latitude + self._longitude = longitude + self._altitude = altitude + self._lockedPositionId = lockedPositionId + self._lockedLatitude = lockedLatitude + self._lockedLongitude = lockedLongitude + self._isLocked = isLocked + self._canSeePosition = canSeePosition + self._canLock = canLock + self._canUnlock = canUnlock + self._canShare = canShare + self._canUnshare = canUnshare + self._canCheckSpeed = canCheckSpeed + self._canSeeStatistics = canSeeStatistics + self._canSendBrokenDownSignal = canSendBrokenDownSignal + self._canSendStolenSignal = canSendStolenSignal + self._status = status + + @property + def trackerId(self): + return self._trackerId + + @property + def trackerName(self): + return self._trackerName + + @property + def deviceButtonAction(self): + return self._deviceButtonAction + + @property + def deviceButtonDelay(self): + return self._deviceButtonDelay + + @property + def vibrationLevel(self): + return self._vibrationLevel + + @property + def isOldTracker(self): + return self._isOldTracker + + @property + def autoLockFreesedTo(self): + return self._autoLockFreesedTo + + @property + def fixtime(self): + return self._fixtime + + @property + def role(self): + return self._role + + @property + def lastPayementDate(self): + return self._lastPayementDate + + @property + def giftCardId(self): + return self._giftCardId + + @property + def expires(self): + return self._expires + + @property + def activationDate(self): + return self._activationDate + + @property + def odometer(self): + return self._odometer + + @property + def isStolen(self): + return self._isStolen + + @property + def isCrashed(self): + return self._isCrashed + + @property + def crashDetectionDisabled(self): + return self._crashDetectionDisabled + + @property + def speed(self): + return self._speed + + @property + def moving(self): + return self._moving + + @property + def positionId(self): + return self._positionId + + @property + def latitude(self): + return self._latitude + + @property + def longitude(self): + return self._longitude + + @property + def altitude(self): + return self._altitude + + @property + def lockedPositionId(self): + return self._lockedPositionId + + @property + def lockedLatitude(self): + return self._lockedLatitude + + @property + def lockedLongitude(self): + return self._lockedLongitude + + @property + def isLocked(self): + return self._isLocked + + @property + def canSeePosition(self): + return self._canSeePosition + + @property + def canLock(self): + return self._canLock + + @property + def canUnlock(self): + return self._canUnlock + + @property + def canShare(self): + return self._canShare + + @property + def canUnshare(self): + return self._canUnshare + + @property + def canCheckSpeed(self): + return self._canCheckSpeed + + @property + def canSeeStatistics(self): + return self._canSeeStatistics + + @property + def canSendBrokenDownSignal(self): + return self._canSendBrokenDownSignal + + @property + def canSendStolenSignal(self): + return self._canSendStolenSignal + + @property + def status(self): + return self._status + + def fromJson(json): + return GeorideTracker( + json['trackerId'], + json['trackerName'], + json['deviceButtonAction'], + json['deviceButtonDelay'], + json['vibrationLevel'], + json['isOldTracker'], + json['autoLockFreezedTo'], + json['fixtime'], + json['role'], + json['lastPaymentDate'], + json['giftCardId'], + json['expires'], + json['activationDate'], + json['odometer'], + json['isStolen'], + json['isCrashed'], + json['crashDetectionDisabled'], + json['speed'], + json['moving'], + json['positionId'], + json['latitude'], + json['longitude'], + json['altitude'], + json['lockedPositionId'], + json['lockedLatitude'], + json['lockedLongitude'], + json['isLocked'], + json['canSeePosition'], + json['canLock'], + json['canUnlock'], + json['canShare'], + json['canUnshare'], + json['canCheckSpeed'], + json['canSeeStatistics'], + json['canSendBrokenDownSignal'], + json['canSendStolenSignal'], + json['status'] + ) + + +class GeorideAccount: + def __init__(self, account_id, email, isAdmin, authToken): + self._account_id = account_id + self._email = email + self._isAdmin = isAdmin + self._authToken = authToken + + @property + def account_id(self): + return self._account_id + + @property + def email(self): + return self._email + + @property + def isAdmin(self): + return self._isAdmin + + @property + def authToken(self): + return self._authToken + + @authToken.setter + def authToken(self, newToken): + self._authToken = newToken + + def fromJson(json): + return GeorideAccount( + json['id'], + json['email'], + json['isAdmin'], + json['authToken'] + ) + + +class GeorideUser: + def __init__(self, account_id, email, firstName, createdAt, phoneNumberp, pushUserToken, legal, dateOfBirth): + self._account_id = account_id + self._email = email + self._firstName = firstName + self._createdAt = createdAt + self._phoneNumberp = phoneNumberp + self._pushUserToken = pushUserToken + self._legal = legal + self._dateOfBirth = dateOfBirth + + @property + def user_id(self): + return self._user_id + + @property + def email(self): + return self._email + + @property + def firstName(self): + return self._firstName + + @property + def createdAt(self): + return self._createdAt + + @property + def phoneNumber(self): + return self._phoneNumber + + @property + def pushUserToken(self): + return self._pushUserToken + + @property + def legal(self): + return self._legal + + @property + def dateOfBirth(self): + return self._dateOfBirth + + def fromJson(json): + return GeorideUser( + json['id'], + json['email'], + json['firstName'], + json['createdAt'], + json['phoneNumber'], + json['pushUserToken'], + json['legal'], + json['dateOfBirth'] + ) + + + +if __name__ == '__main__': + print("Not a main module") \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..7d10829 --- /dev/null +++ b/manifest.json @@ -0,0 +1,10 @@ +{ + "domain": "georide", + "name": "Georide", + "config_flow": true, + "documentation": "https://georide.fr", + "dependencies": [ + "urllib3" + ], + "codeowners": [] +} \ No newline at end of file diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..224a779 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[metadata] +description-file = README.md \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b3b8152 --- /dev/null +++ b/setup.py @@ -0,0 +1,40 @@ +# pylint: disable=invalid-name, exec-used +"""Setup georideapilib package.""" +from __future__ import absolute_import + +import os +import sys + +from setuptools import setup + +sys.path.insert(0, '.') + +CURRENT_DIR = os.path.dirname(__file__) + +# to deploy to pip, please use +# make pythonpack +# python setup.py register sdist upload +# and be sure to test it firstly using +# "python setup.py register sdist upload -r pypitest" +setup( + name='georideapilib', + packages=['georideapilib'], # this must be the same as the name above + version='0.1.0', + description='Lib to control georide tracker devices with their rest api', + author='Matthieu DUVAL', + author_email='georideapilib@duval-dev.fr', + # use the URL to the github repo + url='https://github.com/ptimatth/pyGeoride', + download_url='https://codeload.github.com/ptimatth/pyGeoride/tar.gz/0.1.0', + keywords=['rest', 'georide', 'api', 'grutier'], # arbitrary keywords + classifiers=[], + install_requires=[], + tests_require=[ + 'pytest>=3.7', + 'pytest-pep8', + 'pytest-cov', + 'python-coveralls', + 'pylint', + 'coverage>=4.4' + ] +) \ No newline at end of file diff --git a/test_requirements.txt b/test_requirements.txt new file mode 100644 index 0000000..6cbcae9 --- /dev/null +++ b/test_requirements.txt @@ -0,0 +1,6 @@ +pytest>=3.7 +pytest-pep8 +pytest-cov +python-coveralls +pylint +coverage>=4.4 \ No newline at end of file