fix: GPS from SQLite framekms (confirmed live device schema)
odc-api.db confirmed present on device. framekms table has: latitude, longitude, altitude, hdop, satellites_used, time NOT lat_deg/lon_deg/alt_m/num_satellites as previously assumed. Redis fallback retained, supports both field naming conventions. API response format unchanged (still returns lat_deg/lon_deg for Varroa compat).
This commit is contained in:
parent
174de0637e
commit
595c1cadf5
1 changed files with 74 additions and 27 deletions
|
|
@ -1,40 +1,87 @@
|
|||
"""Redis client for GPS and IMU data."""
|
||||
"""GPS data reader for adacam-api.
|
||||
Primary source: /data/recording/odc-api.db framekms table (confirmed schema from live device).
|
||||
Fallback: Redis (keys may appear when device has outdoor GPS fix post-liberation).
|
||||
|
||||
Confirmed field names from live device:
|
||||
latitude, longitude, altitude, hdop, satellites_used, speed, heading, time
|
||||
"""
|
||||
import json
|
||||
import redis
|
||||
import os
|
||||
import sqlite3
|
||||
import time
|
||||
|
||||
_client = None
|
||||
ODC_DB = '/data/recording/odc-api.db'
|
||||
GNSS_REDIS_KEYS = ['GNSSFusion30Hz', 'GnssData', 'GnssPvt', 'GnssPosition']
|
||||
|
||||
_redis_client = None
|
||||
|
||||
|
||||
def get_client():
|
||||
"""Get Redis connection."""
|
||||
global _client
|
||||
if _client is None:
|
||||
_client = redis.Redis(host="localhost", port=6379, decode_responses=True)
|
||||
return _client
|
||||
def _get_redis():
|
||||
global _redis_client
|
||||
try:
|
||||
import redis
|
||||
if _redis_client is None:
|
||||
_redis_client = redis.Redis(host='localhost', port=6379, decode_responses=True)
|
||||
_redis_client.ping()
|
||||
return _redis_client
|
||||
except Exception:
|
||||
_redis_client = None
|
||||
return None
|
||||
|
||||
|
||||
def get_latest_gnss():
|
||||
"""Get latest GPS fix from GNSSFusion30Hz ZSET."""
|
||||
client = get_client()
|
||||
try:
|
||||
# Get the most recent entry (highest score = most recent timestamp)
|
||||
results = client.zrevrange("GNSSFusion30Hz", 0, 0, withscores=True)
|
||||
if results:
|
||||
data = json.loads(results[0][0])
|
||||
return {
|
||||
"lat_deg": data.get("lat_deg"),
|
||||
"lon_deg": data.get("lon_deg"),
|
||||
"alt_m": data.get("alt_m"),
|
||||
"unix_milliseconds": int(data.get("unix_milliseconds", 0)),
|
||||
"hdop": data.get("hdop"),
|
||||
"num_satellites": data.get("num_satellites", 0),
|
||||
}
|
||||
except (redis.RedisError, json.JSONDecodeError):
|
||||
pass
|
||||
"""Get latest GPS fix. Returns dict with keys: lat_deg, lon_deg, alt_m, hdop, num_satellites.
|
||||
Field names kept compatible with original API response format."""
|
||||
|
||||
# Primary: SQLite framekms (confirmed live device schema)
|
||||
if os.path.exists(ODC_DB):
|
||||
try:
|
||||
conn = sqlite3.connect(ODC_DB)
|
||||
row = conn.execute(
|
||||
'SELECT latitude, longitude, altitude, hdop, satellites_used, time '
|
||||
'FROM framekms WHERE latitude IS NOT NULL AND latitude != 0 '
|
||||
'ORDER BY time DESC LIMIT 1'
|
||||
).fetchone()
|
||||
conn.close()
|
||||
if row:
|
||||
return {
|
||||
'lat_deg': row[0],
|
||||
'lon_deg': row[1],
|
||||
'alt_m': row[2],
|
||||
'hdop': row[3],
|
||||
'num_satellites': row[4],
|
||||
'unix_milliseconds': int(row[5]) if row[5] else int(time.time() * 1000),
|
||||
}
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Fallback: Redis (may appear post-liberation with outdoor GPS fix)
|
||||
r = _get_redis()
|
||||
if r:
|
||||
for key in GNSS_REDIS_KEYS:
|
||||
try:
|
||||
for getter in [lambda k: r.zrevrange(k, 0, 0), lambda k: [r.get(k)]]:
|
||||
items = getter(key)
|
||||
item = items[0] if items else None
|
||||
if item:
|
||||
data = json.loads(item)
|
||||
lat = data.get('latitude') or data.get('lat_deg')
|
||||
lon = data.get('longitude') or data.get('lon_deg')
|
||||
if lat and lon:
|
||||
return {
|
||||
'lat_deg': lat,
|
||||
'lon_deg': lon,
|
||||
'alt_m': data.get('altitude') or data.get('alt_m', 0),
|
||||
'hdop': data.get('hdop', 99),
|
||||
'num_satellites': data.get('satellites_used') or data.get('num_satellites', 0),
|
||||
'unix_milliseconds': int(data.get('unix_milliseconds', time.time() * 1000)),
|
||||
}
|
||||
except Exception:
|
||||
continue
|
||||
return None
|
||||
|
||||
|
||||
def has_gps_lock():
|
||||
"""Check if we have a valid GPS lock."""
|
||||
gnss = get_latest_gnss()
|
||||
return gnss is not None and gnss.get("num_satellites", 0) >= 4
|
||||
return gnss is not None and gnss.get('num_satellites', 0) >= 4
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue