mirror of
https://github.com/gtxaspec/wz_mini_hacks.git
synced 2024-12-26 22:03:35 +00:00
Added 'self-hosted' iCamera patch option to fix intermittent network issues (#312)
* Added iCamera patch option to fix intermittent network issues This commit adds a ENABLE_ICAMERA_PATCH option to wz_mini.conf which will patch the iCamera binary on the most recent firmware version so that the device doesn't try bouncing the wireless interface when iCamera is unable to reach the internet. The iCamera program will be patched as part of the boot process when `ENABLE_ICAMERA_PATCH=true` is set in wz_mini.conf. This patch can be undone by setting `ENABLE_ICAMERA_PATCH=false` and then rebooting. * Updated iCamera patch boot script to uninstall patch on failure In case of an unsupported firmware update / downgrade, the iCamera patch will uninstall itself and revert back to the stock executable. * Set ENABLE_ICAMERA_PATCH default to false The iCamera patch shouldn't be enabled unless network issues are present. The user can toggle this option if they intend to run the Wyze Cam on an isolated network. * Fixed wait_for_icamera pgrep when running patched iCamera The iCamera process may not be at /system/bin/iCamera if we run the patched version of it. This function is used to ensure that iCamera's running before certain things happen. A search for just 'iCamera' should be sufficient for this use case. * Updated the iCamera patch feature as ENABLE_SELFHOSTED_MODE This should make it clear this option should only be used in self-hosted scenarios as it will break functionality with the Wyze App or other Cloud services. * Added iCamera patch support for v2 firmware 4.9.8.1002 This iCamera patch should handle the Wyze Cam v2 firmware 4.9.8.1002 and prevent the firmware from restarting the wireless network after being unable to connect to the Wyze servers. * Fixed iCamera build date check Check was grepping for 'Build' which may include the build time instead of build date. * Updated readme for selfhosted iCamera patch feature * Patched LED lights for v2 firmware After connecting to WiFi, the blue LED status light will no longer blink. * Changed the v2 status LED to remain on when connected Looking at Wyze's documentation, the LED is supposed to be on when it's connected and working. The off state from the last commit was for the powered off state only.
This commit is contained in:
parent
4cb55cbb1e
commit
10dba022a5
14
README.md
14
README.md
@ -540,6 +540,20 @@ ENABLE_CRONTAB="true"
|
||||
|
||||
Enable crontab. Located at `wz_mini/etc/cron/root`
|
||||
|
||||
---
|
||||
### Self-Hosted / Isolated Mode
|
||||
```
|
||||
ENABLE_SELFHOSTED_MODE="true"
|
||||
```
|
||||
|
||||
When enabled, the `iCamera` program will be patched to work nicely in a self-hosted environment. This can be reverted by setting the value to `false` and rebooting. Intended for advanced users only! Do not enable if you use the Wyze App. Disabled by default.
|
||||
|
||||
Normally, the firmware will restart the network interface periodically when it is unable to reach Wyze's servers which results in intermittent network drops. For advanced users that intend to run the Wyze Cam without internet access or on a controlled network, this option will patch the `iCamera` process to function without the Wyze servers.
|
||||
|
||||
Feature supported on:
|
||||
* Wyze Cam v3 firmware: 4.36.9.139, 4.61.0.1
|
||||
* Wyze Cam v2 firmware: 4.9.8.1002
|
||||
|
||||
---
|
||||
|
||||
## Latest Updates
|
||||
|
35
SD_ROOT/wz_mini/etc/init.d/S30patchicamera
Normal file
35
SD_ROOT/wz_mini/etc/init.d/S30patchicamera
Normal file
@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides:
|
||||
# Short-Description: Patches the iCamera binary if in self-hosted mode
|
||||
# Description: The stock iCamera binary will reset the network if it is unable to reach the internet. This binary patch will change this behavior.
|
||||
### END INIT INFO
|
||||
|
||||
. /opt/wz_mini/wz_mini.conf
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
|
||||
echo "#####$(basename "$0")#####"
|
||||
|
||||
if [[ "$ENABLE_SELFHOSTED_MODE" == "true" ]] ; then
|
||||
# Apply the patch. The script here is idempotent.
|
||||
if /opt/wz_mini/usr/bin/patch_icamera.sh apply ; then
|
||||
echo "iCamera patch applied successfully."
|
||||
exit 0
|
||||
else
|
||||
# If the patch failed, we'll fall through and undo
|
||||
echo "iCamera patch failed."
|
||||
fi
|
||||
fi
|
||||
|
||||
# If ENABLE_SELFHOSTED_MODE != "true" or if the patch failed, remove the patch if it exists.
|
||||
/opt/wz_mini/usr/bin/patch_icamera.sh remove
|
||||
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
@ -53,7 +53,7 @@ wait_for_wlan_ip() {
|
||||
}
|
||||
|
||||
wait_for_icamera() {
|
||||
while ! pgrep -f "/system/bin/iCamera" > /dev/null; do
|
||||
while ! pgrep -f "iCamera" > /dev/null; do
|
||||
sleep 5
|
||||
done
|
||||
}
|
||||
|
@ -96,6 +96,7 @@ ENABLE_FSCK_ON_BOOT="false"
|
||||
ENABLE_CAR_DRIVER="false"
|
||||
ENABLE_LOCAL_DNS="false"
|
||||
ENABLE_CRONTAB="false"
|
||||
ENABLE_SELFHOSTED_MODE="false"
|
||||
|
||||
#####DEBUG#####
|
||||
#drops you to a shell via serial, doesn't load app_init.sh
|
||||
|
275
SD_ROOT/wz_mini/usr/bin/patch_icamera.sh
Normal file
275
SD_ROOT/wz_mini/usr/bin/patch_icamera.sh
Normal file
@ -0,0 +1,275 @@
|
||||
#!/opt/wz_mini/bin/bash
|
||||
# Description: Applies the iCamera binary patch to prevent iCamera from restarting the wireless
|
||||
# network when it is unable to reach the internet or Wyze's cloud. This should only be used in
|
||||
# self-hosted environments as it may break Wyze App functionality.
|
||||
# Author: Leo Leung <leo@steamr.com>
|
||||
# Last modified: September 2022
|
||||
#
|
||||
|
||||
set -e
|
||||
PATH=$PATH:/opt/wz_mini/tmp/.bin
|
||||
|
||||
# Firmware version
|
||||
Version=""
|
||||
|
||||
function main() {
|
||||
# Handle remove / apply commands or print the usage message.
|
||||
if [[ "$1" == "remove" ]] ; then
|
||||
remove_patch
|
||||
exit
|
||||
fi
|
||||
|
||||
if [[ "$1" == "apply" ]] ; then
|
||||
apply_patch
|
||||
exit
|
||||
fi
|
||||
|
||||
echo "Usage: $0 [apply|remove]"
|
||||
echo " Applies the iCamera patch to make it work nice without Wyze Cloud connectivity"
|
||||
}
|
||||
|
||||
function determine_version() {
|
||||
# Verify the iCamera version is supported
|
||||
MD5Sum=$(md5sum $1 | awk '{print $1}')
|
||||
|
||||
if [[ "$MD5Sum" == "04b90d6d77be72a4dd8c18da4b31946a" ]] ; then
|
||||
echo "4.61.0.1"
|
||||
elif [[ "$MD5Sum" == "b1c96d966226d76db86c96ecdfdd79e9" ]] ; then
|
||||
echo "4.36.9.139"
|
||||
elif [[ "$MD5Sum" == "b187239d1881a97d4598798a2035c0f3" ]] ; then
|
||||
# v2 camera firmware
|
||||
echo "4.9.8.1002"
|
||||
else
|
||||
echo "Error: Unknown iCamera version with md5sum $MD5Sum"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function apply_patch() {
|
||||
# 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 date" -A 1 | tail -n 1)
|
||||
PatchedDate=$(strings /opt/wz_mini/usr/bin/iCamera.patched | grep "Build date" -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
|
||||
|
||||
# Ensure our version works. This exits if it is unsupported.
|
||||
Version=$(determine_version /system/bin/iCamera)
|
||||
|
||||
# Working in /tmp
|
||||
cd /tmp
|
||||
|
||||
# Make a copy to patch
|
||||
cp /system/bin/iCamera iCamera
|
||||
|
||||
# For the T20/v2 cameras, we also have to patch the libwyzeUtils.so library
|
||||
[ -f /opt/wz_mini/tmp/.T20 ] && cp /system/lib/libwyzeUtils.so libwyzeUtils.so
|
||||
|
||||
# Apply our patches.
|
||||
patch_out_calls_to_test_cloud_url
|
||||
patch_out_jobs_after_connect
|
||||
patch_out_network_reset_to_idle
|
||||
patch_out_code_test_enable
|
||||
# v2 specific
|
||||
patch_wzutil_testconnectbyurl_skip_check
|
||||
patch_v2_led_connect_led
|
||||
|
||||
echo -e "\n\nPatching done."
|
||||
md5sum iCamera
|
||||
[ -f /opt/wz_mini/tmp/.T20 ] && md5sum libwyzeUtils.so
|
||||
|
||||
|
||||
# Place it on the SD card and modify the iCamera script to use it.
|
||||
cp iCamera /opt/wz_mini/usr/bin/iCamera.patched
|
||||
sed -i 's/\/system\/bin\/iCamera/\/opt\/wz_mini\/usr\/bin\/iCamera.patched/' /opt/wz_mini/usr/bin/iCamera
|
||||
|
||||
# the v2 patched library should be copied to /opt/wz_mini/lib
|
||||
if [ -f /opt/wz_mini/tmp/.T20 ]; then
|
||||
cp libwyzeUtils.so /opt/wz_mini/lib/libwyzeUtils.so
|
||||
|
||||
# Fix the LD_PRELOAD to use this patched version first.
|
||||
# The T20 has 'libcallback_t20.so:libtinyalsa.so.2.0.0'
|
||||
sed -i "s/LD_PRELOAD='libcallback_t20.so:libtinyalsa.so.2.0.0'/LD_PRELOAD='\/opt\/wz_mini\/lib\/libwyzeUtils.so:libcallback_t20.so:libtinyalsa.so.2.0.0'/" /opt/wz_mini/usr/bin/iCamera
|
||||
fi
|
||||
|
||||
echo "Installed."
|
||||
}
|
||||
|
||||
function remove_patch() {
|
||||
echo "Reverting iCamera patch."
|
||||
|
||||
# Remove patched iCamera
|
||||
if [ -f /opt/wz_mini/usr/bin/iCamera.patched ] ; then
|
||||
rm -v /opt/wz_mini/usr/bin/iCamera.patched
|
||||
fi
|
||||
|
||||
# Remove patched libwyzeUtils
|
||||
if [ -f /opt/wz_mini/lib/libwyzeUtils.so ] ; then
|
||||
rm -v /opt/wz_mini/lib/libwyzeUtils.so
|
||||
fi
|
||||
|
||||
# Ensure iCamera shim script points to /system/bin/iCamera
|
||||
if grep -q iCamera.patched /opt/wz_mini/usr/bin/iCamera ; then
|
||||
sed -i 's/\/opt\/wz_mini\/usr\/bin\/iCamera.patched/\/system\/bin\/iCamera/' /opt/wz_mini/usr/bin/iCamera
|
||||
fi
|
||||
|
||||
# If the libwyzeUtils is referenced for the t20, remove it
|
||||
if grep -q libwyzeUtils.so:libcallback_t20.so /opt/wz_mini/usr/bin/iCamera ; then
|
||||
sed -i "s/LD_PRELOAD='\/opt\/wz_mini\/lib\/libwyzeUtils.so:libcallback_t20.so:libtinyalsa.so.2.0.0'/LD_PRELOAD='libcallback_t20.so:libtinyalsa.so.2.0.0'/" /opt/wz_mini/usr/bin/iCamera
|
||||
fi
|
||||
|
||||
echo "Removed."
|
||||
}
|
||||
|
||||
|
||||
# Patch out the calls to test cloud url, which calls the DN check function with NOPs
|
||||
# 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"
|
||||
[[ "$Version" == "4.9.8.1002" ]] && return; # Not in v2
|
||||
|
||||
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 calls with NOPs
|
||||
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)"
|
||||
[[ "$Version" == "4.9.8.1002" ]] && Address="$(seq 0x089c8 4 0x08a30)"
|
||||
|
||||
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"
|
||||
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)"
|
||||
[[ "$Version" == "4.9.8.1002" ]] && return; # this is in the libwyzeUtils.so library, I think. Can't find similar code
|
||||
|
||||
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 code_test trigger with NOPs
|
||||
# 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"
|
||||
[[ "$Version" == "4.9.8.1002" ]] && return; # not in the v2 firmware, I think.
|
||||
|
||||
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 libwyzeUtils.so so that the testconnectbyurl function always returns true, regardless of whether
|
||||
# the cloud is available or not.
|
||||
function patch_wzutil_testconnectbyurl_skip_check() {
|
||||
# For the v2 firmware using the libwyzeUtils.so library only.
|
||||
[ ! -f /opt/wz_mini/tmp/.T20 ] && return # Only on the v2
|
||||
[[ "$Version" == "4.61.0.1" ]] && return
|
||||
[[ "$Version" == "4.36.9.139" ]] && return
|
||||
[[ "$Version" == "4.9.8.1002" ]] || return # Only supports 4.9.8.1002
|
||||
|
||||
echo -e "\n\n====> Calling ${FUNCNAME[0]}\n"
|
||||
|
||||
# BEQ $4 $0 0x5E branches to the 'URL is null' section of the code which returns -1
|
||||
# We want to go there and return 0 always instead. So let's blez (always true on an unsigned int)
|
||||
# and patch the -1 to 0
|
||||
|
||||
i="0x203d0" # should have content: 5e 00 80 10, (BEQ $4 $0 0x5E)
|
||||
echo -e "\nOriginal at $i"
|
||||
dd if=libwyzeUtils.so bs=1 count=4 skip=$(($i)) 2>/dev/null | xxd
|
||||
|
||||
echo "Patched" # patch with 5e 00 81 04 (BLEZ $4 0x5E)
|
||||
printf '\x5e\x00\x81\x04' | dd conv=notrunc of=libwyzeUtils.so bs=1 seek=$(($i)) 2> /dev/null
|
||||
dd if=libwyzeUtils.so bs=1 count=4 skip=$(($i)) 2>/dev/null | xxd
|
||||
|
||||
# At 3056c, we load -1 to s0, which is our return code. fix this to 0
|
||||
i="0x2056c" # should have content: ff ff 10 24
|
||||
echo -e "\nOriginal at $i"
|
||||
dd if=libwyzeUtils.so bs=1 count=4 skip=$(($i)) 2>/dev/null | xxd
|
||||
|
||||
echo "Patched" # patch with 00 00 10 24, should load s0 to 0 before returning
|
||||
printf '\x00\x00\x10\x24' | dd conv=notrunc of=libwyzeUtils.so bs=1 seek=$(($i)) 2> /dev/null
|
||||
dd if=libwyzeUtils.so bs=1 count=4 skip=$(($i)) 2>/dev/null | xxd
|
||||
}
|
||||
|
||||
# Patch LED state in iCamera binary so LED stays off after connecting
|
||||
# Applies only to the v2
|
||||
function patch_v2_led_connect_led () {
|
||||
# Applies only to this particular firmware in the v2.
|
||||
[[ "$Version" == "4.9.8.1002" ]] || return
|
||||
|
||||
echo -e "\n\n====> Calling ${FUNCNAME[0]}\n"
|
||||
|
||||
# Use the big NOP space from patch_out_jobs_after_connect to call led_ctrl_run_action_by_state(5)
|
||||
|
||||
i="0x089c8"
|
||||
# li 5 a0
|
||||
printf '\x05\x00\x04\x24' | 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
|
||||
|
||||
|
||||
i="0x089cc"
|
||||
# jal led_ctrl_run_action_by_state
|
||||
printf '\xcc\xc4\x10\x0c' | 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
|
||||
}
|
||||
|
||||
|
||||
main "$@"
|
||||
|
@ -96,6 +96,7 @@ ENABLE_FSCK_ON_BOOT="false"
|
||||
ENABLE_CAR_DRIVER="false"
|
||||
ENABLE_LOCAL_DNS="false"
|
||||
ENABLE_CRONTAB="false"
|
||||
ENABLE_SELFHOSTED_MODE="false"
|
||||
|
||||
#####DEBUG#####
|
||||
#drops you to a shell via serial, doesn't load app_init.sh
|
||||
|
Loading…
Reference in New Issue
Block a user