|
@@ -6,18 +6,20 @@ import threading
|
|
|
import time
|
|
import time
|
|
|
from dataclasses import dataclass
|
|
from dataclasses import dataclass
|
|
|
from pathlib import Path
|
|
from pathlib import Path
|
|
|
-from typing import Dict, List, Optional, Tuple
|
|
|
|
|
|
|
+from typing import List, Optional
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
@dataclass(frozen=True)
|
|
|
class RouteInfo:
|
|
class RouteInfo:
|
|
|
id: int
|
|
id: int
|
|
|
name: str
|
|
name: str
|
|
|
|
|
+ mode: str
|
|
|
created_at: int
|
|
created_at: int
|
|
|
finished_at: Optional[int]
|
|
finished_at: Optional[int]
|
|
|
points: int
|
|
points: int
|
|
|
hazards: int
|
|
hazards: int
|
|
|
active: bool
|
|
active: bool
|
|
|
|
|
+ monitoring: bool
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
@dataclass(frozen=True)
|
|
@@ -28,6 +30,8 @@ class RoutePoint:
|
|
|
lon: float
|
|
lon: float
|
|
|
speed_mps: float
|
|
speed_mps: float
|
|
|
cum_dist_m: float
|
|
cum_dist_m: float
|
|
|
|
|
+ counter_value: int = 0
|
|
|
|
|
+ counter_absolute: int = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
@dataclass(frozen=True)
|
|
@@ -41,6 +45,8 @@ class Hazard:
|
|
|
cum_dist_m: float
|
|
cum_dist_m: float
|
|
|
type: str
|
|
type: str
|
|
|
note: str
|
|
note: str
|
|
|
|
|
+ counter_value: int = 0
|
|
|
|
|
+ counter_absolute: int = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
class NavDB:
|
|
class NavDB:
|
|
@@ -54,7 +60,6 @@ class NavDB:
|
|
|
|
|
|
|
|
@classmethod
|
|
@classmethod
|
|
|
def default(cls) -> "NavDB":
|
|
def default(cls) -> "NavDB":
|
|
|
- # .../main/xiaozhi-server/plugins_func/nav_copilot/storage.py -> parents[2] == .../main/xiaozhi-server
|
|
|
|
|
base = Path(__file__).resolve().parents[2]
|
|
base = Path(__file__).resolve().parents[2]
|
|
|
return cls(str(base / "data" / "nav_copilot.sqlite3"))
|
|
return cls(str(base / "data" / "nav_copilot.sqlite3"))
|
|
|
|
|
|
|
@@ -66,9 +71,11 @@ class NavDB:
|
|
|
CREATE TABLE IF NOT EXISTS routes (
|
|
CREATE TABLE IF NOT EXISTS routes (
|
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
name TEXT NOT NULL,
|
|
name TEXT NOT NULL,
|
|
|
|
|
+ mode TEXT NOT NULL DEFAULT 'gps',
|
|
|
created_at INTEGER NOT NULL,
|
|
created_at INTEGER NOT NULL,
|
|
|
finished_at INTEGER,
|
|
finished_at INTEGER,
|
|
|
- active INTEGER NOT NULL DEFAULT 0
|
|
|
|
|
|
|
+ active INTEGER NOT NULL DEFAULT 0,
|
|
|
|
|
+ monitoring INTEGER NOT NULL DEFAULT 0
|
|
|
)
|
|
)
|
|
|
"""
|
|
"""
|
|
|
)
|
|
)
|
|
@@ -82,6 +89,8 @@ class NavDB:
|
|
|
lon REAL NOT NULL,
|
|
lon REAL NOT NULL,
|
|
|
speed_mps REAL NOT NULL,
|
|
speed_mps REAL NOT NULL,
|
|
|
cum_dist_m REAL NOT NULL,
|
|
cum_dist_m REAL NOT NULL,
|
|
|
|
|
+ counter_value INTEGER NOT NULL DEFAULT 0,
|
|
|
|
|
+ counter_absolute INTEGER NOT NULL DEFAULT 0,
|
|
|
PRIMARY KEY(route_id, seq)
|
|
PRIMARY KEY(route_id, seq)
|
|
|
)
|
|
)
|
|
|
"""
|
|
"""
|
|
@@ -97,19 +106,70 @@ class NavDB:
|
|
|
lon REAL NOT NULL,
|
|
lon REAL NOT NULL,
|
|
|
cum_dist_m REAL NOT NULL,
|
|
cum_dist_m REAL NOT NULL,
|
|
|
type TEXT NOT NULL,
|
|
type TEXT NOT NULL,
|
|
|
- note TEXT NOT NULL DEFAULT ''
|
|
|
|
|
|
|
+ note TEXT NOT NULL DEFAULT '',
|
|
|
|
|
+ counter_value INTEGER NOT NULL DEFAULT 0,
|
|
|
|
|
+ counter_absolute INTEGER NOT NULL DEFAULT 0
|
|
|
)
|
|
)
|
|
|
"""
|
|
"""
|
|
|
)
|
|
)
|
|
|
|
|
+
|
|
|
|
|
+ self._ensure_column(cur, "routes", "mode", "TEXT NOT NULL DEFAULT 'gps'")
|
|
|
|
|
+ self._ensure_column(
|
|
|
|
|
+ cur,
|
|
|
|
|
+ "routes",
|
|
|
|
|
+ "monitoring",
|
|
|
|
|
+ "INTEGER NOT NULL DEFAULT 0",
|
|
|
|
|
+ )
|
|
|
|
|
+ self._ensure_column(
|
|
|
|
|
+ cur,
|
|
|
|
|
+ "route_points",
|
|
|
|
|
+ "counter_value",
|
|
|
|
|
+ "INTEGER NOT NULL DEFAULT 0",
|
|
|
|
|
+ )
|
|
|
|
|
+ self._ensure_column(
|
|
|
|
|
+ cur,
|
|
|
|
|
+ "route_points",
|
|
|
|
|
+ "counter_absolute",
|
|
|
|
|
+ "INTEGER NOT NULL DEFAULT 0",
|
|
|
|
|
+ )
|
|
|
|
|
+ self._ensure_column(
|
|
|
|
|
+ cur,
|
|
|
|
|
+ "hazards",
|
|
|
|
|
+ "counter_value",
|
|
|
|
|
+ "INTEGER NOT NULL DEFAULT 0",
|
|
|
|
|
+ )
|
|
|
|
|
+ self._ensure_column(
|
|
|
|
|
+ cur,
|
|
|
|
|
+ "hazards",
|
|
|
|
|
+ "counter_absolute",
|
|
|
|
|
+ "INTEGER NOT NULL DEFAULT 0",
|
|
|
|
|
+ )
|
|
|
self._conn.commit()
|
|
self._conn.commit()
|
|
|
|
|
|
|
|
- def create_route(self, name: str) -> int:
|
|
|
|
|
|
|
+ def _ensure_column(
|
|
|
|
|
+ self,
|
|
|
|
|
+ cur: sqlite3.Cursor,
|
|
|
|
|
+ table_name: str,
|
|
|
|
|
+ column_name: str,
|
|
|
|
|
+ column_ddl: str,
|
|
|
|
|
+ ) -> None:
|
|
|
|
|
+ columns = {
|
|
|
|
|
+ str(row["name"])
|
|
|
|
|
+ for row in cur.execute(f"PRAGMA table_info({table_name})").fetchall()
|
|
|
|
|
+ }
|
|
|
|
|
+ if column_name not in columns:
|
|
|
|
|
+ cur.execute(
|
|
|
|
|
+ f"ALTER TABLE {table_name} ADD COLUMN {column_name} {column_ddl}"
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ def create_route(self, name: str, mode: str = "gps") -> int:
|
|
|
now = int(time.time())
|
|
now = int(time.time())
|
|
|
|
|
+ route_mode = (mode or "gps").strip() or "gps"
|
|
|
with self._lock:
|
|
with self._lock:
|
|
|
- self._conn.execute("UPDATE routes SET active=0")
|
|
|
|
|
|
|
+ self._conn.execute("UPDATE routes SET active=0, monitoring=0")
|
|
|
cur = self._conn.execute(
|
|
cur = self._conn.execute(
|
|
|
- "INSERT INTO routes(name, created_at, active) VALUES(?, ?, 1)",
|
|
|
|
|
- (name, now),
|
|
|
|
|
|
|
+ "INSERT INTO routes(name, mode, created_at, active, monitoring) VALUES(?, ?, ?, 1, 0)",
|
|
|
|
|
+ (name, route_mode, now),
|
|
|
)
|
|
)
|
|
|
self._conn.commit()
|
|
self._conn.commit()
|
|
|
return int(cur.lastrowid)
|
|
return int(cur.lastrowid)
|
|
@@ -136,6 +196,49 @@ class NavDB:
|
|
|
).fetchone()
|
|
).fetchone()
|
|
|
return int(row["id"]) if row else None
|
|
return int(row["id"]) if row else None
|
|
|
|
|
|
|
|
|
|
+ def set_monitoring_route(self, route_id: Optional[int]) -> None:
|
|
|
|
|
+ with self._lock:
|
|
|
|
|
+ self._conn.execute("UPDATE routes SET monitoring=0")
|
|
|
|
|
+ if route_id is not None:
|
|
|
|
|
+ self._conn.execute(
|
|
|
|
|
+ "UPDATE routes SET monitoring=1 WHERE id=?",
|
|
|
|
|
+ (int(route_id),),
|
|
|
|
|
+ )
|
|
|
|
|
+ self._conn.commit()
|
|
|
|
|
+
|
|
|
|
|
+ def get_monitoring_route_id(self) -> Optional[int]:
|
|
|
|
|
+ with self._lock:
|
|
|
|
|
+ row = self._conn.execute(
|
|
|
|
|
+ "SELECT id FROM routes WHERE monitoring=1 ORDER BY id DESC LIMIT 1"
|
|
|
|
|
+ ).fetchone()
|
|
|
|
|
+ return int(row["id"]) if row else None
|
|
|
|
|
+
|
|
|
|
|
+ # Backward-compatible aliases for older call sites that used sanitized names.
|
|
|
|
|
+ def setmonitoringroute(self, route_id: Optional[int]) -> None:
|
|
|
|
|
+ self.set_monitoring_route(route_id)
|
|
|
|
|
+
|
|
|
|
|
+ def getmonitoringrouteid(self) -> Optional[int]:
|
|
|
|
|
+ return self.get_monitoring_route_id()
|
|
|
|
|
+
|
|
|
|
|
+ def get_route_mode(self, route_id: int) -> str:
|
|
|
|
|
+ with self._lock:
|
|
|
|
|
+ row = self._conn.execute(
|
|
|
|
|
+ "SELECT mode FROM routes WHERE id=?",
|
|
|
|
|
+ (route_id,),
|
|
|
|
|
+ ).fetchone()
|
|
|
|
|
+ if not row:
|
|
|
|
|
+ return "gps"
|
|
|
|
|
+ return str(row["mode"] or "gps")
|
|
|
|
|
+
|
|
|
|
|
+ def update_route_mode(self, route_id: int, mode: str) -> None:
|
|
|
|
|
+ route_mode = (mode or "gps").strip() or "gps"
|
|
|
|
|
+ with self._lock:
|
|
|
|
|
+ self._conn.execute(
|
|
|
|
|
+ "UPDATE routes SET mode=? WHERE id=?",
|
|
|
|
|
+ (route_mode, route_id),
|
|
|
|
|
+ )
|
|
|
|
|
+ self._conn.commit()
|
|
|
|
|
+
|
|
|
def add_point(
|
|
def add_point(
|
|
|
self,
|
|
self,
|
|
|
*,
|
|
*,
|
|
@@ -146,14 +249,28 @@ class NavDB:
|
|
|
lon: float,
|
|
lon: float,
|
|
|
speed_mps: float,
|
|
speed_mps: float,
|
|
|
cum_dist_m: float,
|
|
cum_dist_m: float,
|
|
|
|
|
+ counter_value: int = 0,
|
|
|
|
|
+ counter_absolute: int = 0,
|
|
|
) -> None:
|
|
) -> None:
|
|
|
with self._lock:
|
|
with self._lock:
|
|
|
self._conn.execute(
|
|
self._conn.execute(
|
|
|
"""
|
|
"""
|
|
|
- INSERT OR REPLACE INTO route_points(route_id, seq, t, lat, lon, speed_mps, cum_dist_m)
|
|
|
|
|
- VALUES(?, ?, ?, ?, ?, ?, ?)
|
|
|
|
|
|
|
+ INSERT OR REPLACE INTO route_points(
|
|
|
|
|
+ route_id, seq, t, lat, lon, speed_mps, cum_dist_m, counter_value, counter_absolute
|
|
|
|
|
+ )
|
|
|
|
|
+ VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
""",
|
|
""",
|
|
|
- (route_id, seq, t, lat, lon, speed_mps, cum_dist_m),
|
|
|
|
|
|
|
+ (
|
|
|
|
|
+ route_id,
|
|
|
|
|
+ seq,
|
|
|
|
|
+ t,
|
|
|
|
|
+ lat,
|
|
|
|
|
+ lon,
|
|
|
|
|
+ speed_mps,
|
|
|
|
|
+ cum_dist_m,
|
|
|
|
|
+ int(counter_value or 0),
|
|
|
|
|
+ int(counter_absolute or 0),
|
|
|
|
|
+ ),
|
|
|
)
|
|
)
|
|
|
self._conn.commit()
|
|
self._conn.commit()
|
|
|
|
|
|
|
@@ -168,14 +285,29 @@ class NavDB:
|
|
|
cum_dist_m: float,
|
|
cum_dist_m: float,
|
|
|
hazard_type: str,
|
|
hazard_type: str,
|
|
|
note: str = "",
|
|
note: str = "",
|
|
|
|
|
+ counter_value: int = 0,
|
|
|
|
|
+ counter_absolute: int = 0,
|
|
|
) -> int:
|
|
) -> int:
|
|
|
with self._lock:
|
|
with self._lock:
|
|
|
cur = self._conn.execute(
|
|
cur = self._conn.execute(
|
|
|
"""
|
|
"""
|
|
|
- INSERT INTO hazards(route_id, seq, t, lat, lon, cum_dist_m, type, note)
|
|
|
|
|
- VALUES(?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
|
|
|
|
+ INSERT INTO hazards(
|
|
|
|
|
+ route_id, seq, t, lat, lon, cum_dist_m, type, note, counter_value, counter_absolute
|
|
|
|
|
+ )
|
|
|
|
|
+ VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
""",
|
|
""",
|
|
|
- (route_id, seq, t, lat, lon, cum_dist_m, hazard_type, note or ""),
|
|
|
|
|
|
|
+ (
|
|
|
|
|
+ route_id,
|
|
|
|
|
+ seq,
|
|
|
|
|
+ t,
|
|
|
|
|
+ lat,
|
|
|
|
|
+ lon,
|
|
|
|
|
+ cum_dist_m,
|
|
|
|
|
+ hazard_type,
|
|
|
|
|
+ note or "",
|
|
|
|
|
+ int(counter_value or 0),
|
|
|
|
|
+ int(counter_absolute or 0),
|
|
|
|
|
+ ),
|
|
|
)
|
|
)
|
|
|
self._conn.commit()
|
|
self._conn.commit()
|
|
|
return int(cur.lastrowid)
|
|
return int(cur.lastrowid)
|
|
@@ -185,7 +317,7 @@ class NavDB:
|
|
|
rows = self._conn.execute(
|
|
rows = self._conn.execute(
|
|
|
"""
|
|
"""
|
|
|
SELECT
|
|
SELECT
|
|
|
- r.id, r.name, r.created_at, r.finished_at, r.active,
|
|
|
|
|
|
|
+ r.id, r.name, r.mode, r.created_at, r.finished_at, r.active, r.monitoring,
|
|
|
(SELECT COUNT(1) FROM route_points p WHERE p.route_id=r.id) AS points,
|
|
(SELECT COUNT(1) FROM route_points p WHERE p.route_id=r.id) AS points,
|
|
|
(SELECT COUNT(1) FROM hazards h WHERE h.route_id=r.id) AS hazards
|
|
(SELECT COUNT(1) FROM hazards h WHERE h.route_id=r.id) AS hazards
|
|
|
FROM routes r
|
|
FROM routes r
|
|
@@ -198,11 +330,13 @@ class NavDB:
|
|
|
RouteInfo(
|
|
RouteInfo(
|
|
|
id=int(row["id"]),
|
|
id=int(row["id"]),
|
|
|
name=str(row["name"]),
|
|
name=str(row["name"]),
|
|
|
|
|
+ mode=str(row["mode"] or "gps"),
|
|
|
created_at=int(row["created_at"]),
|
|
created_at=int(row["created_at"]),
|
|
|
finished_at=int(row["finished_at"]) if row["finished_at"] else None,
|
|
finished_at=int(row["finished_at"]) if row["finished_at"] else None,
|
|
|
points=int(row["points"]),
|
|
points=int(row["points"]),
|
|
|
hazards=int(row["hazards"]),
|
|
hazards=int(row["hazards"]),
|
|
|
active=bool(int(row["active"])),
|
|
active=bool(int(row["active"])),
|
|
|
|
|
+ monitoring=bool(int(row["monitoring"] or 0)),
|
|
|
)
|
|
)
|
|
|
for row in rows
|
|
for row in rows
|
|
|
]
|
|
]
|
|
@@ -211,7 +345,7 @@ class NavDB:
|
|
|
with self._lock:
|
|
with self._lock:
|
|
|
rows = self._conn.execute(
|
|
rows = self._conn.execute(
|
|
|
"""
|
|
"""
|
|
|
- SELECT seq, t, lat, lon, speed_mps, cum_dist_m
|
|
|
|
|
|
|
+ SELECT seq, t, lat, lon, speed_mps, cum_dist_m, counter_value, counter_absolute
|
|
|
FROM route_points
|
|
FROM route_points
|
|
|
WHERE route_id=?
|
|
WHERE route_id=?
|
|
|
ORDER BY seq ASC
|
|
ORDER BY seq ASC
|
|
@@ -226,6 +360,8 @@ class NavDB:
|
|
|
lon=float(row["lon"]),
|
|
lon=float(row["lon"]),
|
|
|
speed_mps=float(row["speed_mps"]),
|
|
speed_mps=float(row["speed_mps"]),
|
|
|
cum_dist_m=float(row["cum_dist_m"]),
|
|
cum_dist_m=float(row["cum_dist_m"]),
|
|
|
|
|
+ counter_value=int(row["counter_value"] or 0),
|
|
|
|
|
+ counter_absolute=int(row["counter_absolute"] or 0),
|
|
|
)
|
|
)
|
|
|
for row in rows
|
|
for row in rows
|
|
|
]
|
|
]
|
|
@@ -234,10 +370,11 @@ class NavDB:
|
|
|
with self._lock:
|
|
with self._lock:
|
|
|
rows = self._conn.execute(
|
|
rows = self._conn.execute(
|
|
|
"""
|
|
"""
|
|
|
- SELECT id, route_id, seq, t, lat, lon, cum_dist_m, type, note
|
|
|
|
|
|
|
+ SELECT
|
|
|
|
|
+ id, route_id, seq, t, lat, lon, cum_dist_m, type, note, counter_value, counter_absolute
|
|
|
FROM hazards
|
|
FROM hazards
|
|
|
WHERE route_id=?
|
|
WHERE route_id=?
|
|
|
- ORDER BY cum_dist_m ASC
|
|
|
|
|
|
|
+ ORDER BY cum_dist_m ASC, id ASC
|
|
|
""",
|
|
""",
|
|
|
(route_id,),
|
|
(route_id,),
|
|
|
).fetchall()
|
|
).fetchall()
|
|
@@ -252,7 +389,8 @@ class NavDB:
|
|
|
cum_dist_m=float(row["cum_dist_m"]),
|
|
cum_dist_m=float(row["cum_dist_m"]),
|
|
|
type=str(row["type"]),
|
|
type=str(row["type"]),
|
|
|
note=str(row["note"] or ""),
|
|
note=str(row["note"] or ""),
|
|
|
|
|
+ counter_value=int(row["counter_value"] or 0),
|
|
|
|
|
+ counter_absolute=int(row["counter_absolute"] or 0),
|
|
|
)
|
|
)
|
|
|
for row in rows
|
|
for row in rows
|
|
|
]
|
|
]
|
|
|
-
|
|
|