Category suggestion: Third-party integrations / MQTT / Automation
I run a few cloud-managed IP cameras where RTSP is either unavailable or undesirable (CGNAT, rotating credentials). The vendor exposes a cloud OpenAPI; Home Assistant still wants local entities. This is how I split responsibilities.
Boundary: cloud API vs ONVIF/RTSP
-
ONVIF/RTSP/generic camera — LAN path,
stream_sourcein YAML, Frigate-friendly, no per-vendor token dance. -
Cloud OpenAPI — device list, live bind URLs, alarm callbacks. HA should not hold
appSecret; a small sidecar service signs requests and publishes MQTT.
I use ONVIF for wired attic cams; cloud API for doorbell-class devices behind carrier NAT. If you already have Frigate pulling substreams over RTSP, keep that path—cloud live bind is for devices where RTSP never leaves the vendor's relay.
End-to-end flow in my setup
Vendor cloud --(alarm POST)--> sidecar (sign/token) --(MQTT)--> Mosquitto --> HA Core
|
+-- refreshes HLS URL on demand for camera entity
The sidecar is a 120-line Node service on the same host as Mosquitto. It holds appId/appSecret, calls listDeviceDetailsByPage every 15 minutes to sync device ids, and registers setMessageCallback on startup. HA never sees the cloud API directly.
Install path
-
Deploy a custom integration or lightweight AppDaemon / Node-RED add-on in
custom_components/(or install via HACS if someone packages a generic "cloud camera bridge"—search HACS for your vendor). -
Store credentials in
secrets.yaml:
# secrets.yaml
camera_cloud_app_id: "YOUR_APP_ID"
camera_cloud_app_secret: "YOUR_APP_SECRET"
camera_cloud_api_host: "https://YOUR_REGIONAL_HOST"
Reference in configuration.yaml:
mqtt:
broker: 127.0.0.1
# sidecar publishes to camera/alarm/#
Never put appSecret in configuration.yaml checked into git or in Lovelace.
Entities I expose
| Entity | Source |
|---|---|
camera.porch |
Live stream via proxy (HLS); refresh URL on stream call |
binary_sensor.porch_motion |
MQTT camera/alarm/porch/motion |
sensor.porch_last_alarm |
MQTT retained JSON timestamp |
Example MQTT sensor in configuration.yaml:
binary_sensor:
- platform: mqtt
name: "Porch Motion"
unique_id: porch_motion_cloud
state_topic: "camera/alarm/porch/motion"
payload_on: "ON"
payload_off: "OFF"
device_class: motion
camera:
- platform: generic
name: Porch Cloud
still_image_url: /local/porch_placeholder.jpg
stream_source: !secret porch_stream_url # set by sidecar automation
Automation — motion to light
automation:
- alias: "Porch motion — lights"
trigger:
- platform: mqtt
topic: "camera/alarm/+/motion"
payload: "ON"
action:
- service: light.turn_on
target:
entity_id: light.porch_overhead
- delay: "00:05:00"
- service: light.turn_off
target:
entity_id: light.porch_overhead
Automation — MQTT notify on person detection
automation:
- alias: "Cloud cam person notify"
trigger:
- platform: mqtt
topic: "camera/alarm/#"
condition:
- condition: template
value_template: "{{ 'person' in trigger.payload }}"
action:
- service: notify.mobile_app_pixel
data:
title: "Camera alert"
message: "{{ trigger.topic }}"
HA-specific pitfall — HLS in frontend
Lovelace picture-glance / WebRTC cards often use hls.js. When you navigate away without destroying the player, some cards leak MediaSource buffers and the next live bind URL appears "stuck." Fix: use a card that calls hls.destroy() on panel unload, or proxy FLV/WebRTC through go2rtc with a stable internal URL while the cloud URL rotates underneath.
Also: do not poll the cloud every 30 s from inside HA—rate limits hit fast. Push alarms to MQTT from your sidecar; let HA subscribe.
Second pitfall — template sensors on raw JSON
Early on I fed the full alarm JSON into a template sensor without parsing msgId. Duplicate retries incremented my "alarms today" counter threefold. Now the sidecar dedupes and publishes a normalized ON/OFF on a dedicated motion topic; HA only sees clean states.
Debugging checklist
-
mosquitto_sub -h localhost -t 'camera/alarm/#' -v— confirm sidecar publishes before touching HA. -
Developer tools → States: verify
binary_sensor.porch_motiontoggles when you wave at the camera. -
If stream fails but MQTT works, re-bind live URL in sidecar logs—expired URLs look like HA regressions.
Keeping secrets off the Pi that runs HA Core was the main win. The sidecar can restart without taking down automations as long as MQTT retained messages mark bridge online state.