Category Archives: 3dprinting

LMS Record player V.something .. final? No

But it works! Many iterations .. almost perfect

Recordplayer model by kriswillcode, but heavily remixed

Record player is going to be re-printed at a higher quality.

  • Put a printed image on the player, and it plays the album
  • Move the arm, and the next track will be played
  • Press upper white button, and the music will pause/resume
  • Press lower button … ??? Don’t know yet

Updated python client (see previous posts)

import paho.mqtt.client as mqtt
import urllib.request
from time import sleep

def on_connect(client, userdata, flags, rc):  # The callback for when the client connects to the broker 
        print("Connected with result code {0}".format(str(rc)))  

def on_message(client, userdata, msg):  # The callback for when a PUBLISH message is received from the server. 
        print("Message received-> " + msg.topic + " " + str(msg.payload))  # Print a received msg
        if msg.topic == "spotify/rfid/idlms":
            urllib.request.urlopen("http://LMS-SERVER-IP:9000/anyurl?p0=playlistcontrol&p1=album_id:" + msg.payload.decode() + "&p2=cmd:load&player=00:04:20:16:d9:04")
        if msg.topic == "spotify/rfid/but1":
        if msg.topic == "spotify/rfid/but2":
        if msg.topic == "spotify/rfid/arm":

client = mqtt.Client("lmsclient")  # Create instance of client with client ID “digi_mqtt_test”
client.on_connect = on_connect  # Define callback function for successful connection
client.on_message = on_message  # Define callback function for receipt of a message
client.connect('MQTTSERVER', 1883)
client.loop_forever()  # Start daemon

Wemos INO file

#include <Arduino.h>
#include <SPI.h>
#include <MFRC522.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <PubSubClient.h>
#define SS_PIN 15
#define RST_PIN 0

const int buttonPin1 = D1;  
const int buttonPin2 = D2;   

int buttonState1 = 0; 
int buttonState2 = 0; 

MFRC522 mfrc522(SS_PIN, RST_PIN);
  MFRC522::StatusCode status; //variable to get card status
  byte buffer[18];  //data transfer buffer (16+2 bytes data+CRC)
  byte size = sizeof(buffer);

  uint8_t pageAddr = 0x06;  //In this example we will write/read 16 bytes (page 6,7,8 and 9).
                            //Ultraligth mem = 16 pages. 4 bytes per page.  
                            //Pages 0 to 4 are for special functions.           
unsigned long cardId = 0;
WiFiClient net;
PubSubClient client(net);
const char* mqtt_server = "MQTTBROKER";
const char* ssid = "MYSSID";
const char* password = "MYWIFIPASWORD";
String topicStr = "";
byte buffer2[8];

boolean Rflag=false;
int r_len;
char payload[5];
byte value[5];
void setup() {
    pinMode(buttonPin1, INPUT_PULLUP);
    pinMode(buttonPin2, INPUT_PULLUP  );

  WiFi.begin(ssid, password);
  client.setServer(mqtt_server, 1883);
void reconnect() {
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
  while (!client.connected()) {
    String clientId = "rfid-";
    clientId += String(random(0xffff), HEX);
    if (!client.connect(clientId.c_str(), "rfidclient", "...")) {
void callback(char* topic, byte* payload, unsigned int length) {
   Rflag=true; //will use in main loop
   r_len=length; //will use in main loop
   int j=0;
     for (j;j<length;j++) {
if (r_len < 3) {
  Serial.print(F("Set false"));
buffer2[j]='\0'; //terminate string

void loop() {
    if (!client.connected()) {

buttonState1 = digitalRead(buttonPin1);
  if (buttonState1 == 0 ) {
    client.publish("spotify/rfid/but1", "0");
buttonState2 = digitalRead(buttonPin2);
  if (buttonState2 == 0 ) {
    client.publish("spotify/rfid/but2", "0");

int reading = analogRead(0);
  if (reading > 500 ) {
    client.publish("spotify/rfid/arm", "0");
  if (!mfrc522.PICC_IsNewCardPresent()) {
  if (!mfrc522.PICC_ReadCardSerial()) {
if (Rflag) {
        for (int i=0; i < 4; i++) {
    //data is writen in blocks of 4 bytes (4 bytes per page)
    status = (MFRC522::StatusCode) mfrc522.MIFARE_Ultralight_Write(pageAddr+i, &buffer2[i*4], 4);
    if (status != MFRC522::STATUS_OK) {

  cardId = getCardId();
  char buffer3[10];
  sprintf(buffer3, "%lu", cardId);
  client.publish("spotify/rfid/id", buffer3);

  status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(pageAddr, buffer, &size);
  if (status != MFRC522::STATUS_OK) {
    Serial.println(F("MIFARE_Read() failed: (R)"));

  Serial.println(F("Read data: "));
  for (byte i = 0; i < 5; i++) {
  client.publish("spotify/rfid/idlms", buffer,5);

unsigned long getCardId() {
  byte readCard[4];
  for (int i = 0; i < 4; i++) {
    readCard[i] = mfrc522.uid.uidByte[i];
  return (unsigned long)readCard[0] << 24
    | (unsigned long)readCard[1] << 16
    | (unsigned long)readCard[2] << 8
    | (unsigned long)readCard[3];

Several things in progress, help me if you can.

I used MCE to control some Windows VMs and programs running in it in the past. (Below link and a web interface engine which on the backend converted BWW/BMW (bagpipe music files) to PDF automated comes to mind)

Now, I implemented this:

Controlling a Windows VM using MQTT, very nice!
(Use HA mqtt or mosquitto_pub in bash)

Question: anyone got a better solution to control programs within a VM? Let me know.


I’m creating a new case for my Wemos, LCD16x2, button, Led, Buzzer project (see other post)

I’m redesigning my previous case in blender.

But I really miss something like a generator function for different cases, like the one I made using Openscad.
Question: Anyone know a tool/add-on to generate cases?
I used a model of a wemos to get the usb connector/screw holes in place.

My spotify rfid case I will create using wooden lasercut cutouts.

Next one:

In the past, I’ve controlled some blender lights using python and MQTT. But now I’m trying to control it using DMX.

Example of lighting in our living using mock-up couch and tables.

I found a cool add-on called Blender-DMX.
(B.t.w. wled can also use DMX)

Looks cool but, can I make a floorplan with this?

Blender add-on configuration

In Home Assistant I used a HACS add-on called : Art-net LED Lighting for DMX

Configuration can be done in configuration.yaml

- platform: artnet_led
  host: BLENDERHOSTIP                   # IP of Art-Net Node
  max_fps: 25                           
  refresh_every: 0                      # Resend values if no fades are running every x seconds, 0 disables automatic refresh
  node_type: artnet-direct              # Which protocol to use
  universes:                            # Support for multiple universes
    1:                                  # .Nr of Universe (see configuration of your Art-Net Node)
      send_partial_universe: True       # Only send the universe which contains data
        - channel: 1                    # first channel of dmx dimmer
          name: dmx_dimmer_rgbw         # name
          type: rgbw                    # type
          transition: 1                 # default duration of fades in sec. 
          channel_size: 8bit            # width of the channel sent to DMX device, default "8bit", "16bit", "24bit" and "32bit" 
          channel_setup: Wrgb           # This is the magic to get colors correct

It works, but I’m not happy, anyone got a better solution?

And I have to check out GDTF profiles for fixtures.

At a later stage I’m going to 3d print a white floorplan about 1cm high, with LEDs and buttons. A floorplan you can hang on your wall.

Big media button V2

Back in 2019 I made a volume/mute button using an ATtiny85.
(Digispark/trinkey thingy)

Same device as my password paster

It’s USB connection is perfect for this password paste thingy, but not for a big button like this. (even with a ugly usb extending cable)

2019 Version using digispark ATtiny85

Button is 3D printed (found on yeggi)

For my big battlestation i’m using:

The old way of flashing using Arduino IDE (for digispark)

Install Boards using : preferences, add board URL

Note: There being no regular USB device, you need to add some udev rules.
cat /etc/udev/rules.d/digispark.rules
SUBSYSTEM==”usb”, ATTR{idVendor}==”16d0″, ATTR{idProduct}==”0753″, MODE=”0660″, GROUP=”dialout”

When compiling and uploading the program, you get a message to plug in the device. See below screenshot.

Now the 2024 change.
Reason to change:

  • Want to have USB-C
  • Python to get a more flexible setup
  • I want to use more pins, so I can add LEDs and more buttons.
  • I wanted to play with my Waveshare RP2040 Zero.

This is the first setup, with same functionality as before.

Now I can add more stuff!

Putting the code on the RP2040-zero

Press boot button and insert into your pc.
Download uf2 file from here and save in RP2 drive.
Open Thonny, and configure interpreter to:

Download the zip file from
And copy only the subdirectory adafruit_hid to the drive in subdir lib

Open the file from the device, and remove example hello world code.
Paste in the following code.

import rotaryio
import board
import time

import board
import digitalio
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
from adafruit_hid.keycode import Keycode
from adafruit_hid.consumer_control import ConsumerControl
from adafruit_hid.consumer_control_code import ConsumerControlCode

but = digitalio.DigitalInOut(board.GP4)
but.direction = digitalio.Direction.INPUT
but.pull = digitalio.Pull.UP

cc = ConsumerControl( usb_hid.devices )

encoder = rotaryio.IncrementalEncoder(board.GP5, board.GP6)
last_position = 0
while True:
    position = encoder.position
    if int(last_position) < int(position):
        command = ConsumerControlCode.VOLUME_DECREMENT
    #last_position = position
    if int(last_position) > int(position):
        command = ConsumerControlCode.VOLUME_INCREMENT
    last_position = position
    if not but.value:
        command = ConsumerControlCode.MUTE

Above code is the bare minimum, I’ll add more functionality soon.
(LEDs and more buttons)
Next and Previous Track and mode change.
From Audio to Navigation for example.

Last week’s stuff


Case for presence detector

Update: BBQ watch

Not posted in the past, new version using ESPHOME and a m5stickc

Previous version using a ESP12
A “watch” with core and environment temperature of my smoker with a alarm, and button for timers.

ESP32 dac’s drawing on oscilloscope ( no additional components)

ESP32 in front of scope, two clips for x and y

For above i used sin/cos functions 2:3, which creates Lissajous figures.

3 battery operated buttons (no wires needed) to control my shelly dimmer at the dinner table.

left button on, middle steps per 20% and 3rd button off.
(This cheapass button only sends ON commands)

Node red code

        "id": "8190a851.8d02b8",
        "type": "mqtt in",
        "z": "44d7a4fb.e41a5c",
        "name": "domoticz-out",
        "topic": "domoticz/out",
        "qos": "0",
        "broker": "8c74c5f6.9a7a48",
        "inputs": 0,
        "x": 190,
        "y": 600,
        "wires": [
        "id": "543a2fa3.af27c",
        "type": "function",
        "z": "44d7a4fb.e41a5c",
        "name": "Filter IDX + nvalue",
        "func": "var varPayload = JSON.parse(msg.payload);\nvar varidx = varPayload.idx;\nvar varnvalue = varPayload.nvalue;\nif(varidx == 2473)\n{\nmsg.payload = {};\nmsg.payload.turn = \"on\";\nmsg.payload.brightness = 50;\nreturn msg;\n}",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 410,
        "y": 600,
        "wires": [
        "id": "c70d463.da52ab8",
        "type": "function",
        "z": "44d7a4fb.e41a5c",
        "name": "Filter IDX + nvalue",
        "func": "var varPayload = JSON.parse(msg.payload);\nvar varidx = varPayload.idx;\nvar varnvalue = varPayload.nvalue;\nif(varidx == 2474)\n{\nmsg.payload = {};\nmsg.payload.turn = \"on\";\nvar count = context.get(\"counter\") || 0;\ncount = (count+1) % 6;\ncontext.set(\"counter\", count);\ncount = count * 20; \nmsg.payload.brightness = count;\nreturn msg;\n}",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 410,
        "y": 680,
        "wires": [
        "id": "ffa2f6be.afe618",
        "type": "function",
        "z": "44d7a4fb.e41a5c",
        "name": "Filter IDX + nvalue",
        "func": "var varPayload = JSON.parse(msg.payload);\nvar varidx = varPayload.idx;\nvar varnvalue = varPayload.nvalue;\nif(varidx == 2475)\n{\nmsg.payload = {};\nmsg.payload.turn = \"off\";\n//msg.payload.brightness = 0;\nreturn msg;\n}",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 410,
        "y": 760,
        "wires": [
        "id": "35f35737.b4f2c8",
        "type": "comment",
        "z": "44d7a4fb.e41a5c",
        "name": "Living Dinner Table Shelly 2024",
        "info": "",
        "x": 250,
        "y": 560,
        "wires": []
        "id": "b080c84e.2c3968",
        "type": "comment",
        "z": "44d7a4fb.e41a5c",
        "name": "butt1 on / (butt2 off)",
        "info": "",
        "x": 510,
        "y": 560,
        "wires": []
        "id": "ac892b87.1c7358",
        "type": "comment",
        "z": "44d7a4fb.e41a5c",
        "name": "butt3 toggle",
        "info": "",
        "x": 390,
        "y": 720,
        "wires": []
        "id": "b5bdbd65.c4e1c",
        "type": "comment",
        "z": "44d7a4fb.e41a5c",
        "name": "butt 2 step dimmer",
        "info": "",
        "x": 410,
        "y": 640,
        "wires": []
        "id": "d7b0f308db912817",
        "type": "mqtt out",
        "z": "44d7a4fb.e41a5c",
        "name": "",
        "topic": "shellies/shellydimmer-D0DF15/light/0/set",
        "qos": "",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "8c74c5f6.9a7a48",
        "x": 860,
        "y": 600,
        "wires": []
        "id": "8c74c5f6.9a7a48",
        "type": "mqtt-broker",
        "name": "MQTTSERVER",
        "broker": "MQTTSERVER",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "compatmode": true,
        "keepalive": "15",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "closeTopic": "",
        "closePayload": "",
        "willTopic": "",
        "willQos": "0",
        "willPayload": ""

Vector graphics on my demo arduino nano.

Busy weekend .. didn´t have time to post

I’ve got my SDK-85 cassette interface PCB’s in, If you want to have the Kicad files. Message me.

My 3D printer has a worn out hot-end .. so a new one to install.

BBQ time! .. That’s from 1-januari till 31-december .. rain, snow storm whatever.
I’ve made a lot of Rubs/Sauces and marinades.
But a new book i always welcome ..

Also new recipes and tips. Let me know.

Sunday a day of music with our folkband.
Played some old and new tunes.

Did some Vulkan / OpenGL benchmark testing.

Cleaned and fixed our wine cellar.

And tomorrow i’m starting new work.

Thunderbird mail notification flag via USB

In 2021 I made a MQTT notification Flag using a Servo and python code and webhooks to get notifications.
Webhook was used for Mattermost.

Now i’ve changed the notification flag for Email using Thunderbird.
Just connect the wemos to a USB on your computer, no mqtt/wifi needed. (On the road solution)


Install FiltaQuilla Add-on in thunderbird
select run program in config.

Next create a filter

Create two bash files (i’ve got mine in ~/bin/ )
Change ttyUSB0 if needed

stty -F /dev/ttyUSB0 ispeed 9600 ospeed 9600 -ignpar cs8 -cstopb -echo
echo 0 > /dev/ttyUSB0

stty -F /dev/ttyUSB0 ispeed 9600 ospeed 9600 -ignpar cs8 -cstopb -echo
echo 1 > /dev/ttyUSB0

Install YAD and a autostart icon to make the systemtray to pull the flag down.

henri@zspot:~$ cat .config/autostart/servoflag.desktop 
[Desktop Entry]
Exec=yad --notification --image="gtk-execute" --command="bash /home/henri/bin/" --image="mail-app"

Arduino Code

#include <Servo.h> 

Servo flag; 
char val;
void setup() {

void loop () {
  val =; 
  if (val == '0') {
  if (val == '1') {

Mikrotik Wifi, 80386 and Lilygo streaming

Quiet days, I working on some art.

But here are the last ‘prutsen’

My current Wifi setup

I’ve got a Wifi outside of my network for guest and emergency. ( 2 SSIDs)

Then a main Wifi router in my livingroom, one in my workshop/studio and one in the Attic (Electronics Lab)

So three main Wifi AccessPoints. These all have the same SSID’s but on different frequencies. That way i’ve got roaming in and outside my house.
Also some virtual accesspoints are configured.
I’ve got a main, folkband, IOT, guest-inside all on 2.4Ghz and 5Ghz.

I watched a lot of YT presentations about Mikrotik Wifi.

So I ended up with DFS safe channels 20Mhz for 2.4 and 20/40Mhz Ce for 5Ghz. (subchannels for each after some frequency scanning)
(2.4 does a failback to 20Mhz whenever there is even one client detected which connects only on this band. Such as some old IOT stuff)
2.4 in only 1,6 and 11 no overlap, each on another device.
300Mbps is sufficient for my wifi 🙂

I’ve got accesslists in place and i’m going to read into kicking a client when the signal strenght is below -50dB

80386 (DX) Computer

Besides my 8088 and 8086 machines I needed a machine which could run our old demo’s. So I bought a new toy.

It has 8Mb Ram and runs at 40Mhz.

I’ve noticed that many of my VGA register manipulation code, can’t be run on a modern VGA monitor, I need to use a CRT for that .. Another thing to buy

Lilygo T-Display S3 Streaming

Not my code:
A very cool project!

Needed to fix arduino code, due to the TFT_eSPI library issues.
And I’ve got a S3 with another resolution, but that was an easy fix.
Then needed to reinstall nodejs with another version.
Had to modify the code because the tcp server would not start.
Weird errors logging, but in the end fixed … very cool

I probably end up designing a 3D printed case that looks like a monitor or tv.

3D printing problem and Fluxengine

3D printed a case for my fluxengine.

Last week I got my 1.2MB 5.25″ drive.
And tested it with the fluxengine.
Now i can read old 5.25″ disks again. And convert these to disk images.
Amiga/Atari ST/C64 (single side) and my old MSDos disks.
(That’s what I’m using, the fluxengine can read many more)

Why single side C64? you ask?
Those are flippy disks, that means they are single sided and you flip the disk in the drive to read the other side.

Why can’t the fluxengine read those?

  • There is only one sensor in my drive.
  • Reading side 2 without turning the disk won’t work, the sectors are in reverse!
    (Maybe there is a trick to read in reverse? Fluxengine is reading and decoding raw disk sectors, but i have to read into this)

Note: The 1541 Drive for the commodore’s is a complete 6502 computer with 2x 6522 VIA and ram/rom chips! (2016-15 2K x 8 bit Static RAM / 27128 16kb x 8)


And this amazing trick:

Maybe i’m going to modify my 5.25 drive with another index sensor.

So i downloaded a diskdrive case from thingiverse, which can hold 2 drives. 3.5″and 5.25″.

I started printing the bottom, no problem there. But because of the large size of bottom and top. (Both about a day of printing) I had to change the filament.
But I didn’t have a good look at what I took!
Below is what you get when printing PLA and switch to PETG!

Temperatures for PLA:
Tool: 200 and bed 50
Temperatures for PETG:
Tool: 240 and bed 70

So 12 hours printing and I had to start again.

I could not remove the knob, else I would have removed the beige front and spray painted this black.

Finished a display case for the SDK-85

So i made a nice display case for this SDK.

I made some designs and came up with this:

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.

Openscad code


    cylinder(h=9, d1=9, d2=9, center=true);
cylinder(h=9, d1=15, d2=15, center=true);
 cylinder(h=30, d1=3.5, d2=3.5, center=true);

I will probably add a powerconnector and lasercut a hole for the keypad at a later stage.