Add multi-panel Pico UDP firmware and Python LED control.

Pico panels get static IPs on 10.1.1.10–14 with per-panel LED counts, Makefile deploy targets, and Python examples for animations, sync tests, and direct Pi SPI control.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-28 22:46:08 +12:00
parent d8323bb9a3
commit d5cab2efdf
52 changed files with 4677 additions and 1 deletions

117
scripts/setup_ap.sh Executable file
View File

@@ -0,0 +1,117 @@
#!/usr/bin/env bash
# Set up a WiFi access point on wlan0 and share internet from ethernet (eth0).
#
# Usage:
# sudo ./scripts/setup_ap.sh
# sudo PORTAL_AP_SSID=mywifi PORTAL_AP_PASSWORD=secret ./scripts/setup_ap.sh
#
# Environment:
# PORTAL_AP_SSID WiFi name (default: portal)
# PORTAL_AP_PASSWORD WPA password, 8+ chars (default: portal1234)
# PORTAL_AP_CON_NAME NetworkManager connection name (default: portal-ap)
# PORTAL_AP_IF AP interface (default: wlan0)
# PORTAL_WAN_IF Uplink interface (default: eth0)
set -euo pipefail
SSID="${PORTAL_AP_SSID:-portal}"
PASSWORD="${PORTAL_AP_PASSWORD:-portal1234}"
CON_NAME="${PORTAL_AP_CON_NAME:-portal-ap}"
AP_IF="${PORTAL_AP_IF:-wlan0}"
WAN_IF="${PORTAL_WAN_IF:-eth0}"
die() {
echo "Error: $*" >&2
exit 1
}
if [[ "${EUID}" -ne 0 ]]; then
die "run as root: sudo $0"
fi
if ((${#PASSWORD} < 8)); then
die "PORTAL_AP_PASSWORD must be at least 8 characters"
fi
if ! command -v nmcli >/dev/null; then
die "NetworkManager (nmcli) is required"
fi
if ! systemctl is-active --quiet NetworkManager; then
die "NetworkManager is not running"
fi
if ! ip link show "${WAN_IF}" >/dev/null 2>&1; then
die "uplink interface ${WAN_IF} not found"
fi
if ! ip link show "${AP_IF}" >/dev/null 2>&1; then
die "AP interface ${AP_IF} not found"
fi
if ! ip link show "${WAN_IF}" | grep -q "state UP"; then
echo "Warning: ${WAN_IF} is not UP — connect ethernet before clients can reach the internet." >&2
fi
# NM shared AP mode uses hostapd on many Pi images.
if ! command -v hostapd >/dev/null; then
echo "Installing hostapd..."
apt-get update -qq
apt-get install -y hostapd
fi
# Allow forwarding between AP clients and ethernet.
sysctl -w net.ipv4.ip_forward=1 >/dev/null
cat >/etc/sysctl.d/99-portal-ap.conf <<'EOF'
# portal AP: share ethernet to WiFi clients
net.ipv4.ip_forward=1
EOF
rfkill unblock wifi >/dev/null 2>&1 || true
nmcli radio wifi on >/dev/null 2>&1 || true
if nmcli -t -f NAME connection show | grep -Fxq "${CON_NAME}"; then
echo "Updating existing connection '${CON_NAME}'..."
nmcli connection delete "${CON_NAME}" >/dev/null
fi
echo "Creating access point '${SSID}' on ${AP_IF}..."
nmcli connection add type wifi ifname "${AP_IF}" con-name "${CON_NAME}" \
autoconnect yes \
ssid "${SSID}" \
802-11-wireless.mode ap \
802-11-wireless.band bg \
ipv4.method shared \
ipv6.method ignore \
wifi-sec.key-mgmt wpa-psk \
wifi-sec.psk "${PASSWORD}" >/dev/null
# Prefer ethernet for upstream internet when both are available.
nmcli connection modify "${CON_NAME}" ipv4.never-default no
if nmcli -t -f NAME connection show | grep -Fxq "Wired connection 1"; then
nmcli connection modify "Wired connection 1" connection.autoconnect-priority 100
fi
nmcli connection modify "${CON_NAME}" connection.autoconnect-priority 50
echo "Starting access point..."
nmcli connection up "${CON_NAME}"
AP_IP="$(nmcli -g IP4.ADDRESS device show "${AP_IF}" 2>/dev/null | cut -d/ -f1)"
WAN_IP="$(nmcli -g IP4.ADDRESS device show "${WAN_IF}" 2>/dev/null | cut -d/ -f1 || true)"
cat <<EOF
Access point is running.
SSID: ${SSID}
Password: ${PASSWORD}
AP IP: ${AP_IP:-unknown} (${AP_IF})
Uplink: ${WAN_IF} ${WAN_IP:+($WAN_IP)}
Clients receive DHCP from the Pi and internet is shared via NAT through ${WAN_IF}.
The AP starts automatically on boot.
Stop it with:
sudo ./scripts/stop_ap.sh
EOF