Skip to content

Repository files navigation

thingino-viewer

Unofficial companion viewer for cameras running the open-source thingino firmware.

thingino-viewer on Android — live view, PTZ pad, push-to-talk

日本語版は README.ja.md をどうぞ。

A tiny self-hosted web app — installable on your phone as a PWA — that gives you live view, pan/tilt control, push-to-talk and day/night switching for a thingino camera. One container, one config file. No cloud account, no subscription, no port forwarding.

[Phone PWA] ──HTTPS──▶ (optional Cloudflare Tunnel + Access)
                              │
                     [thingino-viewer container]
                       ├─ bundled go2rtc … live video (WebRTC/MSE), talk backchannel
                       └─ viewer app    … UI/PWA, PTZ & camera control over SSH
                              │ RTSP / SSH (LAN only)
                       [thingino camera]

Features

  • Live view — sub-second WebRTC on the LAN, MSE through tunnels; HD / SD / video-off selector to keep mobile data usage down (SD ≈ 2–4 MB/min)
  • PTZ pad — hold-to-move with software end-stop protection (prevents the motor desync that bricks tilt on cheap cameras until reboot) and a one-tap recalibration button (motors -r)
  • Push-to-talk — hold, speak, release; plays on the camera speaker via the RTSP backchannel (go2rtc + thingino audio daemon)
  • Day / Night / Auto — switches the IR-cut mode over SSH
  • PWA — "Add to Home Screen" gives a full-screen app; app name and UI language (en / ja) are configurable
  • Light — measured 43 MiB RAM / 0.3 % CPU on a Raspberry Pi 3B+ (1 GB) running alongside a VPN server; works on a Pi 3 / Zero 2 W, a NAS, or any amd64/arm64 Docker host

Requirements

  • A camera running thingino with RTSP enabled (/ch0 main, /ch1 sub) and SSH reachable from the Docker host (same LAN)
  • For push-to-talk: the camera's audio output (speaker) enabled in thingino
  • Docker + Compose on the host

Quick start

mkdir thingino-viewer && cd thingino-viewer
curl -LO https://raw.githubusercontent.com/Amakata/thingino-viewer/main/docker-compose.example.yml
mv docker-compose.example.yml docker-compose.yml
docker compose up -d          # first start writes ./config/config.json (template)
vi config/config.json         # set camera_ip, RTSP & SSH credentials
docker compose restart thingino-viewer

Open http://<host>:8091. You should see live video; try the PTZ pad.

Configuration (config/config.json)

Key Meaning Default
app_name Name shown in the UI and on the phone home screen thingino-viewer
lang UI language: en or ja en
camera_ip Camera address on your LAN
camera_rtsp_user / camera_rtsp_pass RTSP credentials (thingino web UI → Streamer) thingino
ssh_user / ssh_pass Camera SSH login (root + your thingino password)
webrtc_candidates e.g. ["192.168.1.20:8555"] — host LAN IP for low-latency WebRTC []
daynight_commands Shell commands used for Color / Mono / Auto daynight …
power_commands.reset Command behind the ⟳ Reset button motors -r
ptz.* See PTZ calibration below Cinnado D1 defaults
app_user / app_pass Optional HTTP Basic auth for the LAN port off

To use your own home-screen icon, mount PNGs over the defaults in docker-compose.yml: - ./my-icon-192.png:/app/static/icon-192.png (and the 512px one).

Remote access (free, no port forwarding)

The recommended setup is Cloudflare Tunnel + Access: viewers just open a URL and enter a one-time email code — no VPN app, no Cloudflare account for them.

  1. Add a domain you own to Cloudflare (free plan)
  2. Zero Trust → Networks → Tunnels → Create a tunnel, copy the token
  3. Uncomment the cloudflared service in docker-compose.yml, paste the token, docker compose up -d
  4. Tunnel → Public Hostname: cam.your.domainHTTPthingino-viewer:8091
  5. Access → Applications → Self-hosted app for cam.your.domain → policy Allow / Include Emails (list the viewers; include yourself). Set Session Duration to 1 month
  6. Login method: add One-time PIN (Integrations → Identity providers → Add → One-time PIN) and select only it for the app. ⚠️ By default only the "Cloudflare" member sign-in exists, which locks out everyone but you
  7. On the phone: open https://cam.your.domain, sign in with the email code, then Chrome menu → Add to Home Screen / Install app

Notes: the mic (push-to-talk) only works over HTTPS, i.e. through the tunnel or another TLS front. WebRTC does not traverse the tunnel — remote viewing uses MSE (1–3 s latency); LAN viewing stays low-latency.

PTZ calibration

Cheap pan/tilt cameras track position in motor steps. Driving into a physical end stop desyncs the counter and the axis stops responding until recalibration — thingino-viewer prevents this with software limits, but it needs to know your camera's geometry. Defaults match the Cinnado D1.

  • GET /api/ptz/info shows the live position counter and detected range
  • x_max / y_max: -1 = unlimited axis (e.g. 360° pan), 0 = try auto-detect from motors -i, or a measured number (drive gently to the end, read /api/ptz/info, set that value)
  • margin: how many steps before the physical end to stop (default 80)
  • One-tap direction test: read ypos, tap ▼ once, read again — if the camera moved down and the counter increased, down is counter-positive (default); flip invert_y if your arrows are reversed
  • mirror_x / mirror_y: some thingino builds interpret absolute position commands mirrored (commanding T moves to 2·pos−T). If a single tap moves the camera correctly but the counter goes the opposite way to the command, set mirror for that axis (Cinnado D1: mirror_y: true)
  • Stuck anyway? Tap ⟳ Reset (runs motors -r), or set power_commands.reset to reboot for a full camera reboot

Troubleshooting

Symptom Check
No video docker logs thingino-viewer — go2rtc child should be running; verify RTSP creds with VLC: rtsp://user:pass@cam:554/ch0
PTZ moves the wrong way flip ptz.invert_x / ptz.invert_y
Tilt dies at the end of travel set a measured ptz.y_max, keep margin ≥ 60, use ⟳ Reset to recover
Talk button does nothing HTTPS required for the mic; check thingino audio output volume; see the body field in the /api/talk response
"Install app" missing on Android must be opened via HTTPS; reload once (the manifest is fetched with credentials for Access compatibility)
Day/night fails run daynight on the camera over SSH and align daynight_commands with its usage

Credits & license

Not affiliated with the thingino project — this is a community companion tool. Video engine: go2rtc by @AlexxIT (MIT, bundled — license text included in licenses/ and in the image at /licenses). Remote access: cloudflared (Apache-2.0, separate official container). See licenses/NOTICE.md for all bundled third-party components.

MIT — see LICENSE.

About

Unofficial companion viewer for cameras running the open-source thingino firmware.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages