Skip to content

Commit

Permalink
added wyze sdk tools, update silicone emu
Browse files Browse the repository at this point in the history
carTloyal123 committed Jul 10, 2024
1 parent 7bfff82 commit 7edb179
Showing 19 changed files with 653 additions and 15 deletions.
13 changes: 6 additions & 7 deletions docker/apple_silicone/android/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
FROM --platform=$BUILDPLATFORM eclipse-temurin:latest

FROM --platform=arm64 eclipse-temurin:latest

RUN apt-get update && apt-get install -y \
python3-pip repo wget python-is-python3 unzip curl jq libpcre2-dev adb \
@@ -21,19 +20,19 @@ ENV PATH=$PATH:/opt/android-sdk/cmdline-tools/latest/bin
RUN yes | sdkmanager --update
RUN yes | sdkmanager --licenses

COPY emulator/ /opt/android-sdk/emulator/
COPY linux/emulator/ /opt/android-sdk/emulator/
COPY package.xml /opt/android-sdk/emulator/package.xml

# RUN sdkmanager "system-images;android-34;google_apis;arm64-v8a"
RUN sdkmanager "system-images;android-34;aosp_atd;arm64-v8a"
# RUN sdkmanager "system-images;android-34;google_apis;arm64-v8a"
RUN sdkmanager "system-images;android-34;aosp_atd;arm64-v8a"

ARG EMULATOR_NAME="nexus"
ARG EMULATOR_DEVICE="Nexus 10"
ENV EMULATOR_NAME=$EMULATOR_NAME
ENV DEVICE_NAME=$EMULATOR_DEVICE
RUN echo "no" | avdmanager --verbose create avd --force --name "${EMULATOR_NAME}" --device "${EMULATOR_DEVICE}" --package "system-images;android-34;aosp_atd;arm64-v8a"

RUN mkdir /opt/android-sdk/platforms && mkdir /opt/android-sdk/platform-tools
RUN mkdir /opt/android-sdk/platforms && mkdir /opt/android-sdk/platform-tools
RUN echo "Vulkan = off" >> ~/.android/advancedFeatures.ini && echo "GLDirectMem = on" >> ~/.android/advancedFeatures.ini

# Download the latest release APK URL from GitHub API
@@ -44,4 +43,4 @@ RUN wget -q $(curl -s "https://api.github.com/repos/$GITHUB_REPO/releases/latest
COPY ./run_emu.sh .
RUN chmod a+x run_emu.sh

CMD ["tail", "-f", "/dev/null"]
CMD ["tail", "-f", "/dev/null"]
Empty file.
2 changes: 1 addition & 1 deletion docker/apple_silicone/android/package.xml
Original file line number Diff line number Diff line change
@@ -62,4 +62,4 @@ This is the Android Software Development Kit License Agreement
14.5 EXPORT RESTRICTIONS. THE SDK IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE SDK. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE.
14.6 The rights granted in the License Agreement may not be assigned or transferred by either you or Google without the prior written approval of the other party. Neither you nor Google shall be permitted to delegate their responsibilities or obligations under the License Agreement without the prior written approval of the other party.
14.7 The License Agreement, and your relationship with Google under the License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from the License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.
November 20, 2015</license><localPackage path="emulator" obsolete="false"><type-details xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns5:genericDetailsType"/><revision><major>34</major><minor>2</minor><micro>9</micro></revision><display-name>Android Emulator</display-name><uses-license ref="android-sdk-license"/><dependencies><dependency path="patcher;v4"/><dependency path="tools"><min-revision><major>34</major><minor>2</minor></min-revision></dependency></dependencies></localPackage></ns2:repository>
November 20, 2015</license><localPackage path="emulator" obsolete="false"><type-details xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns5:genericDetailsType"/><revision><major>35</major><minor>1</minor><micro>14</micro></revision><display-name>Android Emulator</display-name><uses-license ref="android-sdk-license"/><dependencies><dependency path="patcher;v4"/><dependency path="tools"><min-revision><major>35</major><minor>1</minor></min-revision></dependency></dependencies></localPackage></ns2:repository>
7 changes: 5 additions & 2 deletions docker/apple_silicone/android/run_emu.sh
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ hw_accel_flag=$(check_hardware_acceleration)

function launch_emulator () {
adb devices | grep emulator | cut -f1 | xargs -I {} adb -s "{}" emu kill

# specific to mac apple silicon for some reason
nohup /opt/android-sdk/emulator/emulator @nexus -no-window -no-audio -ports 5554,5555 -skip-adb-auth -no-boot-anim -show-kernel -qemu -cpu max &

@@ -86,6 +86,9 @@ sleep 1
export ANDROID_HOME=/opt/android
export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools

# Wait for the emulator to start
adb wait-for-device

# # Install the APK on the emulator
adb install -r app.apk

@@ -108,4 +111,4 @@ tail -f /dev/null
# # Launch app
# adb shell monkey -p com.tencentcs.iotvideo -v 1
# echo "APK installed and running"
# tail -f /dev/null
# tail -f /dev/null
11 changes: 6 additions & 5 deletions docker/apple_silicone/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
version: "4"
services:
# Launch emulator and appium instance
# Launch emulator and appium instance
cryze-arm-android-service:
image: cryze-arm-android-emulator
network_mode: host
build:
build:
context: android
container_name: cryze-arm-android-emulator
command:
- bash
- -c
- |
./run_emu.sh
- tail -f /dev/null
# - |
# ./run_emu.sh
privileged: true
tty: true
stdin_open: true

cryze-arm-server-service:
image: cryze-arm-server
network_mode: host
22 changes: 22 additions & 0 deletions tools/local_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import os
import requests
import websockets
import asyncio
import json
import time
import queue
import wyze_sdk
from wyze_sdk.service.base import WpkNetServiceClient
import wyze_sdk.errors

## We need to get device credentials from the Wyze API for a desired device
## We are going to find all devices with the GW_BE1 device model prefix and take the first one
## Once we have a device, we can query Wyze for the P2P connection information
## Once we have the P2P connection information, we can send that info to the wyze server
## Server will hopefully send us back video frames
## Play video frames with opencv or similar

WYZE_EMAIL = os.environ['WYZE_EMAIL'] # Your Wyze email
WYZE_PASSWORD = os.environ['WYZE_PASSWORD'] # Your Wyze password
WYZE_KEY_ID = os.environ['WYZE_KEY_ID'] # Your Wyze key ID
WYZE_API_KEY = os.environ['WYZE_API_KEY']
139 changes: 139 additions & 0 deletions tools/testing/device_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import os
import requests
import websockets
import asyncio
import keyboard
import json
import time
import queue
import wyze_sdk
from wyze_sdk.service.base import WpkNetServiceClient
import wyze_sdk.errors

# p2pUrl = '|wyze-test-list.cloudlinks.cn|42.194.219.201'
# wyzeP2pUrl = '|wyze-mars-asrv.wyzecam.com'
# mars_url = 'https://wyze-mars-service.wyzecam.com/plugin/mars/v2/regist_gw_user/GW_BE1_7C78B2A2AD34'
# mars_path_url = '/plugin/mars/v2/regist_gw_user/GW_BE1_7C78B2A2AD34'

wyze_sdk.set_file_logger('wyze_sdk', filepath='wyze_out.txt', level=wyze_sdk.logging.DEBUG)
mars_base_url = 'https://wyze-mars-service.wyzecam.com'
email = '[email protected]'
psswd = '@Lacylulu123!!!'
key_id = '94458b0d-2e6a-4e9e-b438-5914f735461b'
api_key='4yWuIM9jaSRvDQJ9aIEwqlNYSe0GHDx0LJvudthmiiy1Ju3OAHiMvmiZmBju'
deviceId = "GW_BE1_7C78B2A2AD34"


last_token_fetch_time = 0
current_response = None

async def getLoginInfo():
global last_token_fetch_time, current_response
current_time = time.time()
if current_time - last_token_fetch_time < 30 and current_response is not None:
return current_response

client = wyze_sdk.Client()
response = client.login(
email=email,
password=psswd,
key_id=key_id,
api_key=api_key
)

wpk = WpkNetServiceClient(token=client._token, base_url=mars_base_url)
nonce = wpk.request_verifier.clock.nonce()
json_dict = {"ttl_minutes" : 10080, 'nonce' : str(nonce), 'unique_id' : wpk.phone_id }
header_dict = { 'appid' : wpk.app_id}

try:
resp = wpk.api_call(api_method=mars_path_url, json=json_dict, headers=header_dict, nonce=str(nonce))
print("Got new login info!")
last_token_fetch_time = time.time()
current_response = resp
return resp
except requests.HTTPError as e:
print(f'HTTP Request Error')
print(e.response)
except wyze_sdk.errors.WyzeApiError as e:
print(f'Wyze API Error:')
print(e.response)
except wyze_sdk.errors.WyzeRequestError as e:
print('Request error: ')
print(e.args)

return None



async def send_message(websocket):
resp = await getLoginInfo()
if resp is None:
print("No login info")
return
accessId = resp["data"]["accessId"]
accessToken = resp["data"]["accessToken"]
expireTime = resp["data"]["expireTime"]

print(accessId)
print(accessToken)
# Send a chat message
chat_message = {
"type": "login-info",
"topic": "login-info",
"data": {
"accessId": "".join(accessId),
"accessToken": accessToken,
"expireTime": expireTime,
"deviceId": deviceId,
"timestamp": time.time()
}
}
await websocket.send(json.dumps(chat_message))
print("Sent message")

message_queue = queue.Queue()

def spacebar_event(e):
message_queue.put("Your message")

async def subscribeToLoginInfo(websocket):
chat_message = {
"type": "Subscribe",
"topic": "login-info"
}
await websocket.send(json.dumps(chat_message))

async def websocket_client():
uri = "ws://localhost:3030"
try:
async with websockets.connect(uri, ping_timeout=None) as websocket: # disable the library's automatic pinging
websocket.ping_interval = None # disable the library's automatic pinging
keyboard.on_press_key('right option', spacebar_event)
await subscribeToLoginInfo(websocket)
while True:
try:
while not message_queue.empty():
message = message_queue.get()
await send_message(websocket)
await asyncio.sleep(1)
except KeyboardInterrupt:
print("Ctrl+C pressed. Closing WebSocket connection...")
await websocket.close()
break
except websockets.ConnectionClosedError as e:
print(f"Connection closed: {e}")
except websockets.InvalidStatusCode as e:
print(f"Invalid status code: {e}")
except websockets.InvalidURI as e:
print(f"Invalid URI: {e}")
except websockets.WebSocketProtocolError as e:
print(f"WebSocket protocol error: {e}")
except websockets.WebSocketException as e:
print(f"WebSocket exception: {e}")
except OSError as e:
print(f"OS error: {e}")

if __name__ == "__main__":
print("Starting websocket client")
asyncio.get_event_loop().run_until_complete(websocket_client())
20 changes: 20 additions & 0 deletions tools/testing/frame_saver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import asyncio
import websockets
import os
import json

async def websocket_handler(uri):
message_count = 0
async with websockets.connect(uri) as websocket:
await websocket.send(json.dumps({"type": "Subscribe", "topic": "video-stream"}))

async for message in websocket:
if isinstance(message, bytes):
with open(f'frames/message_{message_count}.bin', 'wb') as f:
f.write(message)
message_count += 1
print(f"Message saved to message_{message_count}.bin")

# Replace with your WebSocket server URI
uri = "ws://localhost:3030"
asyncio.get_event_loop().run_until_complete(websocket_handler(uri))
22 changes: 22 additions & 0 deletions tools/testing/frame_tester.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from PIL import Image
import io
import numpy as np
import cv2

# Load the binary data from the file
with open('frames/message_11.bin', 'rb') as f:
binary_data = f.read()

# Convert the binary data to a bytes-like object
bytes_data = io.BytesIO(binary_data)

# Open the bytes-like object as an image
img = Image.open(bytes_data)

# Convert the image to a numpy array
frame_array = np.array(img)

# Display the frame
cv2.imshow('Frame', frame_array)
cv2.waitKey(0)
cv2.destroyAllWindows()
61 changes: 61 additions & 0 deletions tools/testing/h264_decoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import os
import cv2
import asyncio
import websockets
import numpy as np
import json

# WebSocket URL
websocket_url = "ws://localhost:3030"

# OpenCV window name
window_name = "Decoded Frames"

# Named pipe for H264 data
h264_pipe = "local_pipe"

# Function to handle WebSocket messages
async def on_message(message):
# Write H264 data to the pipe
with open(h264_pipe, 'wb+') as f:
f.write(message)

# Decode H264 data into frames
decoded_frame = decode_h264()
if decoded_frame is None:
print("Error decoding frame")
return
# Display the decoded frame using OpenCV
cv2.imshow(window_name, decoded_frame)
cv2.waitKey(1)

# Function to decode H264 data into frames
def decode_h264():
cap = cv2.VideoCapture(h264_pipe)

ret, frame = cap.read()

if not ret:
print("Error reading frame from pipe")
return None

return frame

# Function to start a WebSocket connection
async def start_websocket():
async with websockets.connect(websocket_url) as ws:
# Subscribe to the video stream
await ws.send(json.dumps({"type": "Subscribe", "topic": "video-stream"}))

async for message in ws:
print("Received message of length " + str(len(message)))
if isinstance(message, bytes):
# Handle H264 data
await on_message(message)
else:
# Handle control messages
data = json.loads(message)
print(data["message"])

# Start the WebSocket connection
asyncio.get_event_loop().run_until_complete(start_websocket())
Binary file added tools/testing/local_pipe
Binary file not shown.
Loading

0 comments on commit 7edb179

Please sign in to comment.