v0.1.1 update

This commit is contained in:
serversdwn
2025-12-02 06:36:13 +00:00
parent 938e950dd6
commit 90ecada35f
17 changed files with 867 additions and 221 deletions

View File

@@ -1,96 +1,121 @@
"""
Mock implementation of emit_status_snapshot().
This will be replaced with real Series3 emitter logic by the user.
"""
from datetime import datetime, timezone
from sqlalchemy.orm import Session
from datetime import datetime, timedelta
import random
from backend.database import get_db_session
from backend.models import Emitter, RosterUnit
def ensure_utc(dt):
if dt is None:
return None
if dt.tzinfo is None:
return dt.replace(tzinfo=timezone.utc)
return dt.astimezone(timezone.utc)
def format_age(last_seen):
if not last_seen:
return "N/A"
last_seen = ensure_utc(last_seen)
now = datetime.now(timezone.utc)
diff = now - last_seen
hours = diff.total_seconds() // 3600
mins = (diff.total_seconds() % 3600) // 60
return f"{int(hours)}h {int(mins)}m"
def emit_status_snapshot():
"""
Mock function that returns fleet status snapshot.
In production, this will call the real Series3 emitter logic.
Returns a dictionary with unit statuses, ages, deployment status, etc.
Merge roster (what we *intend*) with emitter data (what is *actually happening*).
"""
# Mock data for demonstration
mock_units = {
"BE1234": {
"status": "OK",
"age": "1h 12m",
"last": "2025-11-22 12:32:10",
"fname": "evt_1234.mlg",
"deployed": True,
"note": "Bridge monitoring project - Golden Gate"
},
"BE5678": {
"status": "Pending",
"age": "2h 45m",
"last": "2025-11-22 11:05:33",
"fname": "evt_5678.mlg",
"deployed": True,
"note": "Dam structural analysis"
},
"BE9012": {
"status": "Missing",
"age": "5d 3h",
"last": "2025-11-17 09:15:00",
"fname": "evt_9012.mlg",
"deployed": True,
"note": "Tunnel excavation site"
},
"BE3456": {
"status": "OK",
"age": "30m",
"last": "2025-11-22 13:20:45",
"fname": "evt_3456.mlg",
"deployed": False,
"note": "Benched for maintenance"
},
"BE7890": {
"status": "OK",
"age": "15m",
"last": "2025-11-22 13:35:22",
"fname": "evt_7890.mlg",
"deployed": True,
"note": "Pipeline monitoring"
},
"BE2468": {
"status": "Pending",
"age": "4h 20m",
"last": "2025-11-22 09:30:15",
"fname": "evt_2468.mlg",
"deployed": True,
"note": "Building foundation survey"
},
"BE1357": {
"status": "OK",
"age": "45m",
"last": "2025-11-22 13:05:00",
"fname": "evt_1357.mlg",
"deployed": False,
"note": "Awaiting deployment"
},
"BE8642": {
"status": "Missing",
"age": "2d 12h",
"last": "2025-11-20 01:30:00",
"fname": "evt_8642.mlg",
"deployed": True,
"note": "Offshore platform - comms issue suspected"
}
}
db = get_db_session()
try:
roster = {r.id: r for r in db.query(RosterUnit).all()}
emitters = {e.id: e for e in db.query(Emitter).all()}
return {
"units": mock_units,
"timestamp": datetime.now().isoformat(),
"total_units": len(mock_units),
"deployed_units": sum(1 for u in mock_units.values() if u["deployed"]),
"status_summary": {
"OK": sum(1 for u in mock_units.values() if u["status"] == "OK"),
"Pending": sum(1 for u in mock_units.values() if u["status"] == "Pending"),
"Missing": sum(1 for u in mock_units.values() if u["status"] == "Missing")
units = {}
# --- Merge roster entries first ---
for unit_id, r in roster.items():
e = emitters.get(unit_id)
if r.retired:
# Retired units get separated later
status = "Retired"
age = "N/A"
last_seen = None
fname = ""
else:
if e:
status = e.status
last_seen = ensure_utc(e.last_seen)
age = format_age(last_seen)
fname = e.last_file
else:
# Rostered but no emitter data
status = "Missing"
last_seen = None
age = "N/A"
fname = ""
units[unit_id] = {
"id": unit_id,
"status": status,
"age": age,
"last": last_seen.isoformat() if last_seen else None,
"fname": fname,
"deployed": r.deployed,
"note": r.note or "",
"retired": r.retired,
}
# --- Add unexpected emitter-only units ---
for unit_id, e in emitters.items():
if unit_id not in roster:
last_seen = ensure_utc(e.last_seen)
units[unit_id] = {
"id": unit_id,
"status": e.status,
"age": format_age(last_seen),
"last": last_seen.isoformat(),
"fname": e.last_file,
"deployed": False, # default
"note": "",
"retired": False,
}
# Separate buckets for UI
active_units = {
uid: u for uid, u in units.items()
if not u["retired"] and u["deployed"]
}
}
benched_units = {
uid: u for uid, u in units.items()
if not u["retired"] and not u["deployed"]
}
retired_units = {
uid: u for uid, u in units.items()
if u["retired"]
}
return {
"timestamp": datetime.utcnow().isoformat(),
"units": units,
"active": active_units,
"benched": benched_units,
"retired": retired_units,
"summary": {
"total": len(units),
"active": len(active_units),
"benched": len(benched_units),
"retired": len(retired_units),
"ok": sum(1 for u in units.values() if u["status"] == "OK"),
"pending": sum(1 for u in units.values() if u["status"] == "Pending"),
"missing": sum(1 for u in units.values() if u["status"] == "Missing"),
}
}
finally:
db.close()