Skip to content
Open
46 changes: 33 additions & 13 deletions helpers/cfgsetup.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,56 @@
# -*- coding: utf-8 -*-
"""Automatically generate a unique SSID for the MyNaturewatch WiFi hotspot,
based on the Pi's serial number."""
based on the Pi's serial number, and bring the hotspot up.

Works with both the onboard WiFi and USB WiFi dongles: it waits for a wireless
interface to appear (USB adapters enumerate a few seconds later than onboard
WiFi) and auto-detects its name instead of assuming it is called 'wlan0'.
"""
import glob
import os
import subprocess
import time

# Get SSID and passphrase from hostapd.conf
#HOST_CONFIG_FILE_PATH = "/etc/hostapd/hostapd.conf"

#with open(HOST_CONFIG_FILE_PATH, "r", encoding="utf-8") as config_file:
# host_config_file = config_file.readlines()
def find_wifi_interface(timeout=90):
"""Return the name of the first wireless interface, waiting up to `timeout`
seconds for one to appear (a USB dongle can take a few seconds to come up)."""
for _ in range(timeout):
for marker in ("/sys/class/net/*/wireless", "/sys/class/net/*/phy80211"):
found = glob.glob(marker)
if found:
return found[0].split("/")[-2]
time.sleep(1)
return None


#current_ssid = host_config_file[2][5:].strip()
#print(f"hostapd configuration - SSID: {current_ssid}")
# Wait for and detect the wireless interface (onboard WiFi or a USB dongle)
iface = find_wifi_interface()
if iface is None:
print("No wireless interface found; cannot start the hotspot.")
raise SystemExit(1)
print("Using wireless interface: " + iface)

# Generate a unique SSID based on the Pi's serial number
unique_id = subprocess.check_output(
r"sed -n 's/^Serial\s*: 0*//p' /proc/cpuinfo", shell=True
)
unique_ssid = f"MyNaturewatch-{unique_id.strip().decode('utf-8')[-8:]}"

#if unique_ssid == current_ssid:
# print("Unique SSID already set, no further action is needed.")
#else:
print("Updating hotspot")

os.system("sudo iw reg set GB")
os.system("sudo nmcli r wifi on")
os.system("sudo nmcli r wifi on")
os.system("sudo nmcli con delete id Hotspot")
os.system("sudo nmcli con add type wifi con-name hotspot")
os.system("sudo nmcli device wifi hotspot ssid " + unique_ssid + " password badgersandfoxes ifname wlan0")
os.system("sudo nmcli device wifi hotspot ssid " + unique_ssid + " password badgersandfoxes ifname " + iface)
os.system("sudo nmcli connection modify Hotspot connection.autoconnect yes")
# Force plain WPA2-PSK (RSN/CCMP) and disable management-frame protection.
# NetworkManager 1.42 otherwise runs the hotspot in WPA2/WPA3 "transition mode"
# (key_mgmt "WPA-PSK WPA-PSK-SHA256 SAE"), which many USB WiFi drivers can't do
# properly in AP mode -- the network then won't show on some phones and fails the
# handshake on others. Plain WPA2 works on every modern client.
os.system("sudo nmcli connection modify Hotspot wifi-sec.key-mgmt wpa-psk wifi-sec.proto rsn wifi-sec.pairwise ccmp wifi-sec.group ccmp wifi-sec.pmf 1")
os.system("sudo systemctl restart NetworkManager")
time.sleep(5)
time.sleep(5)
os.system("sudo nmcli con up Hotspot")
35 changes: 32 additions & 3 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,50 @@ echo -e "dtparam=act_led_activelow=on" >> $CONFIG_FILE
echo -e "# Set CPU speed to 600MHz - fixes unstable WiFi issue" >> $CONFIG_FILE
echo -e "arm_freq=600" >> $CONFIG_FILE

# The bundled CustomPiOS 'raspicam' module enables the LEGACY camera stack
# (start_x=1, camera_auto_detect=0) meant for raspistill/MMAL. This image uses
# picamera2/libcamera, which needs the modern path -- with start_x=1 set, the
# Pi Camera Module is never detected. Switch to libcamera auto-detection.
sed -i 's/^start_x=1/start_x=0/' /boot/firmware/config.txt
sed -i 's/^camera_auto_detect=.*/camera_auto_detect=1/' /boot/firmware/config.txt

# Copy to installation path
mkdir -p $INSTALLATION_PATH/NaturewatchCameraServer >/dev/null 2>&1
cp -r $DIR $INSTALLATION_PATH >/dev/null 2>&1

# Update and upgrade
# Make apt/dpkg fully non-interactive so a modified-config-file prompt
# (e.g. /etc/initramfs-tools/initramfs.conf) can't stall an automated build.
# Writing this apt.conf.d drop-in makes EVERY apt-get below inherit it.
export DEBIAN_FRONTEND=noninteractive
cat > /etc/apt/apt.conf.d/99naturewatch-noninteractive <<'APTEOF'
Dpkg::Options {
"--force-confdef";
"--force-confold";
}
APT::Get::Assume-Yes "true";
APTEOF

# Update package lists only.
# NOTE: full 'apt-get upgrade' / 'dist-upgrade' is intentionally NOT run here.
# On the (now older) pinned base image it pulls a large kernel upgrade and then
# hangs forever regenerating the arm64 (v8) initramfs under 32-bit armhf QEMU
# emulation. The base image's own kernel runs the camera fine; every package we
# actually need is installed explicitly below.
apt-get clean
apt-get update
apt-get upgrade -y
apt-get dist-upgrade -y

# Install extra packages (with specific versions) to avoid breaking the system:
# apt list python3-picamera2 git python3-pip python3-libcamera libcap-dev ffmpeg python3-flask python3-numpy python3-opencv python3-kms++ --installed
apt-get install -y python3-picamera2 --no-install-recommends
apt-get install -y git python3-pip python3-libcamera libcap-dev ffmpeg python3-flask python3-numpy python3-opencv python3-kms++

# Bring the libcamera stack up to the build that matches the installed libpisp.
# The base image can ship an older libcamera0.3 built against a different libpisp,
# so rpicam / picamera2 crash with an undefined-symbol error
# (libpisp ... compute_optimal_stride). This upgrades ONLY the camera libraries
# (no kernel), so it won't trigger a full-image upgrade / initramfs rebuild.
apt-get install -y --only-upgrade libcamera0.3 libcamera-ipa python3-libcamera python3-picamera2

# Setup a venv
python -m venv --system-site-packages ${INSTALLATION_PATH}/NaturewatchCameraServer/.venv

Expand Down
3 changes: 2 additions & 1 deletion os/config
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export BASE_IMAGE_ENLARGEROOT=2000
export AUTO_HOTSPOT_NAME=MyNaturewatch
export AUTO_HOTSPOT_PASSWORD=badgersandfoxes
export options loop max_loop=128
export ADMIN_TOOLKIT_UPDATE_PACKAGES=yes
export ADMIN_TOOLKIT_UPDATE_PACKAGES=no
export ADMIN_TOOLKIT_NAME=pi
export ADMIN_TOOLKIT_PASSWORD=badgersandfoxes