Skip to content

Video Streaming

tsightler edited this page Mar 24, 2023 · 9 revisions

While ring-mqtt is primarily designed to integrate Ring devices into home automation platforms via MQTT to allow driving automations from those devices, there was high demand to provide video streaming integration as well, especially for Home Assistant users, but also to provide features such as on-demand recording via automations. With the release of version 4.8.0 video streaming and recording automation is now fully integrated into this project.

The goal of this document is to provide enough information to allow configuration of your camera platform of choice for use with ring-mqtt.

!!!! Important note regarding camera support !!!!
The ring-mqtt project does not turn Ring cameras into 24x7/continuous streaming CCTV cameras. Ring cameras are designed to work with Ring cloud servers for on-demand streaming based on detected events (motion/ding) or short term (10 minute) interactive viewing/recording. Even when using ring-mqtt, all streaming still goes through Ring cloud servers and is not local. Attempting to leverage this project for continuous streaming is not a supported use case and attempts to do so will almost certainly end in disappointment, this includes use with NVR tools like Frigate, Zoneminder or others and there are significant functional side effects to doing so, most notably loss of motion/ding events while streaming (Ring cameras only send alerts when they are not actively streaming/recording).

Overview

Ring video streaming support is implemented by running a local RTSP server provided by the excellent go2rtc project. Each discovered camera creates two RTSP paths that allow viewing the live camera stream and also to play back recorded streams saved on Ring servers. These streams use the following format:

Live Stream: rtsp://<ip_or_hostname>/<camera_id>_live
Event Stream: rtsp://<ip_or_hostname>/<camera_id>_event

Optionally, users can define the livestream_user and livestream_pass configuration options and those values will be used to require authentication to the RTSP server, changing the paths as follows:

Live Stream: rtsp://<livestream_user>:<livestream_password>@<ip_or_hostname>/<camera_id>_live
Event Stream: rtsp://<livestream_user>:<livestream_password>@<ip_or_hostname>/<camera_id>_event

To make the camera setup as simple as possible, ring-mqtt attempts to "guess" the required RTSP and publishes these values as attributes of the camera info sensor. Note that these values aren't always 100% correct, and you may need to tweak the hostname/IP or port numbers in some cases. These values can be viewed using a MQTT client or, when using ring-mqtt with Home Assistant, they can be accessed in the UI via the following these steps:

  1. Find and select the desired camera from the Home Assistant Devices list view
  2. In the Sensors section of the device view select the Info sensor and, in the pop-up window, click the Control icon in the upper right corner
  3. Select Attributes to expand the available attribute properties
  4. View and make a copy of the Stream Source value which is the guessed RTSP URL

Once you have the RTSP URL starting a stream is simply a matter of using any media client that support the RTSP protocol (VLC for example) to connect to the RTSP server using the URL. The path ending in "_live" starts a live stream for the camera, while the path ending in "_event" starts a stream of the selected event recording. By default, the event stream plays back the most recently recorded motion event by streaming the recording directly from Ring servers, however the event select feature allows selecting any of the five most recent motion, ding (doorbells only), or on-demand recording events. For more details see the event stream section below.

Home Assistant Generic Camera Configuration

The live and event streams use RTSP for streaming and, as there is no automatic discovery support for Generic Cameras, the cameras must be configured in Home Assistant manually. Starting with Home Assistant version 2022.4.0, Generic Camera configuration is performed via the Home Assistant UI.

Note that, in addition to the RTSP URL, Home Assistant also supports an HTTP(S) URL for retrieving a still image from the camera. This image will be displayed in the UI rather than always trying to grab images from the stream. While not absolutely required, this is ideal for Ring cameras since they are not intended for continuous viewing and starting a stream interrupts motion detection. The best source of this still image is the snapshot camera and the still_image_url attribute on the info sensor provides the addons "best guess" as to the correct URL to acquire this image from the Home Assistant camera proxy for the snapshot camera. If the Home Assistant URL is different from the guessed URL, replace the Home Assistant base URL with the value template on the end and make sure there is no slash after the hostname or port.

Example: Home Assistant UI: https://myha.mydomain.local/
Guessed URL: http://localhost:8123/{{ states.camera.front_porch_snapshot.attributes.entity_picture }}
Correct URL: https://myha.mydomain.local{{ states.camera.front_porch_snapshot.attributes.entity_picture }}.

If HTTPS is in use with self-signed certificates or where the URL does not match the hostname of the certificate, then you will need to uncheck the Verify SSL certificate option in the UI, however, this should not be required if you use the correct hostname with a "real" certificate (for example from Let's Encrypt).

Once you have the correct stream source and still image URLs then configuration is just a matter of adding a Generic Camera device and providing the required information to the configuration wizard. General steps are as follows:

  1. From the Home Assistant Devices list select the Camera to be added
  2. Select the Info sensor and, on the pop-up window click the Control icon in the upper right corner
  3. Click Attributes to expand the available attribute properties
  4. Copy the Stream Source and Still Image URL values to a temporary location
  5. In the Home Assistant UI select Configuration and then Devices & Services
  6. Select Add Integration search for Generic Camera and click to open Options window
  7. Use the copied Stream Source and Still Image URL to add the settings, tweaking as required for the specific environment
  8. Note that the username/password fields in the wizard are for HTTP only and should not be used. If you have configured a livestream username/password you should include them as part of the Stream Source URL.
  9. Complete the workflow to add the camera, enter video/mp4 if prompted for media type
  10. If desired, select the Devices tab, find the camera and enter a user friendly Name/Entity ID
  11. Use the camera!

Most of the other options can be left blank or as-is and they will be automatically detected, but, if desired, the RTSP protocol can be forced to TCP (the only option currently supported by the addon) and the framerate set to 20Hz (most Ring cameras will do between 15-25Hz, but a few higher end models support 30Hz and I've been unable to tell that this setting makes any actual difference). In some cases Home Assistant may prompt for media type (I have no idea why this happens sometimes but not others) but, if you get this prompt, simply enter video/mp4.

The following example uses a camera with the name "Front Porch" in the Ring app. The MQTT discovered snapshot camera has a Home Assistant entity ID of camera.front_porch_snapshot and the camera device ID is 3452b19184fa so the attributes for the example info sensor are as follows:

Still Image URL: http://<MY_HA_HOSTNAME>:8123{{ states.camera.front_porch_snapshot.attributes.entity_picture }}  
Stream Source URL: rtsp://03cabcc9-ring-mqtt:8554/3452b19184fa_live

Technically, the above are all that are required, however, the entity names/IDs generated by Home Assistant when adding generic cameras via the UI can be overly complex and quite frustrating, thus it may be desirable to edit the automatically generated values to something more user friendly. To do this, either select the newly added camera from the Generic Camera integrations panel and then click the entity link to go directly to the camera entity, or select the entities tab in the UI and search for the newly added camera (just typing "Generic" into the search field will quickly filter to devices with generic in the ). Once you see the camera simply click it and edit the display name and entity ID into something easier to remember and recognize.

Once the configuration steps are complete the camera can be added to the dashboard via a Picture Glance card or any other card that supports cameras. The card will automatically display the current image from the still image URL and a click will open a window that starts the associated live/event stream.

The picture glance card is quite flexible and it's possible to add the additional camera entities to this card as well, like the motion, light and siren switches (for devices with those features) and the stream switch. With this setup it's possible to see at a glance if any motion/ding event is active, see the latest snapshot from that event, see the light/siren/stream state, and a simple click opens the live stream.

Event Stream

Please note that use of this feature requires a Ring Protect plan that supports video storage

As mentioned above, this addon provides two separate paths for video streams, one that always provides a live stream, and a second that can stream a selected, previously recorded stream. Camera setup for this feature is the same as above but uses the "<camera_id>_event" path vs the live path in the previous example.

On initial setup the default event is set to the most recent motion (Motion 1) but the play back event can be selected using the Event Selector entity in Home Assistant or the equivalent MQTT command topic and this setting is saved as part of the device state so it will be persistent across restarts of ring-mqtt. Each camera allows selecting from any of the last five motion, ding, or on-demand events (ding events are available only for doorbells). For example, selecting "Ding 1" will cause the event stream to play back the recording of the most recent doorbell ding event, while selecting "Motion 3" would play back the 3rd most recently recorded motion event. On-demand recording events occur any time a video stream is started for on-demand viewing without a motion/ding event.

When a recorded stream is playing it is streamed only a single time for each RTSP client request and then the stream shuts down until the next request for a stream. Stream playback can be manually stopped via the event stream switch, although note that, unlike live streams, playback of recorded events can only be started via on-demand viewing.

If a recorded stream is actively playing, changing the event selector immediately cancels playback of the existing event stream and the stream will not start again until a new client makes an RTSP request (for example, just closing and re-opening the playback window in Home Assistant).

External RTSP Access

Streaming to external media clients requires the RTSP server to be exposed either via the addon configuration settings or via the Docker -p port forwarding option. It's recommended to use TCP port 8554, but you can actually forward any external TCP port to the 8554 on the RTSP server in the container. Note that streams will start automatically on-demand, and end ~5-10 seconds after the last client disconnects. Multiple clients can connect to the same stream concurrently. No MQTT access is needed for this to work, simply enter the RTSP URL into your media player. If you defined a livestream username and password this will need to be included as well, most players will prompt for a username/password, but some require them to be included in the URL, for example:

rtsp://streaming_user:let_me_stream!@3ba32cf2-ring-mqtt:8554/3452b19184fa_live

Manually Starting a Live Stream

When a media client connects to the live stream server the stream is started automatically, however, there may be cases where starting a stream without a media client is desired. When used with a Ring Protect plan all live streams also create a recording so being able to manually start a stream allows an automation to effectively manually start and stop a recording. This is possible utilizing the "live stream" switch, which is exposed as an entity to Home Assistant and can be accessed by MQTT as well. It performs like any switch, accepting "ON" and "OFF" to start and stop a stream respectively.

Note that turning the stream off ALWAYS stops the local live stream immediately, no matter how many clients are connected to the local RTSP server, and those clients will be disconnected, however, if the clients automatically reconnect, the stream will start back on its own and thus the switch will "turn back on". This is expected behavior as any client connect will always start a stream.

Downloading recorded videos using the Event Stream

If this addon is used with an account that includes a Ring Protect Plan that supports saving videos to the Ring Cloud service, it is possible to leverage this to automatically download recordings once they have been processed. To assist with this, the "Select Event Stream" entity includes attributes for both the current eventId and the recordingUrl.

Note that recordingUrls are only valid for 15 minutes so the addon automatically requests a new URL around the 10 minute mark prior to the old URL expiring. Also, any time a new event stream is selected the eventId and recordingUrl are immediately updated with the information for the selected event. This means it's not a good idea to trigger downloads specifically on eventId changes.

As an alternative, the best method is to use an automation that triggers on the desire event type (motion or ding event for example), and then use a wait for trigger to perform the download as soon as the eventId changes. This way arbitrary changes of the event select will not trigger downloads of already downloaded recordings. The following is a simple example automation using this technique (note that the below automation assumes the Home Assistant downloader service has been enabled):

alias: Download Ring Video (Front Porch)
trigger:
  - platform: state
    entity_id: binary_sensor.front_porch_motion
    to: 'on'
action:
  - wait_for_trigger:
      - platform: state
        entity_id: select.front_porch_event_select
        attribute: eventId
    timeout: '00:05'
  - service: downloader.download_file
    data_template:
      url: '{{ states.select.front_porch_event_select.attributes.recordingUrl }}'
      subdir: front_porch
      filename: '{{ now().strftime( ''%Y%m%dT%H%M%S_motion.mp4'' ) }}'
      overwrite: false

This automation is initially triggered any time a motion event starts. Once triggered, it waits for the eventId attribute to change, which indicates that the recording of the new event is ready. At that point it uses the Home Assistant downloader service with the recordingUrl attribute to download the file to a subdirectory with a date based filename.

Of course there are other possible automation options as well, and, even without a Ring Protect Plan, you can do things like start an FFmpeg stream on a motion event to record a video, however, the Ring Protect Plan still offers a significant value in that it pulls the seconds just before the event, while triggering a recording of the stream will always miss the first few seconds at least since it won't know to start recording until after the motion event is received. Of course, if you are using other devices or events as the start trigger, this might be good enough for you.

FAQ

See the Video Streaming section of the main FAQ page.

How it works - the gory details

The concept for streaming is quite simple and credit for the original idea must go to gilliginsisland's post on the ring-hassio project. While I was already working on a concept implementation for ring-mqtt, when I read that post I realized that it was a really strong model that could be married with ring-mqtt to support live streaming in a way that fit well within the project. The post described a method to use rtsp-simple-server and its ability to run a script on demand to directly run a node instance that leveraged ring-client-api to connect to Ring and start the live stream. Since ring-mqtt already ran in node and used ring-client-api, and already contained code for starting streams, I decided that instead of starting a separate node script, which had high startup delay and memory overhead, I could just have rtsp-simple-server run a simple shell script that used MQTT as the lightweight control channel to signal ring-mqtt to start/stop the stream on demand from streaming clients while also allowing streams/recording to be easily controlled manually via MQTT commands, which was also a commonly requested feature.

Digging more into rtsp-simple-server, I found that it not only had the ability to run a script on demand, but also included a simple REST API so that it could be easily configured and controlled dynamically from the parent ring-mqtt node instance meaning that it would require no additional manual setup. Below is the general workflow:

Step 1 - During startup, ring-mqtt checks if camera support is enabled and, if so, spawns and monitors an rtsp-simple-server process.

Step 2 - After device discovery, ring-mqtt leverages the rtsp-simple-server REST API to register the RTSP paths with a configured on-demand script handler that will execute the shell script and pass the proper MQTT topic information for each path using environment variables.

Step 3a - A stream is started by any media client connecting to the RTSP path for the camera (rtsp://hostname:8554/<camera_id>_live or hostname:8554/<camera_id>_event).
-- or --
Step 3b - The command to manually start a stream is received via MQTT. In this case ring-mqtt internally starts a small FFmpeg process that connects as an RTSP client to trigger the on-demand stream. This process does nothing but copy the audio stream to null, just enough to keep the stream alive while keeping CPU usage extremely low.

Step 4a - If an existing stream is already active and publishing to the requested path, the client simply connects to the existing stream in progress
-- or --
Step 4b - If there is not an active publisher for that stream, rtsp-simple-server runs the shell script to start and monitor the progress of the stream via MQTT. Since this is just a simple script sending a single MQTT command to an already running process, the startup process is fast and lightweight as ring-mqtt already has a connection to the Ring API and the communication channel with MQTT is local and takes only a few ms. Usually, the live stream starts in ~2-3 second although buffering by the media client usually means the stream takes a few additional seconds to actually appear in the UI or media client.

Step 5 - The RTSP server continues to stream to the clients, once the stream times out on the Ring side, or the last client disconnects, rtsp-simple-server stops the on-demand script, which sends the MQTT command to stop the stream prior to exiting.

The overall process is fairly light on CPU and memory because the FFmpeg process that is receiving the stream is only copying the existing AVC video stream to the RTSP server with no modification/transcoding. The only transcoding is of the audio stream because the primary stream is G.711 μ-law while the Home Assistant stream component is compatible with AAC so the FFmpeg process does create and stream a second AAC based audio channel for maximum compatibility (players can choose the stream with which they are compatible).