Tag Archives: arduino

Made a Meatloaf device for C64

Awesome opensource project

https://github.com/idolpx/meatloaf-specialty/tree/main

  • Emulates a floppy drive: Meatloaf plugs into the Commodore 64’s IEC serial port and acts like a virtual floppy drive. This allows you to load software and data stored on its internal flash memory, sd card, or stream it via WiFi using various protocols from servers all over the world.
  • Supports multiple virtual drives: Unlike a single floppy drive, Meatloaf can be configured to emulate up to 26 virtual drives (IDs 4-30). Each virtual drive can have a different disk image loaded, essentially offering the equivalent of having thousands of floppies connected to your C64.
  • Supports additional virtual device types: Printers, a network interface, and more.
  • Connects to the internet: Meatloaf also functions as a WiFi modem, enabling your Commodore 64 to connect to Telnet BBS (bulletin board systems) for communication and sharing information.

https://meatloaf.cc/sc/s/shortcodes.php

Load a prg using a url

LOAD"HTTP://C64.ORG/GAMES_AZ/H/H.E.R.O.PRG",8

Or from a D64 image on your own Windows/Samba server (all known CBM image formats supported):

LOAD"SMB://STORAGE/C64/FAVORITES/PIRATES_A.D64/*",8

Load a random game from the internet

LOAD"ML:ARCADE*",8	

Minimal socket test server, client and arduino

Socket connect to server, enter number and get reply test.

server.py

import socket
import threading

# Define the host and port
HOST = '0.0.0.0'  # Localhost (change as needed)
PORT = 65432        # Port to listen on (non-privileged ports are > 1023)

# Function to handle each client connection
def handle_client(conn, addr):
    print(f"Connected by {addr}")
    
    # Send a thank you message to the client upon connection
    thank_you_message = "Thank you for connecting! Please enter a number:\n"
    conn.sendall(thank_you_message.encode('utf-8'))
    
    while True:
        try:
            data = conn.recv(1024)
            if not data:
                break
            
            # Decode the received data
            received_number = data.decode('utf-8').strip()
            print(f"Received from {addr}: {received_number}")
            
            # Try to convert the received data to an integer
            try:
                number = int(received_number)
                response = f"The double of {number} is {number * 2}\n"
            except ValueError:
                response = "Please enter a valid number.\n"
            
            # Send the response back to the client
            conn.sendall(response.encode('utf-8'))
        except ConnectionResetError:
            print(f"Connection with {addr} lost.")
            break

    conn.close()
    print(f"Connection with {addr} closed.")

# Function to start the server and listen for connections
def start_server():
    # Create a socket object
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # Bind the socket to the host and port
    server.bind((HOST, PORT))
    
    # Start listening with a maximum backlog of 5 connections
    server.listen(5)
    print(f"Server listening on {HOST}:{PORT}")
    
    while True:
        # Accept a new connection
        conn, addr = server.accept()
        
        # Create a new thread to handle the client connection
        client_thread = threading.Thread(target=handle_client, args=(conn, addr))
        client_thread.start()

# Run the server
if __name__ == "__main__":
    start_server()

python-client.py

import socket

# Define the server host and port
HOST = 'IPNUMBERSERVER'  # The server's hostname or IP address
PORT = 65432        # The port used by the server

def start_client():
    # Create a socket object
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # Connect to the server
    client.connect((HOST, PORT))
    
    # Receive and print the welcome message from the server
    welcome_message = client.recv(1024).decode('utf-8')
    print(welcome_message)
    
    while True:
        # Enter a number and send it to the server
        number = input("Enter a number (or type 'exit' to quit): ")
        
        if number.lower() == 'exit':
            print("Closing connection...")
            break
        
        client.sendall(number.encode('utf-8'))
        
        # Receive the response from the server and print it
        response = client.recv(1024).decode('utf-8')
        print(response)
    
    # Close the connection after the loop ends
    client.close()

# Run the client
if __name__ == "__main__":
    start_client()

arduino-client.ino

#include <ESP8266WiFi.h> // For ESP8266
//#include <WiFi.h>       // For ESP32

// Replace with your network credentials
const char* ssid     = "your_SSID";     // Replace with your network SSID (name)
const char* password = "your_PASSWORD"; // Replace with your network password

// Define the server's IP address and port
const char* host = "192.168.1.100"; // Replace with your server's IP address
const int port = 65432;             // Server port

WiFiClient client;

void setup() {
  Serial.begin(115200);
  delay(10);

  // Connect to WiFi
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

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

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

  // Connect to the server
  Serial.print("Connecting to server at ");
  Serial.print(host);
  Serial.print(":");
  Serial.println(port);

  if (client.connect(host, port)) {
    Serial.println("Connected to server!");
    
    // Wait for the welcome message from the server
    while (client.available() == 0);

    // Read and print the welcome message
    while (client.available()) {
      char c = client.read();
      Serial.print(c);
    }
  } else {
    Serial.println("Connection failed.");
  }
}
void loop() {
  // Check if connected to the server
  if (client.connected()) {
    // Check if there is any serial input from the user
    if (Serial.available() > 0) {
      String input = Serial.readStringUntil('\n');
      input.trim(); 

      if (input.equalsIgnoreCase("exit")) {
        Serial.println("Closing connection...");
        client.stop(); // Disconnect from the server
        while (true);  // Stop the loop
      }

      // Send the number to the server
      client.println(input);

      // Wait for the server's response
      while (client.available() == 0);

      // Read and print the server's response
      while (client.available()) {
        char c = client.read();
        Serial.print(c);
      }
    }
  } else {
    Serial.println("Disconnected from server.");
    while (true); // Stop the loop
  }
}

Reverse engineering Newton wars, giving it my own twist.

Saw a cool game a while ago, and found some old code.
There was no schematic, so I had to reverse engineer it using the Arduino code.
This one uses a Micro Pro.

Build a working version, now I can use this as base to create other games.
But first i’m going to rebuild it so it can use Wifi and uses a Lipo Battery. Making it usable without wires.

  • Rotary – set angle/speed (Press resets)
  • Blue – toggle angle or speed ( was rotary press )
  • Green – select digit to change
  • Red – Fire
  • Led – not completely working yet, shows color of player
    Wil be changed to addressable leds with more functions
    (Player color, energy warning and more)

Next to do:

  • Build a Wifi version with Lipo
  • Build permanent version in a case
  • Build 2nd 3th or more controllers
  • Create own games

New POC / WIP Rfid Read/Write

yes, again. Another change.

UPDATE: Working example at bottom!

Micros*ft Surface Running Linux!

I don’t want IDs and Paths in a Home Assistant automation.
The RFIDs can store more than enough data to store the paths to albums.

I Also tested with ESPHOME in HA, but you can’t write tags.

ESPHOME Config for my RFID device (NOT USED ANYMORE)

esphome:
  name: rfidtag
  friendly_name: rfidtag

esp8266:
  board: d1_mini

mqtt:
  broker: IPMQTTBROKER

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "xxxxxxxxxxxxxxxxxx="

ota:
  password: "xxxxxxxxxxxxxxxxxxxxx"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Rfidtag Fallback Hotspot"
    password: "xxxxxxxxxxxxxx"

captive_portal:
    
spi:
  clk_pin: D5
  miso_pin: D6
  mosi_pin: D7
rc522_spi:
  cs_pin: D8
  update_interval: 1s
  on_tag:
    then:
      - mqtt.publish:
          topic: rc522/tag
          payload: !lambda 'return x;'
  on_tag_removed:
    then:
      - mqtt.publish:
          topic: rc522/tag_removed
          payload: !lambda 'return x;'

The next iteration of my Rfid controller will have a write function for the RFID tags.

  1. Stick a tag on a cover art piece of cardboard. (see below)
  2. Read path from data sector.
    • Send path to player automation
  3. Send path to program using MQTT or website if needed.

Not sure yet, also want to implement a wifi manager on the wemos.

Changes on above idea:

  • Paths are too long, I could not work out how to create a working program using this.
  • I stopped using paths, instead I’m using the Logitech media server album IDs.
  • Using two python scripts, I can use one for programming the card, and another script to control LMS.

How does it work

RFid device is connected to the network.

Start query.py on your LMS server.
Search for an album name, it will present an ID and Album name in a list.
Enter the ID you want to program, or 0 to exit.
(This will also reset the programming mode)

Place an empty or previously programmed tag on the device.
It will write the album ID on the tag.

Then it will start the album.
Changing the tags will also just change the album playing.

(NOTE: My genre spotify player still works using this method, using the same device)

A second python script will read the Mqtt topic and control the Squeezebox player.

Python Code DB Query

import sqlite3
#paho-mqtt
import paho.mqtt.publish as publish

host = "IPMQTTBROKER"
port = 1883
topic = "spotify/rfid/in/write"
auth = {'username': 'xxxx','password': 'xxxxx'}
client_id = "spotithing"

def readSqliteTable(albumname):
    try:
        sqliteConnection = sqlite3.connect('/var/lib/squeezeboxserver/cache/library.db')
        cursor = sqliteConnection.cursor()
        albumname = "%" + albumname + "%"
        cursor.execute("select * from albums where title Like ?",
               (albumname,))
        records = cursor.fetchall()
        for row in records:
            print("Id: ", row[0],row[1])
        cursor.close()

    except sqlite3.Error as error:
        print("Failed to read data from sqlite table", error)
    finally:
        if sqliteConnection:
            sqliteConnection.close()

album = input("Album name ? ")
readSqliteTable(album)

number = input("Enter ID or 0 to quit : ")
publish.single(topic, "00000" , qos=1, hostname=host, port=port,
        auth=auth, client_id=client_id)
if number == 0:
        exit()
publish.single(topic, number, qos=1, hostname=host, port=port,
        auth=auth, client_id=client_id)
print("Program your tag")
print("Reset/disable writing using exit with 0!")

Python Code Controller (this one needs to be running at all times)

import paho.mqtt.client as mqtt
import urllib.request

def on_connect(client, userdata, flags, rc):  
        print("Connected with result code {0}".format(str(rc)))
        client.subscribe("spotify/rfid/idlms")

def on_message(client, userdata, msg):
        print("Message received-> " + msg.topic + " " + str(msg.payload))  # Print a received msg
        urllib.request.urlopen("http://IPADDRESLMS:9000/anyurl?p0=playlistcontrol&p1=album_id:" + msg.payload.decode() + "&p2=cmd:load&player=b8:27:eb:11:16:ab")
#NOTE also change b8:27:eb:11:16:ab into you players MACAddress!

client = mqtt.Client("digi_mqtt_test")  
client.on_connect = on_connect  
client.on_message = on_message  
client.connect('IPMQTTBROKER', 1883)
client.loop_forever()  

Arduino Code (see schematic in other post)

#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
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 = "IPMQTTBROKER";
const char* ssid = "MYSSID";
const char* password = "MYSSIDPASS";
String topicStr = "";
byte buffer2[8];

boolean Rflag=false;
int r_len;
char payload[5];
byte value[5];
void setup() {
  Serial.begin(9600);
  SPI.begin();
  mfrc522.PCD_Init();
  WiFi.mode(WIFI_AP_STA);
  WiFi.begin(ssid, password);
  client.setServer(mqtt_server, 1883);
     delay(100);
    client.setCallback(callback);
      delay(100);
    client.subscribe("spotify/rfid/in/#");
}
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", "...")) {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      delay(5000);
    }
  }
  client.subscribe("spotify/rfid/in/#");
}
void callback(char* topic, byte* payload, unsigned int length) {
 
  Serial.print(F("Called"));
   Rflag=true; //will use in main loop
   r_len=length; //will use in main loop
   Serial.print("length message received in callback= ");
   Serial.println(length);
   int j=0;
     for (j;j<length;j++) {
       buffer2[j]=payload[j];
       }
if (r_len < 3) {
  Rflag=false;
  Serial.print(F("Set false"));
}
buffer2[j]='\0'; //terminate string
}

void loop() {
    if (!client.connected()) {
    reconnect();
  }
  client.loop();
  if (!mfrc522.PICC_IsNewCardPresent()) {
    return;
  }
  if (!mfrc522.PICC_ReadCardSerial()) {
    return;
  }
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) {
      Serial.print(F("MIFARE_Read() failed: (W) "));
      Serial.println(mfrc522.GetStatusCodeName(status));
      return;
    }
  }
  Serial.println(F("MIFARE_Ultralight_Write() OK "));
  Serial.println();
  Rflag=false;
}
  cardId = getCardId();
  char buffer3[10];
  sprintf(buffer3, "%lu", cardId);
  client.publish("spotify/rfid/id", buffer3);
  // Read data ***************************************************
  Serial.println(F("Reading data ... "));
  //data in 4 block is readed at once.
  status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(pageAddr, buffer, &size);
  if (status != MFRC522::STATUS_OK) {
    Serial.println(F("MIFARE_Read() failed: (R)"));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  Serial.println(F("Read data: "));
  //Dump a byte array to Serial
  for (byte i = 0; i < 5; i++) {
    Serial.write(buffer[i]);
       buffer2[i]=buffer[i];
    }
  client.publish("spotify/rfid/idlms", buffer,5);
  delay(1000);
  mfrc522.PICC_HaltA();
}

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];
}

C64Pico part 3

Today we worked on this project again. (Bigred and me)

There were some problems we needed to fix since last time:

  • It was quite hard to get the correct parts.
    Our display connector was only fitted with connection pins on the wrong side of the connector. (up/down)
    So I bought a connector with both positions populated.
    So we had to replace this hard to solder (40 pin) connector.
  • It was not clear what the orientation should be of the atmega328pb.
    We looked at the pinout, and followed the VCC/GND. But these are also available of the opposite side of the chip. (We missed that)
    Later, we saw a tiny line on the PCB, which showed the pin 1 placement.
    So we had to remove and replace the chip.
    When turning on the power, (with incorrect placement) probably fried R5 (10k resistor), on both our boards.
    Had to replace those also.
  • Programming the atmega328pb was not easy, see below fixes.
  • Compiling the pico firmware resulted in a black screen.
    Below the fixes I had to make to get the screen working.

Other things still to fix.

  • Bigreds screen.
  • atmega328p didn’t work for Bigred, so probably needs to replace with the pb version.
  • My battery controller is not charging.
    See bottom of page
  • Some of my buttons are working. The pewpew and some of the cursor keys (not as I expect, there are some up/down issues)
    And none of the other keys are working.

Some other things we noticed.

  • sdcard: remove partitions, format using mkfs.exfat
    Create a c64 directory on this filesystem where you can put the d64 files!
  • 0402 SMD is far too small for me.
    There is enough room on the board to use 0805 for example.
    Even THT is possible, there are only a few components.
  • Some components are TOO close together, removing a component resulted in other small parts disconnecting also.

My friend Bigred said: If I can see it, I can solder it.
But it is not easy. This probably keeps a lot of people from building it!

Below the diff from the source we got from:

https://github.com/silvervest/MCUME/tree/c64pico

UPDATE 20240501: We needed to clone the c64pico branch!

git clone -b c64pico https://github.com/silvervest/MCUME.git

Then it worked with the screen and keyboard!

Programming the atmega328pb using usbasp

https://www.henriaanstoot.nl/2022/06/30/morse-with-a-attiny85/
Link above shows the programmer.

To get your Arduino IDE up and running

  • Open the Arduino IDE.
  • Open the File > Preferences menu item.
  • Enter the following URL in Additional Boards Manager URLs:https://mcudude.github.io/MiniCore/package_MCUdude_MiniCore_index.json
  • Open the Tools > Board > Boards Manager… menu item.
  • Wait for the platform indexes to finish downloading.
  • Scroll down until you see the MiniCore entry and click on it.
  • Click Install.
  • After installation is complete close the Boards Manager window.

Above settings worked for me, maybe you can also try Programmer: usbasp (slow)

First install the bootloader.

When compiling the keyboard program of silvervest, you can find “Upload using programmer” in the Sketch menu!
(https://github.com/silvervest/c64pico/tree/master/keyboard)

CHARGING using BQ24230RGTT

Maybe I’ve got a problem with the ground plating of the charger.
Also very hard to solder the sides!

Music Cover Art Display using ILI9341

Little Sunday afternoon project.

Two PHP scripts.

Install on your webserver (see previous post)

Resizes images and removes the onkyo header.
(See previous posts)

<?php
// onkyo.php
// write jpeg header
header('Content-type: image/jpg');

$lines = file_get_contents('http://IP-ONKYO-AMPLIFIER/album_art.cgi', false);
$lines = explode("\n", $lines);
// remove weird Onkyo header (3 lines)
$content = implode("\n", array_slice($lines, 3));
print $content;
?>

CoverArt from a squeezeboxserver

<?php    
// squeezebox.php
// leave playerid as is, for the default.
// change to MAC address of player to get coverart specific player
$img = file_get_contents('http://IP-LOGITECH_MEDIA_SERVER:9000/music/current/cover.jpg?player=<playerid>');
$im = imagecreatefromstring($img);
$width = imagesx($im);
$height = imagesy($im);
$newwidth = '240';
$newheight = '240';
$thumb = imagecreatetruecolor($newwidth, $newheight);
imagecopyresized($thumb, $im, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
//imagejpeg($thumb,'small.jpg'); //save image as jpg
header('Content-Type: image/jpeg');
imagejpeg($thumb);
imagedestroy($thumb); 
imagedestroy($im);
?>

Arduino install:

Start IDE
Install TJpg_Decoder library
Open examples>Tjpeg_decoder>SPIFFS>SPIFFS_web_spiffs
change wifi credentials
and the url to your php script.
  bool loaded_ok = getFile("https://myserver/onkyo.php", "/M81.jpg"); // Note name preceded with "/"

replace bottom part with

 // while(1) yield();
 delay(5000);
     SPIFFS.remove("/M81.jpg");

Arduino Tiny Machine Learning Kit

A while ago I bought a little machine learning kit.

I’ve been reading at listening to ML podcasts and websites.

One on Spotify I liked was:

Also, the following Coursera was interesting
https://www.coursera.org/learn/machine-learning

I’ve been testing using Python on my Laptop.
(see other posts)

And a camera with esp32 using face detection.

See here multiple posts about these experiments.

https://www.henriaanstoot.nl/tag/machinelearning/

Today the first experiments using this kit.

  • Arduino Nano 33 BLE Sense board
  • OV7675 Camera
  • Arduino Tiny Machine Learning Shield
  • USB A to Micro USB Cable
  • 9 axis inertial sensor: what makes this board ideal for wearable devices
  • humidity, and temperature sensor: to get highly accurate measurements of the environmental conditions
  • barometric sensor: you could make a simple weather station
  • microphone: to capture and analyse sound in real time
  • gesture, proximity, light color and light intensity sensor : estimate the room’s luminosity, but also whether someone is moving close to the board
  • Microcontroller nRF52840
  • Operating Voltage 3.3V
  • Input Voltage (limit) 21V
  • DC Current per I/O Pin 15 mA
  • Clock Speed 64MHz
  • CPU Flash Memory 1MB (nRF52840)
  • SRAM 256KB (nRF52840)
  • EEPROM none
  • Digital Input / Output Pins 14
  • PWM Pins all digital pins
  • UART 1
  • SPI 1
  • I2C 1
  • Analog Input Pins 8 (ADC 12 bit 200 ksamples)
  • Analog Output Pins Only through PWM (no DAC)
  • External Interrupts all digital pins
  • LED_BUILTIN 13
  • USB Native in the nRF52840 Processor
  • IMU LSM9DS1 (datasheet)
Gesture test ( yes on a windows surface tablet, but Vincent and I installed linux on it!)

I just started and will update this page, with other experiments.

Note: displaying Arduino output without installing the IDE

stty -F /dev/ttyACM0 raw 9600
cat /dev/ttyACM0
................................
................................
................................
................................
................................
................................
................................
................................
................................
................####............
...............##..#............
..............##...##...........
..............#.....#...........
..............###...#...........
..............##.....#..........
..............##.....#..........
...............#....##..........
...............######...........
................................
................................
................................
................................

Started working on C64Pico with Bigred

A week ago I got the last components delivered to my doorstep.

This project was made by Silvervest and it’s f*ckin awesome.

https://github.com/silvervest/c64pico

I was afraid to start this myself, SMD is on another level for me.
But my good friend Marco said … No problem!

So I ordered components online, which was not easy.
Selecting the correct parts, sizes and options.

These things are really really small

Using tweezers to place the components was even difficult.
The slippery tiny bastard got catapulted everywhere. (Or got stuck on fingers, soldering iron and alike)
Many small components got lost into the 7th dimension. Never to be found again.

Awesome to work on this together, but Marco said that I have to try it myself.
Welllll, I got 3/4 of the ATmega328PB-A perfectly soldered, then I notished that it was crooked.
Desoldering was a mess, and I heated the PCB TOO much with the heatgun.

My messed-up PCB, and f*cked-up IC. Leave it to the professionals.

Next step for me is soldering the 75 mini buttons!

Got a Trinitron display from him, I was looking for this for a long time.

Revisiting the Spotify Cube

In the past I posted about my genre selector for Spotify using a cube.

UPDATE: 20240501 below – using esphome

Most was done using NodeRed and a python script.

Now, I’ve moved it to Home Assistant using a single automation.
(Maybe the Arduino sketch can be made with Esphome also.
But I don’t have time for that)
It still uses the Arduino sketch as before, which uses Mqtt to post the RFID code to Mosquitto.

My new Home Assistant automation

alias: SpotifyCube
description: ""
trigger:
  - platform: mqtt
    topic: spotify/rfid/id
condition:
  - condition: template
    value_template: "{{ trigger.payload in playlistkeys.keys() }}"
action:
  - service: media_player.play_media
    target:
      entity_id: media_player.spotify_fash
    data:
      media_content_type: playlist
      media_content_id: spotify:user:spotify:playlist:{{ playlistkeys.get(trigger.payload) }}
variables:
  playlistkeys:
    "70539770": 2KeRLMmGMxI5UgzE7m0iCx
    "70277626": 37i9dQZF1EQmK1rjZuPGDx
    "69229050": 0SOay3RkjojjevrF5lHMOx
    "70015482": 37i9dQZF1DX9HwI3Crikcx
    "69753338": 0bJvpsn0TDZwIDUjz4d75x
    "69491194": 5f8w3UHlD9Ozz6Y4VHs6kx

Some notes about above script:

  • The MQTT topic is configured in the sketch below
  • The playlist keys are at the bottom
    “RFIDID”: playliststring as can be found in web spotify

Pasted link

Arduino Code

#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

MFRC522 mfrc522(SS_PIN, RST_PIN);
unsigned long cardId = 0;

WiFiClient net;
PubSubClient client(net);
const char* mqtt_server = "IPMQTTBROKER";
const char* ssid = "MYSSID";
const char* password = "MYWIFIPASSWORD";

void setup() {

  Serial.begin(115200);
  SPI.begin();
  mfrc522.PCD_Init();
  WiFi.mode(WIFI_AP_STA);
  WiFi.begin(ssid, password);

  client.setServer(mqtt_server, 1883);
     delay(100);
    client.setCallback(callback);
      delay(100);
    client.subscribe("spotify/rfid/in/#");
}

void reconnect() {
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
  }

  while (!client.connected()) {
    String clientId = "NodeMCUClient-";
    clientId += String(random(0xffff), HEX);

    if (!client.connect(clientId.c_str(), "rfidclient", "...")) {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      delay(5000);
    }

  }
  client.subscribe("spotify/rfid/in/#");
}

void callback(char* topic, byte* payload, unsigned int length) {
    String topicStr = topic;
      byte value = atoi((char*)payload);
}

void loop() {
    if (!client.connected()) {
    reconnect();
  }
  client.loop();

  if (!mfrc522.PICC_IsNewCardPresent()) {
    return;
  }

  if (!mfrc522.PICC_ReadCardSerial()) {
    return;
  }

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

  uint8_t control = 0x00;
  do {
    control = 0;
    for (int i = 0; i < 3; i++) {
      if (!mfrc522.PICC_IsNewCardPresent()) {
        if (mfrc522.PICC_ReadCardSerial()) {
          control |= 0x16;
        }
        if (mfrc522.PICC_ReadCardSerial()) {
          control |= 0x16;
        }
        control += 0x1;
      }
      control += 0x4;
    }

    delay(0);
  } while (control == 13 || control == 14);

  reconnect();
  client.publish("spotify/rfid/id", "0");
  delay(500);

  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}

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];
}

ESPHOME Config same as above

esphome:
  name: rfidtag
  friendly_name: rfidtag

esp8266:
  board: d1_mini

mqtt:
  broker: 192.168.1.1

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "xxxxxxxxxxxxxxx="

ota:
  password: "xxxxxxxxxxxxxx"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Rfidtag Fallback Hotspot"
    password: "xxxxxxxxxxx"

captive_portal:
    
spi:
  clk_pin: D5
  miso_pin: D6
  mosi_pin: D7
rc522_spi:
  cs_pin: D8
  update_interval: 1s
  on_tag:
    then:
      - mqtt.publish:
          topic: spotify/rfid/id
          payload: !lambda 'return x;'
  on_tag_removed:
    then:
      - mqtt.publish:
          topic: spotify/rfid/idremoved
          payload: !lambda 'return x;'