A big fuck-off commit with a bunch of bug fixes, bug additions, and a lot of work put into navigationd to the point that it actually does shit

This commit is contained in:
Innovation 2024-05-04 12:01:15 +01:00
parent 1d403fc838
commit d973245735
5 changed files with 280 additions and 9 deletions

View file

@ -0,0 +1,107 @@
import gpsd
import time
import requests
import geopandas as gpd
import osmnx as ox
import networkx as nx
import os
urlBase = 'http://localhost:5000'
urlLocation = urlBase + '/api/navigation/position'
urlImage = urlBase + '/api/navigation/image'
urlAddCyberware = urlBase + '/api/cyberware/add'
urlRemoveCyberware = urlBase + '/api/cyberware/remove'
uuid = ""
def connectCyberware():
global uuid
# Add to Cyberware and get UUID
try:
uuidRequest = requests.post(urlAddCyberware, json={ 'name': 'GPS', 'hotpluggable': True, 'canSet': [ '/api/navigation/position', '/api/navigation/image' ] })
uuid = uuidRequest.json()[0]['uuid']
except:
print("Cannot connect to NightCall. Stopping.")
exit()
def disconnectCyberware():
try:
disconnectRequest = requests.post(urlRemoveCyberware, json={ 'uuid': uuid })
except:
print("Cannot disconnect Cyberware.")
gpsdData = None
def getMapImage(distance):
ox.settings.use_cache = True
if(gpsdData.lat == 0 and gpsdData.lon == 0):
point = (42.352593, -83.2640164)
try:
G = ox.graph_from_point(point, dist=distance, dist_type="bbox", network_type="drive")
# impute edge (driving) speeds and calculate edge travel times
G = ox.routing.add_edge_speeds(G)
G = ox.routing.add_edge_travel_times(G)
# I'm not sure how to handle this short of saving it and then reading it. :(
filepath = uuid+".png"
ox.plot_graph(G, show=True, node_size=0, edge_linewidth=2, bgcolor="#0B1629", edge_color="#5FE0E9", save=True, filepath=filepath)
except ox._errors.InsufficientResponseError:
print("Insufficient response. Skipping.")
#def getMapImage(area):
# #lat, lon = gpsdData.position()
# lat, lon = 41.7573113, -93.8128377
# bbox = lat-(area/2.0), lat+(area/2.0), lon+(area/2.0), lon-(area/2.0)
#
# G = ox.graph_from_bbox(bbox=bbox, network_type="drive_service")
def sendLocation():
try:
#request = requests.post(urlLocation, json={ 'x': gpsdData.lat, 'y': gpsdData.lon, 'z': gpsdData.alt, 'o': gpsdData.track })
request = requests.post(urlLocation, json={ 'x': None, 'y': None, 'z': None, 'o': None, 'uuid': uuid })
except:
print('Could not contact NightCall')
def sendMapImage():
try:
files = { 'image': open(uuid+".png", 'rb') }
request = requests.post(urlImage, files=files)
except:
print("Could not contact NightCall")
print("Connecting to gpsd")
gpsd.connect() # Connect to gpsd
continueFlag = True
print("Adding Cyberware")
connectCyberware()
while continueFlag:
try:
time.sleep(1)
try:
gpsdData = gpsd.get_current()
except gpsd.NoFixError:
gpsdData = None
print("No GPS fix yet! Using default coordinates.")
getMapImage(1000)
sendLocation()
sendMapImage()
#print(packet.position())
except KeyboardInterrupt:
print("Exiting.")
continueFlag = False;
print("Removing Cyberware")
disconnectCyberware()
print("Cleaning up")
os.remove(uuid+".png")

View file

@ -1 +1,7 @@
pygarmin
gpsd-py3
osmnx
gdal==3.6.2
geopandas
matplotlib
networkx
numpy

View file

@ -1,10 +1,11 @@
from flask import Flask, render_template, jsonify, request
from flask import Flask, render_template, jsonify, request, send_file
from flask_apscheduler import APScheduler
from copy import copy
import uuid
import time
from datetime import datetime
import requests
import io
app = Flask(__name__)
@ -432,6 +433,103 @@ def setEnvironmentHumidity():
return 'Incorrect usage.\nUsage: { humidity: INT, uuid: STRING }\n', 400
return '', 204
navigationX = None
navigationY = None
navigationZ = None
navigationO = None
navigationImage = None
# Navigation
@app.route('/api/navigation')
def getNavigation():
returnArr = [ { 'x': navigationX, 'y': navigationY, 'z': navigationZ, 'o': navigationO, 'img': navigationImage } ]
return jsonify(returnArr), 200
# Navigation//Position
# Position consists of: { x: FLOAT, y: FLOAT, z: FLOAT, o: FLOAT }
# o stands for ORIENTATION. o may be NoneType to indicate that such data is not available.
@app.route('/api/navigation/position')
def getNavigationPosition():
returnArr = [ { 'x': navigationX, 'y': navigationY, 'z': navigationZ, 'o': navigationO } ]
return jsonify(returnArr), 200
@app.route('/api/navigation/position', methods=['POST'])
def setNavigationPosition():
global navigationX
global navigationY
global navigationZ
global navigationO
json = request.get_json()
try:
uuid = json['uuid']
if not authenticate(uuid, '/api/navigation/position'):
return 'Forbidden.', 403
tempX = json['x']
tempY = json['y']
tempZ = json['z']
tempO = json['o']
navigationX = tempX
navigationY = tempY
navigationZ = tempZ
navigationO = tempO
except:
return 'Incorrect usage.\nUsage: { x: FLOAT, y: FLOAT, z: FLOAT, o: FLOAT }\n', 400
return '', 204
# Navigation//Position//x
#@app.route('/api/navigation/position/x')
#def getNavigationPositionX():
# return jsonify( [ 'x': navigationX ]), 200
#@app.route('/api/navigation/position/x', methods=['POST'])
#def setNavigationPositionX():
# global navigationX
#
# json = request.get_json()
#
# try:
# if not authenticate(url,
# except:
#
# Navigation//Image
@app.route('/api/navigation/image')
def getNavigationImage():
#returnArr = [ { 'img': navigationImage } ]
#return jsonify(returnArr), 200
if(navigationImage != None):
imageStream = io.BytesIO(navigationImage)
return send_file(imageStream, mimetype="image/png", download_name="minimap.png", max_age=0) # We don't want this to cache ever
else:
return '', 200
@app.route('/api/navigation/image', methods=['POST'])
def setNavigationImage():
global navigationImage
try:
filename = request.files['image'].filename
uuid = filename.split('.')[0]
if not authenticate(uuid, '/api/navigation/image'):
return "Forbidden.", 403
file = request.files['image'].read()
navigationImage = file
except:
return 'Auth failed, or no file was sent.\n', 400
return '', 204
def resetNavigationImage():
global navigationImage
navigationImage = None
# Authentication method
# This authorizes the given UUID to determine whether the request is
# allowed to set the requested endpoint.
@ -441,12 +539,16 @@ def authenticate(uuid, endpoint):
if uuid == internalUUID:
return True
requestedHardware = None
for c in cyberware: # UUID Match
if c['uuid'] == uuid:
requestedHardware = c
c['lastContact'] = datetime.now() # Update last contact
break
if requestedHardware == None:
return False
if requestedHardware['canSet'] == None:
return False
@ -458,14 +560,16 @@ def authenticate(uuid, endpoint):
@app.route('/')
def uiindex():
return render_template('index.html')
address = request.base_url
return render_template('index.html', access_addr=address )
# Maintenance functions
# The jank, my oh my
valuesToValidate = [ '/api/vitals/heartrate', '/api/vitals/oxygen', '/api/vitals/bodytemp',
'/api/fitness/steps',
'/api/environment/temperature', '/api/environment/humidity']
'/api/environment/temperature', '/api/environment/humidity',
'/api/navigation/position', '/api/navigation/image']
baseURL = "http://localhost:5000"
# Value invalidation. A value is deemed invalid when there's no hardware attached
# that can set it.
@ -490,6 +594,13 @@ def valueInvalidation():
endpointToReset = baseURL + invalidValue
# Don't look at the special cases. STOP LOOKING AT IT
match invalidValue:
case '/api/navigation/position':
requests.post(endpointToReset, json={ 'x': None, 'y': None, 'z': None, 'o': None, 'uuid': internalUUID })
case '/api/navigation/image':
resetNavigationImage()
case _:
requests.post(endpointToReset, json={ key: None, 'uuid': internalUUID })
invalidStr = invalidStr + invalidValue + ", "

View file

@ -1,4 +1,9 @@
flask
Flask-APScheduler
pygarmin
gpsd-py3
gdal=3.6.2
geopandas
osmnx
matplotlib
numpy
requests

View file

@ -7,6 +7,7 @@
}
p {
font-size 24px;
color: red;
}
@ -114,6 +115,30 @@
width: 100%;
border: 1px solid #5FE0E9;
max-width: 100%;
overflow: hidden;
position: relative;
/*display: flex;
justify-content: center;*/
/*align-items: center;*/
}
#mapImage {
width: 150%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
#mapDot {
width: 5px;
height: 5px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #F00;
border-radius: 50%;
}
/* Contains the time */
@ -191,7 +216,8 @@
</div>
</div>
<div id="mapProper">
<img id="mapImage" alt=" "></img>
<div id="mapDot"></div>
</div>
<div id="mapTime">
<p id="time">00:00:00</p>
@ -216,12 +242,13 @@
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.2/jquery.min.js" integrity="sha512-tWHlutFnuG0C6nQRlpvrEhE4QpkG1nn2MOUMWmUeRePl4e3Aki0VB6W1v3oLjFtd0hVOtRQ9PHpSfN6u6/QXkQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="text/javascript">
// TODO: Make baseUrl be set by Flask
var baseUrl = "http://localhost:5000";
//var baseUrl = "http://192.168.6.48:5000";
var baseUrl = "{{ access_addr }}";
var vitalsUrl = baseUrl + "/api/vitals";
var environmentUrl = baseUrl + "/api/environment";
var malfunctionUrl = baseUrl + "/api/cyberware/malfunctions";
var messageUrl = baseUrl + "/api/cyberware/messages";
var navImageUrl = baseUrl + "/api/navigation/image";
// Malfunction Messages (human-friendly)
malfunctionOrigin = [ "API Malfunction" ];
@ -297,7 +324,20 @@
}
function setEnvironmentHumidity(humidity) {
}
//function handleMapImage() {
// document.getElementById("mapProper").innerHTML = "<img src=" + navImageUrl + "></img>";
//}
//function displayMapStatic() {
// document.getElementById("mapProper").innerHTML = "";
//}
function updateNavigationImage() {
//handleMapImage()
var image = document.getElementById("mapImage");
image.src = navImageUrl + "?" + new Date().getTime();
}
// Malfunction handling
@ -347,6 +387,8 @@
}
});
//stopInterval(t)
updateNavigationImage()
}
var t=setInterval(updateAll, 1000)
</script>