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>
118 lines
3.4 KiB
Bash
Executable File
118 lines
3.4 KiB
Bash
Executable File
#!/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
|