fix(v2): Serial port auto-detection and channel_messages query

- Add _detect_serial_port() to DeviceManager — resolves 'auto' to
  actual device via /dev/serial/by-id with common path fallbacks
- Make channel_idx optional in get_channel_messages() so status and
  channel-updates endpoints can query across all channels

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
MarekWo
2026-03-01 10:15:44 +01:00
parent e98acf6afa
commit 2e95bbf9b5
2 changed files with 46 additions and 23 deletions

View File

@@ -194,36 +194,31 @@ class Database:
)
return cursor.lastrowid
def get_channel_messages(self, channel_idx: int, limit: int = 50,
def get_channel_messages(self, channel_idx: int = None, limit: int = 50,
offset: int = 0, days: int = None) -> List[Dict]:
with self._connect() as conn:
query = "SELECT * FROM channel_messages WHERE channel_idx = ?"
params: list = [channel_idx]
conditions = []
params: list = []
if channel_idx is not None:
conditions.append("channel_idx = ?")
params.append(channel_idx)
if days is not None and days > 0:
cutoff = int((datetime.now() - timedelta(days=days)).timestamp())
query += " AND timestamp >= ?"
conditions.append("timestamp >= ?")
params.append(cutoff)
query += " ORDER BY timestamp ASC"
where = (" WHERE " + " AND ".join(conditions)) if conditions else ""
if limit > 0:
# Get the last N messages (most recent) with offset
query = f"""SELECT * FROM ({query} LIMIT -1 OFFSET ?)
ORDER BY timestamp ASC"""
# We need a subquery approach to get "last N"
# Simpler: reverse order, limit, then re-reverse
query = """SELECT * FROM (
SELECT * FROM channel_messages
WHERE channel_idx = ?"""
params = [channel_idx]
if days is not None and days > 0:
cutoff = int((datetime.now() - timedelta(days=days)).timestamp())
query += " AND timestamp >= ?"
params.append(cutoff)
query += " ORDER BY timestamp DESC LIMIT ? OFFSET ?"
if limit and limit > 0:
query = f"""SELECT * FROM (
SELECT * FROM channel_messages{where}
ORDER BY timestamp DESC LIMIT ? OFFSET ?
) ORDER BY timestamp ASC"""
params.extend([limit, offset])
query += ") ORDER BY timestamp ASC"
else:
query = f"SELECT * FROM channel_messages{where} ORDER BY timestamp ASC"
rows = conn.execute(query, params).fetchall()
return [dict(r) for r in rows]

View File

@@ -74,6 +74,33 @@ class DeviceManager:
self._loop.run_until_complete(self._connect())
self._loop.run_forever()
def _detect_serial_port(self) -> str:
"""Auto-detect serial port when configured as 'auto'."""
port = self.config.MC_SERIAL_PORT
if port.lower() != 'auto':
return port
from pathlib import Path
by_id = Path('/dev/serial/by-id')
if by_id.exists():
devices = list(by_id.iterdir())
if len(devices) == 1:
resolved = str(devices[0].resolve())
logger.info(f"Auto-detected serial port: {resolved}")
return resolved
elif len(devices) > 1:
logger.warning(f"Multiple serial devices found: {[d.name for d in devices]}")
else:
logger.warning("No serial devices found in /dev/serial/by-id")
# Fallback: try common paths
for candidate in ['/dev/ttyUSB0', '/dev/ttyACM0', '/dev/ttyUSB1', '/dev/ttyACM1']:
if Path(candidate).exists():
logger.info(f"Auto-detected serial port (fallback): {candidate}")
return candidate
raise RuntimeError("No serial port detected. Set MC_SERIAL_PORT explicitly.")
async def _connect(self):
"""Connect to device via serial or TCP and subscribe to events."""
from meshcore import MeshCore
@@ -87,9 +114,10 @@ class DeviceManager:
auto_reconnect=self.config.MC_AUTO_RECONNECT,
)
else:
logger.info(f"Connecting via serial: {self.config.MC_SERIAL_PORT}")
port = self._detect_serial_port()
logger.info(f"Connecting via serial: {port}")
self.mc = await MeshCore.create_serial(
port=self.config.MC_SERIAL_PORT,
port=port,
auto_reconnect=self.config.MC_AUTO_RECONNECT,
)