auto: update RTK rover/base + config (2026-05-01 17:00:43)
This commit is contained in:
+25
-1
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys, time, struct, argparse, threading, os, sqlite3, uuid, select, termios, tty
|
||||
import sys, time, struct, argparse, threading, os, sqlite3, uuid, select, termios, tty, json
|
||||
from typing import Optional, Tuple, Dict
|
||||
import serial
|
||||
from serial.serialutil import SerialException
|
||||
@@ -570,6 +570,8 @@ def main():
|
||||
help="Start SQLite recording automatically on service start")
|
||||
ap.add_argument("--record-note", default="auto",
|
||||
help="Note stored in sessions table when --auto-record is used")
|
||||
ap.add_argument("--cmd-file", default="/home/naue/rtk/rtk_rover_cmd.json",
|
||||
help="Command file for web UI start/stop recording")
|
||||
|
||||
ap.add_argument("--site-log", action="store_true",
|
||||
help="Enable construction-site FIX-only CSV/GeoJSON/status logging")
|
||||
@@ -667,6 +669,28 @@ def main():
|
||||
recorder.start(note="manual")
|
||||
print(f"⏺️ Recording START (session={recorder.session_id})")
|
||||
|
||||
# Web/API command file: {"cmd":"start"} or {"cmd":"stop"}
|
||||
try:
|
||||
if args.cmd_file and os.path.exists(args.cmd_file):
|
||||
with open(args.cmd_file, "r", encoding="utf-8") as f:
|
||||
cmd = json.load(f)
|
||||
try:
|
||||
os.remove(args.cmd_file)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
action = str(cmd.get("cmd", "")).lower()
|
||||
note = str(cmd.get("note", "web"))
|
||||
|
||||
if action == "start" and not recorder.is_recording():
|
||||
recorder.start(note=note)
|
||||
print(f"⏺️ Web Recording START (session={recorder.session_id})", flush=True)
|
||||
elif action == "stop" and recorder.is_recording():
|
||||
recorder.stop()
|
||||
print("⏹️ Web Recording STOP", flush=True)
|
||||
except Exception as e:
|
||||
print(f"WEB CMD ERROR: {e}", flush=True)
|
||||
|
||||
f = read_ubx_frame(zed, timeout=0.05)
|
||||
pvt = None
|
||||
hpp = None
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python3
|
||||
import sqlite3, json, time, os
|
||||
from flask import Flask, render_template, request, Response, redirect, url_for
|
||||
|
||||
DB_PATH = "/home/naue/rtk/rtk_rover.db"
|
||||
CMD_FILE = "/home/naue/rtk/rtk_rover_cmd.json"
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def db():
|
||||
con = sqlite3.connect(DB_PATH)
|
||||
con.row_factory = sqlite3.Row
|
||||
return con
|
||||
|
||||
def write_cmd(cmd):
|
||||
tmp = CMD_FILE + ".tmp"
|
||||
with open(tmp, "w", encoding="utf-8") as f:
|
||||
json.dump({"cmd": cmd, "note": "web", "ts": time.time()}, f)
|
||||
os.replace(tmp, CMD_FILE)
|
||||
|
||||
@app.route("/", methods=["GET"])
|
||||
def index():
|
||||
con = db()
|
||||
sessions = con.execute("""
|
||||
SELECT session_id,
|
||||
datetime(start_ts,'unixepoch','localtime') AS start_time,
|
||||
CASE WHEN end_ts IS NULL THEN '' ELSE datetime(end_ts,'unixepoch','localtime') END AS end_time,
|
||||
note,
|
||||
end_ts
|
||||
FROM sessions
|
||||
ORDER BY start_ts DESC
|
||||
LIMIT 50
|
||||
""").fetchall()
|
||||
|
||||
active_session = con.execute("""
|
||||
SELECT session_id, datetime(start_ts,'unixepoch','localtime') AS start_time, note
|
||||
FROM sessions
|
||||
WHERE end_ts IS NULL
|
||||
ORDER BY start_ts DESC
|
||||
LIMIT 1
|
||||
""").fetchone()
|
||||
|
||||
session_id = request.args.get("session_id") or (sessions[0]["session_id"] if sessions else "")
|
||||
only_fix = request.args.get("only_fix", "0") == "1"
|
||||
|
||||
params = []
|
||||
where = ""
|
||||
if session_id:
|
||||
where += " WHERE session_id=?"
|
||||
params.append(session_id)
|
||||
if only_fix:
|
||||
where += " AND carr_soln=2" if where else " WHERE carr_soln=2"
|
||||
|
||||
points = con.execute(f"""
|
||||
SELECT datetime(unix_ts,'unixepoch','localtime') AS t,
|
||||
lat, lon, hmsl_corr_m, hacc_m, vacc_m, carr_soln, num_sats, source
|
||||
FROM gnss_pvt
|
||||
{where}
|
||||
ORDER BY unix_ts DESC
|
||||
LIMIT 200
|
||||
""", params).fetchall()
|
||||
|
||||
count = con.execute(f"SELECT COUNT(*) AS n FROM gnss_pvt {where}", params).fetchone()["n"]
|
||||
|
||||
return render_template("index.html",
|
||||
sessions=sessions,
|
||||
session_id=session_id,
|
||||
only_fix=only_fix,
|
||||
points=points,
|
||||
count=count,
|
||||
active_session=active_session)
|
||||
|
||||
@app.route("/record/start", methods=["POST"])
|
||||
def record_start():
|
||||
write_cmd("start")
|
||||
return redirect(url_for("index"))
|
||||
|
||||
@app.route("/record/stop", methods=["POST"])
|
||||
def record_stop():
|
||||
write_cmd("stop")
|
||||
return redirect(url_for("index"))
|
||||
|
||||
@app.route("/export.csv")
|
||||
def export_csv():
|
||||
session_id = request.args.get("session_id")
|
||||
only_fix = request.args.get("only_fix", "0") == "1"
|
||||
|
||||
params = []
|
||||
where = ""
|
||||
if session_id:
|
||||
where += " WHERE session_id=?"
|
||||
params.append(session_id)
|
||||
if only_fix:
|
||||
where += " AND carr_soln=2" if where else " WHERE carr_soln=2"
|
||||
|
||||
con = db()
|
||||
rows = con.execute(f"""
|
||||
SELECT datetime(unix_ts,'unixepoch','localtime') AS t,
|
||||
lat, lon, hmsl_m, hmsl_corr_m, hacc_m, vacc_m,
|
||||
fix_type, carr_soln, diff_soln, gnss_ok, num_sats, source
|
||||
FROM gnss_pvt
|
||||
{where}
|
||||
ORDER BY unix_ts ASC
|
||||
""", params).fetchall()
|
||||
|
||||
def generate():
|
||||
yield "time,lat,lon,hmsl_m,hmsl_corr_m,hacc_m,vacc_m,fix_type,carr_soln,diff_soln,gnss_ok,num_sats,source\n"
|
||||
for r in rows:
|
||||
yield ",".join(str(r[k]) if r[k] is not None else "" for k in r.keys()) + "\n"
|
||||
|
||||
return Response(generate(), mimetype="text/csv",
|
||||
headers={"Content-Disposition": "attachment; filename=rtk_export.csv"})
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8080)
|
||||
@@ -0,0 +1,76 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>RTK Rover DB</title>
|
||||
<style>
|
||||
body { font-family: sans-serif; margin: 2rem; background: #f6f6f6; }
|
||||
h1 { margin-top: 0; }
|
||||
.card { background: white; padding: 1rem; border-radius: 10px; margin-bottom: 1rem; box-shadow: 0 1px 5px #ccc; }
|
||||
table { width: 100%; border-collapse: collapse; background: white; }
|
||||
th, td { padding: .45rem; border-bottom: 1px solid #ddd; font-size: .9rem; }
|
||||
th { text-align: left; background: #eee; }
|
||||
.fix { color: green; font-weight: bold; }
|
||||
.float { color: orange; font-weight: bold; }
|
||||
select, button, input { padding: .4rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>RTK Rover Datenbank</h1>
|
||||
|
||||
<div class="card">
|
||||
<form method="get">
|
||||
<label>Session:</label>
|
||||
<select name="session_id">
|
||||
{% for s in sessions %}
|
||||
<option value="{{s.session_id}}" {% if s.session_id == session_id %}selected{% endif %}>
|
||||
{{s.start_time}} | {{s.note}} | {{s.session_id[:8]}}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" name="only_fix" value="1" {% if only_fix %}checked{% endif %}>
|
||||
nur RTK FIX
|
||||
</label>
|
||||
|
||||
<button type="submit">Anzeigen</button>
|
||||
<a href="/export.csv?session_id={{session_id}}{% if only_fix %}&only_fix=1{% endif %}">CSV exportieren</a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<b>Punkte:</b> {{count}} |
|
||||
<b>Anzeige:</b> letzte {{points|length}}
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Zeit</th>
|
||||
<th>Lat</th>
|
||||
<th>Lon</th>
|
||||
<th>hMSL corr</th>
|
||||
<th>hAcc</th>
|
||||
<th>vAcc</th>
|
||||
<th>RTK</th>
|
||||
<th>Sats</th>
|
||||
<th>Quelle</th>
|
||||
</tr>
|
||||
{% for p in points %}
|
||||
<tr>
|
||||
<td>{{p.t}}</td>
|
||||
<td>{{"%.8f"|format(p.lat)}}</td>
|
||||
<td>{{"%.8f"|format(p.lon)}}</td>
|
||||
<td>{{"%.3f"|format(p.hmsl_corr_m)}}</td>
|
||||
<td>{{"%.3f"|format(p.hacc_m)}}</td>
|
||||
<td>{{"%.3f"|format(p.vacc_m)}}</td>
|
||||
<td class="{% if p.carr_soln == 2 %}fix{% elif p.carr_soln == 1 %}float{% endif %}">
|
||||
{% if p.carr_soln == 2 %}FIX{% elif p.carr_soln == 1 %}FLOAT{% else %}—{% endif %}
|
||||
</td>
|
||||
<td>{{p.num_sats}}</td>
|
||||
<td>{{p.source}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user