Commit 632ad024 authored by Léo-Paul Géneau's avatar Léo-Paul Géneau 👾

software/js-drone: print pubsub logs in the GUI

parent eae3a24e
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
# not need these here). # not need these here).
[index-html] [index-html]
_update_hash_filename_ = web-gui/index.html.jinja2 _update_hash_filename_ = web-gui/index.html.jinja2
md5sum = 1eedc017ecc9d1a6761dc2fff3bbab9b md5sum = 94479f7e7299650fc41878fab06e6555
[instance-profile] [instance-profile]
filename = instance.cfg.in filename = instance.cfg.in
...@@ -38,8 +38,8 @@ md5sum = 1555496ad591a31a845f33488d5c335d ...@@ -38,8 +38,8 @@ md5sum = 1555496ad591a31a845f33488d5c335d
[script-js] [script-js]
_update_hash_filename_ = web-gui/script.js.jinja2 _update_hash_filename_ = web-gui/script.js.jinja2
md5sum = e28492276416c2d84e770217ae97a88f md5sum = a88028c1248d2b6a91b7d3cb03047196
[worker] [worker]
_update_hash_filename_ = drone-scripts/worker.js.jinja2 _update_hash_filename_ = drone-scripts/worker.js.jinja2
md5sum = 48540afedd5437129196d84832d2ed40 md5sum = 06a322cc711830262fbbfdc1bfe7947a
...@@ -11,6 +11,7 @@ import { ...@@ -11,6 +11,7 @@ import {
getClimbRate, getClimbRate,
getInitialAltitude, getInitialAltitude,
gpsIsOk, gpsIsOk,
getLog,
getPosition, getPosition,
getYaw, getYaw,
initPubsub, initPubsub,
...@@ -36,8 +37,8 @@ import { evalScript, fdopen, loadFile, open } from "std"; ...@@ -36,8 +37,8 @@ import { evalScript, fdopen, loadFile, open } from "std";
(function (Drone, SIGTERM, WNOHANG, Worker, close, console, evalScript, exec, (function (Drone, SIGTERM, WNOHANG, Worker, close, console, evalScript, exec,
fdopen, getAltitude, getInitialAltitude, gpsIsOk, getPosition, fdopen, getAltitude, getInitialAltitude, gpsIsOk, getPosition,
getYaw, initPubsub, kill, isLanding, loadFile, loiter, open, pipe, getLog, getYaw, initPubsub, isLanding, kill, loadFile, loiter, open,
setAirSpeed, setMessage, setReadHandler, setTargetCoordinates, pipe, setAirSpeed, setMessage, setReadHandler, setTargetCoordinates,
triggerParachute, updateLogAndProjection, waitpid) { triggerParachute, updateLogAndProjection, waitpid) {
// Every script is evaluated per drone // Every script is evaluated per drone
"use strict"; "use strict";
...@@ -200,7 +201,7 @@ import { evalScript, fdopen, loadFile, open } from "std"; ...@@ -200,7 +201,7 @@ import { evalScript, fdopen, loadFile, open } from "std";
} }
function handleMainMessage(evt) { function handleMainMessage(evt) {
var type = evt.data.type, message, peer_id; var type = evt.data.type, message, peer_id, log;
switch (type) { switch (type) {
...@@ -234,7 +235,15 @@ import { evalScript, fdopen, loadFile, open } from "std"; ...@@ -234,7 +235,15 @@ import { evalScript, fdopen, loadFile, open } from "std";
} }
} }
}); });
// Call the drone onStart function
if (clientId !== undefined) {
log = getLog();
if (log.length > 0) {
user_me.writeWebsocketMessage(JSON.stringify({log: log}));
}
}
// Call the drone onUpdate function
if (user_me.hasOwnProperty("onUpdate")) { if (user_me.hasOwnProperty("onUpdate")) {
user_me.onUpdate(evt.data.timestamp); user_me.onUpdate(evt.data.timestamp);
} }
...@@ -267,7 +276,7 @@ import { evalScript, fdopen, loadFile, open } from "std"; ...@@ -267,7 +276,7 @@ import { evalScript, fdopen, loadFile, open } from "std";
} }
}; };
}(Drone, SIGTERM, WNOHANG, Worker, close, console, evalScript, exec, }(Drone, SIGTERM, WNOHANG, Worker, close, console, evalScript, exec,
fdopen, getAltitude, getInitialAltitude, gpsIsOk, getPosition, getYaw, fdopen, getAltitude, getInitialAltitude, gpsIsOk, getPosition, getLog, getYaw,
initPubsub, isLanding, kill, loadFile, loiter, open, pipe, setAirSpeed, initPubsub, isLanding, kill, loadFile, loiter, open, pipe, setAirSpeed,
setMessage, setReadHandler, setTargetCoordinates, triggerParachute, setMessage, setReadHandler, setTargetCoordinates, triggerParachute,
updateLogAndProjection, waitpid)); updateLogAndProjection, waitpid));
...@@ -284,6 +284,49 @@ class SubscriberTestCase(SlapOSInstanceTestCase): ...@@ -284,6 +284,49 @@ class SubscriberTestCase(SlapOSInstanceTestCase):
b'Unknown instruction %s' % ws.sock.getsockname()[0].encode(), b'Unknown instruction %s' % ws.sock.getsockname()[0].encode(),
ws.recv_frame().data ws.recv_frame().data
) )
self.assertIn(
b'\\u001b[32minfo/userland\\u001b[0m\\tfieldsSize 3\\n"}',
ws.recv_frame().data,
)
self.assertEqual(
ws.recv_frame().data,
b''.join((
b'{"drone_dict":{"0":{"latitude":',
b'"%.6f","longitude":"%.6f","altitude":"%.2f",' % (0, 0, 0),
b'"yaw":"%.2f","speed":"%.2f","climbRate":"%.2f",' % (0, 0, 0),
b'"timestamp":%d}}}' % 0,
))
)
self.assertIn(
b'\\u001b[32minfo/client\\u001b[0m\\tReceived position of drone 0: %.6f ? %.6f ? %.2f m %.2f m\\n"}' % (0, 0 , 0, 0),
ws.recv_frame().data,
)
self.assertEqual(
ws.recv_frame().data,
b''.join((
b'{"drone_dict":{"0":{"latitude":',
b'"%.6f","longitude":"%.6f","altitude":"%.2f",' % (0, 0, 0),
b'"yaw":"%.2f","speed":"%.2f","climbRate":"%.2f",' % (0, 0, 0),
b'"timestamp":%d}}}' % 0,
))
)
self.assertIn(
b'\\u001b[32minfo/client\\u001b[0m\\tReceived speed of drone 0: %.2f ? %.2f m/s %.2f m/s\\n"}' % (0, 0 , 0),
ws.recv_frame().data,
)
self.assertEqual(
ws.recv_frame().data,
b''.join((
b'{"drone_dict":{"0":{"latitude":',
b'"%.6f","longitude":"%.6f","altitude":"%.2f",' % (0, 0, 0),
b'"yaw":"%.2f","speed":"%.2f","climbRate":"%.2f",' % (0, 0, 0),
b'"timestamp":%d}}}' % 0,
))
)
self.assertIn(
b'\\u001b[32minfo/userland\\u001b[0m\\tfieldsSize 1\\n"}',
ws.recv_frame().data,
)
self.assertEqual( self.assertEqual(
ws.recv_frame().data, ws.recv_frame().data,
b''.join(( b''.join((
...@@ -296,6 +339,10 @@ class SubscriberTestCase(SlapOSInstanceTestCase): ...@@ -296,6 +339,10 @@ class SubscriberTestCase(SlapOSInstanceTestCase):
self.send_ua_networkMessage() self.send_ua_networkMessage()
time.sleep(0.1) time.sleep(0.1)
self.assertEqual(ws.recv_frame().data, MESSAGE_CONTENT.replace(b'\\', b'')) self.assertEqual(ws.recv_frame().data, MESSAGE_CONTENT.replace(b'\\', b''))
self.assertIn(
b'\\u001b[32minfo/client\\u001b[0m\\tReceived position of drone 0: %.6f ? %.6f ? %.2f m %.2f m\\n"}' % POSITION_ARRAY_OUTPUT_VALUES,
ws.recv_frame().data,
)
self.assertEqual( self.assertEqual(
ws.recv_frame().data, ws.recv_frame().data,
b''.join(( b''.join((
...@@ -305,4 +352,8 @@ class SubscriberTestCase(SlapOSInstanceTestCase): ...@@ -305,4 +352,8 @@ class SubscriberTestCase(SlapOSInstanceTestCase):
b'"timestamp":%d}}}' % POSITION_ARRAY_INPUT_VALUES[-1], b'"timestamp":%d}}}' % POSITION_ARRAY_INPUT_VALUES[-1],
)) ))
) )
self.assertIn(
b'\\u001b[32minfo/client\\u001b[0m\\tReceived speed of drone 0: %.2f ? %.2f m/s %.2f m/s\\n"}' % SPEED_ARRAY_VALUES,
ws.recv_frame().data,
)
ws.close() ws.close()
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
<style> <style>
button { button {
padding: 0.5%; margin: 2vh;
padding: 2vh;
font-size: 24px; font-size: 24px;
cursor: pointer; cursor: pointer;
border: none; border: none;
...@@ -20,38 +21,60 @@ ...@@ -20,38 +21,60 @@
box-shadow: 0 2px #666; box-shadow: 0 2px #666;
transform: translateY(4px); transform: translateY(4px);
} }
div > * {margin: 1%} label {margin: auto 2%}
label {margin: 2%} table {
table {width: 30%} min-width: 1028px;
height: max-content;
}
th, td{ th, td{
padding: 1%; padding: 1%;
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
} }
.blue-text {color: blue}
.connected {color: green} .connected {color: green}
.container { .container {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.cyan-text {color: cyan}
.disconnected {color: red} .disconnected {color: red}
.gray-button {background-color: lightgray} .gray-button {background-color: lightgray}
.gray-button:hover {background-color: gray} .gray-button:hover {background-color: gray}
.green-text {color: green}
.green-button {background-color: #4caf50} .green-button {background-color: #4caf50}
.green-button:hover {background-color: #3e8e41} .green-button:hover {background-color: #3e8e41}
.magenta-text {color: magenta}
.red-button {background-color: red} .red-button {background-color: red}
.red-button {background-color: #e42828} .red-button:hover {background-color: #e42828}
.red-text {color: red}
.white-text {color: white}
.yellow-text {color: yellow}
#drones-status {height: 50vh}
#prompt {
background-color: rgb(18, 19, 20);
max-width: 1028px;
height: 20vh;
margin: auto;
}
#prompt-div {
height: max-content;
}
</style> </style>
</head> </head>
<body> <body>
<header class="container"> <div id="prompt-div">
<label for="web-socket-status">web socket status:</label> <div class="container">
<output class="disconnected" id="web-socket-status">Disconnected</output> <label for="web-socket-status">web socket status:</label>
</header> <output class="disconnected" id="web-socket-status">Disconnected</output>
</div>
<pre id="prompt"></pre>
</div>
<div class="container"> <div class="container" id="drones-status">
<table> <table>
<tr> <tr>
<th></th> <th></th>
......
...@@ -13,6 +13,9 @@ ...@@ -13,6 +13,9 @@
GREEN_BTN_CLASS_NAME = "green-button", GREEN_BTN_CLASS_NAME = "green-button",
LATITUDE_BASE_ID = "latitude_", LATITUDE_BASE_ID = "latitude_",
LONGITUDE_BASE_ID = "longitude_", LONGITUDE_BASE_ID = "longitude_",
PROMPT_COLOR_RE = /\u001b.{2,3}m/g,
PROMPT_ID = "prompt",
PROMPT_MAX_MSG,
QUIT_BTN_ID = "quit-btn", QUIT_BTN_ID = "quit-btn",
RED_BTN_CLASS_NAME = "red-button", RED_BTN_CLASS_NAME = "red-button",
SWITCH_BTN_ID = "switch-btn", SWITCH_BTN_ID = "switch-btn",
...@@ -21,8 +24,12 @@ ...@@ -21,8 +24,12 @@
socket; socket;
function updateConnexionClass(element, status) { function updateConnexionClass(element, status) {
element.classList.remove(status ? DISCONNECTED_CLASS_NAME : CONNECTED_CLASS_NAME); element.classList.remove(
element.classList.add(status ? CONNECTED_CLASS_NAME : DISCONNECTED_CLASS_NAME); status ? DISCONNECTED_CLASS_NAME : CONNECTED_CLASS_NAME
);
element.classList.add(
status ? CONNECTED_CLASS_NAME : DISCONNECTED_CLASS_NAME
);
} }
function setWebSocketStatus(connected, status) { function setWebSocketStatus(connected, status) {
...@@ -49,15 +56,22 @@ ...@@ -49,15 +56,22 @@
socket = new WebSocket('ws://{{ websocket_url }}'); socket = new WebSocket('ws://{{ websocket_url }}');
socket.onopen = function(event) { socket.onopen = function (event) {
setWebSocketStatus(true, "Connected"); setWebSocketStatus(true, "Connected");
}; };
socket.onmessage = function(event) { socket.onmessage = function (event) {
var message = JSON.parse(event.data), var color_array,
flight_state_cell; flight_state_cell,
i,
message = JSON.parse(event.data),
prompt,
new_div,
new_span,
text_array;
if (message.hasOwnProperty("drone_dict")) { if (message.hasOwnProperty("drone_dict")) {
Object.entries(message["drone_dict"]).forEach(function ([id, drone]) { Object.entries(message.drone_dict).forEach(function ([id, drone]) {
document.getElementById(LATITUDE_BASE_ID + id).innerHTML = drone["latitude"]; document.getElementById(LATITUDE_BASE_ID + id).innerHTML = drone["latitude"];
document.getElementById(LONGITUDE_BASE_ID + id).innerHTML = drone["longitude"]; document.getElementById(LONGITUDE_BASE_ID + id).innerHTML = drone["longitude"];
document.getElementById(ALTITUDE_BASE_ID + id).innerHTML = drone["altitude"]; document.getElementById(ALTITUDE_BASE_ID + id).innerHTML = drone["altitude"];
...@@ -69,6 +83,56 @@ ...@@ -69,6 +83,56 @@
flight_state_cell = document.getElementById(FLIGHT_STATUS_BASE_ID + message['id']); flight_state_cell = document.getElementById(FLIGHT_STATUS_BASE_ID + message['id']);
flight_state_cell.innerHTML = message['state']; flight_state_cell.innerHTML = message['state'];
updateConnexionClass(flight_state_cell, message['inAir']); updateConnexionClass(flight_state_cell, message['inAir']);
} else if(message.hasOwnProperty("log")) {
prompt = document.getElementById(PROMPT_ID);
if (PROMPT_MAX_MSG === undefined && prompt.children.length > 0) {
PROMPT_MAX_MSG = Math.trunc(
prompt.offsetHeight / prompt.children[0].offsetHeight
);
}
new_div = document.createElement("div");
text_array = message['log'].split(PROMPT_COLOR_RE);
color_array = message['log'].match(PROMPT_COLOR_RE);
for (i = 0; i < text_array.length; i++) {
new_span = document.createElement("span");
new_span.appendChild(document.createTextNode(text_array[i]));
if (i > 0 && i < color_array.length + 1) {
switch (color_array[i - 1]) {
case "\u001b[31m":
new_span.classList.add('red-text');
break;
case "\u001b[32m":
new_span.classList.add('green-text');
break;
case "\u001b[33m":
new_span.classList.add('yellow-text');
break;
case "\u001b[34m":
new_span.classList.add('blue-text');
break;
case "\u001b[35m":
new_span.classList.add('magenta-text');
break;
case "\u001b[36m":
new_span.classList.add('cyan-text');
break;
default:
new_span.classList.add('white-text');
break;
};
} else {
new_span.classList.add('white-text');
}
new_div.appendChild(new_span);
}
if (prompt.children.length === PROMPT_MAX_MSG) {
prompt.removeChild(prompt.firstElementChild);
}
prompt.appendChild(new_div);
} else { } else {
console.info(message); console.info(message);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment