Thursday, September 18, 2025
Tuesday, September 16, 2025
rp2040 breakout board for prototyping
its pretty cool you can just order the gerbers from pcbway, solder some headers and have easy access to those awkward pins to maximize the use of this tiny footprint
Monday, September 15, 2025
Friday, September 12, 2025
getting a usb qwerty to be a midi keyboard without a computer
samd2695 + esp32s3
akai mpk play has built in sounds and a speaker but wasnt a fan. you could get a qy100 or some other old midi module on ebay or a pawn shop. An mt-32, soundcanvas, maybe a proteus. but now for 30$ on ali you can get one of these
Wednesday, September 10, 2025
Tuesday, September 9, 2025
how to convert mkv to mp4
so you've recorded a video on linux with guvcview and now you want to play it/edit it on an iphone,
heres a one liner you can use with ffmpeg to convert it to mp4:
for f in *.mkv; do ffmpeg -i "$f" -c:v libx264 -profile:v high -level 4.1 -c:a aac -movflags +faststart "${f%.mkv}.mp4"; done
Tuesday, September 2, 2025
beam forming
pretty cool these days to be able to dip your toes into medical ultrasound technology using cheaply available microcontrollers and sensors.
diy sonar scanner
Saturday, August 30, 2025
adding more gpio to an arduino nano/ raspberry pi
the mcp3008 for adc good for adding pots
picoIO64
22$ some soldering required. gives you 64 gpio
modmypi mcp2308 pi zero hat adds 16 gpio 14.95$
Tuesday, August 26, 2025
Thursday, August 21, 2025
Tuesday, August 19, 2025
my sunvox shortcuts
reposting this because I put down sunvox for a while and had to relearn it.
- cyclic shift is #1 the most important shortcut to add.
- being able to move between patterns is another one.
- shift space to play from line
- doing chords with ctrl g b i
- ctrl p paste evenly
- ctrl t select track
Friday, August 15, 2025
remaping the f310 to send midi with watchdog for auto reload
#!/usr/bin/env python3
import evdev
import rtmidi
from evdev import ecodes
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import os
import sys
DEVICE_PATH = '/dev/input/by-id/usb-Logitech_Logitech_Dual_Action_DF5CB332-event-joystick'
# ----------------------------
# Corrected human-readable button mappings
# ----------------------------
buttons = {
'A': 61, # physical A triggers MIDI note B
'B': 62, # physical B triggers MIDI note X
'X': 60, # physical X triggers MIDI note A
'Y': 63,
'L': 64,
'R': 65,
'Select': 66,
'Start': 67,
'Up': 68,
'Down': 69,
'Left': 70,
'Right': 71
}
evdev_button_map = {
288: 'A',
289: 'B',
290: 'X',
291: 'Y',
292: 'L',
293: 'R',
296: 'Select',
297: 'Start',
294: 'Up',
295: 'Down',
298: 'Left',
299: 'Right'
}
# ----------------------------
# Axis mappings
# ----------------------------
axes = {
'LX': (10, -32768, 32767),
'LY': (11, -32768, 32767),
'LT': (12, 0, 255),
'RT': (13, 0, 255),
'RX': (14, -32768, 32767),
'RY': (15, -32768, 32767)
}
evdev_axis_map = {0: 'LX', 1: 'LY', 2: 'LT', 5: 'RT', 3: 'RX', 4: 'RY'}
# ----------------------------
# MIDI setup
# ----------------------------
midi_out = rtmidi.MidiOut()
midi_out.open_virtual_port("F310 MIDI")
def scale(value, min_val, max_val):
return int((value - min_val) / (max_val - min_val) * 127)
# ----------------------------
# Main gamepad loop
# ----------------------------
def run():
gamepad = evdev.InputDevice(DEVICE_PATH)
print(f"Listening on {gamepad.name} ({gamepad.path})")
for event in gamepad.read_loop():
if event.type == ecodes.EV_KEY and event.code in evdev_button_map:
label = evdev_button_map[event.code]
note = buttons[label]
if event.value == 1:
midi_out.send_message([0x90, note, 112])
print(f"Button pressed: {label}")
elif event.value == 0:
midi_out.send_message([0x80, note, 0])
elif event.type == ecodes.EV_ABS and event.code in evdev_axis_map:
label = evdev_axis_map[event.code]
cc, min_val, max_val = axes[label]
val = scale(event.value, min_val, max_val)
midi_out.send_message([0xB0, cc, val])
# ----------------------------
# Watchdog for hot-reload
# ----------------------------
class ReloadHandler(FileSystemEventHandler):
def on_modified(self, event):
if event.src_path.endswith(os.path.basename(__file__)):
print("Script changed. Restarting...")
os.execv(sys.executable, ['python3'] + sys.argv)
observer = Observer()
observer.schedule(ReloadHandler(), path='.', recursive=False)
observer.start()
# ----------------------------
# Run forever
# ----------------------------
try:
while True:
run()
except KeyboardInterrupt:
observer.stop()
observer.join()
Thursday, August 14, 2025
1 liner gpg encryption + qr
gpg - c creates, gpg - d decodes
this uses python qrcode (pip install it if you dont have it)
read -p "Input GPG file: " infile; read -p "Output PNG file: " outfile; python3 -c "import qrcode, base64; f=open('$infile','rb'); data=base64.b64encode(f.read()).decode(); f.close(); qrcode.make(data).save('$outfile')"
this passes the input of the qr as input and decodes the gpg (requires pyzbar. opencv is good to have also
read -p "QR PNG file: " qrfile; read -p "Output file: " outfile; python3 -c "import cv2, pyzbar.pyzbar as pyzbar, base64, sys; img=cv2.imread('$qrfile'); data=pyzbar.decode(img)[0].data; sys.stdout.buffer.write(base64.b64decode(data))" | gpg -d > "$outfile"
Saturday, August 9, 2025
tgpt ios push notifications from anywhere with pi connect
This script lets you ask tgpt a question and it will send the response as notification to your phone
using the ios app ntfy.sh
you can remotely trigger it outside your local network using raspberry pi connect
alias ntfygpt='f(){ curl -d "$(tgpt -q "$*")" https://ntfy.sh/YOURTOPICGOESHERE; }; f'
make sure YOURTOPICGOES HERE is replaced on your phone, thats where it will be sent to
Friday, August 8, 2025
Udev Rules and Systemd Service for Auto Running python scripts on USB insert / removal
How to Run .py When usb is plugged/unplugged
1. /etc/udev/rules.d/99-gamepad.rules
- CREATED
# Start service when F310 is plugged in
ACTION=="add", SUBSYSTEM=="input", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c216", KERNEL=="event*", TAG+="systemd", ENV{SYSTEMD_WANTS}="macros@%k.service"
# Stop service when F310 is unplugged
ACTION=="remove", SUBSYSTEM=="input", ENV{ID_MODEL}=="Logitech_Dual_Action", KERNEL=="event*", RUN+="/bin/systemctl stop macros@%k.service"
Purpose: Detects when the Logitech F310 gamepad (product ID c216) is plugged in or unplugged and triggers systemd service actions.
2. /etc/systemd/system/macros@.service
- CREATED
[Unit]
Description=Logitech F310 Macros for %i
After=multi-user.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /home/mint22/macros.py
Restart=on-failure
User=mint22
Group=mint22
Environment=HOME=/home/mint22
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
Purpose: Systemd template service that runs the Python script when triggered by udev. The @
makes it a template service that can be instantiated with device names (like macros@event13.service
).
3. /home/mint22/macros.py
- EXISTING (permissions updated)
Changes made:
- Ensured executable permissions:
chmod +x /home/mint22/macros.py
- Added user to input group:
sudo usermod -a -G input mint22
Purpose: Your existing Python script that contains the gamepad macro functionality.
Commands Run to Apply Changes:
# Reload udev rules to recognize the new gamepad detection rule
sudo udevadm control --reload-rules
# Reload systemd to recognize the new service template
sudo systemctl daemon-reload
# Set proper permissions
chmod +x /home/mint22/macros.py
sudo usermod -a -G input mint22
How It Works:
- When F310 is plugged in → udev detects it → starts
macros@eventX.service
→ runsmacros.py
- When F310 is unplugged → udev detects removal → stops the service → terminates
macros.py
The system automatically handles starting and stopping the script based on the physical presence of the gamepad.
prettify json from cli with jq and this bash alias
alias prettifyjson='f(){ jq . "$1" > tmp && mv tmp "$1"; }; f'
source ~/.bashrc
Thursday, August 7, 2025
Using Logitech FCB310 Gamepad as a Macropad on Raspberry Pi 4
This tutorial shows how to use your Logitech FCB310 USB gamepad as a macropad on a Raspberry Pi 4, with automatic startup and hotplug detection. When plugged in, your gamepad buttons will trigger keyboard macros on the Pi, no manual script launching needed.
Requirements
- Raspberry Pi 4 with Raspberry Pi OS (desktop)
- Logitech FCB310 USB Gamepad
- Internet connection for installing packages
Step 1: Install Required Software
Open a terminal and run:
sudo apt update
sudo apt install python3-pip xdotool
pip3 install inputs pyudev watchdog
xdotool
: simulates keyboard keypressesinputs
: reads gamepad eventspyudev
: detects USB device plug/unplugwatchdog
: monitors macro config file changes
Step 2: Prepare Macro Configuration File
Create a CSV file to map gamepad buttons to keyboard shortcuts.
Example file: /home/pi/macropad/macros.csv
BTN_A,ctrl+alt+t
BTN_B,ctrl+w
- First column: gamepad button code (e.g.,
BTN_A
) - Second column: key combo for
xdotool
(e.g.,ctrl+alt+t
)
Step 3: Create the Macro Script
Create a folder and the Python script:
mkdir -p ~/macropad
vim ~/macropad/gamepad_macro.py
Paste this full script into it:
import csv
import subprocess
from inputs import get_gamepad
import pyudev
import threading
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import time
mapping = {}
def load_macros():
global mapping
mapping = {}
try:
with open("/home/pi/macropad/macros.csv", newline='') as csvfile:
reader = csv.reader(csvfile)
for row in reader:
if len(row) >= 2:
btn = row[0].strip()
keys = row[1].strip()
mapping[btn] = [keys]
print("Macros reloaded:", mapping)
except Exception as e:
print("Failed to load macros:", e)
def send_macro(keys):
for combo in keys:
subprocess.run(["xdotool", "key", combo])
def listen_gamepad(stop_event):
while not stop_event.is_set():
try:
events = get_gamepad()
for event in events:
if event.ev_type == "Key" and event.state == 1:
if event.code in mapping:
send_macro(mapping[event.code])
except Exception:
pass
class ConfigChangeHandler(FileSystemEventHandler):
def on_modified(self, event):
if event.src_path.endswith("macros.csv"):
print("Config file changed, reloading macros")
load_macros()
def device_event(observer, device):
global gamepad_thread, stop_event
if device.action == "add" and "event" in device.device_node:
print("Gamepad connected, starting listener")
load_macros()
if gamepad_thread and gamepad_thread.is_alive():
stop_event.set()
gamepad_thread.join()
stop_event.clear()
gamepad_thread = threading.Thread(target=listen_gamepad, args=(stop_event,), daemon=True)
gamepad_thread.start()
elif device.action == "remove":
print("Gamepad disconnected")
stop_event.set()
if gamepad_thread:
gamepad_thread.join()
if __name__ == "__main__":
stop_event = threading.Event()
gamepad_thread = None
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by('input')
observer = pyudev.MonitorObserver(monitor, device_event)
observer.start()
# Watch macros.csv for changes
config_handler = ConfigChangeHandler()
config_observer = Observer()
config_observer.schedule(config_handler, path="/home/pi/macropad/", recursive=False)
config_observer.start()
print("Waiting for gamepad to connect...")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
stop_event.set()
if gamepad_thread:
gamepad_thread.join()
config_observer.stop()
config_observer.join()
Step 4: Make Script Executable
chmod +x ~/macropad/gamepad_macro.py
Step 5: Setup Autostart with systemd
Create a service file:
sudo vim /etc/systemd/system/macropad.service
Add:
[Unit]
Description=Gamepad Macro Pad Service
After=graphical.target
[Service]
ExecStart=/usr/bin/python3 /home/pi/macropad/gamepad_macro.py
Restart=always
User=pi
[Install]
WantedBy=graphical.target
Enable and start service:
sudo systemctl enable macropad.service
sudo systemctl start macropad.service
Step 6: Reboot and Test
Reboot your Pi:
sudo reboot
- Plug in your FCB310 gamepad.
- Press buttons mapped in
macros.csv
. - Macros should trigger automatically as keyboard inputs.
Customization
- Edit
/home/pi/macropad/macros.csv
anytime. - The script auto-reloads macros on file changes.
- Add/remove mappings without restarting.
Troubleshooting
- Ensure your gamepad device shows up in
/dev/input/
(useevtest
to confirm). - Adjust key combos to fit your needs (see
xdotool
docs). - Check logs with
journalctl -u macropad.service -f
.
Tuesday, July 29, 2025
wpa_supplicant no longer works to setup wifi on boot
nmtui worked for me to connect my rav filehub
I'm using it so I can run a server with music on a raspberry pi that I can connect to from the ios files app
It's cool because I can use Tau DJ without worrying about running out of internal storage space