diff --git a/app/routers.py b/app/routers.py index af62fde..40ecaf8 100644 --- a/app/routers.py +++ b/app/routers.py @@ -545,12 +545,6 @@ async def stop_measurement(unit_id: str, db: Session = Depends(get_db)): try: await client.stop() logger.info(f"Stopped measurement on unit {unit_id}") - - # Query device status to update database with "Stop" state - snap = await client.request_dod() - snap.unit_id = unit_id - persist_snapshot(snap, db) - except ConnectionError as e: logger.error(f"Failed to stop measurement on {unit_id}: {e}") raise HTTPException(status_code=502, detail="Failed to communicate with device") @@ -560,6 +554,15 @@ async def stop_measurement(unit_id: str, db: Session = Depends(get_db)): except Exception as e: logger.error(f"Unexpected error stopping measurement on {unit_id}: {e}") raise HTTPException(status_code=500, detail="Internal server error") + + # Query device status to update database — non-fatal if this fails + try: + snap = await client.request_dod() + snap.unit_id = unit_id + persist_snapshot(snap, db) + except Exception as e: + logger.warning(f"Stop succeeded but failed to update status for {unit_id}: {e}") + return {"status": "ok", "message": "Measurement stopped"} diff --git a/app/services.py b/app/services.py index 6967b01..7e4c554 100644 --- a/app/services.py +++ b/app/services.py @@ -245,7 +245,12 @@ class NL43Client: self.device_key = f"{host}:{port}" async def _enforce_rate_limit(self): - """Ensure ≥1 second between commands to the same device.""" + """Ensure ≥1 second between commands to the same device. + + NL43 protocol requires ≥1s after the device responds before sending + the next command. The timestamp is recorded after each command completes + (connection closed), so we measure from completion, not from send time. + """ async with _rate_limit_lock: last_time = _last_command_time.get(self.device_key, 0) elapsed = time.time() - last_time @@ -253,7 +258,6 @@ class NL43Client: wait_time = 1.0 - elapsed logger.debug(f"Rate limiting: waiting {wait_time:.2f}s for {self.device_key}") await asyncio.sleep(wait_time) - _last_command_time[self.device_key] = time.time() async def _send_command(self, cmd: str) -> str: """Send ASCII command to NL43 device via TCP. @@ -334,6 +338,9 @@ class NL43Client: writer.close() with contextlib.suppress(Exception): await writer.wait_closed() + # Record completion time for rate limiting — NL43 requires ≥1s + # after response before next command, so measure from connection close + _last_command_time[self.device_key] = time.time() async def request_dod(self) -> NL43Snapshot: """Request DOD (Data Output Display) snapshot from device.