Skip to content

About

onvif implementation for waveshare tharmal hat on raspberry pi. You can use your raspberry pi as low-cost thermal surveillance camera with this.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

Thermal Camera ONVIF Server

Python ONVIF IP-camera server for Raspberry Pi with the Waveshare Thermal Camera HAT (Meridian Innovation MI48 sensor, 80×62 px). Reads frames via SPI, renders them as a colour-mapped MJPEG stream with a live temperature scale, and exposes a full ONVIF interface so any NVR or VMS can discover and connect to it like a regular IP camera.

A separate mediamtx service transcodes the MJPEG stream to H.264 and serves it over standard RTSP (port 554) for NVRs that require it.


Features

  • Full ONVIF profile – Device, Media, and Events services over SOAP/HTTP
  • WS-Security UsernameToken – PasswordDigest and PasswordText (Synology-compatible)
  • MJPEG HTTP stream – direct access via browser, VLC, or any HTTP client
  • H.264 RTSP stream – via mediamtx on standard port 554, tested with Synology Surveillance Station
  • Motion detection – ONVIF PullPoint events (tns1:VideoSource/MotionAlarm) based on per-pixel temperature change
  • Thermal image pipeline – Gaussian spatial smoothing → motion-adaptive temporal EMA → percentile normalisation → JET colormap → 640×480 upscale
  • Live temperature scale – 80 px colorbar strip with 5 tick labels and date/time stamp, cached and updated only when the scene range shifts
  • Single-file server – everything in onvif_thermal_server.py, easy to audit and deploy
  • systemd services – auto-start and auto-restart for both the Python server and the RTSP gateway

Hardware

Component Detail
Board Raspberry Pi (tested on Pi 3 / 4, 64-bit OS)
Sensor Meridian Innovation MI48 – 80×62 pixels, up to 25.5 FPS
HAT Waveshare Thermal Camera HAT
Interface SPI (frames) + I²C (control)

GPIO wiring

Signal BCM GPIO RPi pin
SPI CS_N 7 26
DATA_READY 24 18
RESET_N 23 16
SPI CLK 11 23
SPI MOSI 10 19
SPI MISO 9 21
I²C SDA 2 3
I²C SCL 3 5

CS is driven manually via GPIO (spi.no_cs = True). Read sequence: assert CS → 100 µs → mi48.read() → 100 µs → deassert CS.


Architecture

MI48 sensor (SPI)
      │
      ▼
camera thread          ─────────────────────────────────
  Gaussian smooth                                       │
  Temporal EMA                                         │  ffmpeg
  Percentile norm      → _latest_jpeg (JPEG, 720×480)  │  MJPEG → H.264
  JET colormap                │                        │  libx264 baseline
  Colorbar + timestamp        │                        │  1500 kbps, 25 fps
                              │                        │  (internal TCP)
                        HTTP :8000                     │
                    ┌─────────┼──────┐           mediamtx :554
                    ▼         ▼      ▼                 │
                 /stream  /snapshot  ONVIF SOAP    /thermal (RTSP/H.264)
                  MJPEG    JPEG    device_service        │
                              media_service         ─────────────────────
                              events_service        NVR / VLC / ffplay
                    │              │
                 browsers      Synology SS
                  VLC          Blue Iris
                               Milestone …

Installation

git clone <this-repo> /home/pi/thermalcam_onvif
cd /home/pi/thermalcam_onvif
sudo bash setup.sh

setup.sh is idempotent – safe to re-run after updates. It:

  1. Installs system packages (python3-numpy, python3-opencv, ffmpeg, …)
  2. Installs the pysenxor driver (Meridian Innovation, bundled in Thermal_Camera_Hat/)
  3. Enables SPI and I²C via raspi-config
  4. Adds dtoverlay=spi0-0cs to /boot/config.txt – required so the MI48's manual GPIO chip-select (BCM7) doesn't conflict with the SPI hardware CS line
  5. Creates default auth.json if absent
  6. Downloads mediamtx v1.17.1 (arm64)
  7. Writes /etc/mediamtx/mediamtx.yml
  8. Installs and starts both systemd services

Reboot required on first install. If config.txt was modified (step 4), setup.sh will print a reminder. The thermal camera HAT will not be accessible until after sudo reboot.

Manual dependency install (without setup.sh)

sudo apt install python3-numpy python3-opencv python3-smbus python3-spidev python3-gpiozero ffmpeg
pip3 install -e Thermal_Camera_Hat/pysenxor-master/
sudo raspi-config   # → Interface Options → SPI + I²C

Credentials

auth.json in the project directory (single source of truth for HTTP, ONVIF, and RTSP):

{
  "admin": {"password": "admin"},
  "user":  {"password": "password"}
}

Change before deployment. Changes require a service restart:

sudo systemctl restart onvif-thermal.service

Running

# Foreground (development / debugging)
sudo python3 onvif_thermal_server.py

# Service management
sudo systemctl start   onvif-thermal.service
sudo systemctl stop    onvif-thermal.service
sudo systemctl restart onvif-thermal.service
sudo systemctl status  onvif-thermal.service
sudo journalctl -u onvif-thermal.service -f

# RTSP gateway
sudo systemctl restart mediamtx.service
sudo journalctl -u mediamtx.service -f

# Log file
tail -f /var/log/onvif-thermal.log

Ports

Port Protocol Service Description
8000 TCP onvif-thermal MJPEG stream, JPEG snapshot, ONVIF SOAP, rtsp_auth
554 TCP mediamtx RTSP H.264 (standard port)
5000 UDP mediamtx RTP (RTSP media data)
5001 UDP mediamtx RTCP (RTSP timing/control)

No WS-Discovery (UDP 3702) – add the camera manually in your NVR using the IP and port 8000.


Endpoints

All HTTP endpoints require Basic Auth.

Path Method Description
/stream GET MJPEG live stream
/snapshot GET Single JPEG frame
/onvif/device_service POST ONVIF Device SOAP
/onvif/media_service POST ONVIF Media SOAP
/onvif/events_service POST ONVIF Events / PullPoint SOAP
/onvif/events GET Motion status (XML)

Quick test

# Snapshot
curl -u admin:admin http://localhost:8000/snapshot -o snap.jpg

# Live stream (Ctrl-C to stop)
curl -u admin:admin http://localhost:8000/stream

# RTSP stream
ffplay rtsp://admin:admin@localhost/thermal
vlc    rtsp://admin:admin@<pi-ip>/thermal

Frame layout

┌────────────────────┬──────────────────┐
│                    │ ▓ 34.1°C         │
│   640×480 thermal  │ ▒                │
│   (JET colormap)   │ ░ 26.3°C         │
│                    │                  │
│                    │   14.04.26       │
│                    │   23:07:21       │
│                    │                  │
│                    │ ░ 18.7°C         │
└────────────────────┴──────────────────┘
         640 px              80 px

Total output: 720×480 px. The 80 px colorbar shows the JET gradient, 5 temperature tick labels, and a date/time stamp. The range is set to the 0.5th–99.5th percentile of the current frame so small hot spots always appear on the scale.


NVR / VMS integration

Generic ONVIF

Point your NVR at http://<pi-ip>:8000/onvif/device_service. The server advertises ONVIF Device, Media, and Events services. Motion alarms are delivered via CreatePullPointSubscription / PullMessages.

Supported ONVIF operations: see TECHREF.md.

RTSP (direct, without ONVIF)

rtsp://admin:admin@<pi-ip>/thermal

H.264 Constrained Baseline, 720×480, 25 fps, 1500 kbps.


Synology Surveillance Station

Via ONVIF (recommended)

The server fully supports WS-Security UsernameToken (PasswordDigest and PasswordText) — the authentication method Synology uses by default.

  1. Open Surveillance Station → IP Camera → Add

  2. Skip camera search → Add Manually

  3. Fill in the fields:

    Field Value
    Brand ONVIF
    Model ONVIF Camera
    Protocol HTTP
    IP address <pi-ip>
    Port 8000
    Username admin
    Password admin
  4. Test Connection → Apply.

Surveillance Station retrieves the stream URL and snapshot URL automatically via ONVIF and then connects over RTSP (H.264).

GetSystemDateAndTime is intentionally unauthenticated per the ONVIF spec — Synology requires this to compute the digest nonce before it has credentials.


Via RTSP (fallback)

If ONVIF discovery fails, add the camera manually as a custom RTSP source:

Field Value
Brand User-defined (RTSP)
Protocol RTSP
IP address <pi-ip>
Port 554
Primary stream rtsp://<pi-ip>/thermal
Username admin
Password admin

Motion detection in Surveillance Station

  • Camera-side (ONVIF Events): Surveillance Station subscribes to tns1:VideoSource/MotionAlarm via PullPoint. An alarm fires when more than 5 % of pixels change by more than 2 °C. Enable under Camera → Motion Detection → By camera.
  • Surveillance Station internal: Surveillance Station analyses the stream itself using frame differencing. For thermal images, higher sensitivity levels are recommended since the JET colormap strongly amplifies temperature differences.

Configuration

All tunable constants at the top of onvif_thermal_server.py:

PORT             = 8000
STREAM_RES       = (640, 480)   # output resolution (before colorbar)
FRAME_RATE       = 25           # FPS (MI48 max 25.5)
JPEG_QUALITY     = 85
COLORMAP         = cv.COLORMAP_JET
MOTION_THRESHOLD = 2.0          # °C per-pixel change threshold
MOTION_MIN_PCT   = 5.0          # % of pixels that must change to trigger
COLORBAR_W       = 80           # colorbar strip width (px)
COLORBAR_TICKS   = 5            # temperature labels on scale

RTSP transcoding parameters (libx264, H.264 Baseline) are in /etc/mediamtx/mediamtx.yml.


Troubleshooting

Symptom Likely cause Fix
Camera thread: CRC errors every frame CS timing wrong or SPI wiring issue Check GPIO wiring, especially CS_N on BCM7
HTTP 401 on all endpoints Wrong credentials Check auth.json, restart service
NVR stuck on "Activating" Leftover ONVIF session state Remove camera from NVR and re-add
RTSP stream connects then drops mediamtx not running sudo systemctl restart mediamtx.service
av_interleaved_write_frame: Broken pipe in mediamtx log onvif-thermal restarted while mediamtx was running Normal – mediamtx/ffmpeg restarts automatically

Logs:

sudo journalctl -u onvif-thermal.service -f
sudo journalctl -u mediamtx.service -f
tail -f /var/log/onvif-thermal.log

Technical reference

Full technical documentation (architecture, ONVIF operation table, authentication flows, image pipeline, threading model, hardware SPI timing, Synology compatibility notes): TECHREF.md

About

onvif implementation for waveshare tharmal hat on raspberry pi. You can use your raspberry pi as low-cost thermal surveillance camera with this.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages