diff --git a/app/database.py b/app/database.py index fcc8b01..d2c7173 100644 --- a/app/database.py +++ b/app/database.py @@ -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] diff --git a/app/device_manager.py b/app/device_manager.py index f4be437..87d96af 100644 --- a/app/device_manager.py +++ b/app/device_manager.py @@ -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, )