Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
API - initial commit
- Loading branch information
Showing
8 changed files
with
251 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
from sqlalchemy import create_engine | ||
from sqlalchemy import Column, Integer, String, Binary, Float | ||
from sqlalchemy.orm import relationship, sessionmaker, deferred | ||
from sqlalchemy.orm.collections import attribute_mapped_collection | ||
from sqlalchemy.ext.declarative import declarative_base | ||
|
||
from datetime import datetime | ||
|
||
Base = declarative_base() | ||
|
||
class LocationData(Base): | ||
""" | ||
Location Data for HuskyTrack | ||
Attributes: | ||
uuid: The Location Data's universally unique identifier | ||
uid: The user ID of the user this data belongs to | ||
latitude: The latitude of the device when this measurement was taken | ||
longitude: The longitude of the device when this measurement was taken | ||
accuracy: The accuracy of the measurement as reported by the device | ||
speed: The speed of the device when this measurement was taken | ||
heading: The heading of the device when this measurement was taken | ||
altitude: The altitude of the device when this measurement was taken | ||
timestamp: The time at which this measurement was taken [ISO-8601 UTC] | ||
""" | ||
|
||
__tablename__ = 'location_data' | ||
|
||
uuid = Column('uuid', String, primary_key=True) | ||
uid = Column('uid', String, nullable=False) | ||
latitude = Column('latitude', Float, nullable=False) | ||
longitude = Column('longitude', Float, nullable=False) | ||
accuracy = Column('accuracy', Float, nullable=False) | ||
speed = Column('speed', Float, nullable=False) | ||
heading = Column('heading', Float, nullable=False) | ||
altitude = Column('altitude', Float, nullable=False) | ||
timestamp = Column('timestamp', String, nullable=False) | ||
|
||
def __repr__(self): | ||
return self.uuid |
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import configparser | ||
import sys | ||
import json | ||
from datetime import datetime | ||
|
||
from flask import Flask, request | ||
|
||
from DataObjects import LocationData | ||
from sqlalchemy import create_engine | ||
from sqlalchemy.orm import sessionmaker | ||
|
||
from collections import defaultdict | ||
|
||
app = Flask(__name__) | ||
|
||
ISO8601 = "%Y%m%dT%H%M%S" | ||
ISO8601_O = "%Y-%m-%d %H:%M:%S" | ||
|
||
|
||
def get_config(): | ||
""" | ||
Get the configuration data for the application | ||
""" | ||
try: | ||
config = configparser.SafeConfigParser() | ||
config.read('config.ini') | ||
return config | ||
except Exception as e: | ||
print("No configuration file found.", e) | ||
sys.exit() | ||
|
||
def get_session(config): | ||
""" | ||
Attempt to initialize the database session, quit if the | ||
program cannot find the database. | ||
""" | ||
try: | ||
# Collect Configuration | ||
dao_type = config.get('database', 'type').lower() | ||
username = config.get('database', 'username') | ||
password = config.get('database', 'pass') | ||
host = config.get('database', 'host') | ||
port = config.get('database', 'port') | ||
database = config.get('database', 'database') | ||
|
||
# Build URL | ||
if dao_type == 'sqlite': | ||
url = dao_type + ":///" + host | ||
else: | ||
url = dao_type + "://" + username +\ | ||
":" + password + "@" + host + \ | ||
":" + port + "/" + database | ||
|
||
# Create session | ||
engine = create_engine(url) | ||
Session = sessionmaker(bind=engine) | ||
session = Session() | ||
return session | ||
|
||
except Exception as e: | ||
print("Unable to configure database connection. Error:", e) | ||
sys.exit() | ||
|
||
@app.route('/api') | ||
def api(): | ||
""" | ||
Returns the version for compatibility/availability checks" | ||
""" | ||
return 'v0.1' | ||
|
||
@app.route('/api/locationdata', methods=('GET', 'POST')) | ||
def location_data(): | ||
""" | ||
Request or post location data | ||
""" | ||
session = get_session(get_config()) | ||
if request.method == 'POST': | ||
if request.is_json: | ||
try: | ||
raw_location_data = request.get_json() | ||
location = raw_location_data["location"] | ||
coords = location["coords"] | ||
lat = coords["latitude"] | ||
lng = coords["longitude"] | ||
acc = coords["accuracy"] | ||
spd = coords["speed"] | ||
hed = coords["heading"] | ||
alt = coords["altitude"] | ||
tim = location["timestamp"] | ||
uuid = location["uuid"] | ||
uid = "1" | ||
locationData = LocationData(uuid = uuid, | ||
uid = uid, | ||
latitude = lat, | ||
longitude = lng, | ||
accuracy = acc, | ||
speed = spd, | ||
heading = hed, | ||
altitude = alt, | ||
timestamp = tim) | ||
session.add(locationData) | ||
session.commit() | ||
return "Success" | ||
except Exception as e: | ||
session.rollback() | ||
return ("Fail", str(e)) | ||
else: | ||
return "NOT JSON" | ||
else: | ||
try: | ||
start = request.args.get('start') | ||
end = request.args.get('end') | ||
|
||
start = datetime.strptime(start, ISO8601) | ||
end = datetime.strptime(end, ISO8601) | ||
|
||
print(str([str(start), str(end)])) | ||
query_results = session.query(LocationData).filter(LocationData.timestamp > start, LocationData.timestamp < end).all() | ||
|
||
dataPoints = defaultdict(list) | ||
for result in query_results: | ||
dataPoints[result.uid].append(result) | ||
|
||
result = [] | ||
for user in dataPoints: | ||
print(user) | ||
json_entry = json.loads('{}') | ||
json_entry['user_id'] = user | ||
json_entry['start_time'] = min(dataPoints[user], key=lambda x:x.timestamp).timestamp | ||
json_entry['end_time'] = max(dataPoints[user], key=lambda x:x.timestamp).timestamp | ||
json_entry['locations'] = [] | ||
for location in dataPoints[user]: | ||
json_location = json.loads('{}') | ||
json_location['latitude'] = location.latitude | ||
json_location['longitude'] = location.longitude | ||
json_location['timestamp'] = location.timestamp | ||
json_entry['locations'].append(json_location) | ||
result.append(json_entry) | ||
|
||
return json.dumps(result) | ||
except Exception as e: | ||
print(e) | ||
return json.dumps([[l.uuid, l.latitude, l.longitude, l.timestamp] for l in session.query(LocationData).all()]) | ||
|
||
if __name__ == '__main__': | ||
app.run(debug=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[database] | ||
type = sqlite | ||
host = C:\Users\demel\Documents\GitHub\GPS-Tracking-of-On-Campus-Walking-Project\API\db\test.db | ||
username = mason | ||
pass = mason | ||
port = 3306 | ||
database = mason |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
BEGIN TRANSACTION; | ||
DROP TABLE IF EXISTS `location_data`; | ||
CREATE TABLE IF NOT EXISTS `location_data` ( | ||
`uuid` TEXT NOT NULL PRIMARY KEY UNIQUE, | ||
`uid` TEXT NOT NULL, | ||
`latitude` REAL NOT NULL, | ||
`longitude` REAL NOT NULL, | ||
`accuracy` REAL NOT NULL, | ||
`speed` REAL NOT NULL, | ||
`heading` REAL NOT NULL, | ||
`altitude` REAL NOT NULL, | ||
`timestamp` TEXT NOT NULL | ||
); | ||
COMMIT; |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import json | ||
import urllib2 | ||
import uuid | ||
import datetime | ||
|
||
data = { | ||
"location": { | ||
"coords": { | ||
"latitude": 1.5, | ||
"longitude": 1.5, | ||
"accuracy": 1.5, | ||
"speed": 1.5, | ||
"heading": 1.5, | ||
"altitude": 1.5 | ||
}, | ||
"extras": { | ||
"foo": "bar" | ||
}, | ||
"activity": { | ||
"type": "still", | ||
"confidence": 100 | ||
}, | ||
"geofence": { | ||
"identifier": "identifier", | ||
"action": "ENTER" | ||
}, | ||
"battery": { | ||
"level": 1.5, | ||
"is_charging": True | ||
}, | ||
"timestamp": str(datetime.datetime.now().replace(microsecond=0).isoformat()), | ||
"uuid": str(uuid.uuid4()), | ||
"event": "EVENT", | ||
"is_moving": 1.0, | ||
"odometer": 1.0 | ||
} | ||
} | ||
|
||
req = urllib2.Request('http://127.0.0.1:5000/api/locationdata') | ||
req.add_header('Content-Type', 'application/json') | ||
|
||
response = urllib2.urlopen(req, json.dumps(data)) | ||
|
||
print(response.read()) |