Wyze Cam: Difference between revisions

From Leo's Notes
This page was last edited on 16 September 2022, at 04:27.
No edit summary
No edit summary
Line 206: Line 206:


==== Running without internet ====
==== Running without internet ====
Newer versions of the firmware ([https://github.com/gtxaspec/wz_mini_hacks/issues/38#issuecomment-1152235863 4.36.2.5 or later?]) requires a constant internet connection to function. On newer firmware versions, the iCamera process will reboot the camera when it's unable to contact the Wyze's servers. 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.  
Newer versions of the firmware ([https://github.com/gtxaspec/wz_mini_hacks/issues/38#issuecomment-1152235863 4.36.2.5 or later?]) requires a constant internet connection to function. On 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) 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. Additionally, the RTSP beta firmware (4.61.0.1) does not have this issue either and can work without internet.  
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 so that the iCamera retries forever as to never restart the networking on the domain check failure. There are other jobs that spawn which attempts to validate the network (net-valid) and uploading reboot log (upload-rebootlog) which can probably be removed as well.
Here's the patch I came up with for 4.0.61.1.
{{Highlight
| code = #!/bin/bash
cd /tmp
cp /system/bin/iCamera iCamera.org
MD5Sum=$(md5sum iCamera.org {{!}} awk '{print $1}')
if [[ "$MD5Sum" != "04b90d6d77be72a4dd8c18da4b31946a" ]] ; then
        echo "This patch is for iCamera in firmware 4.61.0.1"
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() {
        for i in  0x603b0  0x602d4 ; do
                echo "Patched $i"
                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 () {
        # Everything up until the last branch instruction
        for i in $(seq 0x0070d0 4 0x07114) ; do
                echo "Patched $i"
                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
function patch_out_network_reset_to_idle () {
        for i in $(seq 0x006041c 4 0x06045c) ; do
                echo "Patched $i"
                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
| lang = bash
}}
===== 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:
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:


* Downgrade to a version 4.36.2.5 or below
* Configure the DHCP server so its DNS server is invalid (we don't need to resolve anything, not even NTP)
* Configure the DHCP server so its DNS server is invalid (we don't need to resolve anything, not even NTP)
* If the subnet has internet access, you can also configure the default gateway to a non-routable address to block it from accessing the internet.
* If the subnet has internet access, you can also configure the default gateway to a non-routable address to block it from accessing the internet.

Revision as of 04:27, 16 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.

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 such as with WyzeHack's OTA update method or by exploiting the fact that uboot attempts to load a file from the SD card called factory_t31_ZMC6tiIDQN which can then be used to sideload hacks.[1]

RTSP streaming and firmware hacks

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).

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.

Here are some alternatives to the unsupported RTSP beta firmware. 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.

  1. Use the wyze-bridge docker stack to stream the video data from the Wyze cloud to a local RTMP server. This requires no changes to the firmware on the camera but 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
  2. Use wz_mini_hacks project which is new as of 2022. This project takes the WyzeHacks work a little further and adds additional features. Thsi hack allows the camera to transmit its video feed to a remote RTMP server directly. Installation also involves using a SD card only. See: https://github.com/gtxaspec/wz_mini_hacks
  3. (Old and unsupported now) Use the WyzeHacks project to expose a video stream on your camera which can be transmitted to a local RTMP server using an externally running ffmpeg process. See: https://github.com/HclX/WyzeHacks

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.

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"

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.

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.

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?

WyzeHacks

Unsupported
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:

  1. 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.
  2. Start a local RTMP server. Easiest thing to do is just run the RTSP server container with the following docker-compose stack. 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.
    version: '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"
    
    Place the contents in a docker-compose.yml file and then start up the stack with docker-compose up -d. This should bring up both the RTSP server and the ffmpeg conversions for each camera.
  3. 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: WYom2020 or, on newer firmwares: WYom20200 (passwd hash is aVG8.5PMEOfnQ)

Firmware notes

Here are some notes on Wyze Cam v3 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:

Version Notes Download URL
4.61.0.1 RTSP beta https://download.wyzecam.com/firmware/v3/demo_v3_RTSP_4.61.0.1.zip
4.36.0.125 Nov 2020, Initial firmware https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.0.125.bin.zip
4.36.0.228 https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.0.228.bin.zip
4.36.0.248 https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.0.248.bin.zip
4.36.0.280 Mar 2021 https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.0.280.bin.zip
4.36.1.4 May 2021 https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.1.4.bin.zip
4.36.2.5 Jun 2021, last to not require internet https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.2.5.bin.zip
4.36.3.19 Aug 2021 https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.3.19.zip
4.36.6.17 Nov 2021 https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.6.17.zip
4.36.7.22 Nov 2021 https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.7.22.zip
4.36.8.15 Dec 2021 https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.8.15.zip
4.36.8.26 Feb 2022 https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.8.26.zip
4.36.8.32 Feb 2022 https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.8.32.zip
4.36.9.131 Apr 2022 https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.9.131.zip
4.36.9.139 May 2022 https://download.wyzecam.com/firmware/v3/demo_wcv3_4.36.9.139.zip

How to downgrade firmware

To 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.

However, 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.

Running without internet

Newer versions of the firmware (4.36.2.5 or later?) requires a constant internet connection to function. On 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 so that the iCamera retries forever as to never restart the networking on the domain check failure. There are other jobs that spawn which attempts to validate the network (net-valid) and uploading reboot log (upload-rebootlog) which can probably be removed as well.

Here's the patch I came up with for 4.0.61.1.

#!/bin/bash
cd /tmp

cp /system/bin/iCamera iCamera.org

MD5Sum=$(md5sum iCamera.org | awk '{print $1}')
if [[ "$MD5Sum" != "04b90d6d77be72a4dd8c18da4b31946a" ]] ; then
        echo "This patch is for iCamera in firmware 4.61.0.1"
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() {
        for i in  0x603b0  0x602d4 ; do
                echo "Patched $i"
                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 () {

        # Everything up until the last branch instruction
        for i in $(seq 0x0070d0 4 0x07114) ; do
                echo "Patched $i"
                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
function patch_out_network_reset_to_idle () {
        for i in $(seq 0x006041c 4 0x06045c) ; do
                echo "Patched $i"
                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
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:

  • Configure the DHCP server so its DNS server is invalid (we don't need to resolve anything, not even NTP)
  • If the subnet has internet access, you can also configure the default gateway to a non-routable address to block it from accessing the internet.
  • Without NTP, you can set the date/time by having a remote server connect in periodically to run the date command to set the hardware clock.
  • If you need to change a camera setting that's controlled by the Wyze App, the /configs/.user_configs file might be of interest to you (more about this below).

You might be wondering why I don't allow NTP. I tried to let only NTP traffic through during my testing but the system clock was never set. I think iCamera gets stuck in some sort of loop when it's unable to contact the Wyze servers and never gets around to setting the system clock. Setting the clock manually via telnet/SSH works decently enough for my needs.

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"
  • cfg on mtdblock6 is mounted rw as /configs.
  • app on mtdblock3 is mounted ro as /system.
  • rootfs on mtdblock2 is mounted ro as /.

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

Some setting keys 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

Other notes

A few other notes about the v3.

  • I am running my Wyze Cam v3's on firmware version 4.36.0.200. This was set up in mid 2021. These cameras are configured so the DNS server and network gateway is set to an unused IP address on my network to prevent them from accessing the internet or phoning home. I am streaming RTMP from the cameras to a RTSP server. The correct time is set automatically by a script from my RTSP server using telnet. Everything is self hosted without needing the Wyze app. The only limitation is that there is no audio being recorded.
  • Applying the Wyze hacks on the newer firmware is potentially not possible due to the https requirement and possible DNS validation during the firmware update step.
  • Users have reported that the Wyze is forcing new firmware versions on the cameras now.

Wyze Cam v2

There are two firmwares available to the v2:

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:

  1. Clone the git repository as well as the WyzeUpdater repo
  2. Run build.sh on the root directory. This should generate a new release under the release directory.
  3. Go into the latest release directory cd ./release/release_0_5_06/. Execute the wyze_updater.py script.
  4. If prompted, enter your Wyze credentials. If you get an invalid token error, remove the existing token by running rm ~/.wyze_token.
  5. Any cameras associated with your account should be visible. Update the desired camera.
  6. 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:

  1. Spoof s3-us-west-2.amazonaws.com to a local web server hosting your wyze hacks firmware file
  2. 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.bin works
  3. 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.

See Also