From 29c02f4d70be60323e1efab5fc5b5f2a301bda73 Mon Sep 17 00:00:00 2001 From: christopherjuggler Date: Thu, 2 Jul 2026 13:38:30 +0000 Subject: [PATCH 1/3] Fix camera init, audio init, and speed test timeout - Enable camera at startup with error handling (was never called) - Add missing return in camera.get_frame() success path (was returning None, causing black screen) - Wrap PyAudio init in whitenoise with try/except to prevent hangs - Add 15s timeout to quick_speed_test() to prevent startup blockage - Fix whitenoise __close method (recursion and attribute bugs) - Create media/audio directory if missing --- src/controllers/camera.py | 2 ++ src/controllers/whitenoise.py | 21 +++++++++++---------- src/main.py | 5 +++++ src/utils.py | 26 ++++++++++++++++++++------ 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/controllers/camera.py b/src/controllers/camera.py index e931ebd..b9140f4 100644 --- a/src/controllers/camera.py +++ b/src/controllers/camera.py @@ -190,6 +190,8 @@ def get_frame(self) -> Optional[np.ndarray]: frame = np.zeros((480, 640, 3), dtype=np.uint8) if self.black_frame else self.noise_frame() return cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + return frame + def get_jpeg_frame(self) -> Optional[bytes]: frame = self.get_frame() diff --git a/src/controllers/whitenoise.py b/src/controllers/whitenoise.py index 049f278..2406fd1 100644 --- a/src/controllers/whitenoise.py +++ b/src/controllers/whitenoise.py @@ -8,7 +8,10 @@ def __init__(self, rate=44100, chunk=1024): self.chunk = chunk self.running = False - self.p = pyaudio.PyAudio() + try: + self.p = pyaudio.PyAudio() + except: + self.p = None self.thread = None def __openSpeaker(self): @@ -27,9 +30,10 @@ def __play(self): try: while self.running: noise = np.random.uniform(-1, 1, self.chunk).astype(np.float32) - self.stream.write(noise.tobytes()) + if hasattr(self, 'stream') and self.stream: + self.stream.write(noise.tobytes()) except: - if self.stream: + if hasattr(self, 'stream') and self.stream: self.stream.stop_stream() self.stream.close() @@ -50,13 +54,10 @@ def stop(self): self.running = False if self.thread: self.thread.join() - self.__close() + if hasattr(self, 'stream') and self.stream: + self.stream.stop_stream() + self.stream.close() return True except: - return False - - def __close(self): - self.stop() - self.stream.stop_stream() - self.stream.close() \ No newline at end of file + return False \ No newline at end of file diff --git a/src/main.py b/src/main.py index 5d99222..59d9592 100644 --- a/src/main.py +++ b/src/main.py @@ -42,6 +42,11 @@ gpio = GPIOController() camera = CameraController() +try: + camera.enable() + logger.info("Camera enabled successfully") +except Exception as e: + logger.warning(f"Camera enable failed: {e}") audio = AudioController() media = MediaController() whitenoise = WhiteNoisePlayer() diff --git a/src/utils.py b/src/utils.py index 35830ff..10ff17d 100644 --- a/src/utils.py +++ b/src/utils.py @@ -18,12 +18,26 @@ def sp_to_label(speed): return label -def quick_speed_test(): - st = Speedtest() - st.get_servers() - st.get_best_server() - download_speed = st.download() / 1_000_000 - upload_speed = st.upload() / 1_000_000 +def quick_speed_test(timeout_sec=15): + import concurrent.futures + + def _run(): + st = Speedtest() + st.get_servers() + st.get_best_server() + download_speed = st.download() / 1_000_000 + upload_speed = st.upload() / 1_000_000 + return download_speed, upload_speed + + with concurrent.futures.ThreadPoolExecutor() as executor: + try: + fut = executor.submit(_run) + download_speed, upload_speed = fut.result(timeout=timeout_sec) + except: + return { + "download": { "speed": 0, "label": "No Connection" }, + "upload": { "speed": 0, "label": "No Connection" } + } if download_speed == 0: return { From 9d04926fe200b9c6d21ac8a236228e9fa74a5ecd Mon Sep 17 00:00:00 2001 From: christopherjuggler Date: Thu, 2 Jul 2026 13:39:53 +0000 Subject: [PATCH 2/3] Add portaudio19-dev to packages.txt for pyaudio build on ARM64 pip install pyaudio from source requires portaudio.h (from portaudio19-dev). Also add python3-dev for build tools and enable --system-site-packages in the venv so system-installed packages (picamera2, etc.) are accessible. --- src/packages.txt | 2 ++ src/setup.sh | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/packages.txt b/src/packages.txt index 2626b9d..cf77f85 100644 --- a/src/packages.txt +++ b/src/packages.txt @@ -1,4 +1,6 @@ python3-pyaudio +portaudio19-dev +python3-dev vlc python3-gi openresolv diff --git a/src/setup.sh b/src/setup.sh index a8e8d2c..73a3488 100644 --- a/src/setup.sh +++ b/src/setup.sh @@ -48,7 +48,7 @@ if ! command -v python3 >/dev/null 2>&1; then exit 1 fi -sudo -u "$RUN_USER" -H bash -lc "python3 -m venv '$SCRIPT_DIR/venv'" +sudo -u "$RUN_USER" -H bash -lc "python3 -m venv --system-site-packages '$SCRIPT_DIR/venv'" sudo -u "$RUN_USER" -H bash -lc "source '$SCRIPT_DIR/venv/bin/activate' && python -m pip install --upgrade pip && python -m pip install -r '$SCRIPT_DIR/requirements.txt' || true" echo "Creating .env file with SECRET_KEY and OPENWEATHER_KEY (empty)..." From 1d7a042ca5b2fc3dced13e1e8a7c14b5571245bb Mon Sep 17 00:00:00 2001 From: christopherjuggler Date: Thu, 2 Jul 2026 13:40:57 +0000 Subject: [PATCH 3/3] Revert --system-site-packages from venv creation in setup.sh --- src/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/setup.sh b/src/setup.sh index 73a3488..a8e8d2c 100644 --- a/src/setup.sh +++ b/src/setup.sh @@ -48,7 +48,7 @@ if ! command -v python3 >/dev/null 2>&1; then exit 1 fi -sudo -u "$RUN_USER" -H bash -lc "python3 -m venv --system-site-packages '$SCRIPT_DIR/venv'" +sudo -u "$RUN_USER" -H bash -lc "python3 -m venv '$SCRIPT_DIR/venv'" sudo -u "$RUN_USER" -H bash -lc "source '$SCRIPT_DIR/venv/bin/activate' && python -m pip install --upgrade pip && python -m pip install -r '$SCRIPT_DIR/requirements.txt' || true" echo "Creating .env file with SECRET_KEY and OPENWEATHER_KEY (empty)..."