pyronear / pyronear/pyro-engine

Patrol thread can hang forever and freeze latest_image

Open
#421 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
19
Forks
8
PR merge metrics
No merged PRs in 30d

Description

The camera API can serve frozen images for hours while everything looks healthy.

Seen on 2026-09-16 at chateau-eau-douadic (Pi 192.168.255.170, two Reolink cameras):

  • latest_image returned the exact same JPEG for all 8 camera/pose pairs over 12 minutes
  • camera 192.168.1.11 served a night IR frame at 12:05, while a live capture on the same camera at the same second returned a sharp daylight image
  • the engine kept scoring those dead frames and logging No wildfire, so the site was blind with no error anywhere

Cause

The patrol thread was alive but blocked in a PTZ call. In camera/adapters/reolink.py the 9 requests.post calls have no timeout, so move_camera, called by patrol_loop, can wait forever. The stop flag was set meanwhile and the frozen thread never saw it.

From there the API cannot recover:

  • start_patrol only checks thread.is_alive(), so it answers already_running and never starts a new thread
  • patrol_status also checks the flag, so it answers patrol_running: false
  • last_images is never updated again, and latest_image carries no timestamp, so nobody can tell the frame is old
  • the stuck detector skips when the patrol is not running, which is exactly this case

What to change

  1. Add a default timeout to every request in the Reolink adapter, with one helper instead of 9 call sites.
  2. Share one "is patrol running" check, and let start_patrol replace a thread that is alive but has its flag set.
  3. Store the capture time with each image in last_images, expose it, and let the engine refuse a frame that is too old.
  4. Do not disable the stuck detector when the patrol is not running.
  5. Engine side: core.py stops the patrol only when it is already stopped (inverted condition), and is_day is overwritten at each pose, so the last camera of the loop decides day or night for the whole site.

Workaround

Restart the camera API container. The engine starts a clean patrol on the next cycle.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with camera/adapters/reolink.py and trace move_camera through patrol_loop, then inspect the patrol state and image handling named in the issue. Read core.py for the inverted stop condition and is_day overwrite. Done means stalled requests recover, patrol status and replacement behave consistently, image age is exposed and enforced, the detector still checks stopped patrols, and day/night state is correct across poses.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend, embedded-iot
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.