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 @@ ...@@ -14,7 +14,7 @@
# not need these here). # not need these here).
[index-html] [index-html]
_update_hash_filename_ = web-gui/index.html.jinja _update_hash_filename_ = web-gui/index.html.jinja
md5sum = d652b1b4769bae17b0b8c92ed233144b md5sum = ed0356dab0213a99fcd56e8a48e1c4d2
[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.jinja _update_hash_filename_ = web-gui/script.js.jinja
md5sum = 90bf6eaf67e2941d8a34e2cf2afdae2a md5sum = 0d51149929f3cbcaac966b815bb1fb0b
[worker] [worker]
_update_hash_filename_ = drone-scripts/worker.js.jinja _update_hash_filename_ = drone-scripts/worker.js.jinja
md5sum = ccbdd75b2a58e8d92d7cb990f2565b37 md5sum = 6e2a44716c44728e9441145fe0c2a829
...@@ -12,6 +12,7 @@ import { ...@@ -12,6 +12,7 @@ import {
getInitialAltitude, getInitialAltitude,
getLatitude, getLatitude,
getLongitude, getLongitude,
getLog,
getYaw, getYaw,
initPubsub, initPubsub,
loiter, loiter,
...@@ -34,9 +35,9 @@ import { evalScript, fdopen, loadFile, open } from "std"; ...@@ -34,9 +35,9 @@ 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, getAltitudeRel, getInitialAltitude, fdopen, getAltitude, getAltitudeRel, getInitialAltitude,
getLatitude, getLongitude, getYaw, initPubsub, kill, loadFile, getLatitude, getLongitude, getLog, getYaw, initPubsub, kill,
loiter, open, pipe, setAirspeed, setMessage, setReadHandler, loadFile, loiter, open, pipe, setAirspeed, setMessage,
setTargetCoordinates, triggerParachute, waitpid) { setReadHandler, setTargetCoordinates, triggerParachute, 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);
} }
...@@ -262,6 +271,6 @@ import { evalScript, fdopen, loadFile, open } from "std"; ...@@ -262,6 +271,6 @@ 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, getAltitudeRel, getInitialAltitude, fdopen, getAltitude, getAltitudeRel, getInitialAltitude,
getLatitude, getLongitude, getYaw, initPubsub, kill, loadFile, getLatitude, getLongitude, getLog, getYaw, initPubsub, kill, loadFile,
loiter, open, pipe, setAirspeed, setMessage, setReadHandler, loiter, open, pipe, setAirspeed, setMessage, setReadHandler,
setTargetCoordinates, triggerParachute, waitpid)); setTargetCoordinates, triggerParachute, waitpid));
...@@ -304,6 +304,46 @@ class JSDroneTestCase(SlapOSInstanceTestCase): ...@@ -304,6 +304,46 @@ class JSDroneTestCase(SlapOSInstanceTestCase):
def test_pubsub_subscription(self): def test_pubsub_subscription(self):
ws = websocket.WebSocket() ws = websocket.WebSocket()
ws.connect(self.websocket_server_address, timeout=5) 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( self.assertEqual(
ws.recv_frame().data, ws.recv_frame().data,
b''.join(( b''.join((
...@@ -315,6 +355,10 @@ class JSDroneTestCase(SlapOSInstanceTestCase): ...@@ -315,6 +355,10 @@ class JSDroneTestCase(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_VALUES,
ws.recv_frame().data,
)
self.assertEqual( self.assertEqual(
ws.recv_frame().data, ws.recv_frame().data,
b''.join(( b''.join((
...@@ -323,3 +367,7 @@ class JSDroneTestCase(SlapOSInstanceTestCase): ...@@ -323,3 +367,7 @@ class JSDroneTestCase(SlapOSInstanceTestCase):
b'"yaw":"%.2f","speed":"%.2f","climbRate":"%.2f"}}}' % SPEED_ARRAY_VALUES, 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 @@ ...@@ -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