From e3a612f207400eb17edd7ca4ad67f4c054afc26b Mon Sep 17 00:00:00 2001 From: Benjamin Ramhorst Date: Mon, 14 Feb 2022 20:16:37 +0000 Subject: [PATCH 1/4] Added endpoints for last location and total steps today --- api/data.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/api/data.py b/api/data.py index f140548..e8b47f0 100644 --- a/api/data.py +++ b/api/data.py @@ -46,3 +46,41 @@ def getAllReadings(): results = {'data': data} return Response(json.dumps(results), status=200, mimetype='application/json') + +@data.route('/readings/last/location', methods=['GET']) +def getLastLocation(): + deviceId = request.headers.get('deviceid') + if deviceId is None: + resp = {'error': 'Device not specified'} + return Response(json.dumps(resp), status=400, mimetype='application/json') + + doc = firestore.client().collection(u'readings').document(deviceId).get() + if doc.exists: + data = doc.to_dict()['data'] + lastEntry = data[-1] + lat = lastEntry['latitude'] + lon = lastEntry['longitude'] + else: + lat = -1.0 + lon = -1.0 + + results = {'latitude': lat, 'longitude': lon} + return Response(json.dumps(results), status=200, mimetype='application/json') + +@data.route('/readings/last/steps', methods=['GET']) +def getStepsToday(): + deviceId = request.headers.get('deviceid') + if deviceId is None: + resp = {'error': 'Device not specified'} + return Response(json.dumps(resp), status=400, mimetype='application/json') + + doc = firestore.client().collection(u'readings').document(deviceId).get() + if doc.exists: + data = doc.to_dict()['data'] + lastEntry = data[-1] + steps = lastEntry['cumulative_steps_today'] + else: + steps = 0 + + results = {'cumulative_steps_today': steps} + return Response(json.dumps(results), status=200, mimetype='application/json') From 78ac68cb2dca707f8a9e506fbf850c1efed83e38 Mon Sep 17 00:00:00 2001 From: Benjamin Ramhorst Date: Mon, 14 Feb 2022 21:14:22 +0000 Subject: [PATCH 2/4] =?UTF-8?q?Added=20functionality=20for=20reading=20las?= =?UTF-8?q?t=205=20step=20counts=C2=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/data.py | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/api/data.py b/api/data.py index e8b47f0..4b4fb50 100644 --- a/api/data.py +++ b/api/data.py @@ -1,5 +1,6 @@ import time import json +from datetime import datetime, time, timedelta from flask import Response, Blueprint, request from firebase_admin import firestore @@ -12,12 +13,14 @@ def uploadReadings(): resp = {'error': 'Device not specified'} return Response(json.dumps(resp), status=400, mimetype='application/json') + # Check that measurements are provided body = request.json if body is None: resp = {'error': 'Invalid request - please provide a body'} return Response(json.dumps(resp), status=400, mimetype='application/json') body['timestamp'] = time.time() + # Save all the measurements doc = firestore.client().collection(u'readings').document(deviceId).get() if doc.exists: list = doc.to_dict()['data'] @@ -25,9 +28,9 @@ def uploadReadings(): data = list else: data = [body] - upload = {'data': data} firestore.client().collection(u'readings').document(deviceId).set(upload) + resp = {'success': 'Data saved'} return Response(json.dumps(resp), status=200, mimetype='application/json') @@ -47,7 +50,7 @@ def getAllReadings(): results = {'data': data} return Response(json.dumps(results), status=200, mimetype='application/json') -@data.route('/readings/last/location', methods=['GET']) +@data.route('/readings/location/last', methods=['GET']) def getLastLocation(): deviceId = request.headers.get('deviceid') if deviceId is None: @@ -67,7 +70,7 @@ def getLastLocation(): results = {'latitude': lat, 'longitude': lon} return Response(json.dumps(results), status=200, mimetype='application/json') -@data.route('/readings/last/steps', methods=['GET']) +@data.route('/readings/steps/today', methods=['GET']) def getStepsToday(): deviceId = request.headers.get('deviceid') if deviceId is None: @@ -84,3 +87,35 @@ def getStepsToday(): results = {'cumulative_steps_today': steps} return Response(json.dumps(results), status=200, mimetype='application/json') + +@data.route('/readings/steps/last-five-days', methods=['GET']) +def getStepsLastFiveDays(): + deviceId = request.headers.get('deviceid') + if deviceId is None: + resp = {'error': 'Device not specified'} + return Response(json.dumps(resp), status=400, mimetype='application/json') + + upcomingMidnight = datetime.combine(datetime.today(), time.min) + timedelta(days=1) + doc = firestore.client().collection(u'readings').document(deviceId).get() + + if doc.exists: + data = doc.to_dict()['data'] + listOfDailySteps = [] + + for i in range(0, 5): + found = False + previousMidnight = upcomingMidnight - timedelta(days=1) + print(previousMidnight.timestamp()) + steps = 0 + for reading in reversed(data): + if reading['timestamp'] <= upcomingMidnight.timestamp() and reading['timestamp'] >= previousMidnight.timestamp() and not found: + steps = reading['cumulative_steps_today'] + found = True + listOfDailySteps.append(steps) + upcomingMidnight = previousMidnight + else: + listOfDailySteps = [0] * 5 + + results = {'daily_steps': listOfDailySteps} + return Response(json.dumps(results), status=200, mimetype='application/json') + From 9851513288d6f69e1162e5fb34ed87315db9b1cf Mon Sep 17 00:00:00 2001 From: Benjamin Ramhorst Date: Tue, 15 Feb 2022 00:10:56 +0000 Subject: [PATCH 3/4] Added endpoint for metric summary --- api/data.py | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/api/data.py b/api/data.py index 4b4fb50..ff16579 100644 --- a/api/data.py +++ b/api/data.py @@ -18,7 +18,7 @@ def uploadReadings(): if body is None: resp = {'error': 'Invalid request - please provide a body'} return Response(json.dumps(resp), status=400, mimetype='application/json') - body['timestamp'] = time.time() + body['timestamp'] = datetime.now().timestamp() # Save all the measurements doc = firestore.client().collection(u'readings').document(deviceId).get() @@ -119,3 +119,38 @@ def getStepsLastFiveDays(): results = {'daily_steps': listOfDailySteps} return Response(json.dumps(results), status=200, mimetype='application/json') +@data.route('/readings/metrics-summary', methods=['GET']) +def getMetricsSummary(): + deviceId = request.headers.get('deviceid') + if deviceId is None: + resp = {'error': 'Device not specified'} + return Response(json.dumps(resp), status=400, mimetype='application/json') + + upcomingMidnight = datetime.combine(datetime.today(), time.min) #+ timedelta(days=1) + lastMidnight = datetime.combine(datetime.today(), time.min) - timedelta(days=1) + doc = firestore.client().collection(u'readings').document(deviceId).get() + + if doc.exists: + allData = doc.to_dict()['data'] + currentDayData = [x for x in allData if x['timestamp'] <= upcomingMidnight.timestamp() and x['timestamp'] >= lastMidnight.timestamp()] + if len(currentDayData) >= 1: + maxAirTemp = max(currentDayData, key=lambda x: x['air_temp'])['air_temp'] + maxSkinTemp = max(currentDayData, key=lambda x: x['skin_temp'])['skin_temp'] + maxHumidity = max(currentDayData, key=lambda x: x['humidity'])['humidity'] + minAirTemp = min(currentDayData, key=lambda x: x['air_temp'])['air_temp'] + minSkinTemp = min(currentDayData, key=lambda x: x['skin_temp'])['skin_temp'] + minHumidity = min(currentDayData, key=lambda x: x['humidity'])['humidity'] + results = { + 'last_air_temp': currentDayData[-1]['air_temp'], 'min_air_temp': minAirTemp, 'max_air_temp': maxAirTemp, + 'last_skin_temp': currentDayData[-1]['skin_temp'], 'min_skin_temp': minSkinTemp, 'max_skin_temp': maxSkinTemp, + 'last_humidity': currentDayData[-1]['humidity'], 'min_humidity': minHumidity, 'max_humidity': maxHumidity + } + return Response(json.dumps(results), status=200, mimetype='application/json') + else: + return Response(json.dumps({'error': 'Could not get data from database'}), status=500, mimetype='application/json') + else: + return Response(json.dumps({'error': 'Could not get data from database'}), status=500, mimetype='application/json') + + + + From 2f770d1098781b077b75ef46985c4dd252c7882b Mon Sep 17 00:00:00 2001 From: Benjamin Ramhorst Date: Tue, 1 Mar 2022 11:06:43 +0000 Subject: [PATCH 4/4] Minor fix --- api/authentication.py | 17 +++++++++++++++++ api/data.py | 16 ++++++++-------- lib/utils.py | 9 +-------- main.py | 1 - 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/api/authentication.py b/api/authentication.py index 0aa80dd..0ad9b04 100644 --- a/api/authentication.py +++ b/api/authentication.py @@ -74,3 +74,20 @@ def verify(): lib.utils.sendVerificationMail(user.display_name, user.email, code) resp = {'error': 'Server could not find code, creating new one and sending email'} return Response(json.dumps(resp), status=500, mimetype='application/json') + +@authentication.route('/authentication/get-user-devices', methods=['GET']) +def uploadReadings(): + uid = request.headers.get('UID') + if uid is None: + resp = {'error': 'UID not specified'} + return Response(json.dumps(resp), status=400, mimetype='application/json') + + # Save all the measurements + doc = firestore.client().collection(u'devices').document(uid).get() + if doc.exists: + list = doc.to_dict()['devices'] + data = list + else: + data = [] + res = {'devices': data} + return Response(json.dumps(res), status=200, mimetype='application/json') diff --git a/api/data.py b/api/data.py index ff16579..629cf53 100644 --- a/api/data.py +++ b/api/data.py @@ -8,7 +8,7 @@ data = Blueprint('data', __name__) @data.route('/readings/save', methods=['POST']) def uploadReadings(): - deviceId = request.headers.get('deviceid') + deviceId = request.headers.get('Device-ID') if deviceId is None: resp = {'error': 'Device not specified'} return Response(json.dumps(resp), status=400, mimetype='application/json') @@ -36,7 +36,7 @@ def uploadReadings(): @data.route('/readings/getall', methods=['GET']) def getAllReadings(): - deviceId = request.headers.get('deviceid') + deviceId = request.headers.get('Device-ID') if deviceId is None: resp = {'error': 'Device not specified'} return Response(json.dumps(resp), status=400, mimetype='application/json') @@ -52,7 +52,7 @@ def getAllReadings(): @data.route('/readings/location/last', methods=['GET']) def getLastLocation(): - deviceId = request.headers.get('deviceid') + deviceId = request.headers.get('Device-ID') if deviceId is None: resp = {'error': 'Device not specified'} return Response(json.dumps(resp), status=400, mimetype='application/json') @@ -72,7 +72,7 @@ def getLastLocation(): @data.route('/readings/steps/today', methods=['GET']) def getStepsToday(): - deviceId = request.headers.get('deviceid') + deviceId = request.headers.get('Device-ID') if deviceId is None: resp = {'error': 'Device not specified'} return Response(json.dumps(resp), status=400, mimetype='application/json') @@ -90,7 +90,7 @@ def getStepsToday(): @data.route('/readings/steps/last-five-days', methods=['GET']) def getStepsLastFiveDays(): - deviceId = request.headers.get('deviceid') + deviceId = request.headers.get('Device-ID') if deviceId is None: resp = {'error': 'Device not specified'} return Response(json.dumps(resp), status=400, mimetype='application/json') @@ -121,13 +121,13 @@ def getStepsLastFiveDays(): @data.route('/readings/metrics-summary', methods=['GET']) def getMetricsSummary(): - deviceId = request.headers.get('deviceid') + deviceId = request.headers.get('Device-ID') if deviceId is None: resp = {'error': 'Device not specified'} return Response(json.dumps(resp), status=400, mimetype='application/json') - upcomingMidnight = datetime.combine(datetime.today(), time.min) #+ timedelta(days=1) - lastMidnight = datetime.combine(datetime.today(), time.min) - timedelta(days=1) + upcomingMidnight = datetime.combine(datetime.today(), time.min) + timedelta(days=1) + lastMidnight = datetime.combine(datetime.today(), time.min) doc = firestore.client().collection(u'readings').document(deviceId).get() if doc.exists: diff --git a/lib/utils.py b/lib/utils.py index ba7fbbf..2488e41 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -1,7 +1,7 @@ from random import randint from flask import current_app from flask_mail import Mail, Message -from firebase_admin import auth, firestore +from firebase_admin import firestore def sendMail(subject, sender, recipients, body): mail = Mail(current_app) @@ -24,10 +24,3 @@ def sendVerificationMail(name, email, code): body = '''Hey {}! Thank you for signing up for BarkFinder. In order to use our sevices, could you please verify your email address by logging in and entering this code {}'''.format(name, code) sendMail(subject, sender, recipients, body) - -def userLoggedInAndVerfied(token): - # Need frontend to test this - # decoded_token = auth.verify_id_token(token) - # uid = decoded_token['uid'] - # isVerified = auth.get_user(uid).email_verified - return True #placeholder \ No newline at end of file diff --git a/main.py b/main.py index fc5d5fb..779d57e 100644 --- a/main.py +++ b/main.py @@ -9,7 +9,6 @@ app = Flask(__name__) app.register_blueprint(authentication) app.register_blueprint(data) - # Initialize Mail instance app.config['MAIL_SERVER'] = MAIL_SERVER app.config['MAIL_PORT'] = MAIL_PORT