Docker container to expose a local RTMP, RTSP, and HLS or Low-Latency HLS stream for ALL your Wyze cameras including the outdoor and doorbell cams. No third-party or special firmware required.
It just works!
Now with Web-UI - view all your cams in one place!
Based on @noelhibbard's script with kroo/wyzecam and aler9/rtsp-simple-server.
Please consider starring or sponsoring this project if you found it useful.
Install docker and use your Wyze credentials to run:
docker run \
-e [email protected] \
-e WYZE_PASSWORD=yourpassw0rd \
-p 8888:8888 mrlt8/wyze-bridge:latest
You can view your stream by visiting: http://localhost:8888/cam-nickname
where localhost is the hostname or ip of the machine running the bridge followed by the cam nickname in lowercase with -
in place of spaces.
See basic usage for additional information.
- Fixed: Custom strftime in the RECORD_FILE_NAME would produce the wrong format. #487 Thanks @WasabiNME
- Changed: Sleep 2 seconds on TutkError
- Updated: rtsp-simple-server to v0.19.3
- NEW - Dark mode for Web-UI!
- NEW - Custom url config for HA. (#473)
- CHANGED - Cleanup connections before exit.
- NEW - SD card storage info and audio status icons in Web-UI.
- FIXED - extra padding around image/video.
- FIXED - Preview image would not load in some situations.
- FIXED - Wrong version number in previous release.
Some wyze cams have have a built-in http server "boa" that is enabled when downloading a time lapse from the camera. By enabling this http server, we can have access to the SD card on the camera, so you can download whatever you need off the SD card without having to take each camera down.
PLEASE NOTE: If enabled, anyone on your local network will be able to access/download stuff from the SD Card on the camera.
NEW ENV options:
ENABLE_BOA
- Enable the boa HTTP server on select cameras with an SD card.BOA_INTERVAL
- The number of seconds between image pulls/keep alives.TAKE_PHOTO
- Take a high quality photo on the camera SD Card onBOA_INTERVAL
.PULL_PHOTO
- Download latest high-quality photo from camera.PULL_ALARM
- Download latest alarm file from camera and notify via MQTT if available.MOTION_HTTP
- Make a Webhook/HTTP request to any url on motion, e.g.,http://localhost/triggerMotion?cam={cam_name}
.MOTION_COOLDOWN
- Number of seconds to keep the motion flag set to true before resetting it.
Other changes:
- WEB-UI:
/photo/<cam-name>.jpg
endpoint to take a photo on the camera sensor and return it. - WEB-UI: Display additional
camera_info
from the current session. #436 - MQTT:
/takePhoto
endpoint to take a photo on the camera sensor. - MQTT:
/motion
endpoint that updates when a new file is detected in the alarm folder on the camera's SD card. RequiresPULL_ALARM
to be enabled.
- Web-UI to view all Wyze cameras in one place.
- Access to video and audio for all Wyze-supported cameras via RTSP/RTMP/HLS/Low-Latency HLS.
- Access to HD or SD stream with configurable bitrate.
- Local and remote access to any of the cams on your account.
- Runs on almost any x64 or armv7/arm64 based system like a Raspberry Pi that supports docker.
- Support for Wyze 2FA.
- Ability to rotate video for Wyze Doorbell.
- Ability to record streams locally.
- Ability to take snapshots on an interval or on demand.
- Ability to live stream directly from the bridge.
- Ability to send a IFTTT webhook when a camera is offline (-90).
- Start an HTTP server on the camera for local SD card access. ✨ NEW
- On-demand high quality photos on the camera. ✨ NEW
- Trigger MQTT/Webhook/HTTP on a motion event. ✨ NEW
Camera | Model | Supported |
---|---|---|
Wyze Cam v1 | WYZEC1 | ✅ |
Wyze Cam V2 | WYZEC1-JZ | ✅ |
Wyze Cam V3 | WYZE_CAKP2JFUS | ✅ |
Wyze Cam Floodlight | WYZE_CAKP2JFUS | ✅ |
Wyze Cam Pan | WYZECP1_JEF | ✅ |
Wyze Cam Pan v2 | HL_PAN2 | ✅ |
Wyze Cam Outdoor | WVOD1 | ✅ |
Wyze Cam Outdoor v2 | HL_WCO2 | ✅ |
Wyze Cam Doorbell | WYZEDB3 | ✅ |
Wyze Cam Doorbell Pro | GW_BE1 | ❓ |
The bridge should be compatible with official firmware from wyze.
Should work on most x64 systems as well as on some arm-based systems like the Raspberry Pi.
The container can be run on its own, in Portainer, Unraid, as a Home Assistant Add-on, locally or remotely in the cloud.
This is similar to the docker run command, but will save all your options in a yaml file.
- Install Docker Compose.
- Use the sample as a guide to create a
docker-compose.yml
file with your wyze credentials. - Run
docker-compose up
.
Once you're happy with your config you can use docker-compose up -d
to run it in detached mode.
To update your container, cd
into the directory where your docker-compose.yml
is located and run:
docker-compose pull # Pull new image
docker-compose up -d # Restart container in detached mode
docker image prune # Remove old images
Visit the wiki page for additional information on Home Assistant.
- Two-Step Verification
- ARM/Raspberry Pi
- LAN mode
- Portainer
- Unraid
- Home Assistant
- Homebridge Camera FFmpeg
- HomeKit Secure Video
If your email or password contains a %
or $
character, you may need to escape them with an extra character. e.g., pa$$word
should be entered as pa$$$$word
By default, the bridge will create three streams for each of your cameras which can be accessed at the following URIs, where camera-nickname
is the name of the camera set in the Wyze app and converted to lower case with hyphens in place of spaces. e.g. 'Front Door' would be /front-door
Replace localhost with the hostname or ip of the machine running the bridge:
-
RTMP:
rtmp://localhost:1935/camera-nickname
-
RTSP:
rtsp://localhost:8554/camera-nickname
-
HLS:
http://localhost:8888/camera-nickname/stream.m3u8
-
HLS can also be viewed in the browser using:
http://localhost:8888/camera-nickname
-
Low-Latency HLS (enable with
LLHLS=true
):https://localhost:8888/camera-nickname or https://localhost:8888/camera-nickname/stream.m3u8
Two-factor authentication ("Two-Step Verification" in the wyze app) is supported and will automatically be detected, however additional steps are required to enter your verification code.
-
Echo the verification code directly to
/tokens/mfa_token.txt
by opening a second terminal window and using:docker exec -it wyze-bridge sh -c 'echo "123456" > /tokens/mfa_token.txt'
-
Mount
/tokens/
locally and add your verification code to a file namedmfa_token.txt
:volumes: - ./tokens:/tokens/
-
Generate Time-based One-Time Passwords:
You can have the bridge auto generate and enter a Time-based One-Time Password (TOTP) by adding the secret key to the file
/tokens/totp
on standard installs or/config/wyze-bridge/totp
for Home Assistant installs. You will need to create the file if it doesn't exist and mount it if necessary. -
🏠 Home Assistant:
Add your code to the text file:
/config/wyze-bridge/mfa_token.txt
. -
Portainer:
Use the console to echo your code to the container:
echo "123456" > /tokens/mfa_token.txt
WYZE_EMAIL and WYZE_PASSWORD are the only two required environment variables.
The following envs are all optional.
Audio is disabled by default and must be enabled in the ENV.
-
For all cameras:
environment: .. - ENABLE_AUDIO=True
-
For a specific camera:
where
CAM_NAME
is the camera name in UPPERCASE and_
in place of spaces and hyphens:- ENABLE_AUDIO_CAM_NAME=True - ENABLE_AUDIO_OTHER_CAM=True
🏠 Home Assistant - Use
CAM_OPTIONS
and add a new entry for each camera:- CAM_NAME: Cam Name AUDIO: true - CAM_NAME: other cam AUDIO: true
By default, the bridge will attempt to copy the audio from the camera without re-encoding unless the camera is using a codec that isn't supported by RTSP, in which case the audio will be converted to AAC.
The AUDIO_CODEC
ENV can be used should you need to re-encode the audio to another format for compatibility:
- AUDIO_CODEC=AAC
Custom ffmpeg audio filters can be set with AUDIO_FILTER
, but please note that audio filters will only be applied if re-encoding to another codec.
- AUDIO_FILTER=highpass=f=300,lowpass=f=2500,volume=volume=2
The default option will automatically create a stream for all the cameras on your account, but you can use the following environment options in your docker-compose.yml
to filter the cameras.
All options are case-insensitivE, and take single or comma separated values.
-
Whitelist by Camera Name (set in the wyze app):
environment: .. - FILTER_NAMES=Front Door, Driveway, porch cam
-
Whitelist by Camera MAC Address:
- FILTER_MACS=00:aA:22:33:44:55, Aa22334455bB
-
Whitelist by Camera Model:
- FILTER_MODELS=WYZEC1-JZ
-
Whitelist by Camera Model Name:
- FILTER_MODELS=V2, v3, Pan
-
Blacklisting:
You can reverse any of these whitelists into blacklists by setting
FILTER_BLOCK
.environment: .. - FILTER_NAMES=Bedroom - FILTER_BLOCK=true
Like the wyze app, the tutk library has three different modes to connect to the camera and will attempt to stream directly from the camera when on the same LAN as the camera in "LAN mode". If the camera is not available locally, it will either attempt to stream directly from your network using "P2P Mode" or relay the stream via the wyze servers (AWS) in "relay mode".
LAN mode is more ideal as all streaming will be local and won't use additional bandwidth.
By default, the bridge will attempt to connect via "LAN Mode", but will fallback to other methods if LAN mode fails.
You can restrict streaming to LAN only by setting the NET_MODE=LAN
environment variable:
environment:
..
- NET_MODE=LAN
NET_MODE=P2P
is ideal when running the bridge remotely on a different network or on a VPS and will allow the bridge to stream directly from the camera over the internet while blocking "Relay Mode".
NET_MODE=ANY
is the equivalent to leaving NET_MODE
unset and will allow the connection to fallback to P2P or relay mode.
In the event that you need to allow the bridge to access a select number of cameras outside of your LAN, you can specify them by appending the camera name to NET_MODE
, where CAM_NAME
is the camera name in UPPERCASE and _
in place of spaces and hyphens:
..
- NET_MODE=LAN
- NET_MODE_CAM_NAME=P2P
🏠 Home Assistant - Use CAM_OPTIONS
and add a new entry for each camera:
- CAM_NAME: Cam Name
NET_MODE: P2P
-
SNAPSHOT=API
Will run ONCE at startup and will grab a high-quality thumbnail from the wyze api and save it to/img/cam-name.jpg
on docker installs or/config/www/cam-name.jpg
in Home Assistant mode. -
SNAPSHOT=RTSP
Will run every 180 seconds (configurable) and wll grab a new frame from the RTSP stream every iteration and save it to/img/cam-name.jpg
on standard docker installs or/config/www/cam-name.jpg
in Home Assistant mode. Can specify a custom interval withSNAPSHOT=RTSP(INT)
e.g.SNAPSHOT=RTSP30
to run every 30 seconds -
IMG_DIR=/img/
Specify the directory where the snapshots will be saved within the container. Use volumes in docker to map to an external directory. -
IMG_TYPE
Specify the file type of the image, e.g.IMG_TYPE=png
. Will default to jpg.
Some wyze cams have have a built-in http server "boa" that is enabled when downloading a time lapse from the camera. By enabling this http server, we can have full local access to the SD card on the camera, so you can download whatever you need off the SD card without having to take each camera down.
SD Card and local connection REQUIRED.
This will enable the boa server on each camera http://<cam-ip>:80/
that has the boa server and has an SD card in the camera.
PLEASE NOTE: If enabled, anyone on your local network will be able to access/download stuff from the SD Card on the camera.
environment:
..
- ENABLE_BOA=true
The boa server will go down after some time and needs to be restarted from time to time. This interval will keep the server up and pull any new images at the same time.
This will default to 5 if not set.
- ENABLE_BOA=true
- BOA_INTERVAL=30
SD Card and local connection REQUIRED.
This will take a high quality photo on the camera on each BOA_INTERVAL
.
- ENABLE_BOA=true
- TAKE_PHOTO=true
Photos can also be taken on-demand by publishing to the MQTT topic wyzebridge/<camera-name>/takePhoto
.
SD Card and local connection REQUIRED.
This will pull the latest photo from the camera on each BOA_INTERVAL
.
Files will be saved to your local img_dir as cam-name_YYYMMDD_HH_MM_SS.jpg
or cam-name.jpg
if TAKE_PHOTO
is enabled.
- ENABLE_BOA=true
- PULL_PHOTO=true
SD Card and local connection REQUIRED.
In addition to pulling the latest alarm image from the camera on each BOA_INTERVAL
, this will also trigger a motion event to the MQTT topic wyzebridge/<camera-name>/motion
if available.
Files will be saved to your local img_dir as cam-name_alarm.jpg
.
- ENABLE_BOA=true
- PULL_PHOTO=true
SD Card and local connection REQUIRED.
If the MQTT options are configured and enabled, motion events will be sent to the MQTT topic wyzebridge/<camera-name>/motion
.
Motion alerts can also be sent via Webhook/HTTP to any url by specifying the url and using the variable {cam_name}
:
- ENABLE_BOA=true
- MOTION_HTTP=http://localhost/triggerMotion?cam={cam_name}
The number of seconds to keep the motion flag set to true in MQTT before it gets cleared or resending another HTTP/webhook event.
This will default to 10 if not set.
- ENABLE_BOA=true
- MOTION_COOLDOWN=30
The bridge can be configured to record all or select camera streams to the container which can be mapped to a local directory.
environment:
...
- TZ=America/New_York
- RECORD_ALL=True
volumes:
- /local/path/:/record/
Or to specify select cameras, where CAM_NAME
is the camera name in UPPERCASE and _
in place of spaces and hyphens:
- RECORD_CAM_NAME=True
- RECORD_OTHER_CAM=True
🏠 Home Assistant - Use CAM_OPTIONS
and add a new entry for each camera:
- CAM_NAME: Cam Name
RECORD: true
- CAM_NAME: Other cam
RECORD: true
See the Stream Recording wiki page page for additional options.
This option can send a trigger to IFTTT's webhooks integration when the camera is detected as being offline (-90).
Note:This is still experimental as the connection will sometimes just timeout a number of times before going "offline".
- OFFLINE_IFTTT=MyEventName:my_IFTTT_Webhooks_Key
The bridge should then trigger your event with the following values:
{
"value1" : "cam-name", // camera name
"value2" : -90, // error no
"value3" : "IOTC_ER_DEVICE_OFFLINE" // error name
}
Basic livestream support is available for YouTube and Facebook, but you can also specify any custom rtmp server for other services like Twitch.
To use this feature, set a new env in your docker-compose.yml with the service (YOUTUBE_
or FACEBOOK_
) prefix followed by the camera name in UPPERCASE with _
in place of spaces and hyphens, and set your stream key as the value. Custom rtmp servers can be specified using the LIVESTREAM_
prefix:
- YOUTUBE_FRONT_DOOR=MY-STREAM-KEY
- FACEBOOK_OTHER_CAM=MY-STREAM-KEY
# twitch example:
- LIVESTREAM_CAM_NAME=rtmp://jfk.contribute.live-video.net/app/MY-STREAM-KEY
🏠 Home Assistant - Use CAM_OPTIONS
and add a new entry for each camera:
- CAM_NAME: Cam Name
LIVESTREAM: rtmp://jfk.contribute.live-video.net/app/MY-STREAM-KEY
- CAM_NAME: other cam
LIVESTREAM: rtmp://a.rtmp.youtube.com/live2/my-youtube-key
Some basic MQTT support is now available in v0.7.0.
MQTT auth and discovery should be automatic in Home Assistant mode - can be disabled by setting MQTT_HOST
to False.
ENV Name | Description | Example |
---|---|---|
MQTT_HOST | IP/Hostname AND Port of the MQTT broker | core-mosquitto:1883 |
MQTT_AUTH | Username AND password; leave blank if none | user:pass |
MQTT_TOPIC | Optional - Specify topic prefix | myhome |
MQTT_DTOPIC | Optional - Discovery topic for home assistant | homeassistant |
Bitrate and resolution of the stream from the wyze camera can be adjusted with:
environment:
- QUALITY=HD120
where CAM_NAME
is the camera name in UPPERCASE and _
in place of spaces and hyphens:
environment:
- QUALITY_CAM_NAME=HD120
Additional info:
- Resolution can be set to
SD
(360p in the app) orHD
- 640x360/1920x1080 for cams or 480x640/1296x1728 for doorbells. - Bitrate can be set from 30 to 255. Some bitrates may not work with certain resolutions.
- Adjusting the bitrate and resolution in the bridge will also change the stream in the wyze app and vice versa.
- App equivalents would be:
- 360p - SD30
- SD - HD60 (HD120 for doorbell)
- HD - HD120 (HD180 for doorbell)
You can pass a custom command to FFmpeg by using FFMPEG_CMD
in your docker-compose.yml:
environment:
..
- FFMPEG_CMD=-f h264 -i - -vcodec copy -f flv rtmp://rtsp-server:1935/{cam_name}
where CAM_NAME
is the camera name in UPPERCASE and _
in place of spaces and hyphens:
- FFMPEG_CMD_CAM_NAME=ffmpeg -f h264 -i - -vcodec copy -f flv rtmp://rtsp-server:1935/{cam_name}
🏠 Home Assistant - Use CAM_OPTIONS
and add a new entry for each camera:
- CAM_NAME: Cam Name
FFMPEG: ffmpeg -f h264 -i - -vcodec copy -f flv rtmp://rtsp-server:1935/{cam_name}
Additional info:
- The
ffmpeg
command is implied and is optional. - The camera name is available as a variable
{cam_name}
for lowercase and{CAM_NAME}
for uppercase. - The audio pipe and format are available as the variable
{audio_in}
.
Custom ffmpeg flags can easily be tested with:
environment:
..
- FFMPEG_FLAGS=-fflags +flush_packets+genpts+discardcorrupt+nobuffer
or where CAM_NAME
is the camera name in UPPERCASE and _
in place of spaces and hyphens:
- FFMPEG_FLAGS_CAM_NAME=-flags low_delay
NOTE: The bridge may require additional resuorces when rotation is enabled as the video has to be re-encoded.
-
Rotate all doorbells:
environment: .. - ROTATE_DOOR=True
-
Rotate other cameras where
CAM_NAME
is the camera name in UPPERCASE and_
in place of spaces and hyphens:Rotate by 90 degrees clockwise:
environment: .. - ROTATE_CAM_CAM_NAME=True
Rotate video in other directions:
- ROTATE_CAM_OTHER_CAM=1 # 90 degrees clockwise. - ROTATE_CAM_THIRD_CAM=2 # 90 degrees counter-clockwise.
Available options:
0
- Rotate by 90 degrees counter-clockwise and flip vertically. This is the default.
1
- Rotate by 90 degrees clockwise.
2
- Rotate by 90 degrees counter-clockwise.
3
- Rotate by 90 degrees clockwise and flip vertically.
rtsp-simple-server options can be customized as an environment variable in your docker-compose.yml by prefixing RTSP_
to the UPPERCASE parameter.
e.g. use - RTSP_RTSPADDRESS=:8555
to overwrite the default rtspAddress
.
or - RTSP_PATHS_ALL_READUSER=123
to customize a path specific option like paths: all: readuser:123
For camera specific options with spaces in the name of the camera (e.g. Front Door
), be sure to replace the spaces with the URI_SEPARATOR
which defaults to -
. So Front Door
would be represented as FRONT-DOOR
, and paths: Front Door: runOnReady: ffmpeg...
could be set in your docker-compose as:
environment:
...
- RTSP_PATHS_FRONT-DOOR_RUNONREADY=ffmpeg...
- 🏠 For Home Assistant:
Enter each customization into
RTSP_SIMPLE_SERVER
, e.g. usepaths_all_readusers=123
forpaths: all: readuser:123
.
environment options:
-
FRESH_DATA
(bool) Remove local cache and pull new data from wyze servers. -
URI_SEPARATOR
(-|_|#) Customize the separator used to replace spaces in the URI; available values are-
,_
, or use#
to remove spaces. -
CONNECT_TIMEOUT
(int) Adjust the number of seconds to wait before timing out when connecting to camera. Default:15
-
KEEP_BAD_FRAMES
(bool) Keep frames that may be missing a keyframe or preceding frames. -
IGNORE_OFFLINE
(bool) Ignore offline cameras until container restarts. -
OFFLINE_TIME
(int) Customize the sleep time when a camera is offline. Default:10
-
DEBUG_FRAMES
(bool) Show all lost/incomplete frames. -
DEBUG_LEVEL
(debug|info|warning|error) Adjust the level of upstream logging. -
RTSP_READTIMEOUT
(str) Adjust the max number of seconds of missing frames allowed before a stream is restarted. Be sure to include the s after the number. Default:20s
-
RTSP_LOGLEVEL
(debug|info|warn) Adjust the verbosity of rtsp-simple-server; available values are "warn", "info", "debug". -
SKIP_RTSP_LOG
(bool) Prevent "read" spam in the logs when using RTSP based snapshots. Works by only logginng clients that stay connected for longer than 3s. -
DEBUG_FFMPEG
(bool) Enable additional logging from FFmpeg. -
FORCE_FPS_CAM_NAME
(int) Force a specific camera to use a different FPS, whereCAM_NAME
is the camera name in UPPERCASE and_
in place of spaces and hyphens. -
FPS_FIX
(bool) Set camera parameter to match the actual FPS being sent by the camera. Potential fix slow/fast SD card and cloud recordings. -
WEBRTC
(bool) Display WebRTC credentials for cameras.