Skip to content
This repository has been archived by the owner on Mar 25, 2024. It is now read-only.

Commit

Permalink
Add methods to start and stop detection (#14)
Browse files Browse the repository at this point in the history
* Parse doorbell params

* Add methods to start and stop detection

* Support for Python 3.8

* Log unhandled parameters

* Sort methods

* Black

* Version bump

* Fix start/stop detection methods
  • Loading branch information
nonsleepr authored and bachya committed Dec 10, 2019
1 parent 8b42db1 commit 1e4334f
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 6 deletions.
2 changes: 1 addition & 1 deletion eufy_security/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
"""Define the package version."""
__version__: str = "0.1.1"
__version__: str = "0.1.2"
20 changes: 15 additions & 5 deletions eufy_security/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
class API:
"""Define the API object."""

def __init__(self, email: str, password: str, websession: ClientSession) -> None:
def __init__(
self, email: str, password: str, websession: ClientSession
) -> None:
"""Initialize."""
self._email: str = email
self._password: str = password
Expand All @@ -44,7 +46,9 @@ async def async_authenticate(self) -> None:

async def async_get_history(self) -> dict:
"""Get the camera's history."""
history_resp = await self.request("post", "event/app/get_all_history_record")
history_resp = await self.request(
"post", "event/app/get_all_history_record"
)
return history_resp["data"]

async def async_update_device_info(self) -> None:
Expand Down Expand Up @@ -88,15 +92,19 @@ async def request(
data: dict = await resp.json(content_type=None)

if not data:
raise RequestError(f"No response while requesting {endpoint}")
raise RequestError(
f"No response while requesting {endpoint}"
)

_raise_on_error(data)

return data
except ClientError as err:
if "401" in str(err):
if self._retry_on_401:
raise InvalidCredentialsError("Token failed multiple times")
raise InvalidCredentialsError(
"Token failed multiple times"
)

self._retry_on_401 = True
await self.async_authenticate()
Expand All @@ -115,7 +123,9 @@ def _raise_on_error(data: dict) -> None:
raise_error(data)


async def async_login(email: str, password: str, websession: ClientSession) -> API:
async def async_login(
email: str, password: str, websession: ClientSession
) -> API:
"""Return an authenticated API object."""
api: API = API(email, password, websession)
await api.async_authenticate()
Expand Down
47 changes: 47 additions & 0 deletions eufy_security/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
import logging
from typing import TYPE_CHECKING

from .params import ParamType


if TYPE_CHECKING:
from .api import API # pylint: disable=cyclic-import

Expand Down Expand Up @@ -56,6 +59,47 @@ def station_serial(self) -> str:
"""Return the camera's station serial number."""
return self.camera_info["station_sn"]

@property
def params(self):
# Parse camera info
params = {}
for param in self.camera_info["params"]:
param_type = param["param_type"]
value = param["param_value"]
try:
param_type = ParamType(param_type)
value = param_type.read_value(value)
except ValueError:
_LOGGER.warning(
f'Unable to process parameter "{param_type}", '
f'value "{value}"'
)
params[param_type] = value
return params

async def async_set_params(self, params: dict) -> None:
serialized_params = []
for param_type, value in params.items():
if isinstance(param_type, ParamType):
value = param_type.write_value(value)
param_type = param_type.value
serialized_params.append(
{"param_type": param_type, "param_value": value}
)
await self._api.request(
"post",
"app/upload_devs_params",
json={
"device_sn": self.serial,
"station_sn": self.station_serial,
"params": serialized_params,
},
)
await self.async_update()

async def async_start_detection(self):
await self.async_set_params({ParamType.DETECT_SWITCH: 1})

async def async_start_stream(self) -> str:
"""Start the camera stream and return the RTSP URL."""
start_resp = await self._api.request(
Expand All @@ -70,6 +114,9 @@ async def async_start_stream(self) -> str:

return start_resp["data"]["url"]

async def async_stop_detection(self):
await self.async_set_params({ParamType.DETECT_SWITCH: 0})

async def async_stop_stream(self) -> None:
"""Stop the camera stream."""
await self._api.request(
Expand Down
56 changes: 56 additions & 0 deletions eufy_security/params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import json
import base64
from enum import Enum


class ParamType(Enum):
# from com.oceanwing.battery.cam.binder.model.CameraParams
CHIME_STATE = 2015
DETECT_EXPOSURE = 2023
DETECT_MODE = 2004
DETECT_MOTION_SENSITIVE = 2005
DETECT_SCENARIO = 2028
DETECT_SWITCH = 2027
DETECT_ZONE = 2006
DOORBELL_AUDIO_RECODE = 2042
DOORBELL_BRIGHTNESS = 2032
DOORBELL_DISTORTION = 2033
DOORBELL_HDR = 2029
DOORBELL_IR_MODE = 2030
DOORBELL_LED_NIGHT_MODE = 2039
DOORBELL_MOTION_ADVANCE_OPTION = 2041
DOORBELL_MOTION_NOTIFICATION = 2035
DOORBELL_NOTIFICATION_JUMP_MODE = 2038
DOORBELL_NOTIFICATION_OPEN = 2036
DOORBELL_RECORD_QUALITY = 2034
DOORBELL_RING_RECORD = 2040
DOORBELL_SNOOZE_START_TIME = 2037
DOORBELL_VIDEO_QUALITY = 2031
NIGHT_VISUAL = 2002
OPEN_DEVICE = 2001
RINGING_VOLUME = 2022
SDCARD = 2010
UN_DETECT_ZONE = 2007
VOLUME = 2003

# Inferred from source
SNOOZE_MODE = 1271 # The value is base64 encoded
WATERMARK_MODE = 1214 # 1 - hide, 2 - show
DEVICE_UPGRADE_NOW = 1134
CAMERA_UPGRADE_NOW = 1133

# Set only params?
PUSH_MSG_MODE = 1252 # 0 to ???

def read_value(self, value):
if value:
if self is ParamType.SNOOZE_MODE:
value = base64.b64decode(value, validate=True).decode()
return json.loads(value)
return None

def write_value(self, value):
value = json.dumps(value)
if self is ParamType.SNOOZE_MODE:
value = base64.b64encode(value.encode()).decode()
return value
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def run(self):
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
],
Expand Down

0 comments on commit 1e4334f

Please sign in to comment.