Skip to content

Pan/tilt for Frigate: ONVIF endpoint backed by Baichuan PTZ - #12

Closed
mzspicoli wants to merge 3 commits into
VoltTech21:mainfrom
mzspicoli:ptz-onvif
Closed

mzspicoli wants to merge 3 commits into
VoltTech21:mainfrom
mzspicoli:ptz-onvif

Conversation

@mzspicoli

Copy link
Copy Markdown

Adds pan/tilt for cameras that only speak Baichuan, so Frigate can move them. Follows up on #6, where PTZ was listed as not done yet.

What it does

Frigate steers cameras over ONVIF. A Reolink E1 has no ONVIF of its own, so reostream now serves a small ONVIF endpoint per camera and turns Frigate's requests into Baichuan messages.

[[camera]]
name = "nursery"
...
onvif = "127.0.0.1:8656"
# optional: onvif_user / onvif_password (accept $ENV like the camera's own fields)
# Frigate
cameras:
  nursery:
    onvif: { host: 127.0.0.1, port: 8656 }
  • internal/baichuan/ptz.go: PtzControl (18) move/stop, PtzPreset (19) go to preset, preset list (190), pan/tilt counters (433).
  • internal/ptz: a controller with its own Baichuan session, opened on the first command and closed after 30 s idle. A move nobody stops is stopped after 15 s.
  • internal/onvif: discovery, one profile with a PTZ configuration, ContinuousMove, Stop, GetStatus, GetPresets, GotoPreset, optional WS-Security login (digest or text).
  • Config: onvif, onvif_user, onvif_password on [[camera]]; kept across edits on the camera page; a changed endpoint is reported as needing a restart. Docs in docs/ptz.md.

Video is untouched; PTZ uses a separate session.

Tested on a real Reolink E1

Reolink E1, firmware v3.2.0.4858, running next to a live reostream and Frigate:

  • onvif-zeep-async (the library Frigate uses), run inside the Frigate container against the full reostream binary: profile selection, presets, ContinuousMove, Stop, GetStatus (IDLE/MOVING/IDLE) and GotoPreset all worked, with no login and with a digest login (a wrong password is refused).
  • At the protocol level: left moved the pan counter (ptzcurpos) from 1938 to 1601, right brought it back to 1937, up/down moved tilt, and go-to-preset 0 returned the camera to its starting position.
  • Unit tests for the message documents, the controller (session reuse, idle release, stale-session retry, safety stop), the ONVIF handler (including auth) and the config handling.

Findings worth knowing

  • An E1 answers 200 to diagonal commands (leftUp etc.) and does nothing, so a velocity with both axes set moves along the stronger one.
  • The E1 ignores <speed>: speeds 1 to 100 moved it the same distance in the same time.
  • Reading presets on message 19 answers 200 with an empty body; the list is on 190.

Not covered

  • Only the E1 was tested. Zoom, variable speed and diagonals on other models are untested, so none of them is advertised. No zoom, focus, absolute or relative moves, no saving presets, so no Frigate autotracking.
  • The message bodies were checked against the camera's behaviour and its own replies (pasted verbatim in ptz_test.go), without reading or copying Neolink source. There is no .pcap fixture; if you want one for internal/baichuan/testdata I can capture it.
  • go test ./... passes except six discover_test.go tests in internal/control that need 127.0.0.2, which macOS doesn't allow to bind; unrelated to this change.
  • If trackmix-lens lands first there are two adjacent-line conflicts (config_test.go, camform.go) that keep both sides.

🤖 Generated with Claude Code

mzspicoli and others added 3 commits October 23, 2026 08:00
PtzControl (18) moves and stops, PtzPreset (19) goes to a saved position,
the preset list is read with 190 and the pan/tilt counters with 433.
Checked on a Reolink E1: each command moved the pan counter and the
opposite one brought it back; a diagonal is answered 200 and ignored.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The controller keeps its own Baichuan session, opened on the first
command and closed after 30s idle, and stops a move nobody stopped.
The ONVIF handler serves what Frigate's client needs: discovery, one
profile with a PTZ configuration, continuous move, stop, status and
presets, with optional WS-Security login.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Adds onvif, onvif_user and onvif_password to [[camera]], keeps them
across edits on the camera page, flags a changed endpoint as needing a
restart, and documents it in docs/ptz.md.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@VoltTech21

Copy link
Copy Markdown
Owner

Thanks a ton for putting this together, it's a great idea! I won't be merging outside code due to licensing, but PTZ for Frigate is on my list now and I'll ping you here when it's in so you can test it on your E1. Thanks!

@VoltTech21 VoltTech21 closed this Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants