Nerd or Geek Logo
Home / Projects / Morse-Pi

Morse-Pi

A browser-based Morse code trainer for Raspberry Pi with a recommended native Rust backend and optional legacy Python backend

Tutorial Raspberry Pi Rust Pi Zero Morse Code
Morse-Pi Logo

Overview

Morse-Pi is a browser-based Morse code trainer built for Raspberry Pi. The project now has a recommended native Rust backend for the fastest, most reliable install, plus an optional legacy Python backend if you want to tinker. A Pi Zero, Zero W, or Zero 2 W makes a great dedicated Morse trainer, but you can also practice from any browser with on-screen controls and keyboard shortcuts.

Read the full official documentation: https://nerd-or-geek.github.io/Morse-Pi/
Plan your time: allow about 20–45 minutes to flash Raspberry Pi OS, connect your Pi Zero, and run the setup. The very first Rust build usually takes 10–30 minutes on a Pi Zero and only a few minutes on faster boards like the Pi 4.
No Pi Required! A Raspberry Pi is optional — the web UI works on other Linux machines too. GPIO, speaker output, and USB HID keyboard mode still need real Pi hardware.

Hardware Requirements

Raspberry Pi Zero Setup

Raspberry Pi Zero, Zero W, or Zero 2 W; a 16 GB or larger microSD card; and a stable 5 V power supply.

Setup Computer

A Windows, macOS, or Linux computer with an SD card reader and Raspberry Pi Imager installed.

Optional Morse Hardware

Morse key or iambic paddle, jumper wires, and a piezo buzzer or small speaker for GPIO audio output.

Network Access

Wi-Fi is the easiest way to reach the web UI. Ethernet via adapter also works if your Zero setup supports it.

USB HID Mode

For keyboard-emulation mode, use a Pi Zero-family board with a real USB data cable connected to the port labeled USB, not PWR.

Recommended Board

Pi Zero 2 W is the sweet spot: same tiny form factor, but much faster build and better general responsiveness.

OS choice matters: use Raspberry Pi OS Lite (32-bit) for an original Pi Zero or Zero W. If you have a Pi Zero 2 W, you can use 32-bit or 64-bit Raspberry Pi OS Lite.

Install Raspberry Pi OS on the SD Card

Use Raspberry Pi Imager to write Raspberry Pi OS to your microSD card before you install Morse-Pi.

Get Raspberry Pi Imager: https://www.raspberrypi.com/software/
1

Install Raspberry Pi Imager

Download and install Raspberry Pi Imager on your Windows, macOS, or Linux computer. It is the official tool for writing Raspberry Pi OS to an SD card.

2

Insert Your microSD Card

Put the microSD card into your computer's card reader, then launch Raspberry Pi Imager.

3

Choose Device and OS

Click Choose Device and select your exact Pi Zero model. Then click Choose OS and select Raspberry Pi OS Lite. Use the 32-bit image for Pi Zero / Zero W, or 32-bit/64-bit for Pi Zero 2 W.

4

Configure Advanced Settings

Before writing the image, open the advanced settings prompt and set a hostname, username, password, Wi-Fi country, Wi-Fi SSID/password, locale, and enable SSH. That saves you from setup headaches later — like tiny keyboards and big sighs.

5

Write the Image

Select your storage device, confirm the erase/write prompt, and wait for Raspberry Pi Imager to finish. Safely eject the card when it is done.

6

Boot the Pi Zero

Insert the card into the Pi, power it on, and wait a minute or two for first boot. On a Pi Zero, use the port marked PWR for power and the port marked USB for data accessories or HID mode.

Update Raspberry Pi OS

Once your Pi Zero is online, connect over SSH or use a local terminal and bring the base system up to date before installing Morse-Pi.

Bash
sudo apt update
sudo apt upgrade -y

If the upgrade installs a new kernel, firmware, or USB modules, a reboot is a smart move before the Morse-Pi installer:

Bash
sudo reboot
If curl is missing on a minimal image, install it with sudo apt install curl -y before running the Rust installer.

Install Morse-Pi with the Rust Installer

The Rust backend is the recommended install path. It compiles to a native binary, runs well on dedicated Pi hardware, and is the version the official docs now lead with.

Bash
curl -sSL https://raw.githubusercontent.com/Nerd-or-Geek/Morse-Pi/main/install-rust.sh | sudo bash

The installer automatically:

  • Configures the USB HID keyboard gadget for supported Pi models
  • Installs the Rust toolchain, build tools, and pigpio development packages
  • Clones Morse-Pi to /opt/morse-pi and builds the Rust backend with GPIO support
  • Creates systemd services so Morse-Pi starts on boot
Pi Zero heads-up: the first build can take a while. That is normal. If you plan to use the USB HID keyboard feature, run sudo reboot after the installer finishes so the kernel modules are fully active.

When the installer finishes, open the IP address printed on screen in your browser, for example:

URL
http://192.168.1.42:5000

Already Running the Python Version?

You can switch an existing Python install to Rust without wiping your settings:

Bash
curl -sSL https://raw.githubusercontent.com/Nerd-or-Geek/Morse-Pi/main/transition-rust.sh | sudo bash

GPIO Wiring

Important: all GPIO numbers below are BCM numbers, not physical pin numbers.

Straight Key (Single-Pin Mode)

Component GPIO (BCM) Physical Pin Notes
Key signal 17 Pin 11 Active-low (key shorts pin to GND)
Key ground GND Pin 9 or 14
Speaker + 18 Pin 12 Speaker pin 1
Speaker − 13 Pin 33 Speaker pin 2 for push-pull audio

Iambic Paddle (Dual-Pin Mode)

Component GPIO (BCM) Physical Pin Notes
Dot paddle 22 Pin 15 Active-low
Dash paddle 27 Pin 13 Active-low
Speaker + 18 Pin 12 Speaker pin 1
Speaker − 13 Pin 33 Speaker pin 2 for push-pull audio

Pi GPIO Header Reference

┌──────────────────────────────────┐ │ 1 3V3 │ 2 5V │ │ 3 BCM2 │ 4 5V │ │ 5 BCM3 │ 6 GND │ │ 7 BCM4 │ 8 BCM14 │ │ 9 GND │ 10 BCM15 │ │ 11 BCM17 │ 12 BCM18 ← spkr +│ ← key (single) │ 13 BCM27 │ 14 GND │ ← dash (dual) │ 15 BCM22 │ 16 BCM23 │ ← dot (dual) │ … │ … │ │ 33 BCM13 │ 34 GND │ ← spkr − └──────────────────────────────────┘
Dual-pin speaker output is louder and cleaner because the two GPIO pins drive the speaker in opposite phases. If you leave Speaker Pin 2 empty in the CONFIG tab, Morse-Pi falls back to simpler single-pin PWM output.

Features

SEND Mode

Key Morse in real time and watch character-by-character decoding as you go.

ENCODE & DECODE

Translate text to Morse or practice decoding dots and dashes with quiz-style feedback.

SPEED Trainer

Practice sending at a target WPM and get scored on timing and accuracy.

Stats Tracking

Track accuracy, longest streak, and session history.

Farnsworth Timing

Stretch gaps between letters and words — great for beginners.

Multi-Pi Networking

Discover other Morse-Pi devices on your LAN and send messages between them.

USB HID Keyboard

Turn decoded Morse into real keystrokes on a connected computer through USB gadget mode.

Keyboard Control

Works without hardware — Space = straight key, Z/X = dot/dash paddles.

GPIO Support

Connect a real Morse key or iambic paddle via Raspberry Pi GPIO pins.

Push-Pull Audio

Drive a speaker from two GPIO pins in anti-phase for louder, cleaner sound.

Live Configuration

Adjust GPIO pins, tones, WPM, Farnsworth timing, theme, and keyboard settings from the browser.

Configuration

All settings are changed live from the CONFIG tab in the browser — no config files to hand-edit and no restart dance required for normal tweaks.

Setting Default Description
Device Name Morse Pi Name shown to other devices on the network
WPM 20 Words per minute; all timing is derived from this
Pin mode single single = straight key, dual = iambic paddle
Data pin 17 BCM pin for straight key
Dot pin 22 BCM pin for dot paddle
Dash pin 27 BCM pin for dash paddle
Speaker pin 18 Primary speaker GPIO (speaker pin 1)
Speaker pin 2 13 / null Optional second speaker GPIO for push-pull audio
Ground output pins [] Optional GPIO pins driven LOW to act as software-configured grounds
Output type speaker Use PWM speaker output or LED-style on/off output
Dot frequency 700 Hz Tone pitch for dots
Dash frequency 500 Hz Tone pitch for dashes
Volume 75% PWM duty cycle
Farnsworth mode Off Stretch letter/word gaps independently for learners
Letter gap mult How much longer the between-letter pause is
Word gap mult How much longer the between-word pause is
KB mode letters Decoded letters or custom dot/dash key mapping for USB HID mode
Theme dark Switch between dark and light UI themes
Settings are stored in /opt/morse-pi/morse-translator/settings.json and are preserved across updates and backend switches.

Keyboard Shortcuts

You can use your computer keyboard as a virtual Morse key — no hardware required!

Key Action
Space Straight key (hold = dash, tap = dot)
Z Dot paddle (dual-pin mode)
X Dash paddle (dual-pin mode)
In dual-pin mode, holding Z and X together activates squeeze keying so the keyer alternates dots and dashes automatically.

Multi-Pi Networking

Multiple Morse-Pi devices on the same Wi-Fi or wired LAN will automatically discover each other — no configuration required.

1

Install on Multiple Pis

Install and run Morse-Pi on two or more Raspberry Pis on the same network.

2

Open Network Tab

Open the NETWORK tab in any browser connected to a Morse-Pi device.

3

Discover Devices

Discovered devices appear within a few seconds.

4

Send Messages

Type a message and hit SEND — it arrives at the other Pi and is played as audio.

Each Pi broadcasts a UDP beacon on port 5001 every few seconds. Peers that disappear for about 15 seconds are automatically removed from the list.

Give each Pi a human-readable name in CONFIG → Device Name or directly in the NETWORK tab so peers are easier to recognize.

Service Management

Update a Rust Installation

To pull the latest code, rebuild the binary, and restart the service, use the dedicated Rust updater:

Bash
curl -sSL https://raw.githubusercontent.com/Nerd-or-Geek/Morse-Pi/main/update-rust.sh | sudo bash

Systemd Services

If you used the installer, Morse-Pi runs as a systemd service. These are the commands you will use most often:

Bash
# Check if running
sudo systemctl status morse-pi

# Restart the service
sudo systemctl restart morse-pi

# Stop the service
sudo systemctl stop morse-pi

# Last 50 log lines
sudo journalctl -u morse-pi -n 50

# View live logs
sudo journalctl -u morse-pi -f

# USB HID gadget service
sudo systemctl status morse-pi-hid
sudo systemctl restart morse-pi-hid

# GPIO daemon used by the Rust backend
sudo systemctl status pigpiod
sudo systemctl restart pigpiod
Want to verify which backend is active? Run grep ExecStart /etc/systemd/system/morse-pi.service. If it points to morse-pi, you are on Rust. If it runs python3 app.py, you are on the legacy Python backend.

Troubleshooting

If Morse-Pi misbehaves, these are the fastest fixes to try before you start glaring at the Pi like it has personally offended you.

Web UI Won't Load

  • Check the service: sudo systemctl status morse-pi
  • Review logs: sudo journalctl -u morse-pi -n 50
  • Confirm the IP address with hostname -I
  • Make sure port 5000 is not blocked by a firewall

Rust Build Fails on Pi Zero

  • Add or enlarge swap if the linker runs out of memory
  • Install missing build tools: sudo apt install build-essential -y
  • Install missing pigpio headers: sudo apt install libpigpio-dev -y
  • If cargo is missing, run source "$HOME/.cargo/env"
Bash
sudo dphys-swapfile swapoff
sudo sed -i 's/CONF_SWAPSIZE=.*/CONF_SWAPSIZE=512/' /etc/dphys-swapfile
sudo dphys-swapfile setup
sudo dphys-swapfile swapon

GPIO or Sound Issues

  • Check pigpiod: sudo systemctl status pigpiod
  • Verify the speaker and key wiring against the BCM pin table above
  • Make sure the CONFIG tab matches your actual pin assignments
  • Add your user to the gpio group if needed: sudo usermod -aG gpio $USER

USB HID Keyboard Problems

  • Reboot after install so dwc2 and gadget modules fully load
  • Check the HID service: sudo systemctl status morse-pi-hid
  • Verify modules: lsmod | grep dwc2
  • If g_ether is loaded first, it can block HID mode on Pi Zero boards

Networking Problems

  • Put both Morse-Pi devices on the same subnet for automatic peer discovery
  • Wait at least 5 seconds for UDP beacons to appear
  • Test another Pi directly with curl http://<peer-ip>:5000/status
  • Check sudo ufw status if peers or messages do not arrive

Still Stuck?

  • Run the app manually to surface startup errors
  • Rust backend: cd /opt/morse-pi/morse-translator && ./morse-pi
  • Re-run the installer to repair services and dependencies
  • Use the full official troubleshooting page linked below for deeper fixes

Project Structure

Directory Tree
Morse-Pi/
├── install.sh                  ← fresh installer — legacy Python backend
├── install-rust.sh             ← fresh installer — recommended Rust backend
├── transition-rust.sh          ← migrate Python installs to Rust
├── update.sh                   ← updater — Python backend
├── update-rust.sh              ← updater — Rust backend
├── docs/                       ← official documentation site
├── morse-translator/           ← runtime files, templates, settings, stats
└── morse-translator-rust/
    ├── Cargo.toml              ← Rust package manifest
    └── src/
        ├── main.rs             ← HTTP server and routes
        ├── gpio.rs             ← GPIO integration via pigpio
        ├── sound.rs            ← tone generation and keyer logic
        ├── keyboard.rs         ← USB HID keyboard support
        └── network.rs          ← UDP peer discovery
The installer also creates service files such as /etc/systemd/system/morse-pi.service and /etc/systemd/system/morse-pi-hid.service so everything auto-starts on boot.

Resources

Official Morse-Pi Docs

The full documentation site with getting started, maintenance, USB HID, reference, and troubleshooting guides.

Read the official docs →

GitHub Repository

Source code, issues, and releases.

View on GitHub →

Raspberry Pi Imager

The official tool for flashing Raspberry Pi OS to your SD card or USB storage.

Download Imager →

Official Troubleshooting

Deeper fixes for Rust builds, GPIO, USB HID conflicts, and networking edge cases.

Open troubleshooting guide →
License: MIT — do whatever you like with it.