Wyze Cam: Difference between revisions
No edit summary |
|||
| Line 63: | Line 63: | ||
The default value when left unset is 8, or constant quality. Which one should you use? For surveillance applications, probably constant quality (8) if bandwidth isn't an issue, or variable bitrate (VBR) if bandwidth is constrained. You can read more about these different rate controls: https://slhck.info/video/2017/03/01/rate-control.html | The default value when left unset is 8, or constant quality. Which one should you use? For surveillance applications, probably constant quality (8) if bandwidth isn't an issue, or variable bitrate (VBR) if bandwidth is constrained. You can read more about these different rate controls: https://slhck.info/video/2017/03/01/rate-control.html | ||
Under the hood, these values are set by calling the firmware built-in <code>/system/bin/impdbg</code> utility. | Under the hood, these values are set by calling the firmware built-in <code>/system/bin/impdbg</code> utility. To check the current encoding values, just run <code>/system/bin/impdbg --enc_info</code> and look for the <code>chnAttr->rcAttr->rcMode</code> and <code>chnAttr->rcAttr->CappedQuality</code> values. | ||
===== RTMP support ===== | ===== RTMP support ===== | ||
Revision as of 21:19, 18 September 2022
Wyze Cams are cheap wireless network cameras by Wyze Labs.
Wyze Cam v3
The Wyze Cam v3 is Wyze Lab's newest IP camera released in late 2020. It improves on the v2 with better night vision, higher FPS (15fps to 20fps for day / 10fps to 15fps for night), and is now better weather-proof by being able to operate between -20°C and 40°C. I have 2 Wyze Cams outdoors and exposed to the elements for the entirety of winter 2021-2022 and they're still working without any issues. However, the camera that faces west and is in direct sunlight appears to have a small fracture in its lens but doesn't appear to greatly affect the image quality.
RTSP support
As of 2022, the only official support for RTSP by Wyze Labs is an old beta version of the RTSP firmware (4.61.0.1). Their official statement is this firmware is not supported and recommends against using it. You may still download the firmware and flash it and the Wyze App still allows you to enable RTSP with this firmware version installed.
Why would you want RTSP? Real-time Streaming Protocol (RTSP) support exposes the camera's live video feed via the RTSP protocol. This is typically useful if you want to watch your camera (such as with VLC or MPC-HC), use some sort of network video recording (NVR), or use some sort of motion monitoring/recording system (like with Kerberos.io or Frigate). If you have multiple IP Cameras with RTSP support, you can use something like aler9's rtsp-simple-server to 'collect' all the streams onto one server.
Hacking the Wyze Cam v3
Because the v3 uses the Ingenic T31 chip with secure boot enabled, you cannot load a modified firmware file (demo.bin) on the SD card as you could with the Wyze Cam v2. Rather, you need to rely on other approaches to modifying the firmware. Currently, there are two known options:
- Use WyzeHack's OTA update method where your customized firmware is sent instead of the official firmware.
- Exploit the fact that uboot attempts to load a file from the SD card called
factory_t31_ZMC6tiIDQNwhich can then be used to sideload hacks.[1] The firmware on the onboard flash memory will remain in tact, making this a very safe and irreversible option with the only downside that you need a SD card.
Community firmware hacks
These hacks work with the latest official firmware released by Wyze. These methods may be preferable to the beta firmware simply because they're more up to date with known vulnerabilities being patched.
- wyze-bridge isn't a firmware hack per-se, but it lets you obtain a RTSP steam from your Wyze Cam. This project achieves this by streaming the video data from the Wyze cloud to a local RTMP server. The downside to this is that it wastes lots of internet bandwidth as the video feed is constantly uploaded (and downloaded if you're recording it locally). See: https://github.com/mrlt8/docker-wyze-bridge
- wz_mini_hacks project side-loads firmware changes using a SD card. This does not change the firmware on the flash and is very safe to use and experiment with. This project takes the WyzeHacks work a little further and adds additional features. RTSP and RTMP streaming is supported. Installation is extremely easy. See: https://github.com/gtxaspec/wz_mini_hacks
- (Old and unsupported now) Use the WyzeHacks project which pushes a modified firmware by faking the Wyze App. This is technically more involved as you must now spoof your DNS. It may also be slightly more risky as you are modifying the firmware on flash that Wyze did not intend. Using the FiveLeavesLeft modification, you can expose a MPEG video stream via HTTP which can be re-encoded to a RTSP stream using ffmpeg. See: https://github.com/HclX/WyzeHacks
More information on each of these hacks below.
Wyze-bridge
Use the wyze-bridge docker stack available at https://github.com/mrlt8/docker-wyze-bridge. This will set up a container that will retrieve live video data from the Wyze cloud using your Wyze credentials and create a RTMP stream which is then pushed to a RTSP server running in another container. The end result is a local RTSP server that broadcasts your Wyze Cam.
The downside to this approach is that the video data is constantly streamed from your Wyze Cam to the cloud and then subsequently downloaded from the cloud to your local RTSP server. This introduces latency and uses lots of bandwidth. My testing with a relatively quiet video feed shows the camera uploading at around 100kb/s which would result in approximately 250GB being uploaded and an additional 250GB downloaded per month.
wz_mini_hacks
wz_mini_hacks is a collection of neat hacks that bundles a bunch of features. You may find it at https://github.com/gtxaspec/wz_mini_hacks. wz_mini_hacks side loads hacks to the official firmware using a SD card as part of the camera's boot process. This hack is completely reversible by either removing the SD card or removing the factory image that's loaded (factory_t31_ZMC6tiIDQN), since nothing is changed on the camera's flash memory itself.
To install the hack, it's suggested that you update to the latest supported version (4.36.9.139), though any versions from around this time frame should be compatible as they all use the same kernel version. If the install process doesn't work, try upgrading your firmware in the Wyze App or by manually reflashing the firmware. Next, copy the contents of the SD_ROOT directory to a FAT formatted SD card. Insert the SD card into the camera and power it on.
LED control
There is a cmd command that sends commands to iCamera. To control the IR LEDs, you can run cmd irled on and cmd irled off.
RTSP support
To get RTSP working, you will then need to edit the file wz_mini/wz_mini.conf file and enable the RTSP options. Eg:
RTSP_LOGIN="admin"
RTSP_PASSWORD="wyzecam"
RTSP_PORT="8554"
RTSP_HI_RES_ENABLED="true"
RTSP_HI_RES_ENABLE_AUDIO="true"
RTSP_HI_RES_FPS="15"
RTSP_HI_RES_MAX_BITRATE="2048"
RTSP_HI_RES_TARGET_BITRATE="1024"
RTSP_HI_RES_ENC_PARAMETER="2"
The bitrate values here get applied to the underlying hardware encoder. When left unset, the target bitrate is set to 720kb/s and max bitrate set to 960kb/s. You may choose to set these bitrates higher at the cost of more bandwidth.
The ENC_PARAMETER value specifies the biitrate control modes. The wz_mini hack has some notes on the possibe values, though I'm unable to find any other notes that support these yet. Values are:
0. FIXQP / CQP - Fixed/Constant Quantization Parameter. Not supported here.1. CBR - Constant Bitrate. This forces the encoder to always use the target bitrate. Not supported here.2. VBR - Variable Bitrate, or 2-Pass Average Bitrate.4. CVBR / VBV - Constrained VBR or Video Buffering Verifier. Ensures bitrates are constrained to a certain maximum.8. CQ / CRF - Constant Quality / Constant Rate Factor. This gives a constant quality for the entire stream.
The default value when left unset is 8, or constant quality. Which one should you use? For surveillance applications, probably constant quality (8) if bandwidth isn't an issue, or variable bitrate (VBR) if bandwidth is constrained. You can read more about these different rate controls: https://slhck.info/video/2017/03/01/rate-control.html
Under the hood, these values are set by calling the firmware built-in /system/bin/impdbg utility. To check the current encoding values, just run /system/bin/impdbg --enc_info and look for the chnAttr->rcAttr->rcMode and chnAttr->rcAttr->CappedQuality values.
RTMP support
If you want the Wyze Cam to also push its video stream to a remote RTMP server, you can use the RTMP_STREAM_ENABLED options. However, this option only supports a few specific services such as YouTube, Twitch, and Facebook (based on the source code on the rtmp-stream.sh script). If you need to push it to a custom RTMP server, you will have to edit this script.
Issues with wz_mini_hacks
RTSP Stream codec: I had issues pushing the RTSP stream to the aler9 rtsp-simple-server using the default ffmpeg options. Because the aler9 RTSP server only accepts H264 and AAC codecs only, and because the Wyze Cam RTSP stream is using H265 and PCM, the audio stream has to be reencoded to AAC using ffmpeg.
The issue however is that when using the default ffmpeg command from the wz_mini_hacks RTMP stream script which uses the AAC HE profile, the aler9 RTSP server will drop the connection, resulting in ffmpeg logging av_interleaved_write_frame(): Broken pipe before quitting. The only way to get this working is to not use the aac_he audio profile. The ffmpeg command that seems to work for me is this:
$ /opt/wz_mini/bin/ffmpeg \
-rtsp_transport udp -y -i rtsp://admin:password@0.0.0.0:8554/unicast \
-vcodec copy -f flv \
-c:a libfdk_aac -afterburner 1 -channels 1 -b:a 128k \
rtmp://rtsp-server:1935/v3f
Even with this tweak, the ffmpeg stream to the aler9 RTSP server is very unreliable and constantly breaks.
Solution - You can tweak the rtsp-simple-server configuration file to automatically stream from the Wyze Cam directly without needing ffmpeg. Edit the rtsp-simple-server.yml config file and add the following:
camera:
source: "rtsp://admin:wyzecam@10.1.1.30:8554/unicast"
sourceProtocol: tcp
Note that I use TCP for this stream. Using UDP causes a lot of smearing to occur on my network. Setting it to TCP seems to fix this for the most part.
SSH not starting: For some reason, the SSH service (dropbear) doesn't start. This seems to only happen when I reboot the device and works again after I go in and delete some empty directories on the root of the SD card. Possibly corrupt FAT causing something to not work which gets fixed when I plug it into my computer?
Power cycling the Wyze Cam when it enters this state one more time seems to fix the issue. Could it be the SD cards I'm using needs a power cycle for it to show up properly to uboot?
Update: This is really starting to look like an issue with this particular SD card. Possibly could be a counterfeit item or the card is just starting to die. I can't replicate this on another camera with a different type of SD card (also 16GB).
Solution: The SD card likely is a counterfeit. It's missing the shiny holographic stripe that my other Kingston cards have. Replacing it seems to fix this particular issue.
aler9 rtsp-simple-server gives 'ERR: Content-Length exceeds 131072 (it's 1666223)': Using rtsp-simple-server v.0.20.0 to relay a RTSP stream from the Wyze Cam, I am getting 'ERR: Content-Length exceeds 131072 (it's 1666223)' with the video stream stalling out. This seemed to happen occasionally after enabling audio with the RTSP stream in wz_mini.conf.
Workaround: Restarting the Wyze Cam seemed to fix the issue.
WyzeHacks
Possibly unsupported or not working
WyzeHacks hasn't been updated for over a year and Wyze Labs has recently required newer firmware versions to be used by the cameras. As a result, this method is likely not viable anymore. See the wz_mini_hacks option below as an alternative.Thanks to the work by the authors of the WyzeHacks project (https://github.com/HclX/WyzeHacks) and its modified version by FiveLeavesLeft with the streaming support available (https://github.com/FiveLeavesLeft/WyzeHacks), you can stream video data directly from the camera without needing to download the data from the cloud as is the case with the wyze-bridge option. The hack sets up a h264 video stream on the Wyze cam (the file utility reports the data as a JVT NAL sequence) that need to be converted using ffmpeg and sent to the RTSP server.
To get this working:
- Load FiveLeavesLeft's version of WyzeHacks onto the Wyze Cam. More information on installing the hack is below. This method requires your Wyze credentials and works over the air without needing physical access to the device or the SD card. More in the WyzeHacks section below.
- Start a local RTMP server. Easiest thing to do is just run the RTSP server container with the following
docker-composestack. Create a docker-compose.yml file with the following contents. Replace the IP addresses as required. Add/remove the ffmpeg conversion containers as required. Make sure you are publishing to a unique path on the RTSP server.Place the contents in aversion: '3' services: rtsp-server: container_name: rtsp-server image: aler9/rtsp-simple-server environment: - RTSP_PROTOCOLS=tcp ports: - "10.1.1.Y:1935:1935" - "10.1.1.Y:8554:8554" - "10.1.1.Y:8888:8888" wyzecam-v2: image: registry.steamr.com/docker/alpine-ffmpeg:latest command: ["sh", "-c", "wget -q -O - 10.1.3.X:12345/ | ffmpeg -f h264 -i - -tune zerolatency -vcodec copy -f flv rtmp://rtsp-server:1935/v2"] restart: "always" wyzecam-v3: image: registry.steamr.com/docker/alpine-ffmpeg:latest command: ["sh", "-c", "wget -q -O - 10.1.3.X:12345/ | ffmpeg -f h264 -i - -tune zerolatency -vcodec copy -f flv rtmp://rtsp-server:1935/v3"] restart: "always"
docker-compose.ymlfile and then start up the stack withdocker-compose up -d. This should bring up both the RTSP server and the ffmpeg conversions for each camera. - If things are working right, you should be able to access the video feed at
rtsp://10.1.1.Y:8554/camera
I've used this hack on 4 Wyze Cam v3 devices and it works without any issues. The only limiting issue is that there is no audio with these streams since the video frames are retrieved using wget from an external server. Furthermore, there's no way to load this hack on newer units.
Remote access
Depending on which firmware hack you installed, you can connect to the Wyze Cam using either telnet or SSH.
The default username and password set on the Wyze Cam v3 is:
- Username:
root - Password:
WYom2020or, on newer firmwares:WYom20200(passwd hash isaVG8.5PMEOfnQ)
Official firmware notes
Here are some notes on Wyze Cam v3 official firmware.
Download older firmware files
You can download the firmware files from their servers at https://download.wyzecam.com/firmware/v3/. There is no directory listing, so you'll have to guess the filenames based on the firmware version numbers. The firmware versions are available from their release notes posted on their website at https://support.wyze.com/hc/en-us/articles/360024852172-Release-Notes-Firmware.
To help anyone who stumbles on this page, here are the links to some older versions:
How to upgrade / downgrade firmware
To upgrade or revert back to a specific firmware on the Wyze Cam, simply extract the .zip file into the root of a SD card. For the Wyze Cam v3, the firmware file should be named demo_wcv3.bin. Insert the SD card into the camera and then power it on while holding the setup button until both blue + red (appearing purple) LEDs are on.[2] The flashing process should take about a minute, though it will likely depend on the speed of your SD card.
As of January 2022, Wyze has restricted the ability to use certain older firmware versions[3] and is forcing users to use an updated Wyze app. I'm unsure what the minimum Wyze Cam version is, though I was able to roll back to 4.36.2.5 without issue.
Side loading hacks
The firmware files for the v3 are signed and verified using ed25519. The signature is placed at the last 64 bytes of the demo.bin file and is checked by uboot. The files on flash don't appear to be verified which is why WyzeHack's OTA firmware update persists.
Fortunately for us, uboot also checks for a file called factory_t31_ZMC6tiIDQN on the SD card and attempts to boot that as the kernel image without any signature verification. You can build a custom image using the instructions at https://github.com/gtxaspec/wz_mini_hacks/blob/master/documentation/developer_environment.md.
Setup a Wyze Cam without the Wyze App or internet
You can indeed set up a Wyze Cam v3 out of the box without the Wyze App and use it as a normal RTSP-enabled IP Camera. This can be accomplished using the wz_mini_hacks firmware hack on an SD card and some tweaks to get the initial setup complete.
- Unbox the Wyze Cam v3
- Place the latest firmware file on a SD card (I used 4.36.9.139) and insert it to the Wyze Cam
- Hold the SETUP button and power on the device. Hold the button down until you see both blue and red lights on
- After the upgrade is done, the camera will reboot and begin flashing the red LED. This red LED probably means the device isn't set up and is awaiting you to do something. Power off the camera.
- Insert the SD card containing wz_mini_hacks into the camera. When you set up the SD card, ensure that your SSH keys are set in
wz_mini/etc/ssh/authorized_keys. We will need to SSH in once the camera comes up to finish up the setup. - Power on the camera. You should hear "WZ Mini initializing" message.
- Press the SETUP button once. You should hear "Ready to connect" and should now be waiting for a QR code.
- Present it with a QR code with your WiFi settings. If you need to generate this QR code without the Wyze App, see the WiFi QR code section below.
- The camera should join your wireless network and you should be able to SSH into it at this point.
- SSH in and ensure that:
- Your WiFi settings are saved in
/configs/.wifissidand/configs/.wifipasswd - Edit the
/configs/.user_configfile and ensure thebindOK=0line is set tobindOK=1. This will allow the camera to use these config files on boot. Without this, the camera will reboot back into the blinking red state. - If you want RTSP, edit
/opt/wz_mini/wz_mini.confand ensure RTSP is enabled.
- Your WiFi settings are saved in
- Reboot the camera and verify it can come up and connect to your network.
WiFi QR code
The initial WiFi configuration is sent to the Wyze Cam using a QR code. This QR code can be generated from the Wyze App without needing to connect the camera to their cloud (Just go through the process of adding a new Camera, enter your WiFi settings, then take a screenshot of the generated QR code for future use).
The QR code generated for the Wyze Cam v3 is a URL encoded string containing 6 variables. The string itself will look like this: b=68c7ebd2-07c6-4c&s=ZGQtd3J0&p=NgcDWVcmOzlZUysDFhs2CgoxOyMbChYGEA==&t=-6&r=USA&ty=1.
Here are each value in a bit more detail:
b=[a-z0-9-]{8}-[a-z0-9-]{4}-[a-z0-9-]{2}- A randomly generated alphanumeric string in 3 sections. 8 characters, dash, 4 characters, dash, 2 characters. I'm not sure if this is actually used anywhere by the camera.s=base64(SSID)- The WiFi SSID in base64p=base64(xor(password, key))- The base64 encoded and XOR encrypted password. The key here isWfb86GZX82JbwzWkkPZBzkwgqtpswmlqqytjfrfxjzccjsyyaylbbdmzspxymdwz.t=-6- Your timezone.r=USA- The country or region? I'm from Canada but the Wyze app still generated it as USA.ty=1- Thank-you? I'll take it.
There's a handy dandy tool at https://codepen.io/ril3y/full/gXyzmO/ which can generate the QR code for you in the browser without needing the Wyze App.
Running without internet
Newer versions of the firmware (4.36.2.5 or later?) requires a constant internet connection to function. On these newer firmware versions, the internal iCamera process will reboot the camera when it's unable to contact the Wyze's servers. The reboot happens within about a minute or so and basically renders the device unusable at this state. The reboot is triggered by iCamera, possibly at a kernel or hardware watchdog level because locking down the reboot command isn't sufficient and killing iCamera eventually triggers a reboot as well. Making the Wyze domains resolve to another server is also ineffective as it also triggers a reboot.
The old firmware versions (4.36.0.x ~ 4.36.2.5 including the RTSP beta firmware 4.61.0.1) does not have the issue and I have had no issues using the Wyze Cam on these older versions after placing it on a non-routable network which effectively blocks all internet traffic to the camera. However, the iCamera process will attempt to restart the wireless connection periodically which results in 4-5 second disconnects every minute or so. The camera is functional even with these short disconnections, but it will cause stuttering and dropped frames.
Fixing the WiFi dropouts in iCamera
The iCamera program appears to bring the WiFi interface down and up when it is unable to reach some servers including Wyze's API server and Google. After 3 retries, the process will bounce the WiFi interface, kill and restart the DHCP client and WPA supplicant processes, and rewrite the hosts and resolv.conf files. It is this bouncing that causes the brief 4-5 second disconnects.
Fortunately, tracing down where exactly in the binary that triggers this behavior within the iCamera binary is made easy with the verbose iCamera debug messages (with source filenames and line numbers!) combined with some strace outputs I collected from the process during these dropout periods. There is a function that handles the network setup which sets up the WiFi interface, obtains an IP from DHCP, then attempts to check whether a domain works (DN something in the logs). When the domain check fails 3 times, it calls a few other functions to restart the network setup process over again.
The dropouts can be 'fixed' by overwriting the domain check with no-ops and ensuring that the retry loop never exits by no-opping out the decrement or store instructions. This will make iCamera retry the domain check rather than bouncing the network interface after 3 tries. There are other jobs that spawn via threadpool messages such as to validate the network (net-valid) and to uploading reboot log (upload-rebootlog). There are other calls to functions that send messages to a dongle (probably some other Wyze peripheral?). All these can be no-op'ed and be bypassed.
Here's the patch script that should work for 4.61.0.1 (RTSP beta) and 4.36.9.139 (latest official as of this writing). You can run this directly on the Wyze Cam and then reboot to apply. To revert, copy the original copy of iCamera script from SD_ROOT/wz_mini/usr/bin/iCamera onto your SD card.
#!/opt/wz_mini/bin/bash
set -e
PATH=$PATH:/opt/wz_mini/tmp/.bin
cd /tmp
# Make a copy to patch
cp /system/bin/iCamera iCamera
Version=""
# Verify the iCamera version is supported
MD5Sum=$(md5sum iCamera | awk '{print $1}')
if [[ "$MD5Sum" == "04b90d6d77be72a4dd8c18da4b31946a" ]] ; then
Version="4.61.0.1"
fi
if [[ "$MD5Sum" == "b1c96d966226d76db86c96ecdfdd79e9" ]] ; then
Version="4.36.9.139"
fi
if [ -z "$Version" ] ; then
echo "Unsupported version. MD5sum: $MD5Sum";
exit 1
fi
# Check to see if the patched version is installed and is up to date
if [ -f /opt/wz_mini/usr/bin/iCamera.patched ] ; then
# Check the build date. (this check may be brittle?)
OriginalDate=$(strings /system/bin/iCamera | grep Build -A 1 | tail -n 1)
PatchedDate=$(strings /opt/wz_mini/usr/bin/iCamera.patched | grep Build -A 1 | tail -n 1)
if [[ "$OriginalDate" == "$PatchedDate" ]] ; then
echo "Patch already applied to current iCamera version."
exit 0
fi
echo "Patched iCamera binary differs in build date. ($OriginalDate vs $PatchedDate)."
echo "Patch is now reapplying."
fi
# Patch out the calls to test cloud url, which calls that DN function
# This isn't strictly necessary, though it will cause iCamera to constantly retry the tests and spam the iCamera outputs with messages like
# DN:854]err: (getaddrinfo) fail:-2(Name or service not known), (domain: www.google.com
# so we'll comment these calls here to make it hush up
function patch_out_calls_to_test_cloud_url() {
[[ "$Version" == "4.61.0.1" ]] && Address="0x603b0 0x602d4"
[[ "$Version" == "4.36.9.139" ]] && Address="0x89938 0x89858"
echo -e "\n\n====> Calling ${FUNCNAME[0]}\n"
for i in $Address ; do
echo -e "\nOriginal at $i"
dd if=iCamera bs=1 count=4 skip=$(($i)) 2>/dev/null | xxd
echo "Patched"
printf '\x00\x00\x00\x00' | dd conv=notrunc of=iCamera bs=1 seek=$(($i)) 2> /dev/null
dd if=iCamera bs=1 count=4 skip=$(($i)) 2>/dev/null | xxd
done
}
# Patch out the threadpool_add_job calls for net-valid and upload-rebootlog, and dongle send
function patch_out_jobs_after_connect () {
[[ "$Version" == "4.61.0.1" ]] && Address="$(seq 0x070d0 4 0x07114)"
[[ "$Version" == "4.36.9.139" ]] && Address="$(seq 0x7b184 4 0x7b1cc)"
echo -e "\n\n====> Calling ${FUNCNAME[0]}\n"
# Everything up until the last branch instruction
for i in $Address ; do
echo -e "\nOriginal at $i"
dd if=iCamera bs=1 count=4 skip=$(($i)) 2>/dev/null | xxd
echo "Patched"
# noop
printf '\x00\x00\x00\x00' | dd conv=notrunc of=iCamera bs=1 seek=$(($i)) 2> /dev/null
dd if=iCamera bs=1 count=4 skip=$(($i)) 2>/dev/null | xxd
done
}
# When our calls to DN check cloud url fails, we run into the code that calls funky_network_function(0). We don't want that. So noop all this out
# All the code that sets DAT_005e4d54=0, prints debug message, and calls funky_network_func(0) is nooped out here.
# This fixes the network from going back to the idle state and bouncing everything
# The call to print debug message could probably be left intact... we don't actually prevent 005e4d50=0 though..
function patch_out_network_reset_to_idle () {
[[ "$Version" == "4.61.0.1" ]] && Address="$(seq 0x6041c 4 0x6045c)"
[[ "$Version" == "4.36.9.139" ]] && Address="$(seq 0x899a4 4 0x899e4)"
echo -e "\n\n====> Calling ${FUNCNAME[0]}\n"
for i in $Address ; do
echo -e "\nOriginal at $i"
dd if=iCamera bs=1 count=4 skip=$(($i)) 2>/dev/null | xxd
echo "Patched"
# noop
printf '\x00\x00\x00\x00' | dd conv=notrunc of=iCamera bs=1 seek=$(($i)) 2> /dev/null
dd if=iCamera bs=1 count=4 skip=$(($i)) 2>/dev/null | xxd
done
}
# For some reason on 4.36.9.139, iCamera starts the code_test section which just constantly lists /tmp over and over every 10 seconds.
# I don't know why this is getting triggered, so I'm going to patch this out from being called.
function patch_out_code_test_enable() {
[[ "$Version" == "4.61.0.1" ]] && return; # No need to do this as it doesn't seem to be a problem
[[ "$Version" == "4.36.9.139" ]] && Address="0x7dfcc"
echo -e "\n\n====> Calling ${FUNCNAME[0]}\n"
for i in $Address ; do
echo -e "\nOriginal at $i"
dd if=iCamera bs=1 count=4 skip=$(($i)) 2>/dev/null | xxd
echo "Patched"
# noop
printf '\x00\x00\x00\x00' | dd conv=notrunc of=iCamera bs=1 seek=$(($i)) 2> /dev/null
dd if=iCamera bs=1 count=4 skip=$(($i)) 2>/dev/null | xxd
done
}
patch_out_calls_to_test_cloud_url
patch_out_jobs_after_connect
patch_out_network_reset_to_idle
patch_out_code_test_enable
echo -en "\n\nPatching done. MD5 hash: "
md5sum iCamera
# Place it on the SD card
cp iCamera /opt/wz_mini/usr/bin/iCamera.patched
# Patch the iCamera script to use the patched executable
sed -i 's/\/system\/bin\/iCamera/\/opt\/wz_mini\/usr\/bin\/iCamera.patched/' /opt/wz_mini/usr/bin/iCamera
This patch isn't quite complete however. I notice that there are DNS lookups to api.wyzecam.com is still being made every 5-7 seconds. Since this is on an isolated network, it might not really matter.
Configuring iCamera without internet
Here are some tips for those that are attempting to run their Wyze Cam on an isolate network or on a network that blocks internet access to these cameras:
- The Wyze firmware sets the clock using
/system/bin/timesyncwhich includes hard coded NTP servers. If these server's hostnames resolve to a local NTP server, it seems like timesync will update the hardware clock when I run it manually. - Alternative ways to set the clock is to use the date command (have something telnet/ssh in periodically to set the clock) or use wz_mini_hacks which include the ntpd busybox applet that can be used to sync the clock through your own NTP server.
- If you need to change a camera setting that's controlled by the Wyze App, the
/configs/.user_configsfile might be of interest to you (more about this below).
Camera configuration
The local camera configuration is stored in /configs/.user_config. The file itself looks something like this:
[NET]
bindOk=1
p2pid=####################
r_encr=################
[SETTING]
night_cut_thr=1
nightVision=3
night_led_ex=2
NIGHT_LED_flag=2
verSwitch=2
horSwitch=2
indicator=1
watermark_flag=2
recordType=3
drawBoxSwitch=2
bitRate=120
timezone=-6
[CAMERA_INFO]
TZ_STR=MST+0700MDT+0600,M3.2.0/02:00:00,M11.1.0/02:00:00
The [NET] section contains bindOk which should always be set to 1. Setting this to 0 will force the Wyze Cam to read a QR code before connecting to a wireless network. The p2pid and r_encr can be left empty if you never intend to have the camera talk to the cloud.
The [SETTING] section contains configuration keys and are described below. This is an incomplete list and was what I found by looking at the /configs/.user_configs file after changing each setting in the Wyze App. You should be able to change the values in this file and restart iCamera for it to take effect.
| key | description | values |
|---|---|---|
nightVision
|
Enable IR | 1 = on, 2 = off, 3 = auto |
night_led_ex
|
IR type? | 1 = near, 2 = far |
night_cut_thr
|
IR threshold | 1 = 'dusk mode', 2 = 'dark mode' |
indicator
|
Camera LED status lights | 1 = on, 2 = off |
verSwitch
|
Flip vertically | 1 = no flip, 2 = flip |
horSwitch
|
Flip horizontally | 1 = no flip, 2 = flip |
osdSwitch
|
Show timestamp | 1 = show, 2 = hide |
watermark_flag
|
Show wyze logo | 1 = show, 2 = hide |
AST
|
Audio recording | 1 = on, 2 = off |
recordType
|
Record to SD card | 1 = continuous, 2 = events only, 3 = no recording |
MASwitch
|
Record when motion detected | 1 = enable, 2 = disable |
AASwitch
|
Record when audio detected | 1 = enable, 2 = disable |
SASwitch
|
Record when smoke alarm detected | 1 = enable, 2 = disable |
CASwitch
|
Record when CO alarm detected | 1 = enable, 2 = disable |
AMALevel
|
Sound detection sensitivity | 2 through 254, higher is more sensitive |
MMALevel
|
Motion detection sensitivity | 2 through 254, higher is more sensitive |
drawBoxSwitch
|
Draw the green boxes around objects | 1 = enable, 2 = disable |
There are other setting keys that can be found in the iCamera startup logs. See below:
<Reading> /configs/.user_config
[user_config.c:373][USER SET] [indicator ] [2]
[user_config.c:373][USER SET] [nightVision ] [3]
[user_config.c:373][USER SET] [bitRate ] [120]
[user_config.c:373][USER SET] [res ] [1]
[user_config.c:373][USER SET] [fps ] [20]
[user_config.c:373][USER SET] [horSwitch ] [2]
[user_config.c:373][USER SET] [verSwitch ] [2]
[user_config.c:373][USER SET] [osdSwitch ] [1]
[user_config.c:373][USER SET] [logSd ] [1]
[user_config.c:373][USER SET] [logUdisk ] [1]
[user_config.c:373][USER SET] [telntSwitch ] [2]
[user_config.c:373][USER SET] [recordType ] [3]
[user_config.c:373][USER SET] [MASwitch ] [2]
[user_config.c:373][USER SET] [MALevel ] [5]
[user_config.c:373][USER SET] [AASwitch ] [2]
[user_config.c:373][USER SET] [AALevel ] [5]
[user_config.c:373][USER SET] [SASwitch ] [2]
[user_config.c:373][USER SET] [CASwitch ] [2]
[user_config.c:373][USER SET] [TBStart ] [0]
[user_config.c:373][USER SET] [TBDuration ] [1440]
[user_config.c:373][USER SET] [drawBoxSwitch] [2]
[user_config.c:360]timezone value -6 read from config file
[timesync_utility.c:160]TZ file is set with UTC-06:00[user_config.c:373][USER SET] [timezone ] [-6]
[user_config.c:373][USER SET] [MMALevel ] [100]
[user_config.c:373][USER SET] [AMALevel ] [100]
[user_config.c:373][USER SET] [MAT ] [0]
[user_config.c:373][USER SET] [AST ] [1]
[user_config.c:373][USER SET] [motionTrack ] [2]
[user_config.c:373][USER SET] [motionCruisin] [2]
[user_config.c:373][USER SET] [AASX ] [25]
[user_config.c:373][USER SET] [AASY ] [25]
[user_config.c:373][USER SET] [AALX ] [50]
[user_config.c:373][USER SET] [AALY ] [50]
[user_config.c:373][USER SET] [motionbackvalue] [1]
[user_config.c:373][USER SET] [slide_x ] [0]
[user_config.c:373][USER SET] [slide_y ] [0]
[user_config.c:373][USER SET] [preset_x ] [0]
[user_config.c:373][USER SET] [preset_y ] [0]
[user_config.c:373][USER SET] [ubootflag ] [0]
[user_config.c:373][USER SET] [exposureModel] [0]
[user_config.c:373][USER SET] [limit_max_x ] [0]
[user_config.c:373][USER SET] [limit_min_x ] [0]
[user_config.c:373][USER SET] [limit_max_y ] [0]
[user_config.c:373][USER SET] [limit_min_y ] [0]
[user_config.c:373][USER SET] [motor_limit_flag] [0]
[user_config.c:373][USER SET] [resolution_select_flag] [1]
[user_config.c:373][USER SET] [low_bitrate_num] [30]
[user_config.c:373][USER SET] [watermark_flag] [2]
[user_config.c:373][USER SET] [speaker_vol ] [50]
[user_config.c:373][USER SET] [pir_alarm_switch] [0]
[user_config.c:373][USER SET] [NIGHT_LED_flag] [2]
[user_config.c:373][USER SET] [sdcard_exist ] [0]
[user_config.c:373][USER SET] [autoRecordNum] [0]
[user_config.c:373][USER SET] [autoRecordMem] [0]
[user_config.c:373][USER SET] [dongle_led ] [1]
[user_config.c:373][USER SET] [alarmDate ] [255]
[user_config.c:373][USER SET] [alarmInterval] [300]
[user_config.c:373][USER SET] [SDEVICE_ACTION] [0]
[user_config.c:373][USER SET] [voice_switch ] [2]
[user_config.c:373][USER SET] [voice_scene ] [1]
[user_config.c:373][USER SET] [auto_clarity ] [2]
[user_config.c:373][USER SET] [cmc_upload ] [1]
[user_config.c:373][USER SET] [p2p_log ] [2]
[user_config.c:373][USER SET] [night_led_ex ] [2]
[user_config.c:373][USER SET] [night_cut_thr] [1]
[user_config.c:373][USER SET] [slightEnable ] [1]
[user_config.c:373][USER SET] [slightMode ] [2]
[user_config.c:373][USER SET] [slightLowLight] [2]
[user_config.c:373][USER SET] [slightBright ] [255]
[user_config.c:373][USER SET] [hms_enable ] [0]
[user_config.c:373][USER SET] [hms_state ] [0]
[user_config.c:373][USER SET] [slightPreemptSw] [0]
[user_config.c:320]timezone string set to [MST+0700MDT+0600,M3.2.0/02:00:00,M11.1.0/02:00:00]
Note that the TZ_STR value is not what libc would expect. If you intend to set the TZ value in Linux as an environment variable, you need to convert the hour-minute values in the first field to be separated by a colon. For example, MST+0700MDT+0600 should instead be MST7:00MDT6:00 or MST7MDT6. In my case, the TZ value should be: TZ=MST7:00MDT6:00,M3.2.0/02:00:00,M11.1.0/02:00:00
iCamera Logs
To see the iCamera output, you'll have to restart iCamera in the foreground. This can be done by running kill -9 $(pgrep iCamera) and then immediately calling /usr/bin/iCamera. There is a hardware watchdog that needs to be satisfied or else the hardware will automatically reset. As a result, you'll have to make sure you start iCamera within 10 or so seconds.
For the RTSP firmware, you'll have to also kill the liveMediaServer for iCamera to come up properly. Run: kill -9 $(pgrep iCamera.patch) ; kill -9 $(pgrep liveMediaServer)
For the wz_mini_hacks, start iCamera with: LD_PRELOAD=libsetunbuf.so /opt/wz_mini/usr/bin/iCamera -- dslog --priority DEBUG --facility USER iCamera
Some observations about the v3
After getting telnet access, here are some stuff about the v3 which might be of interest.
[root@WyzeCam-ED6A:~]# cat /proc/cpuinfo
system type : Swan
machine : Unknown
processor : 0
cpu model : Ingenic Xburst V0.0 FPU V0.0
BogoMIPS : 1391.00
wait instruction : yes
microsecond timers : no
tlb_entries : 32
extra interrupt vector : yes
hardware watchpoint : yes, count: 1, address/irw mask: [0x0fff]
isa : mips32r1
ASEs implemented :
shadow register sets : 1
kscratch registers : 7
core : 0
VCED exceptions : not available
VCEI exceptions : not available
Hardware : isvp
Serial : 00000000 00000000 00000000 00000000
## MTD partitions hard coded to cmdline
[root@WyzeCam-ED6A:~]# cat /proc/cmdline
console=ttyS1,115200n8 mem=96M@0x0 rmem=32M@0x6000000 init=/linuxrc rootfstype=squashfs root=/dev/mtdblock2 rw mtdparts=jz_sfc:256K(boot),1984K(kernel),3904K(rootfs),3904K(app),1984K(kback),3904K(aback),384K(cfg),64K(para)
The firmware version can be found in /system/bin/app.ver:
[root@WyzeCam-7419:system]# cat /system/bin/app.ver
[VER]
appver=4.36.0.280
MTD Partitions
There is a 16MB flash. The MTD partitions are coded into the cmdline: mtdparts=jz_sfc:256K(boot),1984K(kernel),3904K(rootfs),3904K(app),1984K(kback),3904K(aback),384K(cfg),64K(para)
On startup, we see the following kernel message.
# dmesg
[ 0.433992] 8 cmdlinepart partitions found on MTD device jz_sfc
[ 0.440116] Creating 8 MTD partitions on "jz_sfc":
[ 0.445056] 0x000000000000-0x000000040000 : "boot"
[ 0.450404] 0x000000040000-0x000000230000 : "kernel"
[ 0.455910] 0x000000230000-0x000000600000 : "rootfs"
[ 0.461366] 0x000000600000-0x0000009d0000 : "app"
[ 0.466624] 0x0000009d0000-0x000000bc0000 : "kback"
[ 0.472007] 0x000000bc0000-0x000000f90000 : "aback"
[ 0.477436] 0x000000f90000-0x000000ff0000 : "cfg"
[ 0.482645] 0x000000ff0000-0x000001000000 : "para"
cfgonmtdblock6is mountedrwas/configs.apponmtdblock3is mountedroas/system.rootfsonmtdblock2is mountedroas/.
Wyze Cam v2
There are two firmwares available to the v2:
- Dafang Hacks (https://github.com/EliasKotlyar/Xiaomi-Dafang-Hacks) - this is a hack that is loaded with the stock firmware and adds additional features. You may also use the WyzeHacks on the Wyze Cam v2 which allows enabling telnet access on the stock firmware.
- OpenMiko (https://github.com/openmiko/openmiko) - A drop in replacement for the stock firmware and allows you to use the v2 without needing Wyze's cloud services.
RTSP streaming
There is an official firmware with RTSP streaming support built in. However, you may also do the same RTSP streaming hacks with Wyse-bridge and WyzeHacks as I described on the Wyze Cam v3 section above as it works just the same.
I ended up using the WyzeHacks on the v2 even with the RTSP firmware because the RTSP stream was less stable than the hacked h264 stream. Follow the WyzeHacks instructions in the Hacks section below.
Telnet access
The default username and password set on the Wyze Cam v2 is:
- Username:
root - Password:
ismart12
Dafang Hacks
Clone the git repository at https://github.com/EliasKotlyar/Xiaomi-Dafang-Hacks. Format a new SD card with FAT32 and copy everything from firmware_mod to the root of the SD card. Edit config/wpa_supplicant.conf to look something like this:
# For more configuration option please see:
# https://w1.fi/cgit/hostap/plain/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=0
ap_scan=1
network={
ssid="wifi-network-ssid"
# Uncomment to connect to Hidden SSIDs
#scan_ssid=1
key_mgmt=WPA-PSK
pairwise=CCMP TKIP
group=CCMP TKIP WEP104 WEP40
psk="wpa-passphrase"
priority=2
}
The default username and password is root and ismart12.
NFS notes
NFS can be mounted with
# mount -t nfs -o port=2049,nolock,proto=tcp nas:/data/public /mnt
A JPEG can be captured with
# /system/sdcard/bin/getimage > output.jpg
A quick and dirty way of just capturing pictures every couple seconds would be to create /system/sdcard/config/userscripts/startup/record.sh with
#!/bin/sh
while true ; do
while true ; do
if mount | grep -q nfs ; then
break
fi
echo "Attempting to mount /mnt"
mount -t nfs -o port=2049,nolock,proto=tcp nas:/data/public /mnt
done
Dir="/mnt/wyzecam02/snapshots/`date +%Y%m/%d`"
if [ ! -d $Dir ] ; then
mkdir -p $Dir
fi
/system/sdcard/bin/getimage > $Dir/`date +%H%M%S`.jpg
sleep 2
done &
Hacks
Applying the WyzeHacks hack
This option no longer works without spoofing DNS
Wyze Labs has restricted the payload URL and you can no longer arbitrarily pass in a random payload. As a result, this method won't work.You may try to work around the problem by spoofing the DNS for s3-us-west-2.amazonaws.com and try updating the firmware using this URL: http://s3-us-west-2.amazonaws.com/wuv2/upgrade/WLPP1/firmware/1.2.0.80a.bin
But your mileage may vary in the future as Wyze continues to change the way their API works.
This issue is tracked at https://github.com/HclX/WyzeHacks/issues/132
WyzeHacks contains a series of scripts that push an upload payload via the SD card or over the air that enables additional features including telnet access. To get WyzeHacks working, you will need a Linux computer with Python on the same subnet as the Wyze Cams.
What I did to get the Wyze Cam v3 (and later v2) running telnet was:
- Clone the git repository as well as the WyzeUpdater repo
- Run
build.shon the root directory. This should generate a new release under thereleasedirectory. - Go into the latest release directory
cd ./release/release_0_5_06/. Execute thewyze_updater.pyscript. - If prompted, enter your Wyze credentials. If you get an invalid token error, remove the existing token by running
rm ~/.wyze_token. - Any cameras associated with your account should be visible. Update the desired camera.
- You will see the script wait and print lots of
...'s. You can exit out of it by hitting Ctrl-C since the script does nothing past this point. Note that the update is automatic past this point. The Wyze Cam should come back online automatically. For the v3, the update took a few minutes. For the v2, it was nearly instantaneous.
The console output should look something like this:
$ ./remote_install.sh
Found local config file, including into firmware update archive...
Upgrade/config.inc
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: requests in /usr/lib/python3.9/site-packages (2.25.1)
Requirement already satisfied: idna<3,>=2.5 in /usr/lib/python3.9/site-packages (from requests) (2.10)
Requirement already satisfied: urllib3<1.27,>=1.21.1 in /usr/lib/python3.9/site-packages (from requests) (1.25.10)
Requirement already satisfied: chardet<5,>=3.0.2 in /usr/lib/python3.9/site-packages (from requests) (4.0.0)
INFO:root:Trying saved credentials from /home/leo/.wyze_token.
INFO:root:Checking device, mac=7C78B23AF941
Device type: Camera (WYZE_CAKP2JFUS)
Device name: v3b
Firmware version: 4.36.0.280
IP Address: 10.1.3.252
Pushing firmware to this device? [y/N]:y
INFO:root:Serving firmware file './firmware.bin' as 'http://s3-us-west-2.amazonaws.com/wuv2/upgrade/WLPP1/firmware/1.2.0.80a.bin', md5=7cde34dd8669101e0a93ae962109d0be
INFO:root:Checking device, mac=A4DA222C2591
Press Ctrl+C when all the updates are done...
.......^C
INFO:root:Stopping http server...
Troubleshooting
Broken pipe while updating
Initially, I had issues with the script where it kept on getting a Broken Pipe exception and then bailing out. This somehow solved itself after moving the laptop to another room, so it might be an issue with the network.
DNS spoofing
Recently, Wyze Labs have changed their API such that you can no longer set an arbitrary firmware URL. Attempting to do so will result in a RuntimeError: Request failed, error 3005:UnauthorizedOperation error. To work around this, you will need to:
- Spoof
s3-us-west-2.amazonaws.comto a local web server hosting your wyze hacks firmware file - Serve the firmware from this web server, so that the URL
http://s3-us-west-2.amazonaws.com/wuv2/upgrade/WLPP1/firmware/1.2.0.80a.binworks - Edit the wyze_updater.py script so that the URL is set to this specific URL by adding the following line:
url = build_url(args.addr, args.ssl, args.port)
url = "http://s3-us-west-2.amazonaws.com/wuv2/upgrade/WLPP1/firmware/1.2.0.80a.bin"
Ensure that the MD5 checksum the wyze_updater.py script shows matches the MD5 of the file that's being served. If it mismatches, the update will fail and the camera will simply reboot without any changes.