Tag Archives: hardware

68000 Build environment

For my new SBC I’ll need a machine code build environment.

This is what I’ve setup now.

My main workstation is Linux based. While this setup is Linux based, vasm should work on other operating systems also.

Getting and compiling vasm for 68k

wget http://sun.hasenbraten.de/vasm/release/vasm.tar.gz
tar xzvf vasm.tar.gz
cd vasm
# Building
make CPU=m68k SYNTAX=oldstyle
# Using
./vasmm68k_oldstyle -m68000 -Fbin -dotdir -no-opt source.asm
# this generates a.out

# Dumping the file (byte separated and with a offset of 0x8000)
xxd -g 1 -o 0x8000 a.out | head
00008000: 30 3c aa aa 4e f9 00 00 80 04 00 00 00 00 00 00  0<..N...........
00008010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00008020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00008030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00008040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00008050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00008060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00008070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00008080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00008090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

# But my 68k needs an ODD EVEN eeprom 
# so I used another tool - romsplit
git clone https://github.com/ullman/romsplit
cd romsplit
make all
# Using romsplit
./romsplit -s a.out odd.rom even.rom
# Split into 4? Split the splits using above
# Output
xxd -g 1 -o 0x8000 odd | head -1 ; xxd -g 1 -o 0x8000 even | head -1
00008000: 30 aa 4e 00 80 00 00 00 00 00 00 00 00 00 00 00  0.N.............
00008000: 3c aa f9 00 04 00 00 00 00 00 00 00 00 00 00 00  <...............
# Burn these with minipro

Disassemble

m68k-linux-gnu-objdump --disassemble-all --target=binary --architecture=m68k a.out

68030 example for friend

# Compile vasm with
make CPU=m68k SYNTAX=mot
------------
vasmm68k_mot  -Fbin  ./edk.asm
-------------
.68030

	ORG $0

*****
* exception table (256 x 4 bytes)
*****
	dc.l $400	; Program Counter na reset (startadres)
	dc.l $20000	; stackpointer (ram locatie)
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0

	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

	org $400	; hier starten
	move.l #$0,d0
loop1:
	add.l #$1,d0
	cmp.l #$10000,d0
	bne loop1

	move.l #$0,d0
loop2:
	add.l #$1,d0
	cmp.l #$10000,d0
	bne loop2

	nop
	nop
	nop
-----
vasm 1.9f (c) in 2002-2023 Volker Barthelmann
vasm M68k/CPU32/ColdFire cpu backend 2.6c (c) 2002-2023 Frank Wille
vasm motorola syntax module 3.18 (c) 2002-2023 Frank Wille
vasm binary output module 2.3a (c) 2002-2023 Volker Barthelmann and Frank Wille

org0001:0(acrwx1):	           0 bytes
org0002:0(acrwx1):	        1024 bytes
org0003:400(acrwx2):	          30 bytes
-----
-rw-rw-r--  1 henri    henri       1054 aug 27 11:45  a.out

Multiple computer systems in a carrying case.

Test picture of a multiprocessor computer setup.
Using buttons on the right, I want the possibility to change between systems and keyboard settings.
Also, multiple software/OS slots for SDCards will be on the right.

Mockup using a laptop display (eeepc) a bought display controller and a pi2 with Faux86

The lid containing the keyboard has a handle!

After laser cutting a nice front, it could become a nice road warrior hacking station.

I’m going to replace the wireless keyboard, probably with a touch display and a programmable layout for keyboards.
Something like below

Some layouts:

I’ll probably buy this one from waveshare

Info about Faux86

  • 8086/8088, V20, 80186 and limited 286 instruction set.
  • Configurable CPU speeds from 5Mhz up to 100Mhz.
  • Custom Hardware BIOS’s supported.
  • Supports bootable disk images in .img and .raw file format.
  • CGA / EGA / VGA Colour Video emulation, with most modes supported.
  • PC Speaker, Adlib, Soundblaster and Disney SoundSource.
  • UART Com Ports.
  • Standard PC XT Keyboard.
  • Serial Port 2-Button mouse.

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

Amiga week

This week (while preparing for a mini retro party) I fixed some Amiga stuff.

I’ve bought a new gadget.

You place this PCB between the CPU IC socket and the CPU (68000) itself.

Now running a special floppy image, which loads a driver, I can use the 512MB sdcard as “harddisk”.

It at first ran into all kinds of hangups.
Checking everything, I found CIAB (8520) the culprit.
Timing errors I’ve never noticed before!

Switching this one with CIAA resolved the problem.
(I don’t use a printer anyway, but I have to remember that anything using the parallel port can have problems now.)

Meanwhile, I wanted to have a better control over the Amiga drives, so I’m planning to use a second switch to reassign drive numbers using a switch.

For switching Internal/External drive (df0/df1) I was using a Gotek boot switch. (Just press 3x ctrl-Amiga-Amiga)

See https://www.henriaanstoot.nl/2022/05/14/gotek-stuff/

But I have TWO external devices.
The Gotek virtual disk device and a real 5.24″ drive.

So I’m going to use a ON-ON double switch to toggle the external devices.

oppo_32

The internal switch toggles internal and external.
The secondary I’m going to build into the 5.25″ drive toggles df2 and the “df1”.
That way the internal drive can be 0 (boot) or 1.
The external drives can be 0,1 or 2.

NOTE: Switch pin 21 and 9 using the cross switch!

SO: Amiga with internal drive -> External 5.24″ which has a passthrough to the Gotek.

Another amiga thing fixed:
I re-installed Aros (on an old Laptop this time)

And third: I’ve bought the Amiga Forever cdrom.

When you get the ISO image from AmigaForever, and want to run it using Linux, do this to get it working

sudo apt install xkbfile1:i386
sudo apt install libxkbfile1:i386
mkdir -p /cdrom
sudo mount -t iso9660 ~/Downloads/AF.iso /cdrom
cd /cdrom/Private/Linux/e-uae/
./kxlight-start.sh

If you install Wine, you can use the windows gui in linux also.


Amiga samplers

Testing the sampler (demo for Tyrone)

Sampling the sound of a C64 on an Amiga.
Started (booted) the sampling program from second external drive using switch setup as above.

Even realtime echo works!

64×64 Matrixrgb plus Conway’s Game of Life

Yesterday I got this nice led matrix I mentioned before.

I wanted to control this display using Circuit Python and a Raspberry Pico.

Pico  Matrix
GP0   R1
GP1   G1
GP2   B1
GP3   R2
GP4   G2
GP5   B2
GP6   A
GP7   B
GP8   C
GP9   D
GP10  Clock
GP11  E
GP12  Latch
GP13  Output Enable

GND   GND ( I did both )

I installed Circuit Python and the following libraries.

adafruit_imageload, adafruit_display_text.label (the rest was already in the uf2 firmware.)
(Check this link : https://circuitpython.org/board/raspberry_pi_pico/ )
I could not install the Wifi uf2 file, then I got a out of storage space when installing the adafruit libraries.

importing libaries and init display

import board, digitalio, busio, time, displayio, rgbmatrix, framebufferio
import adafruit_imageload, terminalio, random
import adafruit_display_text.label

displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=64, bit_depth=2, height=64,
    rgb_pins=[board.GP0, board.GP1, board.GP2, board.GP3, board.GP4, board.GP5],
    addr_pins=[board.GP6, board.GP7, board.GP8, board.GP9, board.GP11],
    clock_pin=board.GP10, latch_pin=board.GP12, output_enable_pin=board.GP13)
display = framebufferio.FramebufferDisplay(matrix)

I became interested in Conway’s “Game of Life”, in 1983. Reading a article in the Dutch Magazine Kijk.

The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970. It is a zero-player game, meaning that its evolution is determined by its initial state, requiring no further input. One interacts with the Game of Life by creating an initial configuration and observing how it evolves. It is Turing complete and can simulate a universal constructor or any other Turing machine.

https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life

I found these on my server. Bad quality, I know. Scanned these many years ago.

The rules are:

  1. Any live cell with fewer than two live neighbours dies, as if by underpopulation.
  2. Any live cell with two or three live neighbours lives on to the next generation.
  3. Any live cell with more than three live neighbours dies, as if by overpopulation.
  4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

When playing with the Basic code as a kid, I wanted to try if it was possible to make a 3D version of this.

I came up with the following rules:

  1. Birth : 4 alive neighbours needed
  2. Survive : 5 or 6 neighbours
  3. Dead : below 4 and over 6

I think there should be a BBC Acorn basic version I wrote somewhere.

Back to the display

Greetings to my friends
Game of Life starting with my Logo plus a glider
A single Gosper‘s glider gun creating gliders

Code for the glider gun

    conway_data = [
        b'                        +           ',
        b'                      + +           ',
        b'            ++      ++            ++',
        b'           +   +    ++            ++',
        b'++        +     +   ++              ',
        b'++        +   + ++    + +           ',
        b'          +     +       +           ',
        b'           +   +                    ',
        b'            ++                      ',
    ]

Next todo:

  • Line functions
  • Design a Chip tune hardware add-on
  • Make a Game of Life start situation selector
  • Make a new Maze game!

Amiga Action Replay

A long time ago I had an Action Replay II.

I modded it and was planning to rebuild this using pluggable eurocard-prints.
Then it got lost, somewhere.

Today I went to Almelo with Tyrone.
In the morning reverse engineering a lift controller print, and afternoon going to a guy selling a lot of Retro stuff.

And there it was, an Action Replay II for Amiga just catching dust.

I had to buy it, and got a sh*tload of 27256 Eproms for free!

Action Replay Mk I

This version is compatible with the A500/A1000 version only. It also plugs into the side expansion port. It introduces the following features:

1.0 Version

  • Shows and modifies registers (even read-only ones) and memory contents.
  • Trainer maker.
  • M68000 assembler / disassembler.
  • Copper assembler / disassembler.
  • Sprite editor.
  • Virus detector.
  • Picture / music (tracker format) / sample ripper.
  • Save computer memory (freezed programs) to disk.
  • Shows computer status (disk parameters, ChipRAM, FastRAM…).

Features added to the 1.5 Version

  • Mempeeker.
  • Ability to save freezed programs to RAM.
  • RAM testing.
  • Illegal opcode – jumps to freezer mode.

Action Replay Mk II

A special A2000 version is available for this particular revision. Instead of plugging into the side expansion port it plugs into the 86 pin CPU slot.

Features added since MK 1.5 version

  • Boot selector.
  • Picture editor.
  • Sound tracker.
  • Turbo fire manager (separately for both joysticks).
  • Disk encoder.
  • Start menu.
  • Disk monitor.
  • Integrated DOS commands (Dir, Format,…).
  • Diskcopy.
  • 80 characters display with two-way scrolling.
  • Calculator.
  • Notepad.
  • Memory and drive switch (enabling / disabling).
  • Music ripper now finds all tracker formats (SoundTracker, NoiseTracker, other formats with 32 samples).
  • Ripped music / pictures are saved in IFF format.

C64Pico Follow-up

Soldering almost done, except for the space bar all tactile buttons in place.

Using my USBasp programmer I tried to program the Atmega328pb.

Same one I used for:

I first needed to implement some udev rules to get the rights for the reader correct.

#/etc/udev/rules.d/99-usbasp.rules
SUBSYSTEM=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", GROUP="dialout"

Next I tried to burn a bootloader.

Well, not as planned, back to the drawing board.

Hopefully I compiled at least the Pico part correctly.

Home Assistant Alarm with ESP Siren

I used to have a “professional” alarm system, but it was too limited.

But when making a new alarm system using Home Assistant I thought I could reuse some sensors and the very loud alarm.

Setting up the Alarm within HA was as described on the HA website.
I made a group for door and motion sensors.
Then I made groups for lighting and switches.

Now I can “ARM” the house.

  • Motion sensors like PIR and camera sensors are being used for detection.
  • Lights and sound will be turned on when motion is detected.
  • When arming the system, the siren mode of the camera’s is also turned on.
  • When intrusion is detected I get a pushover notification on my phone and watch.

The siren is about 4-5 Euro’s on Ali
https://nl.aliexpress.com/item/1005006066524139.html

Schematic of the wemos controller

(I don’t have a Siren Fritzing part .. hence the speaker)

Used mosfet is a N-Channel 30N06L, resistor is 10K

ESPHome code

esphome:
  name: bigalarm
  friendly_name: BigAlarm

esp8266:
  board: d1_mini

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "1xxfIYKv6tpzt7HQKYOxxxxxxxxTBETHkmy7cwDE="

ota:
  password: "5d23a3af438fe0xxxxxxxx2ff29ab6"

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

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

captive_portal:

output:
  - platform: gpio
    pin: 0
    id: 'generic_out'
switch:
  - platform: output
    name: "BigAlarm"
    output: 'generic_out'

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.

Today some lasercutting for Home Assistant Spotify RFID

see:

Lasercutting a case and the playlist selectors.

Close-up RFID stickers I’m using.

Below is a test with different methods.
I like reading the booklets, so a CD i cool, and I don’t need a CD player.
(The RFID tag is in the case)
The little cards are for bought audio files I don’t have a physical CD for.

Wooden case with RFID reader being powered by external powerbank

What am I gonna do?
Cube as I had? Wooden playlist selectors as in above movies?
The cards I’ve printed?
Maybe a small record player with an RFID reader inside?

3D printed like this? https://makerworld.com/en/models/66671
UPDATE: 20240327 – Little Record I 3D printed with little groves.

Home Assistant code for Playlist and Album automations
(B.t.w. The method is still using an Arduino and MQTT topics, as mentioned before)

# ALBUM PLAYER
alias: SpotifyAlbum
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_fashice
    data:
      media_content_type: album
      media_content_id: spotify:album:{{ playlistkeys.get(trigger.payload) }}
mode: single
variables:
  playlistkeys:
    "71719674": 20TANs4iXVeLp387zjgmec
    "71260666": 5325ECcBhnIysoqyENGCYi
    "71457530": 7wyOeD9HcUuMFMO8pTflap
# PLAYLIST PLAYER
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_fashice
    data:
      media_content_type: playlist
      media_content_id: spotify:user:spotify:playlist:{{ playlistkeys.get(trigger.payload) }}
variables:
  playlistkeys:
    "69229050": 0SOay3RkjojjevrF5lHMON
    "69491194": 5f8w3UHlD9Ozz6Y4VHs6kF
    "69753338": 0bJvpsn0TDZwIDUjz4d75S
    "70015482": 37i9dQZF1DX9HwI3Crikcm
    "70277626": 37i9dQZF1EQmK1rjZuPGDt
    "70539770": 2KeRLMmGMxI5UgzE7m0iCp

In the past, Aloha and I made a simple solution like this using barcodes in < 2000s.
Due to the many obscure recordings I have, I am thinking about creating something like this for Picore player and my local Squeezebox server.

Logitech Squeezebox / Media Server Solution

alias: squeezealbumplay
description: ""
trigger:
  - platform: mqtt
    topic: spotify/rfid/id
condition:
  - condition: template
    value_template: "{{ trigger.payload in playlistkeys.keys() }}"
action:
  - service: squeezebox.call_method
    target:
      entity_id: media_player.squeezebox
    data:
      command: playlist
      parameters:
        - play
        - "{{ playlistkeys.get(trigger.payload) }}"
mode: single
variables:
  playlistkeys:
    "71719674": /tank/celtic/Celtic/M/Martyn Bennett/Bothy Culture/
    "71719675": /tank/celtic/Celtic/D/Davy Spillane/Atlantic Bridge/
    "2159056458": /tank/celtic/Celtic/M/Michael McGoldrick/Arc/