Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
slapos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Léo-Paul Géneau
slapos
Commits
b8965e75
Commit
b8965e75
authored
Jun 03, 2023
by
Léo-Paul Géneau
👾
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
software/js-drone: print pubsub logs in the GUI
parent
3c2ed453
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
170 additions
and
26 deletions
+170
-26
software/js-drone/buildout.hash.cfg
software/js-drone/buildout.hash.cfg
+3
-3
software/js-drone/drone-scripts/worker.js.jinja
software/js-drone/drone-scripts/worker.js.jinja
+15
-6
software/js-drone/test/test.py
software/js-drone/test/test.py
+48
-0
software/js-drone/web-gui/index.html.jinja
software/js-drone/web-gui/index.html.jinja
+33
-10
software/js-drone/web-gui/script.js.jinja
software/js-drone/web-gui/script.js.jinja
+71
-7
No files found.
software/js-drone/buildout.hash.cfg
View file @
b8965e75
...
@@ -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
software/js-drone/drone-scripts/worker.js.jinja
View file @
b8965e75
...
@@ -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, get
Yaw, initPubsub, kill, loadFile
,
getLatitude, getLongitude, get
Log, getYaw, initPubsub, kill
,
lo
iter, open, pipe, setAirspeed, setMessage, setReadHandler
,
lo
adFile, loiter, open, pipe, setAirspeed, setMessage
,
setTargetCoordinates, triggerParachute, waitpid) {
set
ReadHandler, set
TargetCoordinates, 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, get
Log, get
Yaw, initPubsub, kill, loadFile,
loiter, open, pipe, setAirspeed, setMessage, setReadHandler,
loiter, open, pipe, setAirspeed, setMessage, setReadHandler,
setTargetCoordinates, triggerParachute, waitpid));
setTargetCoordinates, triggerParachute, waitpid));
software/js-drone/test/test.py
View file @
b8965e75
...
@@ -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
,
)
software/js-drone/web-gui/index.html.jinja
View file @
b8965e75
...
@@ -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>
...
...
software/js-drone/web-gui/script.js.jinja
View file @
b8965e75
...
@@ -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);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment