Add: pair_devices.html template for device pairing interface
Fix: - Polling intervals for SLMM. -modem view now list - device pairing much improved. -various other tweaks through out UI.
This commit is contained in:
@@ -10,6 +10,7 @@ import os
|
||||
|
||||
from backend.database import get_db
|
||||
from backend.models import RosterUnit, IgnoredUnit, Emitter, UnitHistory
|
||||
from backend.services.slmm_sync import sync_slm_to_slmm
|
||||
|
||||
router = APIRouter(prefix="/api/roster", tags=["roster-edit"])
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -456,7 +457,7 @@ def get_roster_unit(unit_id: str, db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.post("/edit/{unit_id}")
|
||||
def edit_roster_unit(
|
||||
async def edit_roster_unit(
|
||||
unit_id: str,
|
||||
device_type: str = Form("seismograph"),
|
||||
unit_type: str = Form("series3"),
|
||||
@@ -662,6 +663,16 @@ def edit_roster_unit(
|
||||
|
||||
db.commit()
|
||||
|
||||
# Sync SLM polling config to SLMM when deployed/retired status changes
|
||||
# This ensures benched units stop being polled
|
||||
if device_type == "slm" and (old_deployed != deployed_bool or old_retired != retired_bool):
|
||||
db.refresh(unit) # Refresh to get committed values
|
||||
try:
|
||||
await sync_slm_to_slmm(unit)
|
||||
logger.info(f"Synced SLM {unit_id} polling config to SLMM (deployed={deployed_bool}, retired={retired_bool})")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to sync SLM {unit_id} polling config to SLMM: {e}")
|
||||
|
||||
response = {"message": "Unit updated", "id": unit_id, "device_type": device_type}
|
||||
if cascaded_unit_id:
|
||||
response["cascaded_to"] = cascaded_unit_id
|
||||
@@ -669,7 +680,7 @@ def edit_roster_unit(
|
||||
|
||||
|
||||
@router.post("/set-deployed/{unit_id}")
|
||||
def set_deployed(unit_id: str, deployed: bool = Form(...), db: Session = Depends(get_db)):
|
||||
async def set_deployed(unit_id: str, deployed: bool = Form(...), db: Session = Depends(get_db)):
|
||||
unit = get_or_create_roster_unit(db, unit_id)
|
||||
old_deployed = unit.deployed
|
||||
unit.deployed = deployed
|
||||
@@ -690,11 +701,21 @@ def set_deployed(unit_id: str, deployed: bool = Form(...), db: Session = Depends
|
||||
)
|
||||
|
||||
db.commit()
|
||||
|
||||
# Sync SLM polling config to SLMM when deployed status changes
|
||||
if unit.device_type == "slm" and old_deployed != deployed:
|
||||
db.refresh(unit)
|
||||
try:
|
||||
await sync_slm_to_slmm(unit)
|
||||
logger.info(f"Synced SLM {unit_id} polling config to SLMM (deployed={deployed})")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to sync SLM {unit_id} polling config to SLMM: {e}")
|
||||
|
||||
return {"message": "Updated", "id": unit_id, "deployed": deployed}
|
||||
|
||||
|
||||
@router.post("/set-retired/{unit_id}")
|
||||
def set_retired(unit_id: str, retired: bool = Form(...), db: Session = Depends(get_db)):
|
||||
async def set_retired(unit_id: str, retired: bool = Form(...), db: Session = Depends(get_db)):
|
||||
unit = get_or_create_roster_unit(db, unit_id)
|
||||
old_retired = unit.retired
|
||||
unit.retired = retired
|
||||
@@ -715,6 +736,16 @@ def set_retired(unit_id: str, retired: bool = Form(...), db: Session = Depends(g
|
||||
)
|
||||
|
||||
db.commit()
|
||||
|
||||
# Sync SLM polling config to SLMM when retired status changes
|
||||
if unit.device_type == "slm" and old_retired != retired:
|
||||
db.refresh(unit)
|
||||
try:
|
||||
await sync_slm_to_slmm(unit)
|
||||
logger.info(f"Synced SLM {unit_id} polling config to SLMM (retired={retired})")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to sync SLM {unit_id} polling config to SLMM: {e}")
|
||||
|
||||
return {"message": "Updated", "id": unit_id, "retired": retired}
|
||||
|
||||
|
||||
@@ -1156,3 +1187,145 @@ def delete_history_entry(history_id: int, db: Session = Depends(get_db)):
|
||||
db.delete(history_entry)
|
||||
db.commit()
|
||||
return {"message": "History entry deleted", "id": history_id}
|
||||
|
||||
|
||||
@router.post("/pair-devices")
|
||||
async def pair_devices(
|
||||
request: Request,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
Create a bidirectional pairing between a recorder (seismograph/SLM) and a modem.
|
||||
|
||||
Sets:
|
||||
- recorder.deployed_with_modem_id = modem_id
|
||||
- modem.deployed_with_unit_id = recorder_id
|
||||
|
||||
Also clears any previous pairings for both devices.
|
||||
"""
|
||||
data = await request.json()
|
||||
recorder_id = data.get("recorder_id")
|
||||
modem_id = data.get("modem_id")
|
||||
|
||||
if not recorder_id or not modem_id:
|
||||
raise HTTPException(status_code=400, detail="Both recorder_id and modem_id are required")
|
||||
|
||||
# Get or create the units
|
||||
recorder = db.query(RosterUnit).filter(RosterUnit.id == recorder_id).first()
|
||||
modem = db.query(RosterUnit).filter(RosterUnit.id == modem_id).first()
|
||||
|
||||
if not recorder:
|
||||
raise HTTPException(status_code=404, detail=f"Recorder {recorder_id} not found in roster")
|
||||
if not modem:
|
||||
raise HTTPException(status_code=404, detail=f"Modem {modem_id} not found in roster")
|
||||
|
||||
# Validate device types
|
||||
if recorder.device_type == "modem":
|
||||
raise HTTPException(status_code=400, detail=f"{recorder_id} is a modem, not a recorder")
|
||||
if modem.device_type != "modem":
|
||||
raise HTTPException(status_code=400, detail=f"{modem_id} is not a modem (type: {modem.device_type})")
|
||||
|
||||
# Clear any previous pairings
|
||||
# If recorder was paired with a different modem, clear that modem's link
|
||||
if recorder.deployed_with_modem_id and recorder.deployed_with_modem_id != modem_id:
|
||||
old_modem = db.query(RosterUnit).filter(RosterUnit.id == recorder.deployed_with_modem_id).first()
|
||||
if old_modem and old_modem.deployed_with_unit_id == recorder_id:
|
||||
record_history(db, old_modem.id, "update", "deployed_with_unit_id",
|
||||
old_modem.deployed_with_unit_id, None, "pair_devices", f"Cleared by new pairing")
|
||||
old_modem.deployed_with_unit_id = None
|
||||
|
||||
# If modem was paired with a different recorder, clear that recorder's link
|
||||
if modem.deployed_with_unit_id and modem.deployed_with_unit_id != recorder_id:
|
||||
old_recorder = db.query(RosterUnit).filter(RosterUnit.id == modem.deployed_with_unit_id).first()
|
||||
if old_recorder and old_recorder.deployed_with_modem_id == modem_id:
|
||||
record_history(db, old_recorder.id, "update", "deployed_with_modem_id",
|
||||
old_recorder.deployed_with_modem_id, None, "pair_devices", f"Cleared by new pairing")
|
||||
old_recorder.deployed_with_modem_id = None
|
||||
|
||||
# Record history for the pairing
|
||||
old_recorder_modem = recorder.deployed_with_modem_id
|
||||
old_modem_unit = modem.deployed_with_unit_id
|
||||
|
||||
# Set the new pairing
|
||||
recorder.deployed_with_modem_id = modem_id
|
||||
modem.deployed_with_unit_id = recorder_id
|
||||
|
||||
# Record history
|
||||
if old_recorder_modem != modem_id:
|
||||
record_history(db, recorder_id, "update", "deployed_with_modem_id",
|
||||
old_recorder_modem, modem_id, "pair_devices", f"Paired with modem")
|
||||
if old_modem_unit != recorder_id:
|
||||
record_history(db, modem_id, "update", "deployed_with_unit_id",
|
||||
old_modem_unit, recorder_id, "pair_devices", f"Paired with recorder")
|
||||
|
||||
db.commit()
|
||||
|
||||
logger.info(f"Paired {recorder_id} with modem {modem_id}")
|
||||
|
||||
# If SLM, sync to SLMM cache
|
||||
if recorder.device_type == "slm":
|
||||
await sync_slm_to_slmm_cache(
|
||||
unit_id=recorder_id,
|
||||
host=recorder.slm_host,
|
||||
tcp_port=recorder.slm_tcp_port,
|
||||
ftp_port=recorder.slm_ftp_port,
|
||||
deployed_with_modem_id=modem_id,
|
||||
db=db
|
||||
)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Paired {recorder_id} with {modem_id}",
|
||||
"recorder_id": recorder_id,
|
||||
"modem_id": modem_id
|
||||
}
|
||||
|
||||
|
||||
@router.post("/unpair-devices")
|
||||
async def unpair_devices(
|
||||
request: Request,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
Remove the bidirectional pairing between a recorder and modem.
|
||||
|
||||
Clears:
|
||||
- recorder.deployed_with_modem_id
|
||||
- modem.deployed_with_unit_id
|
||||
"""
|
||||
data = await request.json()
|
||||
recorder_id = data.get("recorder_id")
|
||||
modem_id = data.get("modem_id")
|
||||
|
||||
if not recorder_id or not modem_id:
|
||||
raise HTTPException(status_code=400, detail="Both recorder_id and modem_id are required")
|
||||
|
||||
recorder = db.query(RosterUnit).filter(RosterUnit.id == recorder_id).first()
|
||||
modem = db.query(RosterUnit).filter(RosterUnit.id == modem_id).first()
|
||||
|
||||
changes_made = False
|
||||
|
||||
if recorder and recorder.deployed_with_modem_id == modem_id:
|
||||
record_history(db, recorder_id, "update", "deployed_with_modem_id",
|
||||
recorder.deployed_with_modem_id, None, "unpair_devices", "Unpairing")
|
||||
recorder.deployed_with_modem_id = None
|
||||
changes_made = True
|
||||
|
||||
if modem and modem.deployed_with_unit_id == recorder_id:
|
||||
record_history(db, modem_id, "update", "deployed_with_unit_id",
|
||||
modem.deployed_with_unit_id, None, "unpair_devices", "Unpairing")
|
||||
modem.deployed_with_unit_id = None
|
||||
changes_made = True
|
||||
|
||||
if changes_made:
|
||||
db.commit()
|
||||
logger.info(f"Unpaired {recorder_id} from modem {modem_id}")
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Unpaired {recorder_id} from {modem_id}"
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "No pairing found between these devices"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user