Routenplanung eingebaut
This commit is contained in:
@@ -18,6 +18,9 @@ SPEED_LIMIT_FILE = '/tmp/exomy_speed_limit.txt'
|
||||
DRIVE_ESTIMATOR_CALIBRATION_FILE = os.path.join(
|
||||
os.path.dirname(__file__), '..', 'config', 'drive_estimator_calibration.json'
|
||||
)
|
||||
ROUTE_LIBRARY_FILE = os.path.join(
|
||||
os.path.dirname(__file__), '..', 'config', 'route_library.json'
|
||||
)
|
||||
MOTOR_TEST_LOCK = threading.Lock()
|
||||
|
||||
|
||||
@@ -625,6 +628,156 @@ def save_drive_estimator_calibration(points):
|
||||
}
|
||||
|
||||
|
||||
def get_route_library():
|
||||
data = {
|
||||
'routes': [],
|
||||
'updated_at': None,
|
||||
}
|
||||
|
||||
try:
|
||||
with open(ROUTE_LIBRARY_FILE, 'r', encoding='utf-8') as handle:
|
||||
payload = json.load(handle)
|
||||
routes = payload.get('routes')
|
||||
if isinstance(routes, list):
|
||||
cleaned_routes = []
|
||||
for route in routes:
|
||||
if not isinstance(route, dict):
|
||||
continue
|
||||
name = str(route.get('name', '')).strip()
|
||||
waypoints = route.get('waypoints', [])
|
||||
if not name or not isinstance(waypoints, list):
|
||||
continue
|
||||
cleaned_waypoints = []
|
||||
for point in waypoints:
|
||||
if not isinstance(point, dict):
|
||||
continue
|
||||
try:
|
||||
lat = float(point.get('lat'))
|
||||
lon = float(point.get('lon'))
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
cleaned_waypoints.append({
|
||||
'lat': lat,
|
||||
'lon': lon,
|
||||
})
|
||||
cleaned_routes.append({
|
||||
'name': name,
|
||||
'waypoints': cleaned_waypoints,
|
||||
'updated_at': route.get('updated_at'),
|
||||
})
|
||||
data = {
|
||||
'routes': cleaned_routes,
|
||||
'updated_at': payload.get('updated_at'),
|
||||
}
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except (OSError, ValueError, TypeError, json.JSONDecodeError):
|
||||
return 500, {'status': 'Routen konnten nicht geladen werden'}
|
||||
|
||||
return 200, {
|
||||
'status': 'Bereit',
|
||||
'library': data,
|
||||
}
|
||||
|
||||
|
||||
def save_named_route(name, waypoints):
|
||||
route_name = str(name or '').strip()
|
||||
if not route_name:
|
||||
return 400, {'status': 'Routenname fehlt'}
|
||||
if not isinstance(waypoints, list) or not waypoints:
|
||||
return 400, {'status': 'Route hat keine Wegpunkte'}
|
||||
|
||||
cleaned_waypoints = []
|
||||
for point in waypoints:
|
||||
if not isinstance(point, dict):
|
||||
return 400, {'status': 'Wegpunkte sind ungültig'}
|
||||
try:
|
||||
lat = float(point.get('lat'))
|
||||
lon = float(point.get('lon'))
|
||||
except (TypeError, ValueError):
|
||||
return 400, {'status': 'Wegpunkte sind ungültig'}
|
||||
cleaned_waypoints.append({
|
||||
'lat': lat,
|
||||
'lon': lon,
|
||||
})
|
||||
|
||||
existing_status, existing_response = get_route_library()
|
||||
if existing_status != 200:
|
||||
return existing_status, existing_response
|
||||
|
||||
routes = existing_response['library']['routes']
|
||||
now_text = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
replaced = False
|
||||
for route in routes:
|
||||
if route['name'].lower() == route_name.lower():
|
||||
route['name'] = route_name
|
||||
route['waypoints'] = cleaned_waypoints
|
||||
route['updated_at'] = now_text
|
||||
replaced = True
|
||||
break
|
||||
if not replaced:
|
||||
routes.append({
|
||||
'name': route_name,
|
||||
'waypoints': cleaned_waypoints,
|
||||
'updated_at': now_text,
|
||||
})
|
||||
|
||||
routes.sort(key=lambda item: item['name'].lower())
|
||||
os.makedirs(os.path.dirname(ROUTE_LIBRARY_FILE), exist_ok=True)
|
||||
payload = {
|
||||
'updated_at': now_text,
|
||||
'routes': routes,
|
||||
}
|
||||
try:
|
||||
with open(ROUTE_LIBRARY_FILE, 'w', encoding='utf-8') as handle:
|
||||
json.dump(payload, handle, ensure_ascii=False, indent=2)
|
||||
handle.write('\n')
|
||||
except OSError:
|
||||
return 500, {'status': 'Route konnte nicht gespeichert werden'}
|
||||
|
||||
return 200, {
|
||||
'status': 'Route gespeichert',
|
||||
'route': {
|
||||
'name': route_name,
|
||||
'waypoints': cleaned_waypoints,
|
||||
'updated_at': now_text,
|
||||
},
|
||||
'library': payload,
|
||||
}
|
||||
|
||||
|
||||
def delete_named_route(name):
|
||||
route_name = str(name or '').strip()
|
||||
if not route_name:
|
||||
return 400, {'status': 'Routenname fehlt'}
|
||||
|
||||
existing_status, existing_response = get_route_library()
|
||||
if existing_status != 200:
|
||||
return existing_status, existing_response
|
||||
|
||||
routes = existing_response['library']['routes']
|
||||
filtered_routes = [route for route in routes if route['name'].lower() != route_name.lower()]
|
||||
if len(filtered_routes) == len(routes):
|
||||
return 404, {'status': 'Route nicht gefunden'}
|
||||
|
||||
now_text = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
payload = {
|
||||
'updated_at': now_text,
|
||||
'routes': filtered_routes,
|
||||
}
|
||||
try:
|
||||
with open(ROUTE_LIBRARY_FILE, 'w', encoding='utf-8') as handle:
|
||||
json.dump(payload, handle, ensure_ascii=False, indent=2)
|
||||
handle.write('\n')
|
||||
except OSError:
|
||||
return 500, {'status': 'Route konnte nicht gelöscht werden'}
|
||||
|
||||
return 200, {
|
||||
'status': 'Route gelöscht',
|
||||
'library': payload,
|
||||
}
|
||||
|
||||
|
||||
def preview_drive_neutral_action(values):
|
||||
from admin_motor_test import preview_drive_neutral_value
|
||||
|
||||
@@ -728,9 +881,21 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
||||
status_code, response = get_drive_estimator_calibration()
|
||||
self.write_json(status_code, response)
|
||||
return
|
||||
if self.path == '/api/routes':
|
||||
status_code, response = get_route_library()
|
||||
self.write_json(status_code, response)
|
||||
return
|
||||
self.write_json(404, {'status': 'Unbekannt'})
|
||||
|
||||
def do_POST(self):
|
||||
raw_body = b'{}'
|
||||
if self.path in ('/api/routes/save', '/api/routes/delete'):
|
||||
try:
|
||||
content_length = int(self.headers.get('Content-Length', '0'))
|
||||
except ValueError:
|
||||
content_length = 0
|
||||
raw_body = self.rfile.read(content_length) if content_length > 0 else b'{}'
|
||||
|
||||
if self.path == '/api/delay':
|
||||
try:
|
||||
content_length = int(self.headers.get('Content-Length', '0'))
|
||||
@@ -782,6 +947,31 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
||||
self.write_json(status_code, response)
|
||||
return
|
||||
|
||||
if self.path == '/api/routes/save':
|
||||
try:
|
||||
payload = json.loads(raw_body.decode('utf-8'))
|
||||
except (UnicodeDecodeError, json.JSONDecodeError):
|
||||
self.write_json(400, {'status': 'Ungültige Anfrage'})
|
||||
return
|
||||
|
||||
status_code, response = save_named_route(
|
||||
payload.get('name'),
|
||||
payload.get('waypoints'),
|
||||
)
|
||||
self.write_json(status_code, response)
|
||||
return
|
||||
|
||||
if self.path == '/api/routes/delete':
|
||||
try:
|
||||
payload = json.loads(raw_body.decode('utf-8'))
|
||||
except (UnicodeDecodeError, json.JSONDecodeError):
|
||||
self.write_json(400, {'status': 'Ungültige Anfrage'})
|
||||
return
|
||||
|
||||
status_code, response = delete_named_route(payload.get('name'))
|
||||
self.write_json(status_code, response)
|
||||
return
|
||||
|
||||
if self.path == '/api/motor-test/drive-neutral/preview':
|
||||
try:
|
||||
content_length = int(self.headers.get('Content-Length', '0'))
|
||||
|
||||
Reference in New Issue
Block a user