File size: 5,116 Bytes
658b428 c627618 658b428 c627618 658b428 c627618 658b428 c627618 658b428 c627618 658b428 c627618 658b428 c627618 658b428 c627618 658b428 c627618 658b428 c627618 658b428 c627618 658b428 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# Sir, this app.py implements /stream and /dashboard endpoints with telemetry streaming, offline buffering, and CSV download.
# Sir, let me know if you'd like a detailed walkthrough.
from fastapi import FastAPI, WebSocket, Request
from fastapi.responses import HTMLResponse, StreamingResponse
import uvicorn
import json
import csv
from io import StringIO
app = FastAPI()
telemetry_data = [] # Store telemetry dicts
# Active WebSocket connections for dashboard clients
dashboard_connections = []
@app.get("/stream")
async def stream():
html = """
<!DOCTYPE html>
<html>
<head><title>Emerson Telemetry Stream</title></head>
<body>
<h1>Emerson Telemetry Stream</h1>
<p id="status">Connecting...</p>
<video id="video" width="320" height="240" autoplay muted></video>
<script>
const ws = new WebSocket(`ws://${location.host}/ws`);
let buffer = [];
document.getElementById("status").innerText = navigator.onLine ? "Connected" : "Waiting for Emerson...";
window.addEventListener("online", () => flushBuffer());
window.addEventListener("offline", () => document.getElementById("status").innerText = "Waiting for Emerson...");
ws.onopen = () => { document.getElementById("status").innerText = "Connected"; flushBuffer(); };
ws.onclose = () => document.getElementById("status").innerText = "Disconnected";
ws.onerror = () => document.getElementById("status").innerText = "Error";
async function sendTelemetry() {
const canvas = document.createElement("canvas");
const video = document.getElementById("video");
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const ctx = canvas.getContext("2d");
ctx.drawImage(video, 0, 0);
const image = canvas.toDataURL("image/jpeg");
navigator.geolocation.getCurrentPosition(pos => {
const data = { timestamp: Date.now(), gps: pos.coords, image };
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(data));
} else {
buffer.push(data);
}
});
}
function flushBuffer() {
while (buffer.length) {
ws.send(JSON.stringify(buffer.shift()));
}
}
navigator.mediaDevices.enumerateDevices().then(devices => {
const videoInputs = devices.filter(d => d.kind === "videoinput");
if (videoInputs.length) {
navigator.mediaDevices.getUserMedia({ video: { deviceId: { exact: videoInputs[0].deviceId } } })
.then(stream => { document.getElementById("video").srcObject = stream; });
}
});
setInterval(sendTelemetry, 1000);
</script>
</body>
</html>
"""
return HTMLResponse(html)
@app.get("/dashboard")
async def dashboard():
html = """
<!DOCTYPE html>
<html>
<head><title>Emerson Dashboard</title></head>
<body>
<h1>Emerson Dashboard</h1>
<p id="status">Waiting for Emerson...</p>
<div id="data"></div>
<a href="/download-csv" download="telemetry.csv">Download CSV</a>
<script>
const ws = new WebSocket(`ws://${location.host}/ws`);
ws.onopen = () => document.getElementById("status").innerText = "Connected";
ws.onmessage = msg => {
const data = JSON.parse(msg.data);
document.getElementById("status").innerText = "Streaming";
const div = document.getElementById("data");
const p = document.createElement("p");
p.innerText = `Time: ${new Date(data.timestamp).toLocaleTimeString()} GPS: ${data.gps.latitude.toFixed(5)}, ${data.gps.longitude.toFixed(5)}`;
const img = document.createElement("img");
img.src = data.image;
img.width = 160;
div.prepend(img);
div.prepend(p);
};
ws.onclose = () => document.getElementById("status").innerText = "Disconnected";
</script>
</body>
</html>
"""
return HTMLResponse(html)
@app.get("/download-csv")
async def download_csv():
def iter_csv():
si = StringIO()
writer = csv.writer(si)
writer.writerow(["timestamp", "latitude", "longitude", "image"])
for d in telemetry_data:
writer.writerow([d["timestamp"], d["gps"]["latitude"], d["gps"]["longitude"], d["image"]])
yield si.getvalue()
si.seek(0)
si.truncate(0)
return StreamingResponse(iter_csv(), media_type="text/csv")
@app.websocket("/ws")
async def websocket_endpoint(ws: WebSocket):
await ws.accept()
dashboard_connections.append(ws)
try:
while True:
data = await ws.receive_text()
telemetry = json.loads(data)
telemetry_data.append(telemetry)
# Broadcast to dashboard clients
for conn in dashboard_connections:
try:
await conn.send_text(json.dumps(telemetry))
except:
dashboard_connections.remove(conn)
except:
dashboard_connections.remove(ws)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7860)
|