From fab6964d6cc2fbf9b1a7072cefd83b2c55382400 Mon Sep 17 00:00:00 2001 From: Mark Pinsk <6782903+mrribbits@users.noreply.github.com> Date: Sat, 25 Jul 2026 13:29:07 -0400 Subject: [PATCH 01/12] Modify package upgrade commands in install.sh Refactor apt-get commands to use Dpkg options for upgrades. --- install.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index a5dbbc6..da96a5a 100644 --- a/install.sh +++ b/install.sh @@ -46,10 +46,11 @@ mkdir -p $INSTALLATION_PATH/NaturewatchCameraServer >/dev/null 2>&1 cp -r $DIR $INSTALLATION_PATH >/dev/null 2>&1 # Update and upgrade +export DEBIAN_FRONTEND=noninteractive apt-get clean apt-get update -apt-get upgrade -y -apt-get dist-upgrade -y +apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade +apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" dist-upgrade # 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 From 84fa157da8a0b159ffd35ddd2f3179a37a2e7caa Mon Sep 17 00:00:00 2001 From: Mark Pinsk <6782903+mrribbits@users.noreply.github.com> Date: Sat, 25 Jul 2026 13:52:37 -0400 Subject: [PATCH 02/12] Enhance install.sh for non-interactive apt operations Refactor install script to improve non-interactive apt handling and streamline installation process. --- install.sh | 56 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/install.sh b/install.sh index da96a5a..0059c4c 100644 --- a/install.sh +++ b/install.sh @@ -1,20 +1,20 @@ #!/bin/bash # chmod +x install.sh - + # Check for sudo permissions if [ $EUID != 0 ]; then echo "Launch the script as sudo" sudo "$0" "$@" exit $? fi - + echo "-----------------------------------------" - + # Extract argument passed to the script # $1 is the installation path INSTALLATION_PATH="$1" echo "Installation path: $INSTALLATION_PATH" - + # Get install.sh parent directory SOURCE="${BASH_SOURCE:-0}" while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink @@ -24,7 +24,7 @@ while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symli [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" done DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" - + # Append to config file /boot/config.txt CONFIG_FILE="/boot/firmware/config.txt" # echo -e "\n" >> $CONFIG_FILE @@ -33,55 +33,66 @@ echo -e "\n# Deactivate the activity LED\ndtparam=act_led_trigger=none" >> $CONF 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 - + # I'm not sure about the config path, so let also modify the legacy one. CONFIG_FILE="/boot/config.txt" echo -e "\n# Deactivate the activity LED\ndtparam=act_led_trigger=none" >> $CONFIG_FILE 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 - + # 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 and upgrade apt-get clean apt-get update -apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade -apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" dist-upgrade - +apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade -y +apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" 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++ - + # Setup a venv python -m venv --system-site-packages ${INSTALLATION_PATH}/NaturewatchCameraServer/.venv - + # Remove unnecessary packages apt-get autoremove -y - + pushd $INSTALLATION_PATH pushd NaturewatchCameraServer - + # Install python dependencies ${INSTALLATION_PATH}/NaturewatchCameraServer/.venv/bin/pip install -r requirements.txt - + echo "Adding services" # Allows to reinstall the service systemctl stop python.naturewatch.service >/dev/null 2>&1 systemctl stop wifisetup.service >/dev/null 2>&1 - + # Copy service files to /etc/systemd/system and replace ${path} with the installation path root TEMPLATES="${DIR}/helpers" sed -e "s|\${path}|${INSTALLATION_PATH}|g" "${TEMPLATES}/python.naturewatch.service" > "/etc/systemd/system/python.naturewatch.service" sed -e "s|\${path}|${INSTALLATION_PATH}|g" "${TEMPLATES}/wifisetup.service" > "/etc/systemd/system/wifisetup.service" - + popd popd - + echo "Enabling and starting services" chmod 644 /etc/systemd/system/python.naturewatch.service chmod 644 /etc/systemd/system/wifisetup.service @@ -90,8 +101,9 @@ systemctl enable python.naturewatch.service systemctl enable wifisetup.service systemctl start python.naturewatch.service systemctl start wifisetup.service - + # Add Watchdog script to crontab (crontab -l 2>/dev/null; echo "# Start watchdog script at boot time") | crontab - (crontab -l 2>/dev/null; echo "@reboot ${TEMPLATES}/watchdog.sh > /dev/null 2>&1") | crontab - - + + From 2a0256abb820ea8313dc78cd9fcc511788331b6e Mon Sep 17 00:00:00 2001 From: Mark Pinsk <6782903+mrribbits@users.noreply.github.com> Date: Sat, 25 Jul 2026 14:20:33 -0400 Subject: [PATCH 03/12] Make CustomPiOS apt upgrade non-interactive Patched apt upgrade command in CustomPiOS to be non-interactive during build. --- .github/workflows/build-image.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml index c801410..a7f2c44 100644 --- a/.github/workflows/build-image.yml +++ b/.github/workflows/build-image.yml @@ -18,6 +18,17 @@ jobs: ref: devel path: CustomPiOS + - name: Make CustomPiOS apt upgrade non-interactive + run: | + # CustomPiOS's admin-toolkit module runs `apt-get upgrade -y` with no + # dpkg conffile options, so a modified /etc/initramfs-tools/initramfs.conf + # triggers an interactive prompt that fails the (non-interactive) build. + # Force dpkg to keep existing config files instead of prompting. + sed -i 's|apt-get upgrade -y|apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade -y|g' \ + CustomPiOS/src/modules/admin-toolkit/start_chroot_script + echo "----- patched line -----" + grep -n "apt-get .*upgrade" CustomPiOS/src/modules/admin-toolkit/start_chroot_script + - name: Checkout Project Repository uses: actions/checkout@v2 with: From d7ac0910a45e5ef2ecc1b957e287b1610b9802b7 Mon Sep 17 00:00:00 2001 From: Mark Pinsk <6782903+mrribbits@users.noreply.github.com> Date: Sat, 25 Jul 2026 15:55:54 -0400 Subject: [PATCH 04/12] Change ADMIN_TOOLKIT_UPDATE_PACKAGES to 'no' --- os/config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/os/config b/os/config index ca56a4a..f0af3b5 100644 --- a/os/config +++ b/os/config @@ -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 + From cf0e1863d958717179bbbe919f2205f180819bd4 Mon Sep 17 00:00:00 2001 From: Mark Pinsk <6782903+mrribbits@users.noreply.github.com> Date: Sat, 25 Jul 2026 15:56:44 -0400 Subject: [PATCH 05/12] Clarify apt-get upgrade and dist-upgrade comments Updated install.sh to clarify upgrade process and avoid kernel issues. --- install.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/install.sh b/install.sh index 0059c4c..f66dfb3 100644 --- a/install.sh +++ b/install.sh @@ -57,11 +57,14 @@ Dpkg::Options { APT::Get::Assume-Yes "true"; APTEOF -# Update and upgrade +# 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 -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade -y -apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" 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 @@ -106,4 +109,3 @@ systemctl start wifisetup.service (crontab -l 2>/dev/null; echo "# Start watchdog script at boot time") | crontab - (crontab -l 2>/dev/null; echo "@reboot ${TEMPLATES}/watchdog.sh > /dev/null 2>&1") | crontab - - From 2e6efabc6d6fe0e0e5acb66b8bc63a9d8768af3a Mon Sep 17 00:00:00 2001 From: Mark Pinsk <6782903+mrribbits@users.noreply.github.com> Date: Sun, 26 Jul 2026 23:25:04 -0400 Subject: [PATCH 06/12] Simplify build workflow by removing upgrade patching Removed non-interactive upgrade patching step for CustomPiOS. --- .github/workflows/build-image.yml | 38 ++++++++++++------------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml index a7f2c44..32b7ddd 100644 --- a/.github/workflows/build-image.yml +++ b/.github/workflows/build-image.yml @@ -1,7 +1,7 @@ --- name: Build Image on: [push, pull_request, workflow_dispatch] - + jobs: build: runs-on: ubuntu-latest @@ -10,53 +10,42 @@ jobs: run: | sudo apt-get update sudo apt-get install coreutils p7zip-full qemu-user-static python3-git - + - name: Checkout CustomPiOS uses: actions/checkout@v2 with: repository: "guysoft/CustomPiOS" ref: devel path: CustomPiOS - - - name: Make CustomPiOS apt upgrade non-interactive - run: | - # CustomPiOS's admin-toolkit module runs `apt-get upgrade -y` with no - # dpkg conffile options, so a modified /etc/initramfs-tools/initramfs.conf - # triggers an interactive prompt that fails the (non-interactive) build. - # Force dpkg to keep existing config files instead of prompting. - sed -i 's|apt-get upgrade -y|apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade -y|g' \ - CustomPiOS/src/modules/admin-toolkit/start_chroot_script - echo "----- patched line -----" - grep -n "apt-get .*upgrade" CustomPiOS/src/modules/admin-toolkit/start_chroot_script - + - name: Checkout Project Repository uses: actions/checkout@v2 with: repository: ${{ github.repository }} path: repository - + - name: Setup node uses: actions/setup-node@v3 with: node-version: 12 - + - name: Build React frontend run: | pushd repository/naturewatch_camera_server/static/client npm i -y npm run build popd - + - name: Download Raspbian Image run: | cd repository/os/image wget -q -c --trust-server-names 'https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2024-11-19/2024-11-19-raspios-bookworm-armhf-lite.img.xz' - + - name: Update CustomPiOS Paths run: | cd repository/os ../../CustomPiOS/src/update-custompios-paths - + - name: Copy NaturewatchCameraServer to CustomPiOS directory run: | cp -r repository /tmp/NaturewatchCameraServer @@ -67,7 +56,7 @@ jobs: cp -r /tmp/NaturewatchCameraServer repository/os/modules/naturewatchcamera/filesystem/home/pi rm -rf /tmp/NaturewatchCameraServer ls repository/os/modules/naturewatchcamera/filesystem/home/pi/NaturewatchCameraServer - + - name: Build Image run: | export BASE_IMAGE_ENLARGEROOT=2000 @@ -76,17 +65,17 @@ jobs: # export AUTO_HOTSPOT_PASSWORD=badgersandfoxes sudo modprobe loop && cd repository/os sudo bash -x ./build_dist - + - name: Copy Output run: cp ${{ github.workspace }}/repository/os/workspace/*lite.img mynaturewatch-camera.img - + - name: Zip Output run: gzip mynaturewatch-camera.img - uses: actions/upload-artifact@v4 with: name: mynaturewatch-camera.img.gz path: mynaturewatch-camera.img.gz - + - name: Create Release id: create_release uses: actions/create-release@v1 @@ -98,7 +87,7 @@ jobs: release_name: My Naturewatch Camera ${{ github.ref }} draft: true prerelease: false - + - name: Upload Release id: upload-release-asset uses: actions/upload-release-asset@v1 @@ -110,3 +99,4 @@ jobs: asset_path: mynaturewatch-camera.img.gz asset_name: mynaturewatch-camera.img.gz asset_content_type: application/octet-stream + From e4e2511bd339222ef997c8375fb74f47515ee636 Mon Sep 17 00:00:00 2001 From: Mark Pinsk <6782903+mrribbits@users.noreply.github.com> Date: Sun, 26 Jul 2026 23:33:18 -0400 Subject: [PATCH 07/12] Fix missing newline at end of build-image.yml Add a newline at the end of the build-image.yml file. From e3be5193cbdfef27fc036a9856e1ba6def0da5ff Mon Sep 17 00:00:00 2001 From: Mark Pinsk <6782903+mrribbits@users.noreply.github.com> Date: Sun, 26 Jul 2026 23:42:29 -0400 Subject: [PATCH 08/12] Update GitHub Actions workflow for image build --- .github/workflows/build-image.yml | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml index 32b7ddd..c801410 100644 --- a/.github/workflows/build-image.yml +++ b/.github/workflows/build-image.yml @@ -1,7 +1,7 @@ --- name: Build Image on: [push, pull_request, workflow_dispatch] - + jobs: build: runs-on: ubuntu-latest @@ -10,42 +10,42 @@ jobs: run: | sudo apt-get update sudo apt-get install coreutils p7zip-full qemu-user-static python3-git - + - name: Checkout CustomPiOS uses: actions/checkout@v2 with: repository: "guysoft/CustomPiOS" ref: devel path: CustomPiOS - + - name: Checkout Project Repository uses: actions/checkout@v2 with: repository: ${{ github.repository }} path: repository - + - name: Setup node uses: actions/setup-node@v3 with: node-version: 12 - + - name: Build React frontend run: | pushd repository/naturewatch_camera_server/static/client npm i -y npm run build popd - + - name: Download Raspbian Image run: | cd repository/os/image wget -q -c --trust-server-names 'https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2024-11-19/2024-11-19-raspios-bookworm-armhf-lite.img.xz' - + - name: Update CustomPiOS Paths run: | cd repository/os ../../CustomPiOS/src/update-custompios-paths - + - name: Copy NaturewatchCameraServer to CustomPiOS directory run: | cp -r repository /tmp/NaturewatchCameraServer @@ -56,7 +56,7 @@ jobs: cp -r /tmp/NaturewatchCameraServer repository/os/modules/naturewatchcamera/filesystem/home/pi rm -rf /tmp/NaturewatchCameraServer ls repository/os/modules/naturewatchcamera/filesystem/home/pi/NaturewatchCameraServer - + - name: Build Image run: | export BASE_IMAGE_ENLARGEROOT=2000 @@ -65,17 +65,17 @@ jobs: # export AUTO_HOTSPOT_PASSWORD=badgersandfoxes sudo modprobe loop && cd repository/os sudo bash -x ./build_dist - + - name: Copy Output run: cp ${{ github.workspace }}/repository/os/workspace/*lite.img mynaturewatch-camera.img - + - name: Zip Output run: gzip mynaturewatch-camera.img - uses: actions/upload-artifact@v4 with: name: mynaturewatch-camera.img.gz path: mynaturewatch-camera.img.gz - + - name: Create Release id: create_release uses: actions/create-release@v1 @@ -87,7 +87,7 @@ jobs: release_name: My Naturewatch Camera ${{ github.ref }} draft: true prerelease: false - + - name: Upload Release id: upload-release-asset uses: actions/upload-release-asset@v1 @@ -99,4 +99,3 @@ jobs: asset_path: mynaturewatch-camera.img.gz asset_name: mynaturewatch-camera.img.gz asset_content_type: application/octet-stream - From 61491ea20af23deb62ace58d0860c6a18381e486 Mon Sep 17 00:00:00 2001 From: Mark Pinsk <6782903+mrribbits@users.noreply.github.com> Date: Sun, 26 Jul 2026 23:53:28 -0400 Subject: [PATCH 09/12] Add files via upload --- install.sh | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/install.sh b/install.sh index f66dfb3..d34718b 100644 --- a/install.sh +++ b/install.sh @@ -1,20 +1,20 @@ #!/bin/bash # chmod +x install.sh - + # Check for sudo permissions if [ $EUID != 0 ]; then echo "Launch the script as sudo" sudo "$0" "$@" exit $? fi - + echo "-----------------------------------------" - + # Extract argument passed to the script # $1 is the installation path INSTALLATION_PATH="$1" echo "Installation path: $INSTALLATION_PATH" - + # Get install.sh parent directory SOURCE="${BASH_SOURCE:-0}" while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink @@ -24,7 +24,7 @@ while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symli [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" done DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" - + # Append to config file /boot/config.txt CONFIG_FILE="/boot/firmware/config.txt" # echo -e "\n" >> $CONFIG_FILE @@ -33,18 +33,18 @@ echo -e "\n# Deactivate the activity LED\ndtparam=act_led_trigger=none" >> $CONF 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 - + # I'm not sure about the config path, so let also modify the legacy one. CONFIG_FILE="/boot/config.txt" echo -e "\n# Deactivate the activity LED\ndtparam=act_led_trigger=none" >> $CONFIG_FILE 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 - + # Copy to installation path mkdir -p $INSTALLATION_PATH/NaturewatchCameraServer >/dev/null 2>&1 cp -r $DIR $INSTALLATION_PATH >/dev/null 2>&1 - + # 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. @@ -56,7 +56,7 @@ Dpkg::Options { } 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 @@ -65,37 +65,37 @@ APTEOF # actually need is installed explicitly below. apt-get clean apt-get update - + # 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++ - + # Setup a venv python -m venv --system-site-packages ${INSTALLATION_PATH}/NaturewatchCameraServer/.venv - + # Remove unnecessary packages apt-get autoremove -y - + pushd $INSTALLATION_PATH pushd NaturewatchCameraServer - + # Install python dependencies ${INSTALLATION_PATH}/NaturewatchCameraServer/.venv/bin/pip install -r requirements.txt - + echo "Adding services" # Allows to reinstall the service systemctl stop python.naturewatch.service >/dev/null 2>&1 systemctl stop wifisetup.service >/dev/null 2>&1 - + # Copy service files to /etc/systemd/system and replace ${path} with the installation path root TEMPLATES="${DIR}/helpers" sed -e "s|\${path}|${INSTALLATION_PATH}|g" "${TEMPLATES}/python.naturewatch.service" > "/etc/systemd/system/python.naturewatch.service" sed -e "s|\${path}|${INSTALLATION_PATH}|g" "${TEMPLATES}/wifisetup.service" > "/etc/systemd/system/wifisetup.service" - + popd popd - + echo "Enabling and starting services" chmod 644 /etc/systemd/system/python.naturewatch.service chmod 644 /etc/systemd/system/wifisetup.service @@ -104,8 +104,8 @@ systemctl enable python.naturewatch.service systemctl enable wifisetup.service systemctl start python.naturewatch.service systemctl start wifisetup.service - + # Add Watchdog script to crontab (crontab -l 2>/dev/null; echo "# Start watchdog script at boot time") | crontab - (crontab -l 2>/dev/null; echo "@reboot ${TEMPLATES}/watchdog.sh > /dev/null 2>&1") | crontab - - + From 4eaf6937b75c98a728b6fba75a1a4c4484a3159f Mon Sep 17 00:00:00 2001 From: Mark Pinsk <6782903+mrribbits@users.noreply.github.com> Date: Sat, 8 Aug 2026 16:43:44 -0400 Subject: [PATCH 10/12] Add files via upload --- helpers/cfgsetup.py | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/helpers/cfgsetup.py b/helpers/cfgsetup.py index 8b40f4c..9104ca0 100644 --- a/helpers/cfgsetup.py +++ b/helpers/cfgsetup.py @@ -1,18 +1,35 @@ # -*- 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( @@ -20,17 +37,14 @@ ) 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") os.system("sudo systemctl restart NetworkManager") -time.sleep(5) +time.sleep(5) os.system("sudo nmcli con up Hotspot") From 8ef26768e162e7c5cf377185c78cf2c0153bad5d Mon Sep 17 00:00:00 2001 From: Mark Pinsk <6782903+mrribbits@users.noreply.github.com> Date: Sat, 8 Aug 2026 22:49:46 -0400 Subject: [PATCH 11/12] Add files via upload --- install.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/install.sh b/install.sh index d34718b..a15a9cc 100644 --- a/install.sh +++ b/install.sh @@ -41,6 +41,13 @@ 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 @@ -71,6 +78,13 @@ apt-get update 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 From 4b0b1296f5100dea21137e9c03615f76e1486aac Mon Sep 17 00:00:00 2001 From: Mark Pinsk <6782903+mrribbits@users.noreply.github.com> Date: Sat, 8 Aug 2026 22:50:04 -0400 Subject: [PATCH 12/12] Add files via upload --- helpers/cfgsetup.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/helpers/cfgsetup.py b/helpers/cfgsetup.py index 9104ca0..34806b0 100644 --- a/helpers/cfgsetup.py +++ b/helpers/cfgsetup.py @@ -45,6 +45,12 @@ def find_wifi_interface(timeout=90): os.system("sudo nmcli con add type wifi con-name hotspot") 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) os.system("sudo nmcli con up Hotspot")