Tag Archives: programming

20 years www.pipetunesearch.org

I’ve took it offline, maybe someone wants the source code and database.

It was much fun, time to move on.

UPDATE: 20230228 – It is online again.
(I’ve got some mails and mentions in music forums)

https://pipetunesearch.henriaanstoot.nl/

Apparently still a lot of visitors last year
Above example is not showing book covers

At least i’ve got some nice reactions

I’ve create my own bww/bwm to parsons code convertor.
Rest of the website is php, mysql … first one started in 2001 using php3, until php7.

Wow i found a screenshot from one if the first mobile versions!

PARSONS CODE: OMG, you don’t know how long I have been waiting for a search engine to find tunes in my head. I thought about creating some kind of dictionary based on theme notes, or searching through bww files for sequences. What a thrill to find your site. I just hum a tune, use the up, down, repeat letters and… like magic the title is found. You are a genius. I will never be stumped for a title again. Thanks so much, John

Other successes i’ve heard of are: 2 Youtube movies being identified, a nameless bww file and mp3’s

Mail from Dave:

Hiya

My name is Dave Mason. I put a few tunes together a few years ago called "Tummle Yer Wilkies" which, I see, gets mention on your website. However, I see that you're not sure where people can access the tunes.

Well, the book is free to download from https://sites.google.com/site/tummleyerwilkies/home and I hope to have volume 2, "Tummle Yer Wilkies Too!" uploaded in the near future.

Cheers
Dave Mason

Geneva, Switzerland.

NEW - Palm version by Andreas Joebges (updated)
Added stuff changed software
Added parts in booklist and search.
Additions to www.drumscoresearch.org
Many additions by: Chris MacKnight
Palm version by Andreas Joebges
Added index send by : Henning
sat 14 feb: Installed DB on macbumm's site
sun 15 feb: Made some changes, limit search and layout
            Removed own collections from DB 
            Expanded statspage with jig/hornp/march/etc.
mon 16 feb: Imported College of Piping index i got from Ralf .. (thanks!)  
            Imported Irish Tunes for Warpipe
            Added Log, Fixed Members Login for edit purposes
tue 17 feb: Layout, testing new functions
wed 18 feb: Imported Bagpipe Music - John MacFadyen
thu 19 feb: Uploaded some Book Covers, 
            programmed a export-to-xls function, so you can use the
            DB data yourself (bottom of booklist pages) 
            Imported Gordon Highlanders Vol 1
sat 21 feb: Fixed m?c and l*ken search
            Imported Gordon Highlanders Vol 2
            Added AKA search
            Old search request stays in search field
            Added some covers
            code cleanup
mon 23 feb: Fixed bookcover popup
            Imported Mark Saul Vol I 
            Uploaded Mark Saul Cover II and changed faulty cover other Vol
            Bookinfo added ISBN, Price, etc.  Suggestion i got by Email
            Uploaded Queens Own Highlanders The Pipers Day  
            Imported Seaforth Highlanders - Standard Settings
thu 26 feb: DB cleanup
            Added Code
            Imported Donald MacLeod vol 1 2 and 4
fri 27 feb: 1st editor assigned - Henny Barnhoorn 
sat 28 feb: Imported Vol 5 and 6 Donald MacLeod 
sun 29 feb: CD Information added
            2nd editor - Coline Gerritsen
mon 01 feb: Added CDs .. Thanks Coline
            Gordon Highlanders Book 1 checked/added/etc. by Henny .. thanks
            CD displaying code changed
            Imported Robert Mathieson Book 4  (now over 4000 tunes in DB!)
fri 05 mar: Added CDs
            Altered ShowCD Code
sun 07 mar: Imported some books (NOW 50!)
            Henny Completed reediting Gordon Highlanders Vol2
            Add MP3 clip code in cdinfo
mon 08 mar: Imported book
            Fixed image caching for faulty browsers
            Search finds composers also
            Fixed Menu structure
            Added Templates
tue 09 mar: Added link under advanced search - find ALL harmonies. :)
wed 10 mar: Added book with cover + MP3 sample
thu 11 mar: Imported Piob. CD
            Added edit icon help 
fri 12 mar: Find tunes on CD in beta test .. :)
            (click search -> advanced .. enter a keyword, mark the media
            checkbox and click search .. CDs found at bottom of page .. :) 
sat 13 mar: Imported another filled-in cd-template :)
            Added some covers
wed 17 mar: Added 15 Piobaireachd Society Volumes
sat 20 mar: Added 3 CD's
tue 23 mar: Added several books (5166 tunes now!) Thanks John 
thu 25 mar: Changed code, checked book, imported book
tue 30 mar: Uploaded covers, edited book (Murray Blairs) and added books 
till
tue 06 apr: Uploaded Covers, Added books, Changed code
till
sat 17 apr: Imported some books, added parts to export-excell
            (will be in search later)
            Henny checked/edited some books
tue 20 apr: Imported books, testing query caching for speed improvement.
            (yes getting kindda large .. this thingy)
thu 22 apr: 100! BOOKs!
--missing log--
Added book, covers e.t.c.
sun 11 jul: Added Battlefield Book (thanx Markus)
mon 11 jan: Added 2 books (thanx again Markus)
  • 159 Books
  • 9868 Tunes
  • 1047 Air’s
  • 1315 Jigs
  • 638 Hornpipes
  • 3352 Marches
  • 489 Piob’s
  • 1586 Reels
  • 844 Strathspeys

Audio switcher

Doing my work from home via Jitsi (Jabra headset) and Listening to music on my speakers. Sometimes i want to switch output. For example spotify on my headset.

Using below code, i can easily switch between output sinks.

#!/bin/bash

if [ -z "$1" ]; then
    echo "DEVICE"
    pactl list sinks | egrep "^Sink|Description" | sed 'N;s/\n/,/' |sed -e 's/\t/ /g'  | cut -f2,5- -d" "
        echo "APPLICATIONS"
    pactl list sink-inputs | egrep -ie "^Sink|application.name" | grep -v "\-application-name" | sed 'N;s/\n/,/' | sed -e 's/\t/ /g' | sed -e 's/  / /g' | cut -f3,6- -d" "
    echo "Usage: $0 APPID DEVICEID" >&2
    exit 1
fi

pactl move-sink-input $1 $2

It shows output devices, and applications which are using audio sinks.
Just match them up.

MQTT Keyboard

A fancy keyboard….. At last a clickety keyboard. A Razer Blackwidow V3 mechanical keyboard. I’m not a gamer, but i like the clickety sounds. RGB leds are always nice to play with.

One of the nice things about razer is the Linux support!

Some nice links:

https://github.com/openrazer/openrazer

https://openrazer.github.io/

Even several python scripts can be found, but no MQTT.
So made a fast ‘n simple hack to control my keyboard with mqtt/nodered.

When someone is at the frontdoor, my keyboard changes from white to red.

Below a node-red example

My python code:

import paho.mqtt.client as mqttClient
import time
import os
import subprocess
import json

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):
    subprocess.Popen(["razer-cli", "-c", message.payload])

Connected = False

broker_address = "your.mqtt.brokerip.here"
port = 1883
#user = "user"
#password = "password"
client = mqttClient.Client("mqttrazer")
#client.username_pw_set(user, password=password)
client.on_connect = on_connect
client.on_message = on_message

client.connect(broker_address, port=port)
client.loop_start()

while Connected != True:
    time.sleep(0.1)

client.subscribe('razer/in')

try:
    while True:
        time.sleep(1)

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

Ipcam sphere panorama

I made a little script to make a 360 spherical panorama photo, using a remote controlled IP cam,

Looking at the API CGI, i only needed to control the movement of the camera and getting a snapshot.

  • Point camera down
  • Point camera maximal left
  • Take picture
  • Point a little to the right
  • Take picture, loop until max right
  • Point a little more up and go max left
  • Doing same loop as above, until pointing maximal up
Made a little animation in blender

After getting all those pictures, i only needed to stitch them using Hugin.
When viewing the image with VR Glasses, i could look around my room, without image distortion, like below flattend example.

The ipcam generates a token, which you have to use in your curl commands.

TOKEN PART

token=$( curl -s -d  '[{"cmd":"Login","action":0,"param":{"rs": "abcd", "User":{"userName":"admin","password":"SECRETPASSWORD"}}}]'  "http://camera.ip.number.here/cgi-bin/api.cgi?cmd=Login&token=null"  -H 'Content-Type: application/json' | grep name | cut -f4 -d\" )

GETTING A IMAGE FROM IPCAM

wget "http://camera.ip.number.here/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=123asd&user=admin&password=SECRETPASSWORD" -O output.jpg

CONTROLLING MOVEMENT

curl -X POST  -d '[{"cmd":"PtzCtrl","action":0,"param":{"rs": "abcd", "channel":0,"op":"Left","speed":1,"id":1}}]' "http://camera.ip.number.here/cgi-bin/api.cgi?cmd=PtzCtrl&token=$token"

COMPLETE SCRIPT

#!/bin/bash
token=$( curl -s -d  '[{"cmd":"Login","action":0,"param":{"rs": "abcd", "User":{"userName":"admin","password":"SECRETPASSWORD"}}}]'  "http://camera.ip.number.here/cgi-bin/api.cgi?cmd=Login&token=null"  -H 'Content-Type: application/json' | grep name | cut -f4 -d\" )
echo $token

if [ $2 == "max" ]; then
curl -X POST  -d '[{"cmd":"PtzCtrl","action":0,"param":{"rs": "abcd", "channel":0,"op":"'$1'","speed":1,"id":1}}]' "http://camera.ip.number.here/cgi-bin/api.cgi?cmd=PtzCtrl&token=$token"
exit 0
fi


for x in $(seq -w 1 25) ; do
	for y in $(seq -w 1 12) ; do
                wget "http://camera.ip.number.here/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=123asd&user=admin&password=SECRETPASSWORD" -O ${x}${y}.jpg
		curl -X POST  -d '[{"cmd":"PtzCtrl","action":0,"param":{"rs": "abcd", "channel":0,"op":"Right","speed":1,"id":1}}]' "http://camera.ip.number.here/cgi-bin/api.cgi?cmd=PtzCtrl&token=$token"
		sleep 0.5
		curl -X POST  -d '[{"cmd":"PtzCtrl","action":0,"param":{"rs": "abcd", "channel":0,"op":"Stop","speed":1,"id":1}}]' "http://camera.ip.number.here/cgi-bin/api.cgi?cmd=PtzCtrl&token=$token"
		sleep 5
	done

	curl -X POST  -d '[{"cmd":"PtzCtrl","action":0,"param":{"rs": "abcd", "channel":0,"op":"Left","speed":1,"id":1}}]' "http://camera.ip.number.here/cgi-bin/api.cgi?cmd=PtzCtrl&token=$token"
	sleep 30
	curl -X POST  -d '[{"cmd":"PtzCtrl","action":0,"param":{"rs": "abcd", "channel":0,"op":"Stop","speed":1,"id":1}}]' "http://camera.ip.number.here/cgi-bin/api.cgi?cmd=PtzCtrl&token=$token"
	sleep 1
        curl -X POST  -d '[{"cmd":"PtzCtrl","action":0,"param":{"rs": "abcd", "channel":0,"op":"Up","speed":1,"id":1}}]' "http://camera.ip.number.here/cgi-bin/api.cgi?cmd=PtzCtrl&token=$token"
	sleep 0.5
	curl -X POST  -d '[{"cmd":"PtzCtrl","action":0,"param":{"rs": "abcd", "channel":0,"op":"Stop","speed":1,"id":1}}]' "http://camera.ip.number.here/cgi-bin/api.cgi?cmd=PtzCtrl&token=$token"
sleep 5
done
1st panorama (Black and White due to night mode camera)

Bluetooth Macro Keyboard for Photo Management

Arduino Bluetooth Photo view marco keyboard
  • Cursor pad on the left
  • 1 till 5 (see below)
  • star + 1-5, rates 1 till 5 stars
  • outline star – removes rating
  • bookmark + 1-5, color marks image
  • Triangle – start slideshow
  • zoom-in, rotate CCW, reset zoom, rotate CW, zoom-out
  • previous image, open image, fullscreen, exit fullscreen to manager and next image

I’ve used a esp32 with 18650 battery holder.

I still have to 3d print a case 🙂

Code:

#include <BleConnectionStatus.h>
#include <BleKeyboard.h>
#include <KeyboardOutputCallbacks.h>

#define DEBUG 0micro joystick
#define STAR 16
#define FLAG 17
#define COL1 18
#define COL2 19
#define COL3 21
#define COL4 22
#define COL5 23
#define COL6 25
#define ROW1 26
#define ROW2 27
#define ROW3 32
#define ROW4 33

int flagstate = 0;
int starstate = 0;
int row1state = 0;
int row2state = 0;
int row3state = 0;
int row4state = 0;
int col1state = 0;
int col2state = 0;
int col3state = 0;
int col4state = 0;
int col5state = 0;
int col6state = 0;

int colstate = 1;

BleKeyboard bleKeyboard;

void setup() {
#ifdef DEBUG
  Serial.begin(9600);
#endif
  bleKeyboard.begin();
  pinMode(STAR, INPUT_PULLUP);
  pinMode(FLAG, INPUT_PULLUP);
  pinMode(ROW1, INPUT_PULLUP);
  pinMode(ROW2, INPUT_PULLUP);
  pinMode(ROW3, INPUT_PULLUP);
  pinMode(ROW4, INPUT_PULLUP);
  pinMode(COL1, OUTPUT);
  pinMode(COL2, OUTPUT);
  pinMode(COL3, OUTPUT);
  pinMode(COL4, OUTPUT);
  pinMode(COL5, OUTPUT);
  pinMode(COL6, OUTPUT);
}
void loop() {
#ifdef DEBUG
  Serial.print("Colstate : ");
  Serial.print(colstate);
  Serial.print('\n');
#endif

  if (colstate == 1) {
    digitalWrite(COL1, LOW);
    digitalWrite(COL2, HIGH);
    digitalWrite(COL3, HIGH);
    digitalWrite(COL4, HIGH);
    digitalWrite(COL5, HIGH);
    digitalWrite(COL6, HIGH);
  }
  if (colstate == 2) {
    digitalWrite(COL1, HIGH);
    digitalWrite(COL2, LOW);
    digitalWrite(COL3, HIGH);
    digitalWrite(COL4, HIGH);
    digitalWrite(COL5, HIGH);
    digitalWrite(COL6, HIGH);
  }
  if (colstate == 3) {
    digitalWrite(COL1, HIGH);
    digitalWrite(COL2, HIGH);
    digitalWrite(COL3, LOW);
    digitalWrite(COL4, HIGH);
    digitalWrite(COL5, HIGH);
    digitalWrite(COL6, HIGH);
  }
  if (colstate == 4) {
    digitalWrite(COL1, HIGH);
    digitalWrite(COL2, HIGH);
    digitalWrite(COL3, HIGH);
    digitalWrite(COL4, LOW);
    digitalWrite(COL5, HIGH);
    digitalWrite(COL6, HIGH);
  }
  if (colstate == 5) {
    digitalWrite(COL1, HIGH);
    digitalWrite(COL2, HIGH);
    digitalWrite(COL3, HIGH);
    digitalWrite(COL4, HIGH);
    digitalWrite(COL5, LOW);
    digitalWrite(COL6, HIGH);
  }
  if (colstate == 6) {
    digitalWrite(COL1, HIGH);
    digitalWrite(COL2, HIGH);
    digitalWrite(COL3, HIGH);
    digitalWrite(COL4, HIGH);
    digitalWrite(COL5, HIGH);
    digitalWrite(COL6, LOW);
  }
  delay (100);
  flagstate = digitalRead(FLAG);
  starstate = digitalRead(STAR);
  row1state = digitalRead(ROW1);
  row2state = digitalRead(ROW2);
  row3state = digitalRead(ROW3);
  row4state = digitalRead(ROW4);
#ifdef DEBUG
  Serial.print("Rowstates : ");
  Serial.print(row1state);
  Serial.print(row2state);
  Serial.print(row3state);
  Serial.print(row4state);
  Serial.print('\n');
#endif
  // ROW1 = UP,DOWN,LEFT,RIGHT
  if (bleKeyboard.isConnected() && colstate == 1) {
    // UP
#ifdef DEBUG
    Serial.print("Up Pressed ");
    Serial.print('\n');
#endif

    if (row1state == 0) {
      bleKeyboard.press(KEY_UP_ARROW);
      delay (100);
      bleKeyboard.releaseAll();
    }
    // DOWN
    if (row2state == 0) {
      bleKeyboard.press(KEY_DOWN_ARROW);
      delay (100);
      bleKeyboard.releaseAll();
    }
    // LEFT
    if (row3state == 0) {
      bleKeyboard.press(KEY_LEFT_ARROW);
      delay (100);
      bleKeyboard.releaseAll();
    }
    // RIGHT
    if (row4state == 0) {
      bleKeyboard.press(KEY_RIGHT_ARROW);
      delay (100);
      bleKeyboard.releaseAll();
    }
  }
  // ROW2 = (1),(star),ZOOMIN,PREVIOUS
  if (bleKeyboard.isConnected() && colstate == 2) {
    // 1 - star
    if (row1state == 0 && starstate == 0) {
      bleKeyboard.press(KEY_LEFT_CTRL);
      bleKeyboard.press('1');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // 1 - flag
    if (row1state == 0 && flagstate == 0) {
      bleKeyboard.press(KEY_LEFT_ALT);
      bleKeyboard.press('1');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // NO ROWSTATE2

    // zoom in
    if (row3state == 0) {
      bleKeyboard.press('+');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // PREVIOUS
    if (row4state == 0) {
      bleKeyboard.press(KEY_LEFT_CTRL);
      bleKeyboard.press(KEY_LEFT_ARROW);
      delay (100);
      bleKeyboard.releaseAll();
    }
  }
  // ROW3 = (2),unstar,CCWrotate,open
  if (bleKeyboard.isConnected() && colstate == 3) {
    // 2 - star
    if (row1state == 0 && starstate == 0) {
      bleKeyboard.press(KEY_LEFT_CTRL);
      bleKeyboard.press('2');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // 2 - flag
    if (row1state == 0 && flagstate == 0) {
      bleKeyboard.press(KEY_LEFT_ALT);
      bleKeyboard.press('2');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // unstar
    if (row2state == 0) {
      bleKeyboard.press(KEY_LEFT_CTRL);
      bleKeyboard.press('0');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // CCW rotate
    if (row3state == 0) {
      bleKeyboard.press(KEY_LEFT_CTRL);
      bleKeyboard.press(KEY_LEFT_ALT);
      bleKeyboard.press(KEY_LEFT_ARROW);
      delay (100);
      bleKeyboard.releaseAll();
    }
    // open
    if (row4state == 0) {
      bleKeyboard.press(KEY_RETURN);
      delay (100);
      bleKeyboard.releaseAll();
    }
  }

  // ROW4 = (3),(flag),zoom,fullscreen
  if (bleKeyboard.isConnected() && colstate == 4) {
    // 3 - star
    if (row1state == 0 && starstate == 0) {
      bleKeyboard.press(KEY_LEFT_CTRL);
      bleKeyboard.press('3');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // 3 - flag
    if (row1state == 0 && flagstate == 0) {
      bleKeyboard.press(KEY_LEFT_ALT);
      bleKeyboard.press('3');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // NO ROWSTATE2

    // zoom reset
    if (row3state == 0) {
      bleKeyboard.press('*');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // fullscreen
    if (row4state == 0) {
      bleKeyboard.press('f');
      delay (100);
      bleKeyboard.releaseAll();
    }
  }

  // ROW5 = (4),unflag,CWrotate,exit
  if (bleKeyboard.isConnected() && colstate == 5) {
    // 4 - star
    if (row1state == 0 && starstate == 0) {
      bleKeyboard.press(KEY_LEFT_CTRL);
      bleKeyboard.press('4');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // 4 - flag
    if (row1state == 0 && flagstate == 0) {
      bleKeyboard.press(KEY_LEFT_ALT);
      bleKeyboard.press('4');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // unflag
    if (row2state == 0) {
      bleKeyboard.press(KEY_LEFT_ALT);
      bleKeyboard.press('0');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // CW rotate
    if (row3state == 0) {
      bleKeyboard.press(KEY_LEFT_CTRL);
      bleKeyboard.press(KEY_LEFT_ALT);
      bleKeyboard.press(KEY_RIGHT_ARROW);
      delay (100);
      bleKeyboard.releaseAll();
    }
    // exit
    if (row4state == 0) {
      bleKeyboard.press(KEY_ESC);
      delay (100);
      bleKeyboard.releaseAll();
    }
  }

  // ROW6 = (5),slideshow,zoomout,next
  if (bleKeyboard.isConnected() && colstate == 6) {
    // 5 - star
    if (row1state == 0 && starstate == 0) {
      bleKeyboard.press(KEY_LEFT_CTRL);
      bleKeyboard.press('5');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // 5 - flag
    if (row1state == 0 && flagstate == 0) {
      bleKeyboard.press(KEY_LEFT_ALT);
      bleKeyboard.press('5');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // slideshow
    if (row2state == 0) {
      bleKeyboard.press(KEY_ESC);
      bleKeyboard.press(KEY_LEFT_CTRL);
      bleKeyboard.press('s');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // zoom out
    if (row3state == 0) {
      bleKeyboard.press('-');
      delay (100);
      bleKeyboard.releaseAll();
    }
    // next
    if (row4state == 0) {
      bleKeyboard.press(KEY_LEFT_CTRL);
      bleKeyboard.press(KEY_RIGHT_ARROW);
      delay (100);
      bleKeyboard.releaseAll();
    }
  }
  colstate++;
  if (colstate == 7) {
    colstate = 1;
  }
}
Keyboard layout

Hex Dimmer

Control a dimmer using a hex wireless box.

Parts

  • Wemos Mini
  • MPU6050 – Gyroscope Module
  • 10k Resistor
  • TP4056 – Battery Charger Module
  • Mini Battery
  • Wireless Charger

Put the box flat on the table to switch off.
When you put it on one side, it will controll your lights brightness.
20,40,60,80 and 100%, just by rotating and putting it down on its sides.

3D printed case

Schematics (without the wireless charging part)

Wireless part

Node-Red Controll part (source below)

Nice to have’s :
Arduino-sleep mode, wakeup with a movement sensor.

Arduino Code

#include <Wire.h>
//#include <SPI.h>
#include <PubSubClient.h>
//#include <string.h>
//#include <stdio.h>
#include <ESP8266WiFi.h>

// Wifi settings
const char* ssid = "xxxxxx";
const char* password = "xxxxxxxxxx";
const char* mqtt_server = "10.1.0.17";

// I2C address of the MPU-6050 - 0x68 or 0x69 if AD0 is pulled HIGH
const int MPU = 0x68;
int16_t AcX, AcY, AcZ, GyX, GyY, GyZ;
float gForceX, gForceY, gForceZ, rotX, rotY, rotZ;

// Wifi MAC address
byte mac[]= {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };

WiFiClient espClient;
IPAddress ip;
PubSubClient mqttClient(espClient);

// IP address of your MQTT server
const char* server = "10.1.0.17";
//const char* outTopic = "test/";
//const char* server = "iot.eclipse.org";

void dataReceiver(){
  Wire.beginTransmission(MPU);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU,14,true);  // request a total of 14 registers
  AcX = Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)     
  AcY = Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ = Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  GyX = Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY = Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ = Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  processData();
}

void processData(){
  gForceX = AcX / 16384.0;
  gForceY = AcY / 16384.0; 
  gForceZ = AcZ / 16384.0;
  
  rotX = GyX / 131.0;
  rotY = GyY / 131.0; 
  rotZ = GyZ / 131.0;
}

void debugFunction(int16_t AcX, int16_t AcY, int16_t AcZ, int16_t GyX, int16_t GyY, int16_t GyZ){
  // Print the MPU values to the serial monitor
  Serial.print("Accelerometer: ");
  Serial.print("X="); Serial.print(gForceX);
  Serial.print("|Y="); Serial.print(gForceY);
  Serial.print("|Z="); Serial.println(gForceZ);  
  Serial.print("Gyroscope:");
  Serial.print("X="); Serial.print(rotX);
  Serial.print("|Y="); Serial.print(rotY);
  Serial.print("|Z="); Serial.println(rotZ);
}

void reconnect() {
  // Loop until we're reconnected
  while (!mqttClient.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (mqttClient.connect("arduinoClient")){
      Serial.println("connected");
    } 
    else {
      Serial.print("failed, rc=");
      Serial.print(mqttClient.state());
      Serial.println(" try again in 5 seconds");
//      Wait 5 seconds before retrying
      delay(1000);
    }
  }
}

void setup(){
  Serial.begin(9600);

    setup_wifi();
  
  Wire.begin(0,2);
  Wire.beginTransmission(MPU);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);

  mqttClient.setServer(server, 1883);
  
//  Ethernet.begin(mac);
//  ip = Ethernet.localIP();
  
  Serial.println(ip);  
  Serial.println(server);
  //delay(1500);
}

char* init(float val){
  
  char buff[100];

  for (int i = 0; i < 100; i++) {
      dtostrf(val, 4, 2, buff);  //4 is mininum width, 6 is precision
  }
   return buff;

}

void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void dataAcc(){

  char mpu6050X[100]= "";   
  strcat(mpu6050X,init(gForceX));

  char mpu6050Y[100]= "";   
  strcat(mpu6050Y,init(gForceY));

  char mpu6050Z[100]= "";   
  strcat(mpu6050Z,init(gForceZ));

  // accelerometer - "topic, mpu6050"
  mqttClient.publish("AcX/", mpu6050X);
  mqttClient.publish("AcY/", mpu6050Y);
  mqttClient.publish("AcZ/", mpu6050Z);
//  mqttClient.publish(outTopic, "text to send via mqtt");
}


void dataGy(){

  char mpu6050X[100]= "";
  strcat(mpu6050X,init(rotX));

  char mpu6050Y[100]= "";
  strcat(mpu6050Y,init(rotY));

  char mpu6050Z[100]= "";
  strcat(mpu6050Z,init(rotZ));
  
  // gyroscope - "topic, mpu6050"
  mqttClient.publish("GyX/", mpu6050X);
  mqttClient.publish("GyY/", mpu6050Y);
  mqttClient.publish("GyZ/", mpu6050Z);
//  mqttClient.publish(outTopic, "text to send via mqtt");
}

void loop(){
  dataReceiver();
  debugFunction(AcX,AcY,AcZ,GyX,GyY,GyZ);

  if (!mqttClient.connected()) {
    reconnect();
  }

  mqttClient.loop(); 

  dataAcc();
  dataGy();

  delay(2000);
}

Nodered Flow

[
    {
        "id": "7550958a.b29dec",
        "type": "mqtt in",
        "z": "a0126a6a.9c70b8",
        "name": "",
        "topic": "hex/x",
        "qos": "2",
        "broker": "8c74c5f6.9a7a48",
        "x": 270,
        "y": 100,
        "wires": [
            [
                "d251dd79.5700d"
            ]
        ]
    },
    {
        "id": "e84b0a1.18096f8",
        "type": "mqtt in",
        "z": "a0126a6a.9c70b8",
        "name": "",
        "topic": "hex/y",
        "qos": "2",
        "broker": "8c74c5f6.9a7a48",
        "x": 270,
        "y": 180,
        "wires": [
            [
                "9c27bc8f.b62dd"
            ]
        ]
    },
    {
        "id": "6a1a0d8d.b3e754",
        "type": "mqtt in",
        "z": "a0126a6a.9c70b8",
        "name": "",
        "topic": "hex/z",
        "qos": "2",
        "broker": "8c74c5f6.9a7a48",
        "x": 270,
        "y": 260,
        "wires": [
            []
        ]
    },
    {
        "id": "2d2a911a.6af3fe",
        "type": "ui_gauge",
        "z": "a0126a6a.9c70b8",
        "name": "",
        "group": "d43a9f25.6c874",
        "order": 23,
        "width": 0,
        "height": 0,
        "gtype": "gage",
        "title": "gauge",
        "label": "units",
        "format": "{{value}}",
        "min": "0",
        "max": "100",
        "colors": [
            "#00b500",
            "#e6e600",
            "#ca3838"
        ],
        "seg1": "",
        "seg2": "",
        "x": 1010,
        "y": 120,
        "wires": []
    },
    {
        "id": "d251dd79.5700d",
        "type": "function",
        "z": "a0126a6a.9c70b8",
        "name": "Get level from box",
        "func": "var my=msg.payload;\nmsg.payload = {};\nif (my == 0.85){\n    msg.payload=20;\n    return msg;\n}\nelse if (my == 0.86){\n    msg.payload=20;\n    return msg;\n}\nelse if (my == 0.87){\n    msg.payload=20;\n    return msg;\n}\n\nelse if (my == 0.03){\n    msg.payload=40;\n    return msg;\n}\nelse if (my == 0.02){\n    msg.payload=40;\n    return msg;\n}\n\nelse if (my == 3.17){\n    msg.payload=60;\n    return msg;\n}\nelse if (my == 3.18){\n    msg.payload=60;\n    return msg;\n}\n\nelse if (my == 0.04){\n    msg.payload=80;\n    return msg;\n}\nelse if (my == 0.05){\n    msg.payload=80;\n    return msg;\n}\n\nelse if (my == 3.95){\n    msg.payload=100;\n    return msg;\n}\nelse if (my == 3.96){\n    msg.payload=100;\n    return msg;\n}\nelse {\n    return msg;\n    \n}\n",
        "outputs": 1,
        "noerr": 0,
        "x": 510,
        "y": 120,
        "wires": [
            [
                "ecd746cc.fce348",
                "8721e902.45d8b8",
                "39c8f1ac.86affe"
            ]
        ]
    },
    {
        "id": "39c8f1ac.86affe",
        "type": "function",
        "z": "a0126a6a.9c70b8",
        "name": "Set Living spots level (idx 5)",
        "func": "var level = Number(msg.payload);\nmsg.payload = {};\nmsg.payload.idx = 5;\nmsg.payload.switchcmd = (\"Set Level\");\nmsg.payload.command = \"switchlight\";\nmsg.payload.level = level;\nreturn msg;  ",
        "outputs": 1,
        "noerr": 0,
        "x": 820,
        "y": 260,
        "wires": [
            [
                "bc0d6507.1d7748"
            ]
        ]
    },
    {
        "id": "bc0d6507.1d7748",
        "type": "mqtt out",
        "z": "a0126a6a.9c70b8",
        "name": "",
        "topic": "domoticz/in",
        "qos": "",
        "retain": "",
        "broker": "8c74c5f6.9a7a48",
        "x": 1080,
        "y": 260,
        "wires": []
    },
    {
        "id": "9c27bc8f.b62dd",
        "type": "function",
        "z": "a0126a6a.9c70b8",
        "name": "Flat or standing up",
        "func": "var mya=msg.payload;\nmsg.payload = {};\nif (mya < -3.80){\n    flow.set(\"levely\",1);\n    msg.payload  = \"plat\";\n        }\nelse {\n    flow.set(\"levely\",2);\n    msg.payload  = \"rechtop\";\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 450,
        "y": 200,
        "wires": [
            [
                "ecd746cc.fce348"
            ]
        ]
    },
    {
        "id": "ecd746cc.fce348",
        "type": "debug",
        "z": "a0126a6a.9c70b8",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "x": 640,
        "y": 340,
        "wires": []
    },
    {
        "id": "8721e902.45d8b8",
        "type": "function",
        "z": "a0126a6a.9c70b8",
        "name": "Gate for level ",
        "func": "\nvar x = msg.payload;\ny = flow.get(msg.payload);\nvar y = flow.get('levely') || 0;\n\nif (y == 1){\n    msg.payload = {};\n        msg.payload = 0;\n} else {\n    msg.payload = x;\n}\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 810,
        "y": 120,
        "wires": [
            [
                "2d2a911a.6af3fe",
                "da72437e.88376"
            ]
        ]
    },
    {
        "id": "da72437e.88376",
        "type": "debug",
        "z": "a0126a6a.9c70b8",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "x": 890,
        "y": 200,
        "wires": []
    },
    {
        "id": "8c74c5f6.9a7a48",
        "type": "mqtt-broker",
        "z": "",
        "name": "10.1.0.17",
        "broker": "10.1.0.17",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "compatmode": true,
        "keepalive": "15",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "closeTopic": "",
        "closePayload": "",
        "willTopic": "",
        "willQos": "0",
        "willPayload": ""
    },
    {
        "id": "d43a9f25.6c874",
        "type": "ui_group",
        "z": "",
        "name": "Control",
        "tab": "739541e2.18396",
        "order": 1,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "739541e2.18396",
        "type": "ui_tab",
        "z": "",
        "name": "7inch",
        "icon": "dashboard",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]

Mattermost Mqtt Flag Integration

UPDATE 20231020 – Via USB Serial (also schematic for below integration)
https://www.henriaanstoot.nl/2023/10/20/thunderbird-mail-notification-flag-via-usb/

Using a servo which is MQTT controlled, and a slash command in Mattermost, i can be notified by friends and colleages.

Flag, and monitor-stand are 3D printed.

ESP is a simple wemos mini.

Note the slash command, M5 stick flow is unrelated!

Rubber duck debugging, Pair Programming and more

Why “rubber ducking’’? While an undergraduate at Imperial College in London, Dave did a lot of work with a research assistant named Greg Pugh, one of the best developers Dave has known. For several months Greg carried around a small yellow rubber duck, which he’d place on his terminal while coding. ( From “The Pragmatic programmer” page 95)

Why rubber ducking?

A very simple but particularly useful technique for finding the cause of a problem is simply to explain it to someone else or even a object. Explain out loud (or in your mind to the duck) what each line of code is doing.
Often while doing so, you will see the problem.

Why Pair Programming?

It is no secret, i like working on a problem alone. Let me do my ‘thing’. But i like the idea of Pair Programming, why?

  • Differences in thinking, gives alternative solutions
  • 4 eyes principle, typo’s will be seen
  • When working with a novice:
    • Teaches the new guy
    • Give the other space to ask stupid questions, maybe they are NOT!
  • The knowledge of the new code is now known to > 1 person!