kroo / wyzecam Goto Github PK
View Code? Open in Web Editor NEWPython package for streaming video from wyze cameras over the local network
Home Page: https://kroo.github.io/wyzecam/
License: MIT License
Python package for streaming video from wyze cameras over the local network
Home Page: https://kroo.github.io/wyzecam/
License: MIT License
Steps to reproduce the behavior:
python3 wyze.py
AV Client Start: chan_id=0 expected_chan=0 pn_serv_type=16
Sending response: <K10002ConnectAuth code=10002 resp_code=10003>
^CTraceback (most recent call last):
File "wyze.py", line 51, in <module>
main()
File "wyze.py", line 27, in main
with wyze_iotc.connect_and_auth(account, cam) as sess:
File "/home/kcharubin/.local/lib/python3.8/site-packages/wyzecam/iotc.py", line 322, in __enter__
self._auth()
File "/home/kcharubin/.local/lib/python3.8/site-packages/wyzecam/iotc.py", line 295, in _auth
mux.waitfor(resolving)
File "/home/kcharubin/.local/lib/python3.8/site-packages/wyzecam/tutk/tutk_ioctl_mux.py", line 250, in waitfor
time.sleep(0.1)
KeyboardInterrupt
python --version
Expect to see the video stream just like with v2 camera
The Samsung baby cameras seems to somehow reuse the same WyzeCam protocol (at least, I found the same libAVAPIs.so and libIOTCAPIs.so libraries on the device itself). The camera though is not using any cloud, and is only able to connect when in the same WiFi network. The only known application which is able to connect to theese devices is the BabyView application (https://play.google.com/store/apps/details?id=tw.com.surveillance.babyview2&hl=ru&gl=US).
There is no way to access these cameras data except by the help of the BabyView app, which, let's be honest, is buggy like hell. This could be another way to do it.
Except using the BabyView official app, none.
The cameras aren't using any "tokens", but instead are using a some kind of a static "password". It may be converted into the same "token" by some algorythm (because the password itself is supposed to be only 8-15 characters long, so deriving it to a hex 32 characters seems to be doable). Also, the port on which the "AVAPIs_Server" is listening - is the port 9090/tcp and ports 37507/udp, 32761/udp. Apparently the actual used viewing username is "admin".
Description of the project is to stream both Audio and Video with full support for v3.....but the code is only for Video stream.
Okay, not really a question, just leaving some notes for really green Linux users.
# clone repo
git clone https://github.com/kroo/wyzecam.git && cd wyzecam
# Install python, pip and virtual environment
sudo apt-get install python3 python3-pip python3-venv -y
# create venv
python3 -m venv wyzetest
source wyzetest/bin/activate
# Install dependencies
pip install .
pip install requests
pip install opencv-python
pip install av
# Download, compile and install TUTK_IOTC
wget https://github.com/nblavoie/wyzecam-api/raw/master/wyzecam-sdk/TUTK_IOTC_Platform_14W42P1.zip
unzip TUTK_IOTC_Platform_14W42P1.zip
cd Lib/Linux/x64/
g++ -fpic -shared -Wl,--whole-archive libAVAPIs.a libIOTCAPIs.a -Wl,--no-whole-archive -o libIOTCAPIs_ALL.so
sudo cp libIOTCAPIs_ALL.so /usr/local/lib/
cd ../../..
# Set Wyze creds
export [email protected]
export WYZE_PASSWORD=mypassword
# Set your camera name on line 20 of example:
nano examples/streaming_video.py
# run example
python examples/streaming_video.py
Raspi 4B seems to work with Arm11_BCM2835_4.8.3
.
I expect these will be common platforms.
The below code suggested by merlt8 to overcome DTLS feature in new wyze FW, where current code cannot access RTSP with new FW with DTLS
def getAuthKey(mac, enr): key = enr + mac.upper() hash = hashlib.sha256(key.encode()) print(hash.digest()) bArr = bytearray(hash.digest())[0:6] print(bArr) authKey = base64.standard_b64encode(bArr).decode().replace('+', 'Z').replace('/', '9').replace('=', 'A').encode() return authKey
av_account: admin
av_password:Β camera.enr
This will help keep the code compatible with new wyze FW updates (latest one compatabile was in August wyze FW release).
Wyze official RTSP will stay beta, and they will not maintain it, as they mentioned explicitly (they dont have enough resources to maintain 2 branches of FW).
And always, non RTSP wyze FW maintained and updated well....hut this DTLS is now showstopper.
Dont update wyze FW anymore.
issues
.I had assumed that basicInfo.wifidb represented rssi, but it seems to more related to link quality..?
Any additional info would be appreciated!
with wyzecam.WyzeIOTC() as wyze_iotc:
with wyze_iotc.connect_and_auth(account, camera) as sess:
print(sess.camera.camera_info['basicInfo']['wifidb'])
Add native Windows support. (without using WSL and Xming.)
The library can support windows natively if the DLL's are specified in the code instead of using a merged .so/.dylib file. Windows does not support merging DLL's.
Selfishly, I want to be able to view the camera stream using the efficient cv2.imshow()
.
I have not tried running it via WSL but I assume running it natively is faster.
Running it via WSL and Xming like proposed in the install instructions.
I got it to run on Windows by changing the code to specify if tutk_platform_lib
needed AVAPIs or IOTCAPIs.
Now, I can't make a PR because it no longer supports Linux or MacOS. I don't know enough about g++ etc. to see why a merged library file is needed instead of just importing the two separate files. If Linux and MacOS can handle 2 separate files it could be cleaned up and merged, and support all 3 platforms.
I attach 2 patch files with the changes I made to get it to work. It's not a proper Git patch but it shows that the changes needed for Windows functionality are quite few.
wyzecam/iotc.py:
62c62,63
< tutk_platform_lib: Optional[Union[str, CDLL]] = None,
---
> tutk_platform_lib_iotc: Optional[Union[str, CDLL]] = None,
> tutk_platform_lib_av: Optional[Union[str, CDLL]] = None,
78,82c79,89
< if tutk_platform_lib is None:
< tutk_platform_lib = tutk.load_library()
< if isinstance(tutk_platform_lib, str):
< path = pathlib.Path(tutk_platform_lib)
< tutk_platform_lib = tutk.load_library(str(path.absolute()))
---
> if tutk_platform_lib_av is None:
> tutk_platform_lib_av = tutk.load_library("C:\\Users\\[Redacted]\\PycharmProjects\\wyzestream\\tutk_lib\\Lib\\Windows\\x64\\AVAPIs.dll")
> if isinstance(tutk_platform_lib_av, str):
> path = pathlib.Path(tutk_platform_lib_av)
> tutk_platform_lib_av = tutk.load_library(str(path.absolute()))
>
> if tutk_platform_lib_iotc is None:
> tutk_platform_lib_iotc = tutk.load_library("C:\\Users\\[Redacted]\\PycharmProjects\\wyzestream\\tutk_lib\\Lib\\Windows\\x64\\IOTCAPIs.dll")
> if isinstance(tutk_platform_lib_iotc, str):
> path = pathlib.Path(tutk_platform_lib_iotc)
> tutk_platform_lib_iotc = tutk.load_library(str(path.absolute()))
84c91,92
< self.tutk_platform_lib: CDLL = tutk_platform_lib
---
> self.tutk_platform_lib_av: CDLL = tutk_platform_lib_av
> self.tutk_platform_lib_iotc: CDLL = tutk_platform_lib_iotc
108c116
< self.tutk_platform_lib, udp_port=self.udp_port or 0
---
> self.tutk_platform_lib_iotc, udp_port=self.udp_port or 0
114c122
< self.tutk_platform_lib, max_num_channels=self.max_num_av_channels
---
> self.tutk_platform_lib_av, max_num_channels=self.max_num_av_channels
126,127c134,135
< tutk.av_deinitialize(self.tutk_platform_lib)
< tutk.iotc_deinitialize(self.tutk_platform_lib)
---
> tutk.av_deinitialize(self.tutk_platform_lib_av)
> tutk.iotc_deinitialize(self.tutk_platform_lib_iotc)
132c140
< return tutk.iotc_get_version(self.tutk_platform_lib)
---
> return tutk.iotc_get_version(self.tutk_platform_lib_iotc)
161c169
< return WyzeIOTCSession(self.tutk_platform_lib, account, camera)
---
> return WyzeIOTCSession(self.tutk_platform_lib_av, self.tutk_platform_lib_iotc, account, camera)
233c241,242
< tutk_platform_lib: CDLL,
---
> tutk_platform_lib_av: CDLL,
> tutk_platform_lib_iotc: CDLL,
252c261,262
< self.tutk_platform_lib: CDLL = tutk_platform_lib
---
> self.tutk_platform_lib_av: CDLL = tutk_platform_lib_av
> self.tutk_platform_lib_iotc: CDLL = tutk_platform_lib_iotc
275c285
< self.tutk_platform_lib, self.session_id
---
> self.tutk_platform_lib_iotc, self.session_id
301c311
< return TutkIOCtrlMux(self.tutk_platform_lib, self.av_chan_id)
---
> return TutkIOCtrlMux(self.tutk_platform_lib_iotc, self.tutk_platform_lib_av, self.av_chan_id)
357c367
< self.tutk_platform_lib, self.av_chan_id
---
> self.tutk_platform_lib_av, self.av_chan_id
626c636
< session_id = tutk.iotc_get_session_id(self.tutk_platform_lib)
---
> session_id = tutk.iotc_get_session_id(self.tutk_platform_lib_iotc)
632c642
< self.tutk_platform_lib, self.camera.p2p_id, self.session_id
---
> self.tutk_platform_lib_iotc, self.camera.p2p_id, self.session_id
642c652
< self.tutk_platform_lib,
---
> self.tutk_platform_lib_av,
667c677
< tutk.av_client_set_max_buf_size(self.tutk_platform_lib, max_buf_size)
---
> tutk.av_client_set_max_buf_size(self.tutk_platform_lib_av, max_buf_size)
724c734
< tutk.av_client_stop(self.tutk_platform_lib, self.av_chan_id)
---
> tutk.av_client_stop(self.tutk_platform_lib_av, self.av_chan_id)
727c737
< tutk.iotc_session_close(self.tutk_platform_lib, self.session_id)
---
> tutk.iotc_session_close(self.tutk_platform_lib_iotc, self.session_id)
wyzecam/tutk/tutk_ioctl_mux.py
109c109
< def __init__(self, tutk_platform_lib: CDLL, av_chan_id: c_int) -> None:
---
> def __init__(self, tutk_platform_lib_iotc: CDLL, tutk_platform_lib_av: CDLL, av_chan_id: c_int) -> None:
116c116,117
< self.tutk_platform_lib = tutk_platform_lib
---
> self.tutk_platform_lib_iotc = tutk_platform_lib_iotc
> self.tutk_platform_lib_av = tutk_platform_lib_av
122c123
< tutk_platform_lib, av_chan_id, self.queues
---
> tutk_platform_lib_av, av_chan_id, self.queues # original iotc
189c190
< self.tutk_platform_lib, self.av_chan_id, ctrl_type, encoded_msg
---
> self.tutk_platform_lib_av, self.av_chan_id, ctrl_type, encoded_msg
I was trying to find a way to serv frames as an RTMP stream in pure Python but didn't have any luck. So I decided to fire up my own RTMP server and then leverage ffmpeg to stream to this server.
So using this guide I spun up an RTMP server using Nginx and the RTMP module:
https://obsproject.com/forum/resources/how-to-set-up-your-own-private-rtmp-server-using-nginx.50/
Then I wrote a program to pipe the raw Wyze frames into ffmpeg which then streams to my RTMP server. I'm not a Python developer so I'm open to suggestions on making it more robust but it's working and seems to survive connection loss or a power cycle of the camera. I made a systemd service to run it as a service on my Debian server and it's working well. I was then able to feed it into Frigate.
from wyzecam import get_camera_list, get_user_info, login
from wyzecam.iotc import WyzeIOTC
import getopt, sys, signal, subprocess
from time import sleep
def main():
def handler(signum, frame):
sys.exit()
signal.signal(signal.SIGINT, handler)
try:
opts, args = getopt.getopt(sys.argv[1:], "", ["user=", "password=", "cameraname=", "url="])
except getopt.GetoptError as err:
print("--user=<wyzeuser> --password=<wyzepassword> --cameraname=<cameraname> --url=<rtmpServerUrl>")
sys.exit(2)
user = None
password = None
cameraname = None
rtmpurl = None
for opt, arg in opts:
if opt == "--user":
user = arg
if opt == "--password":
password = arg
if opt == "--cameraname":
cameraname = arg
if opt == "--url":
rtmpurl = arg
if user == None or password == None or cameraname == None or rtmpurl == None:
print("--user=<wyzeuser> --password=<wyzepassword> --cameraname=<cameraname> --url=<rtmpServerUrl>")
sys.exit(2)
auth_info = login(user, password)
account = get_user_info(auth_info)
cameras = get_camera_list(auth_info)
cam = [camera for camera in cameras if camera.nickname == cameraname][0]
ffmpeg = subprocess.Popen(['ffmpeg',
'-f', 'h264',
'-i', '-',
'-vcodec', 'copy',
'-f','flv', rtmpurl], stdin=subprocess.PIPE)
while True:
with WyzeIOTC() as wyze_iotc:
try:
with wyze_iotc.connect_and_auth(account, cam) as sess:
session_info = sess.session_check()
for (frame, frame_info) in sess.recv_video_data():
ffmpeg.stdin.write(frame)
except:
print("Reconnect")
sleep(1)
if __name__ == "__main__":
main()
Example command line:
python rtmp.py --user [email protected] --password blablabla --cameraname "Front Porch" --url rtmp://127.0.0.1/live/frountporch
Then playback using a URL like this:
rtmp://myserver.example.com/live/frountporch
Hello, I'm trying to adjust the bitrate/frame size via WyzeIOTCSession as listed in the documentation, however, I keep getting IOTC_ER_NOT_INITIALIZED whenever I try to use WyzeIOTCSession
.
Steps to reproduce the behavior:
import os
import wyzecam
auth_info = wyzecam.login(os.environ["WYZE_EMAIL"], os.environ["WYZE_PASSWORD"])
account = wyzecam.get_user_info(auth_info)
camera = wyzecam.get_camera_list(auth_info)[0]
with wyzecam.iotc.WyzeIOTCSession(wyzecam.tutk.tutk.load_library(),account,camera) as w:
print(w.state)
WyzeIOTCSessionState.AUTHENTICATION_SUCCEEDED
Was working great until I updated the firmware.
Now I get:
wyzecam.tutk.tutk.TutkError: IOTC_ER_CAN_NOT_FIND_DEVICE
Steps to reproduce the behavior:
Update camera firmware in app
python --version
Code seems to always look for the .dylib (mac) version of the shared library even on Linux.
Line 508 in 9cf17fb
Steps to reproduce the behavior:
python3 wyze.py
Traceback (most recent call last):
File "wyze.py", line 10, in <module>
with wyzecam.WyzeIOTC() as wyze_iotc:
File "/home/kcharubin/.local/lib/python3.8/site-packages/wyzecam/iotc.py", line 74, in __init__
tutk_platform_lib = tutk.load_library()
File "/home/kcharubin/.local/lib/python3.8/site-packages/wyzecam/tutk/tutk.py", line 515, in load_library
return cdll.LoadLibrary(shared_lib_path)
File "/usr/lib/python3.8/ctypes/__init__.py", line 451, in LoadLibrary
return self._dlltype(name)
File "/usr/lib/python3.8/ctypes/__init__.py", line 373, in __init__
self._handle = _dlopen(self._name, mode)
OSError: /usr/local/lib/libIOTCAPIs_ALL.dylib: cannot open shared object file: No such file or directory
python --version
issues
.Has anyone managed to get the outdoor cam working?
From what I can tell, I believe the camera needs a wake command in K10000ConnectRequest..?
{"cameraInfo": {"mac": mac, "encFlag": 0, "wakeupFlag": 1}}
I don't have an outdoor cam so can't test it out.
issues
.Is it possible to use this with the Wyze Doorbell + Chime? Will it also integrate with Home Assistant?
Hi,
I am wondering if this would be a better solution for streaming wyze v3 video/audio to blue iris, instead of using the NFS wyzehack and js script solution.
If using your API, it is possible to feed the stream to BI, could you provide an example ? This could be a very popular solution to overcome Wyze's lack of RTSP support for the v3 cam.
Thanks
Not really a feature request, but a quick example to get local AI on the wyze stream with yolov5 using 14 lines of code!
yolov5 requirements: pip install -r https://raw.githubusercontent.com/ultralytics/yolov5/master/requirements.txt
import os
import cv2
import wyzecam
import torch
model = torch.hub.load('ultralytics/yolov5', 'yolov5s')
auth_info = wyzecam.login(os.environ["WYZE_EMAIL"], os.environ["WYZE_PASSWORD"])
account = wyzecam.get_user_info(auth_info)
camera = wyzecam.get_camera_list(auth_info)[0]
with wyzecam.WyzeIOTC() as wyze_iotc:
with wyze_iotc.connect_and_auth(account, camera) as sess:
for (frame, frame_info) in sess.recv_video_frame_ndarray():
results = model(frame)
cv2.imshow("Video Feed", results.render()[0].copy())
cv2.waitKey(1)
Could this be loaded as an addon within home assistant through HACS?
Is it possible to add audio, either to recv_video_data or maybe add another method?
Potentially lots of reasons e.g. baby monitor, child watching
The response from the Wyzecam login API returns
'access_token': None, 'refresh_token': None
even though login appears to be successful.
Here's a minimum working example:
payload = {"email": email, "password": triplemd5(password)} resp = requests.post( "https://auth-prod.api.wyze.com/user/login", json=payload, headers=get_headers(phone_id) ) print(resp.json()) {'access_token': None, 'refresh_token': None, 'user_id': 'fea576c0cXXXXXXXX978ddc792b50187', 'mfa_options': ['PrimaryPhone'], 'mfa_details': {'phone_numbers': {'primary_phone': {'country_code': '+1', 'number': 'XXXXXXXXXX'}, 'backup_phone': None}, 'totp_apps': []}, 'sms_session_id': 'XXXXXXXX-f07f-4314-9f56-488be33f302d'}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.