Camera view: Not connected
+ + +diff --git a/api/index.js b/api/index.js index 70f863ba..c5643657 100644 --- a/api/index.js +++ b/api/index.js @@ -2,18 +2,118 @@ var express = require("express"); var app = express(); const WebSocket = require("ws"); -var ws = new WebSocket("ws://10.100.0.40:9001/"); +//# TODO SSE https://www.digitalocean.com/community/tutorials/nodejs-server-sent-events-build-realtime-app -ws.on('open', function open() { - console.log("connected"); +var last_status = {}; +var last_image; +var received_picture = false; +var received_error = false; + +let sse_clients = []; + +app.use(express.static("public")); +app.use(express.json()); + +var ws; +var api_connected = false; + +function send_events_to_clients(data) { + // console.log("sending events to clients"); + sse_clients.forEach((client) => { + client.response.write("event: message\n"); + client.response.write("data:" + JSON.stringify(data) + "\n\n"); + }); +} + +function handle_sse_client(request, response, next) { + console.log("handling sse client"); + const headers = { + "Content-Type": "text/event-stream", + Connection: "keep-alive", + "Cache-Control": "no-cache", + }; + + response.writeHead(200, headers); + response.write(JSON.stringify("yeet") + "\n\n"); + const clientID = Date.now(); + const newClient = { + id: clientID, + response, + }; + + sse_clients.push(newClient); + + request.on("close", () => { + console.log(`${clientID} Connection closed`); + sse_clients = sse_clients.filter((client) => client.id !== clientID); + }); +} + +var connect_to_api = function () { + console.log("Connecting to API"); + ws = new WebSocket("ws://10.100.0.40:9001/"); + + ws.on("open", function open() { + console.log("connected with websockets to API!"); + api_connected = true; }); -ws.on("message", function message(message) { - var msg = JSON.parse(message); - console.log("RECEIVED: " + msg); -}); + ws.on("message", function message(message) { + try { + var msg = JSON.parse(message); + if (msg.type != "IMAGE") { + // console.log("got message"); + send_events_to_clients(msg); + } else { + console.log("got image"); + } + } catch (error) { + console.log("could not parse as json"); + // send_image_data_to_clients(message); + } + }); -ws.on("error", console.error); + ws.on("error", function error(err) { + console.log("there was an error"); + console.error("error: " + err); + received_error = true; + }); +}; + +function send_image_data_to_clients(videoData) { + sse_clients.forEach((client) => { + // Set the SSE event name as 'message' + client.response.write("event: message\n"); + + // Convert the Buffer to a base64-encoded string + const base64Data = videoData.toString("base64"); + + // Set the SSE event data as the base64-encoded string + client.response.write( + "data: " + JSON.stringify({ image: base64Data }) + "\n\n" + ); + }); +} + +// Define the endpoint to receive video data +app.post("/video", (req, res) => { + // console.log("got video endpoint") + let videoData = Buffer.from(""); + + req.on("data", (chunk) => { + // Accumulate the received video data + videoData = Buffer.concat([videoData, chunk]); + }); + + req.on("end", () => { + // Process the received video data + // console.log("Received video data:" + videoData.length); + send_image_data_to_clients(videoData); + + // Send a response indicating successful receipt + res.sendStatus(200); + }); +}); // set the view engine to ejs app.set("view engine", "ejs"); @@ -22,7 +122,69 @@ app.set("view engine", "ejs"); // index page app.get("/", function (req, res) { - res.render("index"); + res.render("index", { api_connected: api_connected }); +}); + +app.get("/events", handle_sse_client); + +app.get("/image", function (req, res) { + console.log("got picture request"); + var request = JSON.stringify({ + command: 5, + }); + console.log("sending picture request"); + ws.send(request); + res.status(200).send(last_image); +}); + +app.post("/move", function (req, res) { + console.log("got move request"); + var request = JSON.stringify({ + command: 3, + up_down: req.body.up_down, + left_right: req.body.left_right, + forward_backward: req.body.forward_backward, + yaw: req.body.turn_left_right, + }); + ws.send(request); +}); + +app.post("/estop", function (req, res) { + console.log("got estop request"); + var request = JSON.stringify({ + command: 6, + }); + ws.send(request); +}); + +app.post("/land", function (req, res) { + console.log("got land request"); + var request = JSON.stringify({ command: 0 }); + ws.send(request); +}); + +app.post("/arm_disarm", function (req, res) { + console.log("got arm/disarm request"); + var request = JSON.stringify({ command: 1 }); + ws.send(request); +}); + +app.get("/connect", function (req, res) { + console.log("got connect request"); + connect_to_api(); + setTimeout(function () { + if (api_connected) { + console.log("Connected to API"); + res.status(200).json({ connected: true }); + } else { + received_error = false; + res.status(400).json({ connected: false }); + } + }, 1000); +}); + +app.get("/test", function (req, res) { + res.render("test"); }); app.listen(8080); diff --git a/api/public/css/stylesheet.css b/api/public/css/stylesheet.css new file mode 100644 index 00000000..b0d42a40 --- /dev/null +++ b/api/public/css/stylesheet.css @@ -0,0 +1,66 @@ +body { + background-color: azure; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + +html, body { + overflow: auto; +} + +.header { + color: black; + text-align: center; +} + +.video { + width: 100%; + overflow: auto; +} + +.mainvideo { + width: 50%; + float: left; + height: 100%; + border: 1px solid blue; + margin-right: 10px; + padding: 10px; + overflow: visible; +} + +.lastpicture { + width: 40%; + float: right; + /* height: 400px; */ + border: 1px solid red; + padding: 10px; +} + +#connectedbuttons { + overflow: auto; +} + +#buttons { + float: left; +} + +#connectedstatus { + float:left; + width: 80%; +} + +#take_picture { + float:right; +} +#arm_disarm { + float: right; +} + +#button_estop { + background-color: red; + color: white; +} + +.headerimg { + height: 200px; + /* float: right; */ +} \ No newline at end of file diff --git a/api/public/img/droneimage_2023-05-30_14-55-57.jpg b/api/public/img/droneimage_2023-05-30_14-55-57.jpg new file mode 100644 index 00000000..96579256 Binary files /dev/null and b/api/public/img/droneimage_2023-05-30_14-55-57.jpg differ diff --git a/api/views/index.ejs b/api/views/index.ejs index 1b7be72b..c5747652 100644 --- a/api/views/index.ejs +++ b/api/views/index.ejs @@ -1,12 +1,418 @@ -
- - - -Camera view: Not connected
+ + +Last picture:
+Battery percentage
+CPU load
+ + +Current speed
+Current position
+Height
+Failsafe not activated
+
+