Skip to content

Commit

Permalink
113 no support for s series scale (#114)
Browse files Browse the repository at this point in the history
* Initial series s support

* Updated logic to support new S-series scale

* fixed remaining merge conflict

* removed accidental commit

* Fixed generic device parsing for new scale type
  • Loading branch information
shauntarves authored Dec 9, 2022
1 parent f4a7231 commit fd57511
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 30 deletions.
12 changes: 9 additions & 3 deletions wyze_sdk/api/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
from typing import Optional, Sequence

from wyze_sdk.errors import WyzeClientConfigurationError
from wyze_sdk.models.devices.base import DeviceModels
from wyze_sdk.service import (ApiServiceClient, EarthServiceClient,
GeneralApiServiceClient, PlatformServiceClient,
ScaleServiceClient, SiriusServiceClient,
VenusServiceClient, WyzeResponse)
PlutoServiceClient, VenusServiceClient,
WyzeResponse)


class BaseClient(object, metaclass=ABCMeta):
Expand Down Expand Up @@ -60,12 +62,16 @@ def _general_api_client(self) -> GeneralApiServiceClient:
user_id=self._user_id,
)

def _scale_client(self) -> ScaleServiceClient:
return BaseClient._service_client(ScaleServiceClient, token=self._token, base_url=self._base_url)
def _scale_client(self, device_model: str = DeviceModels.SCALE_[0]) -> ScaleServiceClient:
return BaseClient._service_client(
ScaleServiceClient if device_model in DeviceModels.SCALE_ else PlutoServiceClient, token=self._token, base_url=self._base_url)

def _sirius_client(self) -> EarthServiceClient:
return BaseClient._service_client(SiriusServiceClient, token=self._token, base_url=self._base_url)

def _pluto_client(self) -> PlutoServiceClient:
return BaseClient._service_client(PlutoServiceClient, token=self._token, base_url=self._base_url)

def _venus_client(self) -> VenusServiceClient:
return BaseClient._service_client(VenusServiceClient, token=self._token, base_url=self._base_url)

Expand Down
69 changes: 43 additions & 26 deletions wyze_sdk/api/devices/scales.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from datetime import datetime
from datetime import datetime, timedelta
from typing import Optional, Sequence, Union

from wyze_sdk.api.base import BaseClient
from wyze_sdk.errors import WyzeRequestError
from wyze_sdk.errors import WyzeFeatureNotSupportedError, WyzeRequestError
from wyze_sdk.models.devices import DeviceModels, Scale, ScaleRecord, UserGoalWeight
from wyze_sdk.service import WyzeResponse

Expand All @@ -28,54 +28,71 @@ def info(self, *, device_mac: str, **kwargs) -> Optional[Scale]:
:param str device_mac: The device mac. e.g. ``ABCDEF1234567890``
:rtype: Optional[Scale]
:raises WyzeFeatureNotSupportedError: If the scale model isn't supported
"""
scales = [_scale for _scale in self._list_scales() if _scale['mac'] == device_mac]
if len(scales) == 0:
return None

scale = scales[0]

device_setting = super()._scale_client().get_device_setting(did=device_mac)
device_setting = super()._scale_client(scale['product_model']).get_device_setting(did=device_mac)
if "data" in device_setting.data:
scale.update(device_setting.data["data"])

device_member = super()._scale_client().get_device_member(did=device_mac)
device_member = super()._scale_client(scale['product_model']).get_device_member(did=device_mac)
if "data" in device_member.data and device_member.data['data'] is not None:
scale.update({"device_members": device_member.data["data"]})

family_member = super()._scale_client().get_family_member(did=device_mac)
family_member = super()._scale_client(scale['product_model']).get_family_member(did=device_mac)
if "data" in family_member.data and family_member.data['data'] is not None:
scale.update({"family_members": family_member.data["data"]})

user_preference = super()._scale_client().get_user_preference(did=device_mac)
user_preference = super()._scale_client(scale['product_model']).get_user_preference(did=device_mac)
if "data" in user_preference.data and user_preference.data['data'] is not None:
scale.update({"user_preferences": user_preference.data["data"]})

token = super()._scale_client().get_token(did=device_mac)
if "data" in token.data and token.data['data'] is not None:
scale.update(token.data["data"])

if self._user_id is not None:
user_device_relation = super()._scale_client().get_user_device_relation(did=device_mac, user_id=self._user_id)
user_device_relation = super()._scale_client(scale['product_model']).get_user_device_relation(did=device_mac, user_id=self._user_id)
if "data" in user_device_relation.data and user_device_relation.data['data'] is not None:
scale.update({"device_relation": user_device_relation.data["data"]})

user_goal_weight = super()._scale_client().get_goal_weight(user_id=self._user_id)
if "data" in user_goal_weight.data and user_goal_weight.data['data'] is not None:
scale.update({"goal_weight": user_goal_weight.data["data"]})

# com.wyze.ihealth.d.e
user_profile = super()._platform_client().get_user_profile(appid='nHtOAABMsnTbOmg74g3zBsFuHx4iVi5G')
if "data" in user_profile.data and user_profile.data['data'] is not None:
scale.update({"user_profile": user_profile.data["data"]})

latest_records = super()._scale_client().get_latest_records()
if "data" in latest_records.data and latest_records.data['data'] is not None:
scale.update({"latest_records": latest_records.data["data"]})
if scale['product_model'] in DeviceModels.SCALE_S:

# // this returns the same data as above
# device_info = super()._scale_client(scale['product_model']).get_device_info(did=device_mac)
# if "data" in device_info.data:
# scale.update(device_info.data["data"])

if self._user_id is not None:
now = datetime.now()
latest_records = super()._scale_client(scale['product_model']).get_records(user_id=self._user_id, start_time=now-timedelta(days=5), end_time=now)
if "data" in latest_records.data and latest_records.data['data'] is not None:
scale.update({"latest_records": latest_records.data["data"]})
elif scale['product_model'] in DeviceModels.SCALE_X:
raise WyzeFeatureNotSupportedError('Scale Series X')
else:
token = super()._scale_client().get_token(did=device_mac)
if "data" in token.data and token.data['data'] is not None:
scale.update(token.data["data"])

# com.wyze.ihealth.d.e
user_profile = super()._platform_client().get_user_profile(appid='nHtOAABMsnTbOmg74g3zBsFuHx4iVi5G')
if "data" in user_profile.data and user_profile.data['data'] is not None:
scale.update({"user_profile": user_profile.data["data"]})

latest_records = super()._scale_client().get_latest_records()
if "data" in latest_records.data and latest_records.data['data'] is not None:
scale.update({"latest_records": latest_records.data["data"]})

return Scale(**scale)

def get_records(self, *, user_id: Optional[str] = None, start_time: datetime, end_time: Optional[datetime] = datetime.now(), **kwargs) -> Sequence[ScaleRecord]:
def get_records(self, *, device_model: Optional[str] = DeviceModels.SCALE_[0], user_id: Optional[str] = None, start_time: datetime, end_time: Optional[datetime] = datetime.now(), **kwargs) -> Sequence[ScaleRecord]:
"""Retrieves a user's scale event history records.
.. note:: The results are queried and returned in reverse-chronological order
Expand All @@ -86,17 +103,17 @@ def get_records(self, *, user_id: Optional[str] = None, start_time: datetime, en
:rtype: Sequence[ScaleRecord]
"""
return [ScaleRecord(**record) for record in super()._scale_client().get_records(user_id=user_id if user_id is not None else self._user_id, start_time=start_time, end_time=end_time)["data"]]
return [ScaleRecord(**record) for record in super()._scale_client(device_model=device_model).get_records(user_id=user_id if user_id is not None else self._user_id, start_time=start_time, end_time=end_time)["data"]]

def get_goal_weight(self, *, user_id: Optional[str] = None, **kwargs) -> UserGoalWeight:
def get_goal_weight(self, *, device_model: Optional[str] = DeviceModels.SCALE_[0], user_id: Optional[str] = None, **kwargs) -> UserGoalWeight:
"""Retrieves a user's goal weight.
:param str user_id: The user id. e.g. ``abcdef1234567890abcdef1234567890``
:rtype: WyzeResponse
"""
response = super()._scale_client().get_goal_weight(user_id=user_id if user_id is not None else self._user_id)
return UserGoalWeight(**response["data"])
response = super()._scale_client(device_model=device_model).get_goal_weight(user_id=user_id if user_id is not None else self._user_id)
return None if response["data"] is None else UserGoalWeight(**response["data"])

def delete_goal_weight(self, *, user_id: Optional[str] = None, **kwargs) -> WyzeResponse:
"""Deletes a user's goal weight, if one exists.
Expand Down Expand Up @@ -163,16 +180,16 @@ def set_unit(
if unit not in ['kg', 'lb']:
raise WyzeRequestError(f"{unit} must be one of {['kg', 'lb']}")

response = self._set_scale_setting(device_mac, device_model, firmware_ver, mac, unit, broadcast)
response = self._set_scale_setting(device_mac, device_model, unit, firmware_ver, mac, broadcast)
return response

def _set_scale_setting(
self,
device_mac: str,
device_model: str,
unit: str,
firmware_ver: str,
mac: str,
unit: str,
broadcast: int
) -> WyzeResponse:
return super()._scale_client().update_device_setting(did=device_mac, model=device_model, firmware_ver=firmware_ver, mac=mac, unit=unit, broadcast=broadcast)
2 changes: 2 additions & 0 deletions wyze_sdk/models/devices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ def parse(cls, device: Union[dict, "Device"]) -> Optional["Device"]:
model = device["product_model"]
if model in DeviceModels.SWITCH:
return Switch(**device)
elif model in DeviceModels.SCALE:
return Scale(**device)
else:
cls._logger.warning(f"Unknown device type detected ({device})")
return Device(**device)
Expand Down
5 changes: 4 additions & 1 deletion wyze_sdk/models/devices/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ class DeviceModels(object):
MOTION_SENSOR = ['PIR3U', 'PIR2U']
VACUUM = ['JA_RO2']
CAMERA = CAMERA_V1 + CAMERA_V2 + CAMERA_V3 + CAMERA_OUTDOOR
SCALE = ['JA.SC', 'JA.SC2']
SCALE_ = ['JA.SC', 'JA.SC2']
SCALE_S = ['WL_SC2']
SCALE_X = ['WL_SC22135'] # placeholder
SCALE = SCALE_ + SCALE_S + SCALE_X
WATCH = ['RA.WP1', 'RY.WA1']
BAND = ['RY.HP1']

Expand Down
1 change: 1 addition & 0 deletions wyze_sdk/models/devices/scales.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ def __init__(
self.unit = unit if unit else super()._extract_property(ScaleProps.unit(), others)
self._broadcast = super()._extract_attribute('broadcast', others)
self.goal_weight = goal_weight
self._latest_records = []
latest_records = latest_records if latest_records is not None else super()._extract_attribute('latest_records', others)
if latest_records is not None:
self._latest_records = [latest_record if isinstance(latest_record, ScaleRecord) else ScaleRecord(**latest_record) for latest_record in latest_records]
Expand Down
1 change: 1 addition & 0 deletions wyze_sdk/service/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .ford_service import FordServiceClient # noqa
from .general_api_service import GeneralApiServiceClient # noqa
from .platform_service import PlatformServiceClient # noqa
from .pluto_service import PlutoServiceClient # noqa
from .scale_service import ScaleServiceClient # noqa
from .sirius_service import SiriusServiceClient # noqa
from .venus_service import VenusServiceClient # noqa
Expand Down
Loading

0 comments on commit fd57511

Please sign in to comment.