Using a mqtt server with websockets and a website with the Eclipse Paho JavaScript Client
Above video: Joystick sends movement through the internet to my mqtt server, laptop is fetching a webpage from one of my webservers. A piece of javascript connects via websockets to the mqtt server and realtime changes the displayed image.
I intend to display maps and views into a maze you can walk through. like: (shamelessly stolen image from the internet)
I already have written another piece of code which generates a maze, and tells you using samples which way to go.
CODE
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1.0"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js" type="text/javascript"></script>
<script type = "text/javascript"
src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type = "text/javascript">
var connected_flag=0
var mqtt;
var reconnectTimeout = 2000;
var host="MQTTSERVER";
var port=8084;
var sub_topic="web/#";
function onConnectionLost(){
connected_flag=0;
document.getElementById("status").innerHTML = "Connection to HQ Lost";
}
function onFailure(message) {
console.log("Failed");
setTimeout(MQTTconnect, reconnectTimeout);
}
function onMessageArrived(r_message){
var topic=r_message.destinationName;
document.getElementById("status").innerHTML = "";
if(topic=="web/mapviewer")
{
$(".deze").attr("src","tiles/" + r_message.payloadString + ".png");
}
}
function onConnected(recon,url){
console.log(" in onConnected " +reconn);
}
function onConnect() {
// Once a connection has been made, make a subscription and send a message.
connected_flag=1
document.getElementById("status").innerHTML = "Connection made to HQ";
mqtt.subscribe(sub_topic);
}
function MQTTconnect() {
console.log("connecting to "+ host +" "+ port);
var x=Math.floor(Math.random() * 10000);
var cname="controlform-"+x;
//var cname="escape1";
mqtt = new Paho.MQTT.Client(host,port,cname);
var options = {
useSSL:true,
timeout: 3,
onSuccess: onConnect,
onFailure: onFailure,
};
mqtt.onConnectionLost = onConnectionLost;
mqtt.onMessageArrived = onMessageArrived;
mqtt.connect(options);
return false;
}
function sub_topics(){
document.getElementById("messages").innerHTML ="";
if (connected_flag==0){
out_msg="<b>Not Connected so can't subscribe</b>"
console.log(out_msg);
document.getElementById("messages").innerHTML = out_msg;
return false;
}
var stopic= document.forms["subs"]["Stopic"].value;
console.log("Subscribing to topic ="+stopic);
mqtt.subscribe(stopic);
return false;
}
function send_message(msg,topic){
if (connected_flag==0){
out_msg="<b>Not Connected so can't send</b>"
console.log(out_msg);
document.getElementById("messages").innerHTML = out_msg;
return false;
}
var value=msg.value;
console.log("value= "+value);
console.log("topic= "+topic);
message = new Paho.MQTT.Message(value);
message.destinationName = "web/"+topic;
mqtt.send(message);
return false;
}
</script>
<style>
@media only screen and (max-width: 600px) {
div {
max-width: 320px;
}
img {
max-width: 320px;
}
}
div.imageview {
color: white;
background: gray;
padding: 15px;
position: absolute;
top: 50%;
left: 50%;
-ms-transform: translateX(-50%) translateY(-50%);
-webkit-transform: translate(-50%,-50%);
transform: translate(-50%,-50%);
}
</style>
</head>
<body onload="MQTTconnect()">
<div class=imageview>
<img class="deze" src="tiles/00.png">
<div id="status">Connection Status: Not Connected</div>
</div>
</body>
</html>
While working on a harmony for Irmgard and me in Musescore, i tought it would be nice to have it also in another notation.
Above a Musescore screenshot.
When using below button assignment, we can easily rewrite above into another notation.
Write musescore as MusicML/mxl Music xml.
Install xml2abc from https://wim.vree.org/svgParse/xml2abc.html
python xml2abc.py INPUTFILE.mxl output.abc
My abc file
X:1
T:Planxty Irwin
C:OCarolan
L:1/4
M:3/4
I:
K:G
V:1 treble nm="Henri" snm="H"
V:1
|: d | B2 d | c2 A | F2 A | G3/2 d/ B | A G F | G3/2 A/ B | D2 E | F2 d | B2 d | c2 A | F2 A |
G3/2 d/ B | A G F | G3/2 A/ B | e d c | B2 d | B3/2 c/ B | B G B | c3/2 d/ c | c A F | G d e |
c d e | d3/2 c/ A | d c A | B c d | c B A | F G A | G3/2 d/ B | A G F | G3/2 A/ B | e d c | B2 :|
Using below bash script you can convert this to PDF WITH concertina notations.
WARNING: I didn't include all keys (yet).
NOTE: Easy to adjust to other notations.
#!/bin/bash
if [ $# -lt 2 ]; then
print "script orgname convertname"
exit 1
fi
: > parced
org=$1
abc=$2
cat $1 | awk '/^\|/ {exit} {print}' > header
cat $1 | grep "|" | tr -d '[0-9]:/'> parse
(
cat parse | while read ; do
echo $REPLY
echo -n "w: "
for word in $(echo $REPLY) ; do
if [ "$word" == "|" ] ; then echo -n " | "
elif [ "$word" == "D" ] ; then echo -n " 2 ";
elif [ "$word" == "G" ] ; then echo -n " 3 ";
elif [ "$word" == "B" ] ; then echo -n " 4 ";
elif [ "$word" == "d" ] ; then echo -n " 5 ";
elif [ "$word" == "g" ] ; then echo -n " 6 ";
elif [ "$word" == "b" ] ; then echo -n " 7 ";
else echo -n " * "
fi
done
echo ""
echo -n "w: "
for word in $(echo $REPLY) ; do
if [ "$word" == "|" ] ; then echo -n " | "
elif [ "$word" == "F" ] ; then echo -n " 2 ";
elif [ "$word" == "A" ] ; then echo -n " 3 ";
elif [ "$word" == "c" ] ; then echo -n " 4 ";
elif [ "$word" == "e" ] ; then echo -n " 5 ";
elif [ "$word" == "f" ] ; then echo -n " 6 ";
elif [ "$word" == "a" ] ; then echo -n " 7 ";
elif [ "$word" == "E" ] ; then echo -n " 4' "; # <============ example 2nd row
else echo -n " * "
fi
done
echo ""
done
) >> parced
cat header parced > $abc
abcm2ps -x -O - "$abc" | ps2pdf -sPAPERSIZE=a4 - "$(echo $abc | cut -f2 -d/ | sed 's/abc/pdf/g')"
PlatformIO tested ( install StackArray.h in lib/StackArray/StackArray.h )
Reset button and dipswitches for below options
Visited pathmode ( dip switch 1)
Preview maze generation ( dip switch 3)
Hard mode – starts at first position when hitting a wall ( dip 2 )
Longest path mode (longest stackarray before stack.pop (dip 4 )
Prints serial info, like a drawn maze
Pixel remapping for other displays ( Below mapping i had to use, see source sketch )
How is the maze generated?
It is generated using recursive backtracking:
Start at 0,0 mark visited, select a random direction from unvisited neighbours, push current on the stack, goto new location, and mark this visited. Repeat until no possible directions. pop from the stack a previous location, another direction possible? Take that path and repeat. Repeat popping from stack, until stack empty .. now all cells are visited
I’ve gone back and front using Visual Code. For work and now with platformio. (I’ve been using platformio on the commandline only, until recently.)
While i have some private github/gitlab accounts, I alway had some local git repositories. Using in the past GiTea, and a ssh based one.
Below: This own hosted SSH setup allows me to use Visual Code to use as git repository
========== On you ssh server
adduser git
su - git
mkdir .ssh && chmod 700 .ssh
touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys
chsh git -s $(which git-shell)
# Note .. there is no interactive shell!
== locate git-shell-commands
locate git-shell-commands
cp -r /usr/share/doc/git/contrib/git-shell-commands /home/git/
chmod +x /home/git/git-shell-commands/*
== Make sure git-shell is in /etc/shells
== Make a git repo destination
mkdir -p /mygitstuff/git
cd /mygitstuff/git
mkdir project.git
cd project.git
git init --bare
========== On your workstation
== copy ssh public key in .ssh/authorized_keys on the server
cd myproject
git init
git add .
git commit -m 'Initial commit'
git remote add origin git@gitserver:/mygitstuff/git/project.git
git push origin master
Make an initial cell the current cell
mark it as visited
While there are unvisited cells
If the current cell has any neighbours
which have not been visited
Choose randomly one of the unvisited neighbours
Push the current cell to the stack
Mark wall hole
Make the chosen cell the current cell
mark it as visited
Else if stack is not empty
Pop a cell from the stack
Make it the current cell
This is my implementation of backtracking
The displaymatrix function is a implementation of different led mappings
Still have to decide where to place endpoint … At 8,8 or at first stack pop? Maybe both?
Code
#include <WEMOS_Matrix_LED.h>
#include <StackArray.h>
int directions[4]{};
int notalldone = 1;
int tmpx=0;
int tmpy=0;
int x = 1;
int y = 1;
MLED mled(5); //set intensity=5
int maze[8][8] = {
};
int displaymatrix[8][8] = {
{ 0,1,2,3,4,5,6,7 },
{ 8,9,10,11,12,13,14,15 },
{16,17,18,19,20,21,22,23},
{24,25,26,27,28,29,30,31},
{32,33,34,35,36,37,38,39},
{40,41,42,43,44,45,46,47},
{48,49,50,51,52,53,54,55},
{56,57,58,59,60,61,62,63}
};
int visitmatrix[10][10] = {
1,1,1,1,1,1,1,1,1,1,
1,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,1,
1,1,1,1,1,1,1,1,1,1
};
void setup() {
Serial.begin(115200);
randomSeed(analogRead(0));
mazegen();
drawmaze();
}
void mazegen(){
visitmatrix[x][y]=1;
StackArray <int> rowStack;
StackArray <int> colStack;
rowStack.push(x);
colStack.push(y);
while(notalldone == 1){
visitmatrix[x][y]=1;
while(!rowStack.isEmpty()) {
int count=0;
//up
if ( visitmatrix[x-1][y] == 0 ){
directions[count]=1;
count++;
}
//right
if ( visitmatrix[x][y+1] == 0 ){
directions[count]=2;
count++;
}
//down
if ( visitmatrix[x+1][y] == 0 ){
directions[count]=4;
count++;
}
//left
if ( visitmatrix[x][y-1] == 0 ){
directions[count]=8;
count++;
}
// no dir found
if (count == 0 ) {
mled.dot(x-1,y-1);
mled.display();
x = rowStack.pop();
y = colStack.pop();
Serial.println("popping ");
} else {
// count random direction
int dir = directions[random(count)];
Serial.println("push ");
rowStack.push(x);
colStack.push(y);
Serial.print("nr dir : ");
Serial.println(count);
//delay(100);
Serial.println(dir);
// move 1,1 to 0,0
mled.dot(x-1,y-1);
mled.display();
// set direction in maze, dit moet bit set worden
int mybits = maze[x-1][y-1];
int storedir = mybits | dir;
maze[x-1][y-1] = storedir;
if ( dir == 1){
int getup = maze[x-2][y-1];
int storedir = getup | 4;
maze[x-2][y-1] = storedir;
}
if ( dir == 2){
int getup = maze[x-1][y];
int storedir = getup | 8;
maze[x-1][y] = storedir;
}
if ( dir == 4){
int getup = maze[x][y-1];
int storedir = getup | 1;
maze[x][y-1] = storedir;
}
if ( dir == 8){
int getup = maze[x-1][y-2];
int storedir = getup | 2;
maze[x-1][y-2] = storedir;
}
// maze[x-1][y-1] = dir;
//set new square
if (dir == 1){ x--; }
if (dir == 2){ y++; }
if (dir == 4){ x++; }
if (dir == 8){ y--; }
visitmatrix[x][y]=1;
drawmaze();
}
}
notalldone = 0; //#2
// if found 0 in 10x10 matrix visited, do
for(int checkx=0;checkx<10;checkx++){
for(int checky=0;checky<10;checky++){
if ( visitmatrix[checkx][checky] == 0 ){
tmpx=x;
tmpy=y;
notalldone = 1;
}
}
}
}
rowStack.push(tmpx);
colStack.push(tmpy);
}
void drawmaze(){
Serial.println("Generating done - Drawing");
for(int ledx=0;ledx<8;ledx++)
{
for(int ledy=0;ledy<8;ledy++){
Serial.print(maze[ledx][ledy]);
if ( maze[ledx][ledy] != 0 ) {
mled.dot(ledx,ledy); // draw dot
mled.display();
// delay(50);
}
}
Serial.println("");
}
Serial.println("");
delay(100);
}
void loop() {
}
I just took a 12mm x 60mm piece of wood, and made a slit for the acrylic plastic using a circular saw, and removed a part for the back-plate using a wood router. I found a piece of acrylic in my shed, cut it to the right size using the circular saw. Slapped some paint on the wood.
I want to be able to use the sdk whenever i want, so i made a sliding window thingy. ( With wooden handle so the frame looks intact when closed. )
Then I 3D printed some holders, which I designed using Openscad.
The codes are entered using a keypad (Arduino) and send via MQTT
Node Red Dash board
Code
var code = global.get("mysetcode");
var good = 0;
var wrong = 0;
var wrongplace = 0;
var match = false;
var wrongchars = 0;
var wrongplaced = 0;
var goodchars = 0;
var payloadcode = msg.payload.toString();
var usr_input = Array.from(payloadcode);
var secret_code = Array.from(code);
var secret_code1 = secret_code;
if (msg.payload === code) {
match = true;
}
var result = "";
for (var i = 0; i < 4; i++) {
var found = false;
if (usr_input[i] === secret_code[i]) {
usr_input[i] = "a";
secret_code[i] = "b";
good = good + 1;
}
}
for (var i = 0; i < 4; i++) {
var found = false;
for (var j = 0; j < 4; j++) {
if (usr_input[i] === secret_code[j]) {
found = true;
}
}
if (!found) {
wrong = wrong + 1;
}
}
wrongchars = wrong - good;
wrongplaced = 4 - good - wrongchars;
msg.goodchars = good;
msg.wrongchars = wrongchars;
msg.wrongplace = wrongplaced;
msg.result = result;
msg.match = match;
return msg;
"If something is worth doing, it's worth overdoing."