Cameras - cbrightly/hass-aidot-cameras GitHub Wiki

Cameras overview

This page explains how camera streaming works so the timing and limitations make sense. For specific topics see PTZ control, Two-way audio, Resolution, and Cloud recordings.

How live streaming works

When go2rtc is reachable, live view is served over go2rtc WebRTC, which is low-latency once connected. Each camera publishes its video and audio straight into go2rtc from the integration's own process (Direct publish into go2rtc, on by default since 2.35.0), and the integration hands Home Assistant the go2rtc RTSP URL. A standard (DTLS) camera is served on a local port and registered with go2rtc only when the integration cannot reach go2rtc directly, as with Home Assistant's bundled go2rtc. If go2rtc is unavailable, it falls back to Home Assistant's HLS pipeline (higher latency).

Media flows LAN-direct when the camera is on the same network as Home Assistant. When they are on different networks, media is relayed through the AiDot cloud STUN/TURN servers - latency and reliability then depend on the relay, so LAN-direct is always preferable.

Connection timing (cold start)

Opening a cold (idle) camera runs the proprietary handshake before any video appears:

Camera type Cold open
Mains, standard (DTLS) models ~2.4 - 3.3 s
Mains, SDES models (PTZ / spotlight) ~2.3 - 2.8 s
Battery (L2) models, from idle ~3 - 6 s

These are how long the camera takes to start sending video, read from the integration's own log on a live install: the middle 80% of about 300 cold opens, 2026-09-15 to 16. An earlier and much smaller read on 2026-09-07 put battery cameras at 6-9 s; the larger sample is the one to trust, and the figures here now match the README rather than contradicting it.

A warm view starts immediately, because the session is already open. What you see on a dashboard adds Home Assistant's own stream pipeline on top, which depends on your card - see Dashboard cards. One install on one network: treat these as the shape to expect, not a guarantee.

These figures are when the camera starts sending. With direct publish (on by default since 2.35.0) the stream reaches go2rtc sooner than it did through an ffmpeg process - measured side by side on seven cameras, most of all on the standard models. That is a different measurement (when go2rtc has the stream, not when the camera starts sending), so it is not a row in this table.

A battery camera's first view is almost entirely the camera waking up, and that wake is variable: on one camera across one day it announced itself anywhere from 1 s to 33 s after the request (measured 2026-09-07; the spread, not the median, is the point). Most first views land in the range above; an occasional one takes considerably longer, and the view waits it out - showing Connecting and then Buffering - rather than failing. A camera that really is unreachable gives up after about a minute.

Nothing wakes a battery camera unless you are watching it. The thumbnail on a dashboard card comes from the cloud, the periodic sensor refresh skips battery cameras, and they are excluded from the start-up warm-up that mains cameras get. From 2.36.0 a motion event does not warm one either (a notification's tap opens the cloud clip, not a live view), and when you close a view the camera goes back to sleep within about half a minute of the last viewer leaving, plus Home Assistant's own 30 s for the HLS dialog. Before 2.36.0 a closed view kept a battery camera streaming for two to two and a half minutes.

Once connected, the WebRTC stream is low-latency. Subsequent views - and, on a mains camera, views pre-warmed by a recent motion event - are quicker, because the session is already up; a fresh viewer still pays go2rtc's pipeline startup.

Keeping cameras warm

  • Mains cameras: the warm-hold option (default 0 = always warm) keeps the session alive so opening the camera is always instant. Set a positive window in Configuration options to let unwatched cameras go dormant instead.

    Some cameras cannot be held warm, and are better off dormant. A few models stop sending video once nobody is watching, and drop the connection from their end. Held warm, such a camera is detected as stalled and reconnected over and over - on one PTZ that was six reconnects in a day, each leaving a brief burst of damaged timestamps that can make a camera.record fail while live view is unaffected. If you see repeated reconnects on an idle camera, give it a positive warm-hold window (120 s is a reasonable start) so it goes dormant between views instead. The cost is the cold-open delay above on the next view.

  • Battery cameras: warm-hold is ignored; from 2.36.0 they are never held warm and are not pre-warmed on motion either - a stream opens only when someone views the camera, and closes again within about half a minute of the last viewer leaving.

What the camera detects, and what it does about it

Detection types. These cameras separate a person from a vehicle from a package from a pet, and each gets its own switch -- Human, Vehicle, Package and Pet detection. Human detection is typically on from the factory. Use them to make an automation fire only for what you care about, rather than for every motion event.

Automatic siren. Separate from the siren control, which sounds the siren now: Automatic siren decides whether the camera sounds it by itself, and on motion / on a person decide what sets it off. The two triggers are inert while the master is off, and turning a trigger on will not arm the master.

Both groups are camera settings read over a slow round trip, so the switches appear a few minutes after startup rather than immediately, and a camera that has not answered shows unknown rather than off. Battery cameras are asleep and report none of this.

Light when someone appears

Cameras with a floodlight can turn it on by themselves when they see someone. Light when someone appears is that automation - it is the switch that used to be called Floodlight automation, renamed in 2.23.0 because the old name did not say what it did. Its entity ID did not change, so existing automations and dashboards keep working.

Two settings sit under it:

Entity What it does
Light stays on for 20, 30, 40 or 50 seconds after a trigger. Exactly the four values the camera offers - it is not a free range.
Light brightness 10 to 100. The floor is 10, not 0: zero is outside the range the camera accepts, and "off" is the floodlight entity itself.

They appear on different sets of cameras, and that is deliberate. The duration appears only on models that declare the setting - the battery L2 line. The M3 Pro line reports a duration value in the cloud but has no such setting on the camera and discards the write, so it gets no control. Brightness is real on every model that reports it, checked on the camera rather than assumed, so it appears wherever it is reported.

2.23.0 offered the duration everywhere and was wrong to; 2.23.1 fixes it and removes the stale control from your entity list.

Light behavior - Constant or Flash - is the third setting, added in 2.24.0. It appears on the same cameras as the duration.

It was missing for a while because the write was acknowledged and the value never changed. That turned out to have nothing to do with the setting: a battery camera was never given time to wake before the command arrived behind its own wake. Fixed in the library, and every setting on a battery camera should be more reliable as a result.

The stream cap

The concurrent-stream cap sizes itself to your camera count automatically, so every camera - warm or cold - can stream at once. Set the AIDOT_MAX_CONCURRENT_STREAMS environment variable to impose a hard ceiling; warm cameras count against it while held. The practical limit on a small host is CPU: each live mains camera decrypts its stream in-process.

One live viewer per camera (app contention)

Each camera serves a single live session at a time. If the AiDot mobile app has the camera's live view open, Home Assistant cannot connect (and vice versa). Close the live view in the app before streaming in Home Assistant. Recorded clips and snapshots are unaffected.

DTLS retries

Connections to DTLS-mode cameras are probabilistic per attempt; the integration retries silently, so a brief delay before a stream loads is normal.

Commands that need an active stream

PTZ moves ride the active stream session - the camera must be streaming for them to reach it. Open the live view first, then issue the command. Two-way audio does not need one: aidot.talk reuses the live session when one is open and otherwise opens its own temporary session and closes it afterwards. See the linked pages for each.