Tag Archives: mqtt

Calibrating temperature/humidity with mqtt

Example uses a shelly sensor, which has a offset mode in its new firmware. So below is not needed any more.
But the example can be used for any calibration/adjustments.

I’ve put two examples in the NodeRed function

First the solution

var temperature=msg.payload.tC;
var humidity=msg.payload.tF;
// calc new offset example
// simple offset + 2.3 off real measurement
msg.payload.tC=temperature + 2.3;
// more complex example
// take two measurements (with a big difference)
msg.payload.tF=1.11 * (humidity - 1);
return msg;

First adjustment is plus or minus a value.
Second is more precise when the temperature needs more adjusting

Dots on the red line are measured values
Blue is how it should be

So measured was 2.8 but should be 2
And measured 14.5 but needs to be 15

slope = (14.5-2.8)/(15-2) = 0.9

To get the multiplication factor = 1/0.9 = 1.1111

=(2.8-heightadjust)*1,1111 should give us 2

2/1.1111 = 2.8 – heightadjust

1.8 = 2.8 – heightadjust = 1

So the formula is realhumid = 1,1111 * ( measuredhumid – adjust )

Python Spotify Genre Cube v2

Spotify version

Next to do: Lasercut a wooden cube with better lettering.

Run the python part on a server

and

First export some API credentials

export SPOTIPY_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export SPOTIPY_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export SPOTIPY_REDIRECT_URI="http://localhost:8080/callback"

Code below:

from flask import Flask, request, redirect
from requests_oauthlib import OAuth2Session
from requests.auth import HTTPBasicAuth
import requests
import json
import spotipy
from spotipy.oauth2 import SpotifyOAuth
from pprint import pprint
from time import sleep
import spotipy.util as util
import sys
import paho.mqtt.client as mqttClient
import time
import os
import subprocess

Connected = False


broker_address = "MQTTSERVER"
port = 1883


def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("Connected to broker")
        global Connected
        Connected =True
    else:
        print("Connection failed")

def on_message(client, userdata, message):
    print (message.payload)
    myurl = 'spotify:playlist:' + str(message.payload.decode())

    results = sp.start_playback(context_uri=myurl, offset={"position": 1})

client = mqttClient.Client("PythonSpotifyGenreCube")
client.on_connect = on_connect
client.on_message = on_message

client.connect(broker_address, port=port,keepalive=60 )
client.loop_start()
time.sleep(4) # Wait for connection setup to complete
client.subscribe('spotify/playlist')
#client.loop_stop()    #Stop loop

#while Connected != True:
#    client.loop()
#    time.sleep(0.1)
#    print("test")
#    client.subscribe('spotify/playlist')



app = Flask(__name__)

AUTH_URL = 'https://accounts.spotify.com/authorize'
TOKEN_URL = 'https://accounts.spotify.com/api/token'
REDIRECT_URI = 'http://localhost:8080/callback'
CLIENT_ID = "xxxxxxxxxxxxxxxxxx"
CLIENT_SECRET = "xxxxxxxxxxxxxxxxxxxxx"
SCOPE = [
    "user-read-email",
    "playlist-read-collaborative"
]

@app.route("/login")
def login():
    spotify = OAuth2Session(CLIENT_ID, scope=SCOPE, redirect_uri=REDIRECT_URI)
    authorization_url, state = spotify.authorization_url(AUTH_URL)
    return redirect(authorization_url)

@app.route("/callback", methods=['GET'])
def callback():
    code = request.args.get('code')
    res = requests.post(TOKEN_URL,
        auth=HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET),
        data={
            'grant_type': 'authorization_code',
            'code': code,
            'redirect_uri': REDIRECT_URI
        })
    return json.dumps(res.json())


username = "fashice"
scope = "user-read-playback-state,user-modify-playback-state,playlist-read-private"
util.prompt_for_user_token(username,scope,client_id='xxxxxxxxxxxxxxxxxxxxx',client_secret='xxxxxxxxxxxxxxxxxxxxxxxxxxxx',redirect_uri='http://localhost:8080/callback')

sp = spotipy.Spotify(client_credentials_manager=SpotifyOAuth(scope=scope))

# Shows playing devices
res = sp.devices()
pprint(res)


# Change track
#sp.start_playback(uris=['spotify:track:6gdLoMygxxxxxxxxxxxxxxx'])
#results = sp.start_playback(context_uri=myurl, offset={"position": 1})


## Change volume
#sp.volume(100)
#sleep(2)
#sp.volume(50)
#sleep(2)
#sp.volume(100)
#


playlists = sp.user_playlists(username)

#for playlist in playlists['items']:
#    print(playlist['name'])


playlists = sp.current_user_playlists()
#print (playlists)
for playlist in playlists['items']:
    print(playlist['id'] + ' ' +  playlist['name'])



#if __name__ == '__main__':
#   app.run(port=8080,debug=True)


while Connected != True:
    time.sleep(0.1)
    client.subscribe('spotify/playlist')

try:
    while True:
        time.sleep(1)


except KeyboardInterrupt:
    print ("exiting")
    client.disconnect()
    client.loop_stop()

Shelly Dimmer and NodeRed an update ..

Our bedroom has a shelly dimmer, this one is connected with a wall switch and is being controlled by Domoticz, Home Assistant and NodeRed.

I had to fix some stuff, so this was a perfect time to jot down some notes.

I’ve wired it up like this:
(I’ve got a Line wire in my ceiling socket, so i placed the module there instead of the wall socket)

Configure the Shelly as mentioned in the manual. After that do the following:
Advance > Developer settings :
(Enable CoIot if you want a easy auto detect for Home Assistant)
Enable MQTT (This will DISABLE cloud ! )
Server: the ip number of your Mqtt Broker

Next I did was:

Now the wall switch will change/toggle what the current state is.
(If the light is off, and you switch it on using Mqtt, you probably needed to hit the switch two times to turn it off again. Not so with this setting.)

My Nodered Flow ( Not using the Shelly palette nodes in this example)

The Mqtt IN node sets the state of the switch when you use the wall switch!
Cozy turns light on at a specific level.
The slider send an off command when 0% selected, else an on command and the sliders value.

# Cozy function
msg.payload = {};
msg.payload.turn="on";
msg.payload.brightness=30;
return msg;

# Slider function
var varlevel = msg.payload;
msg.payload = {};
if(varlevel == 0){ 
msg.payload.turn="off";
} else
{
    msg.payload.turn="on";
}
msg.payload.brightness=varlevel;
return msg;

DashBoard

The Flow

[
    {
        "id": "32d1c58277d38408",
        "type": "ui_switch",
        "z": "746c372deb597681",
        "name": "",
        "label": "Bedroom lights2",
        "tooltip": "",
        "group": "c387df0cfc06c60e",
        "order": 3,
        "width": 0,
        "height": 0,
        "passthru": false,
        "decouple": "true",
        "topic": "",
        "topicType": "str",
        "style": "",
        "onvalue": "on",
        "onvalueType": "str",
        "onicon": "",
        "oncolor": "",
        "offvalue": "off",
        "offvalueType": "str",
        "officon": "",
        "offcolor": "",
        "animate": true,
        "className": "",
        "x": 220,
        "y": 940,
        "wires": [
            [
                "df432d3faea35f38"
            ]
        ]
    },
    {
        "id": "fb12eddd50d3013e",
        "type": "ui_slider",
        "z": "746c372deb597681",
        "name": "",
        "label": "Bedroom Lights2",
        "tooltip": "",
        "group": "c387df0cfc06c60e",
        "order": 4,
        "width": 0,
        "height": 0,
        "passthru": true,
        "outs": "end",
        "topic": "",
        "topicType": "str",
        "min": 0,
        "max": "100",
        "step": 1,
        "className": "",
        "x": 230,
        "y": 900,
        "wires": [
            [
                "d9c299ec7c0c82b0"
            ]
        ]
    },
    {
        "id": "d9c299ec7c0c82b0",
        "type": "function",
        "z": "746c372deb597681",
        "name": "Get level",
        "func": "var varlevel = msg.payload;\nmsg.payload = {};\n\nif(varlevel == 0){ \nmsg.payload.turn=\"off\";\n} else\n{\n    msg.payload.turn=\"on\";\n}\n\nmsg.payload.brightness=varlevel;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 460,
        "y": 900,
        "wires": [
            [
                "315ffbe441467c10"
            ]
        ]
    },
    {
        "id": "df432d3faea35f38",
        "type": "mqtt out",
        "z": "746c372deb597681",
        "name": "",
        "topic": "shellies/shellydimmer-CFE204/light/0/command",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "8c74c5f6.9a7a48",
        "x": 800,
        "y": 940,
        "wires": []
    },
    {
        "id": "315ffbe441467c10",
        "type": "mqtt out",
        "z": "746c372deb597681",
        "name": "",
        "topic": "shellies/shellydimmer-CFE204/light/0/set",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "8c74c5f6.9a7a48",
        "x": 780,
        "y": 900,
        "wires": []
    },
    {
        "id": "15f1c904607a0adc",
        "type": "function",
        "z": "746c372deb597681",
        "name": "Cozy",
        "func": "msg.payload = {};\n\nmsg.payload.turn=\"on\";\n\nmsg.payload.brightness=30;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 450,
        "y": 860,
        "wires": [
            [
                "315ffbe441467c10"
            ]
        ]
    },
    {
        "id": "57fb1210d37e5325",
        "type": "ui_button",
        "z": "746c372deb597681",
        "name": "",
        "group": "c387df0cfc06c60e",
        "order": 5,
        "width": 0,
        "height": 0,
        "passthru": false,
        "label": "Bedroom lights2 Cozy",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "payload": "",
        "payloadType": "str",
        "topic": "topic",
        "topicType": "msg",
        "x": 240,
        "y": 860,
        "wires": [
            [
                "15f1c904607a0adc"
            ]
        ]
    },
    {
        "id": "30cba96b08f3b830",
        "type": "mqtt in",
        "z": "746c372deb597681",
        "name": "",
        "topic": "shellies/shellydimmer-CFE204/light/0",
        "qos": "2",
        "datatype": "auto-detect",
        "broker": "8c74c5f6.9a7a48",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 240,
        "y": 1000,
        "wires": [
            [
                "32d1c58277d38408"
            ]
        ]
    },
    {
        "id": "c387df0cfc06c60e",
        "type": "ui_group",
        "name": "Bedroom",
        "tab": "f177532a78f3f1d2",
        "order": 3,
        "disp": true,
        "width": "6",
        "collapse": true,
        "className": ""
    },
    {
        "id": "8c74c5f6.9a7a48",
        "type": "mqtt-broker",
        "name": "IPBROKER",
        "broker": "IPBROKER",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "compatmode": true,
        "keepalive": "15",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "closeTopic": "",
        "closePayload": "",
        "willTopic": "",
        "willQos": "0",
        "willPayload": ""
    },
    {
        "id": "f177532a78f3f1d2",
        "type": "ui_tab",
        "name": "House",
        "icon": "dashboard",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]

RFID music playlist genre selector.

Just a proof of concept for a friend.

This one works with Logitech Media Server and Spotify playlists, but also works with generic LMS playlists when you change the url)

Selecting music using the RFID reader module in my game.
(i didn“t have a spare reader)

Cardboard box with rfid tags inside.

Looks nicer using laser lettering.

Maybe a tetrahedron for play,next,previous and stop?
And another with volume settings?

Simple node-red switcher

URL being called:

http://logictechmediaserver:9000/plugins/spotty/index.html?action=play&index=8.12

Mikrotik Plug Alarm

When plugging an ethernet cable in port one, the alarm will sound.
And a mqtt message is being send

I need to dust my desk in the Attic I know!

In the script is a little sound effect loop, maybe I’m going to write a ABC musicnotation / BagpipeMusicWriter to beep commands.

Script

:do {
	:local broker "NR"
        :local topic "crs109/ether1/alarm"
        :local int1 ether1;
	:foreach a in=[/interface find name=$int1] do={
		:local status [/interface get $a running];
		:if ($status=true) do={
                     :for t1 from=1 to=8 step=1 do={
                     :for t2 from=600 to=750 step=8 do={
                     :beep frequency=$t2 length=11ms;
                     :delay 11ms;
                     }
                     }
                /iot mqtt publish broker=$broker topic=$topic message="{\"ether1\":\"connected\"}"
                }
	}
}

Schedule

/system scheduler
add interval=5s name=schedule1 on-event=script1 policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    start-date=may/14/2023 start-time=23:25:36

Wifi monitoring with Mikrotik Mqtt Nodered and Pushover

I’ve made a arpscanner in the past
https://www.henriaanstoot.nl/2019/10/15/arpscanner/
But i’m going to migrate the server this is running on.

So I played with ssh commands using ssh connections with a ssh-key, also using Ansible is possible.

ssh user@mikrotik /interface wireless registration-table print

But I didn’t like the continuous logins with automated logins.

So below solution is what i’ve implemented for now.

I’ve installed the IOT extra package from Mikrotik, now I can send MQTT messages from my Wifi enabled Mikrotiks to my Mosquitto broker.
(Download extra package zip, extract iot-7.x-arm.npk, upload this to your mikrotik files folder, and reboot)
The script I’m running on my Mikrotik, sends the active wifi connections with the comments. ( When a comment is set in the Access List, then it’s a know connection )

[admin@RB40111] /iot/mqtt> export
# may/15/2023 21:45:12 by RouterOS 7.9
# software id = xxxx-xxxx
#
# model = RB4011iGS+5HacQ2HnD
# serial number = xxxxxxxxxxxxxxxxx
/iot mqtt brokers
add address=10.1.x.y client-id=rb4011 name=NR

I made the following script on my MT named mqtt

:local broker "NR"

# MQTT topic where the message should be published
:local topic "rb4011/mac"

:foreach i in=[/interface wireless registration-table print proplist=mac-address as-value] do={
:local message "$i"

/iot mqtt publish broker=$broker topic=$topic message=$message
}

A schedule is needed to run this script every 15 minutes

[admin@RB40111] /system/scheduler> export
# may/15/2023 21:48:14 by RouterOS 7.9
# software id = xxxx-xxx
#
# model = RB4011iGS+5HacQ2HnD
# serial number = xxxxxxxxxxx
/system scheduler
add interval=15m name=mqtt on-event=mqtt policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    start-date=may/15/2023 start-time=13:30:54

Now all wifi connections will be send to topic rb4011/mac.

# Example
.id=*6a;comment=Mobile Henri wlan2;mac-address=44:46:87:xx:xx:xx

Using NodeRed I can make filters and notifications

Below function: get Mac and Comment from payload, if the comment is empty then it is a unknown connection … so send me a warning using Pushover.

// filter function
var output = msg.payload.split(";");

var comment = (output[1].split("="));
var mac = (output[2].split("="));

msg.payload={};
msg.payload = mac[1];
if (comment[1] == "") {
return msg;
}

// is xx:xx:xx:xx:xx:xx online? example
var output = msg.payload.split(";");

var comment = (output[1].split("="));
var mac = (output[2].split("="));

msg.payload={};
msg.payload = mac[1];
if (mac[1] == "xx:xx:xx:xx:xx:xx") {
return msg;
}



Now i’m getting a notification when an unknown wifi connection is made on my Access Point.
( I going to implement the Access List from MT at a later point. No access when not in the Access List)

Realtime draw maze using php gd lib

UPDATE FROM: https://www.henriaanstoot.nl/2023/05/08/wss-websocket-to-mqtt-updating-website/

Mqtt controlled

for f in 1 2 3 4 5 6 7 0 ; do mosquitto_pub -h mqttserver -t web/mapviewer -m $f ;sleep 2 ;done

Below can be used in yesterdays script.
And can be called as image source.

<img src="draw.php?direction=0">

CODE

<?php

function imagelinethick($image, $x1, $y1, $x2, $y2, $color, $thick = 3)
{
    /* this way it works well only for orthogonal lines
    imagesetthickness($image, $thick);
    return imageline($image, $x1, $y1, $x2, $y2, $color);
    */
    if ($thick == 1) {
        return imageline($image, $x1, $y1, $x2, $y2, $color);
    }
    $t = $thick / 2 - 0.5;
    if ($x1 == $x2 || $y1 == $y2) {
        return imagefilledrectangle($image, round(min($x1, $x2) - $t), round(min($y1, $y2) - $t), round(max($x1, $x2) + $t), round(max($y1, $y2) + $t), $color);
    }
    $k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
    $a = $t / sqrt(1 + pow($k, 2));
    $points = array(
        round($x1 - (1+$k)*$a), round($y1 + (1-$k)*$a),
        round($x1 - (1-$k)*$a), round($y1 - (1+$k)*$a),
        round($x2 + (1+$k)*$a), round($y2 - (1-$k)*$a),
        round($x2 + (1-$k)*$a), round($y2 + (1+$k)*$a),
    );
    imagefilledpolygon($image, $points, 4, $color);
    return imagepolygon($image, $points, 4, $color);
}
header("Content-Type: image/png");
$im = imagecreate(640, 640);
$background_color = imagecolorallocate($im, 0, 0, 0);
$text_color = imagecolorallocate($im, 255, 255, 255);
$text_color1 = imagecolorallocate($im, 128, 128, 128);

$max=640;
$depth1=80;
$depth2=160;
$depth3=190;
$depthcolor1 = imagecolorallocate($im, 255, 255, 255);
$depthcolor2 = imagecolorallocate($im, 128, 128, 128);
$depthcolor3 = imagecolorallocate($im, 32, 32, 32);

$direction = $_GET["direction"];


// draw always
imagelinethick($im,0,0,$depth1,$depth1,$depthcolor1);
imagelinethick($im,$max,0,$max-$depth1,$depth1,$depthcolor1);
imagelinethick($im,0,$max,$depth1,$max-$depth1,$depthcolor1);
imagelinethick($im,$max,$max,$max-$depth1,$max-$depth1,$depthcolor1);

if ( $direction == "1" ) {
imagelinethick($im,$max-$depth1,$depth1,$max-$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$max-$depth1,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$max-$depth2,$depth2,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth1,$max-$depth2,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth1,$depth2,$max-$depth2,$depth2,$depthcolor2);
// front
imagelinethick($im,$depth1,$depth1,$depth1,$max-$depth1,$depthcolor1);
}

if ( $direction == "4" ) {
imagelinethick($im,$depth1,$max-$depth1,$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth1,$depth1,$depth2,$depth2,$depthcolor2);
imagelinethick($im,$depth2,$depth2,$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth2,$max-$depth2,$max-$depth1,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth2,$depth2,$max-$depth1,$depth2,$depthcolor2);
// front
imagelinethick($im,$max-$depth1,$depth1,$max-$depth1,$max-$depth1,$depthcolor1);
}

if ( $direction == "5" ) {
imagelinethick($im,$depth1,$depth2,$max-$depth1,$depth2,$depthcolor2);
imagelinethick($im,$depth1,$max-$depth2,$max-$depth1,$max-$depth2,$depthcolor2);
// front
imagelinethick($im,$depth1,$depth1,$depth1,$max-$depth1,$depthcolor1);
imagelinethick($im,$max-$depth1,$depth1,$max-$depth1,$max-$depth1,$depthcolor1);
}

if ( $direction == "2" ) {
imagelinethick($im,$depth1,$depth1,$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$depth1,$max-$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$max-$depth1,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth1,$max-$depth1,$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth2,$depth2,$depth3,$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$depth2,$max-$depth3,$depth3,$depthcolor3);
imagelinethick($im,$depth2,$max-$depth2,$depth3,$max-$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$max-$depth2,$max-$depth3,$max-$depth3,$depthcolor3);
}

if ( $direction == "3" ) {
imagelinethick($im,$max-$depth1,$depth1,$max-$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$max-$depth1,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth2,$depth2,$depth1,$depth2,$depthcolor2);
imagelinethick($im,$depth2,$max-$depth2,$depth1,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth2,$depth2,$depth2,$max-$depth2,$depthcolor2);

//depth3
imagelinethick($im,$depth2,$depth2,$depth3,$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$depth2,$max-$depth3,$depth3,$depthcolor3);
imagelinethick($im,$depth2,$max-$depth2,$depth3,$max-$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$max-$depth2,$max-$depth3,$max-$depth3,$depthcolor3);
//front
imagelinethick($im,$depth1,$depth1,$depth1,$max-$depth1,$depthcolor1);
}

if ( $direction == "6" ) {
imagelinethick($im,$depth1,$depth1,$depth2,$depth2,$depthcolor2);
imagelinethick($im,$depth1,$max-$depth1,$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$depth2,$max-$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$max-$depth2,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$max-$depth2,$max-$depth2,$max-$depth2,$depth2,$depthcolor2);

//depth3
imagelinethick($im,$depth2,$depth2,$depth3,$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$depth2,$max-$depth3,$depth3,$depthcolor3);
imagelinethick($im,$depth2,$max-$depth2,$depth3,$max-$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$max-$depth2,$max-$depth3,$max-$depth3,$depthcolor3);
//front
imagelinethick($im,$max-$depth1,$depth1,$max-$depth1,$max-$depth1,$depthcolor1);
}

if ( $direction == "7" ) {
imagelinethick($im,$depth1,$depth2,$depth2,$depth2,$depthcolor2);
imagelinethick($im,$depth1,$max-$depth2,$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth2,$max-$depth2,$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$depth2,$max-$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$max-$depth2,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$max-$depth2,$max-$depth2,$max-$depth2,$depth2,$depthcolor2);
//depth3
imagelinethick($im,$depth2,$depth2,$depth3,$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$depth2,$max-$depth3,$depth3,$depthcolor3);
imagelinethick($im,$depth2,$max-$depth2,$depth3,$max-$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$max-$depth2,$max-$depth3,$max-$depth3,$depthcolor3);
//front
imagelinethick($im,$max-$depth1,$depth1,$max-$depth1,$max-$depth1,$depthcolor1);
imagelinethick($im,$depth1,$depth1,$depth1,$max-$depth1,$depthcolor1);
}

if ( $direction == "0" ) {
imagelinethick($im,$depth1,$depth1,$max-$depth1,$depth1,$depthcolor1);
imagelinethick($im,$max-$depth1,$depth1,$max-$depth1,$max-$depth1,$depthcolor1);
imagelinethick($im,$max-$depth1,$max-$depth1,$depth1,$max-$depth1,$depthcolor1);
imagelinethick($im,$depth1,$max-$depth1,$depth1,$depth1,$depthcolor1);
}

imagepng($im);
imagedestroy($im);
?>

WSS Websocket to MQTT updating website

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>

HLK-LD2410B Mqtt socket and canvas

Follow up on yesterday’s post

Using a html page with javascript, I made a proof of concept displaying realtime information from the sensor.

The sensor is active using a Home Assistant integration.
https://www.henriaanstoot.nl/2022/11/07/home-assistant-nodered-update/

But using the Node-red integration, i take the payload and write this to a mqtt topic

The HTML page below reads the topic using the websocket configured in mosquitto and draws the distance using canvas

cat /etc/mosquitto/conf.d/websockets.conf
listener 9001
protocol websockets
allow_anonymous true


Distance drawn using canvas. Little dividers on top are meters

HTML PAGE with javascript

<?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, 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=9001;
var sub_topic="web/#";
	function onConnectionLost(){
	console.log("connection lost");
	document.getElementById("status").innerHTML = "Connection Lost";
	document.getElementById("messages").innerHTML ="Connection Lost";
	connected_flag=0;
	}
	function onFailure(message) {
		console.log("Failed");
		document.getElementById("messages").innerHTML = "Connection Failed- Retrying";
        setTimeout(MQTTconnect, reconnectTimeout);
        }
	function onMessageArrived(r_message){
		out_msg="Message received "+r_message.payloadString+"<br>";
		//out_msg=out_msg+"Message received Topic "+r_message.destinationName;
		//console.log("Message received ",r_message.payloadString);
		console.log(out_msg);
		document.getElementById("messages").innerHTML =out_msg;
		var topic=r_message.destinationName;
		if(topic=="web/module1")
		{
		document.getElementById("module1").innerHTML =r_message.payloadString;
		}
		if(topic=="web/module2")
		{
		document.getElementById("module2").innerHTML =r_message.payloadString;
		
		var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var centerX = 10;
context.clearRect(0, 0, 1800, 1000);
var centerY = 10;
var radius = r_message.payloadString;

let circle = new Path2D();  // 
circle.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);

//context.fillStyle = 'white';

context.fillStyle = "rgba(255, 255, 255, 0.2)";
context.fill(circle); //   

context.lineWidth = 5;
context.strokeStyle = '#000066';
context.stroke(circle);  //

// top line
context.beginPath();
context.moveTo(10, 10);
context.lineTo(1500, 10);
context.stroke();

// 3x dividers		
context.beginPath();
context.moveTo(400, 0);
context.lineTo(400, 20);
context.stroke();
		
context.beginPath();
context.moveTo(800, 0);
context.lineTo(800, 20);
context.stroke();
		
context.beginPath();
context.moveTo(1200, 0);
context.lineTo(1200, 20);
context.stroke();
		
		}
		}
	function onConnected(recon,url){
	console.log(" in onConnected " +reconn);
	}
	function onConnect() {
	  // Once a connection has been made, make a subscription and send a message.
	document.getElementById("messages").innerHTML ="Connected to "+host +"on port "+port;
	connected_flag=1
	document.getElementById("status").innerHTML = "Connected";
	console.log("on Connect "+connected_flag);
	mqtt.subscribe(sub_topic);
	  }

    function MQTTconnect() {

	console.log("connecting to "+ host +" "+ port);
	var x=Math.floor(Math.random() * 10000); 
	var cname="controlform-"+x;
	mqtt = new Paho.MQTT.Client(host,port,cname);
	//document.write("connecting to "+ host);
	var options = {
        timeout: 3,
		onSuccess: onConnect,
		onFailure: onFailure,
      
     };
	
        mqtt.onConnectionLost = onConnectionLost;
        mqtt.onMessageArrived = onMessageArrived;
		//mqtt.onConnected = onConnected;

	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>

  </head>
  <body onload="MQTTconnect()">
	

 <table>
<tr><td>Sensor1:<td><td  id="module1"><td><td >
<tr><td>Sensor2:</td><td  id="module2"><td></tr>

</table>
<div id="status">Connection Status: Not Connected</div>
</div>
<br>

Messages:<p id="messages"></p>
     <canvas id="canvas" width="1600" height="1000"></canvas>  
  </body>
</html>

Python Baudot code for Wemos Matrix Led

I wrote a python script to generate binary data to include in my Arduino sketch.
This Arduino displays codes send though MQTT.

https://en.wikipedia.org/wiki/Baudot_code

CODE:

python3 matrix.py apple gives me

byte apple_Char[8] = {
  0b00000000,
  0b01000100,
  0b01111000,
  0b00000000,
  0b00110000,
  0b00000000,
  0b00111000,
  0b00000000
};

Python Code
import sys

a = [ 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ], 
        [0,0,0,0,0,0,0,0 ] 
    ] 

letters = [
        [0,1,1,0,0,0,0,0 ],
        [0,1,0,0,0,1,1,0 ],
        [0,0,1,0,1,1,0,0 ],
        [0,1,0,0,0,1,0,0 ],
        [0,1,0,0,0,0,0,0 ],
        [0,1,0,0,1,1,0,0 ],
        [0,0,1,0,0,1,1,0 ],
        [0,0,0,0,1,0,1,0 ],
        [0,0,1,0,1,0,0,0 ],
        [0,1,1,0,0,1,0,0 ],
        [0,1,1,0,1,1,0,0 ],
        [0,0,1,0,0,0,1,0 ],
        [0,0,0,0,1,1,1,0 ],
        [0,0,0,0,1,1,0,0 ],
        [0,0,0,0,0,1,1,0 ],
        [0,0,1,0,1,0,1,0 ],
        [0,1,1,0,1,0,1,0 ],
        [0,0,1,0,0,1,0,0 ],
        [0,1,0,0,1,0,0,0 ],
        [0,0,0,0,0,0,1,0 ],
        [0,1,1,0,1,0,0,0 ],
        [0,0,1,0,1,1,1,0 ],
        [0,1,1,0,0,0,1,0 ],
        [0,1,0,0,1,1,1,0 ],
        [0,1,0,0,1,0,1,0 ],
        [0,1,0,0,0,0,1,0 ]
        ]

number=0
word=str(sys.argv[1])

for col in range(len(word)) :
    character=word[col]

    number = ord(character) - 97
    nextcol = col + 1
    for row in range(len(a[col])) :
        a[row][nextcol] = letters[number][row]


print("byte " + word + "_Char[8] = {")
for i in range(len(a)) : 
    print("  0b", end = '')
    for j in range(len(a[i])) : 
        print(a[i][j], end="")   
    if i < 7:
        print(",")
print()
print("};")

Arduino test code

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClient.h>


#include "WEMOS_Matrix_LED.h"
MLED mled(5); //set intensity=5

const char* wifi_ssid = "MYSSID"; // Enter your WiFi name
const char* wifi_password =  "MYSSIDPASS"; // Enter WiFi password
const char* mqtt_server = "MYMQTTSERVER";
const int mqtt_port = 1883;
const char* mqttUser = "";
const char* mqttPassword = "";
#define MSG_BUFFER_SIZE  (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;

WiFiClient espClient;

PubSubClient mqtt(espClient);

void setup_wifi() {
  delay(10);
  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}
 
byte clear_Char[8] = {  
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000,
  0b00000000
};
 
byte baudot_Char[8] = {
  0b11111111,
  0b01101010,
  0b00011100,
  0b11111111,
  0b00110100,
  0b00010000,
  0b00000100,
  0b11111111  
};
 

 
#define TIME 500
 
void setup() { 
    Serial.begin(115200);
      setup_wifi();
        mqtt.setServer(mqtt_server, mqtt_port);

WiFiClient espClient;
PubSubClient mqtt(espClient);

  mqtt.setClient(espClient);
  mqtt.setServer(mqtt_server, mqtt_port);
      delay(500);

  mqtt.subscribe("escape/matrixledin");
        delay(500);

  mqtt.setCallback(callback);

  }

void callback(char* topic, byte* payload, unsigned int length) {
        Serial.println("callback");
    String topicStr = topic;
      byte value = atoi((char*)payload);
        snprintf (msg, MSG_BUFFER_SIZE, "%1d", value);

              mqtt.publish("escape/matrixledout", msg);
       if (value == 1){

drawChar(baudot_Char); 

 }else if (value == 0){
  drawChar(cleat_Char); 
  }else if (value == 2){
  drawChar(test_Char); 
  }else if (value == 3){
  drawChar(no_Char); 
 }
 }

void reconnect() {

  while (!mqtt.connected()) {
    String clientId = "matrixClient-";
    clientId += String(random(0xffff), HEX);
    if (mqtt.connect(clientId.c_str())) {
      mqtt.publish("escape/outTopic", "hello from 8x8led module");
                Serial.println("resubscribe");

      mqtt.subscribe("escape/matrixledin");
        mqtt.setCallback(callback);

    } else {
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
 
void loop() {

 if (!mqtt.connected()) {
          Serial.println("reconnect called");
    reconnect();
  }
    mqtt.loop();

}
 
void drawChar(byte character[8]) {
  for(int y=7;y>=0;y--) {
  for (int x=0; x <= 7; x++) { 
    if (character[(7-y)] & (B10000000 >> x)) {
     mled.dot(x,y); // draw dot
    } else {
     mled.dot(x,y,0);//clear dot
    }
  }
  mled.display();  
  }
}