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

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

parent 3c2ed453
......@@ -14,7 +14,7 @@
# not need these here).
[index-html]
_update_hash_filename_ = web-gui/index.html.jinja
md5sum = d652b1b4769bae17b0b8c92ed233144b
md5sum = ed0356dab0213a99fcd56e8a48e1c4d2
[instance-profile]
filename = instance.cfg.in
......@@ -38,8 +38,8 @@ md5sum = 1555496ad591a31a845f33488d5c335d
[script-js]
_update_hash_filename_ = web-gui/script.js.jinja
md5sum = 90bf6eaf67e2941d8a34e2cf2afdae2a
md5sum = 0d51149929f3cbcaac966b815bb1fb0b
[worker]
_update_hash_filename_ = drone-scripts/worker.js.jinja
md5sum = ccbdd75b2a58e8d92d7cb990f2565b37
md5sum = 6e2a44716c44728e9441145fe0c2a829
......@@ -12,6 +12,7 @@ import {
getInitialAltitude,
getLatitude,
getLongitude,
getLog,
getYaw,
initPubsub,
loiter,
......@@ -34,9 +35,9 @@ import { evalScript, fdopen, loadFile, open } from "std";
(function (Drone, SIGTERM, WNOHANG, Worker, close, console, evalScript, exec,
fdopen, getAltitude, getAltitudeRel, getInitialAltitude,
getLatitude, getLongitude, getYaw, initPubsub, kill, loadFile,
loiter, open, pipe, setAirspeed, setMessage, setReadHandler,
setTargetCoordinates, triggerParachute, waitpid) {
getLatitude, getLongitude, getLog, getYaw, initPubsub, kill,
loadFile, loiter, open, pipe, setAirspeed, setMessage,
setReadHandler, setTargetCoordinates, triggerParachute, waitpid) {
// Every script is evaluated per drone
"use strict";
......@@ -200,7 +201,7 @@ import { evalScript, fdopen, loadFile, open } from "std";
}
function handleMainMessage(evt) {
var type = evt.data.type, message, peer_id;
var type = evt.data.type, message, peer_id, log;
switch (type) {
......@@ -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")) {
user_me.onUpdate(evt.data.timestamp);
}
......@@ -262,6 +271,6 @@ import { evalScript, fdopen, loadFile, open } from "std";
};
}(Drone, SIGTERM, WNOHANG, Worker, close, console, evalScript, exec,
fdopen, getAltitude, getAltitudeRel, getInitialAltitude,
getLatitude, getLongitude, getYaw, initPubsub, kill, loadFile,
getLatitude, getLongitude, getLog, getYaw, initPubsub, kill, loadFile,
loiter, open, pipe, setAirspeed, setMessage, setReadHandler,
setTargetCoordinates, triggerParachute, waitpid));
......@@ -304,6 +304,46 @@ class JSDroneTestCase(SlapOSInstanceTestCase):
def test_pubsub_subscription(self):
ws = websocket.WebSocket()
ws.connect(self.websocket_server_address, timeout=5)
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),
))
)
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),
))
)
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),
))
)
self.assertIn(
b'\\u001b[32minfo/userland\\u001b[0m\\tfieldsSize 1\\n"}',
ws.recv_frame().data,
)
self.assertEqual(
ws.recv_frame().data,
b''.join((
......@@ -315,6 +355,10 @@ class JSDroneTestCase(SlapOSInstanceTestCase):
self.send_ua_networkMessage()
time.sleep(0.1)
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_VALUES,
ws.recv_frame().data,
)
self.assertEqual(
ws.recv_frame().data,
b''.join((
......@@ -323,3 +367,7 @@ class JSDroneTestCase(SlapOSInstanceTestCase):
b'"yaw":"%.2f","speed":"%.2f","climbRate":"%.2f"}}}' % SPEED_ARRAY_VALUES,
))
)
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,
)
......@@ -9,7 +9,8 @@
<style>
button {
padding: 0.5%;
margin: 2vh;
padding: 2vh;
font-size: 24px;
cursor: pointer;
border: none;
......@@ -20,38 +21,60 @@
box-shadow: 0 2px #666;
transform: translateY(4px);
}
div > * {margin: 1%}
label {margin: 2%}
table {width: 30%}
label {margin: auto 2%}
table {
min-width: 1028px;
height: max-content;
}
th, td{
padding: 1%;
text-align: center;
vertical-align: middle;
}
.blue-text {color: blue}
.connected {color: green}
.container {
display: flex;
align-items: center;
justify-content: center;
}
.cyan-text {color: cyan}
.disconnected {color: red}
.gray-button {background-color: lightgray}
.gray-button:hover {background-color: gray}
.green-text {color: green}
.green-button {background-color: #4caf50}
.green-button:hover {background-color: #3e8e41}
.magenta-text {color: magenta}
.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>
</head>
<body>
<header class="container">
<div id="prompt-div">
<div class="container">
<label for="web-socket-status">web socket status:</label>
<output class="disconnected" id="web-socket-status">Disconnected</output>
</header>
</div>
<pre id="prompt"></pre>
</div>
<div class="container">
<div class="container" id="drones-status">
<table>
<tr>
<th></th>
......
......@@ -13,6 +13,9 @@
GREEN_BTN_CLASS_NAME = "green-button",
LATITUDE_BASE_ID = "latitude_",
LONGITUDE_BASE_ID = "longitude_",
PROMPT_COLOR_RE = /\u001b.{2,3}m/g,
PROMPT_ID = "prompt",
PROMPT_MAX_MSG,
QUIT_BTN_ID = "quit-btn",
RED_BTN_CLASS_NAME = "red-button",
SWITCH_BTN_ID = "switch-btn",
......@@ -21,8 +24,12 @@
socket;
function updateConnexionClass(element, status) {
element.classList.remove(status ? DISCONNECTED_CLASS_NAME : CONNECTED_CLASS_NAME);
element.classList.add(status ? CONNECTED_CLASS_NAME : DISCONNECTED_CLASS_NAME);
element.classList.remove(
status ? DISCONNECTED_CLASS_NAME : CONNECTED_CLASS_NAME
);
element.classList.add(
status ? CONNECTED_CLASS_NAME : DISCONNECTED_CLASS_NAME
);
}
function setWebSocketStatus(connected, status) {
......@@ -49,15 +56,22 @@
socket = new WebSocket('ws://{{ websocket_url }}');
socket.onopen = function(event) {
socket.onopen = function (event) {
setWebSocketStatus(true, "Connected");
};
socket.onmessage = function(event) {
var message = JSON.parse(event.data),
flight_state_cell;
socket.onmessage = function (event) {
var color_array,
flight_state_cell,
i,
message = JSON.parse(event.data),
prompt,
new_div,
new_span,
text_array;
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(LONGITUDE_BASE_ID + id).innerHTML = drone["longitude"];
document.getElementById(ALTITUDE_BASE_ID + id).innerHTML = drone["altitude"];
......@@ -69,6 +83,56 @@
flight_state_cell = document.getElementById(FLIGHT_STATUS_BASE_ID + message['id']);
flight_state_cell.innerHTML = message['state'];
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 {
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