wyzeapy.services.sensor_service API documentation

# wyzeapy.services.sensor_service

View Source

     1#  Copyright (c) 2021. Mulliken, LLC - All Rights Reserved
     2#  You may use, distribute and modify this code under the terms
     3#  of the attached license. You should have received a copy of
     4#  the license with this file. If not, please write to:
     5#  katie@mulliken.net to receive a copy
     6import asyncio
     7import logging
     8from threading import Thread
     9from typing import List, Callable, Tuple, Optional
    10
    11from aiohttp import ClientOSError, ContentTypeError
    12
    13from ..exceptions import UnknownApiError
    14from .base_service import BaseService
    15from ..types import Device, PropertyIDs, DeviceTypes
    16
    17_LOGGER = logging.getLogger(__name__)
    18
    19
    20class Sensor(Device):
    21    detected: bool = False
    22
    23
    24class SensorService(BaseService):
    25    _updater_thread: Optional[Thread] = None
    26    _subscribers: List[Tuple[Sensor, Callable[[Sensor], None]]] = []
    27
    28    async def update(self, sensor: Sensor) -> Sensor:
    29        # Get updated device_params
    30        async with BaseService._update_lock:
    31            sensor.device_params = await self.get_updated_params(sensor.mac)
    32        properties = await self._get_device_info(sensor)
    33
    34        for property in properties['data']['property_list']:
    35            pid = property['pid']
    36            value = property['value']
    37
    38            try:
    39                if PropertyIDs(pid) == PropertyIDs.CONTACT_STATE:
    40                    sensor.detected = value == "1"
    41                if PropertyIDs(pid) == PropertyIDs.MOTION_STATE:
    42                    sensor.detected = value == "1"
    43            except ValueError:
    44                pass
    45
    46        return sensor
    47
    48    async def register_for_updates(self, sensor: Sensor, callback: Callable[[Sensor], None]):
    49        _LOGGER.debug(f"Registering sensor: {sensor.nickname} for updates")
    50        loop = asyncio.get_event_loop()
    51        if not self._updater_thread:
    52            self._updater_thread = Thread(target=self.update_worker, args=[loop, ], daemon=True)
    53            self._updater_thread.start()
    54
    55        self._subscribers.append((sensor, callback))
    56
    57    async def deregister_for_updates(self, sensor: Sensor):
    58        self._subscribers = [(sense, callback) for sense, callback in self._subscribers if sense.mac != sensor.mac]
    59
    60    def update_worker(self, loop):
    61        while True:
    62            for sensor, callback in self._subscribers:
    63                _LOGGER.debug(f"Providing update for {sensor.nickname}")
    64                try:
    65                    callback(asyncio.run_coroutine_threadsafe(self.update(sensor), loop).result())
    66                except UnknownApiError as e:
    67                    _LOGGER.warning(f"The update method detected an UnknownApiError: {e}")
    68                except ClientOSError as e:
    69                    _LOGGER.error(f"A network error was detected: {e}")
    70                except ContentTypeError as e:
    71                    _LOGGER.error(f"Server returned unexpected ContentType: {e}")
    72
    73    async def get_sensors(self) -> List[Sensor]:
    74        if self._devices is None:
    75            self._devices = await self.get_object_list()
    76
    77        sensors = [Sensor(device.raw_dict) for device in self._devices if
    78                   device.type is DeviceTypes.MOTION_SENSOR or
    79                   device.type is DeviceTypes.CONTACT_SENSOR]
    80        return [Sensor(sensor.raw_dict) for sensor in sensors]

class Sensor(wyzeapy.types.Device): View Source

    21class Sensor(Device):
    22    detected: bool = False

detected: bool = False

##### Inherited Members

wyzeapy.types.Device
  Device
  product_type
  product_model
  mac
  nickname
  device_params
  raw_dict
  callback_function
  available
  type

class SensorService(wyzeapy.services.base_service.BaseService): View Source

    25class SensorService(BaseService):
    26    _updater_thread: Optional[Thread] = None
    27    _subscribers: List[Tuple[Sensor, Callable[[Sensor], None]]] = []
    28
    29    async def update(self, sensor: Sensor) -> Sensor:
    30        # Get updated device_params
    31        async with BaseService._update_lock:
    32            sensor.device_params = await self.get_updated_params(sensor.mac)
    33        properties = await self._get_device_info(sensor)
    34
    35        for property in properties['data']['property_list']:
    36            pid = property['pid']
    37            value = property['value']
    38
    39            try:
    40                if PropertyIDs(pid) == PropertyIDs.CONTACT_STATE:
    41                    sensor.detected = value == "1"
    42                if PropertyIDs(pid) == PropertyIDs.MOTION_STATE:
    43                    sensor.detected = value == "1"
    44            except ValueError:
    45                pass
    46
    47        return sensor
    48
    49    async def register_for_updates(self, sensor: Sensor, callback: Callable[[Sensor], None]):
    50        _LOGGER.debug(f"Registering sensor: {sensor.nickname} for updates")
    51        loop = asyncio.get_event_loop()
    52        if not self._updater_thread:
    53            self._updater_thread = Thread(target=self.update_worker, args=[loop, ], daemon=True)
    54            self._updater_thread.start()
    55
    56        self._subscribers.append((sensor, callback))
    57
    58    async def deregister_for_updates(self, sensor: Sensor):
    59        self._subscribers = [(sense, callback) for sense, callback in self._subscribers if sense.mac != sensor.mac]
    60
    61    def update_worker(self, loop):
    62        while True:
    63            for sensor, callback in self._subscribers:
    64                _LOGGER.debug(f"Providing update for {sensor.nickname}")
    65                try:
    66                    callback(asyncio.run_coroutine_threadsafe(self.update(sensor), loop).result())
    67                except UnknownApiError as e:
    68                    _LOGGER.warning(f"The update method detected an UnknownApiError: {e}")
    69                except ClientOSError as e:
    70                    _LOGGER.error(f"A network error was detected: {e}")
    71                except ContentTypeError as e:
    72                    _LOGGER.error(f"Server returned unexpected ContentType: {e}")
    73
    74    async def get_sensors(self) -> List[Sensor]:
    75        if self._devices is None:
    76            self._devices = await self.get_object_list()
    77
    78        sensors = [Sensor(device.raw_dict) for device in self._devices if
    79                   device.type is DeviceTypes.MOTION_SENSOR or
    80                   device.type is DeviceTypes.CONTACT_SENSOR]
    81        return [Sensor(sensor.raw_dict) for sensor in sensors]

Base service class for interacting with Wyze devices.

async def update( self, sensor: Sensor) -> Sensor: View Source

    29    async def update(self, sensor: Sensor) -> Sensor:
    30        # Get updated device_params
    31        async with BaseService._update_lock:
    32            sensor.device_params = await self.get_updated_params(sensor.mac)
    33        properties = await self._get_device_info(sensor)
    34
    35        for property in properties['data']['property_list']:
    36            pid = property['pid']
    37            value = property['value']
    38
    39            try:
    40                if PropertyIDs(pid) == PropertyIDs.CONTACT_STATE:
    41                    sensor.detected = value == "1"
    42                if PropertyIDs(pid) == PropertyIDs.MOTION_STATE:
    43                    sensor.detected = value == "1"
    44            except ValueError:
    45                pass
    46
    47        return sensor

async def register_for_updates( self, sensor: Sensor, callback: Callable[[Sensor], NoneType]): View Source

    49    async def register_for_updates(self, sensor: Sensor, callback: Callable[[Sensor], None]):
    50        _LOGGER.debug(f"Registering sensor: {sensor.nickname} for updates")
    51        loop = asyncio.get_event_loop()
    52        if not self._updater_thread:
    53            self._updater_thread = Thread(target=self.update_worker, args=[loop, ], daemon=True)
    54            self._updater_thread.start()
    55
    56        self._subscribers.append((sensor, callback))

async def deregister_for_updates(self, sensor: Sensor): View Source

    58    async def deregister_for_updates(self, sensor: Sensor):
    59        self._subscribers = [(sense, callback) for sense, callback in self._subscribers if sense.mac != sensor.mac]

def update_worker(self, loop): View Source

    61    def update_worker(self, loop):
    62        while True:
    63            for sensor, callback in self._subscribers:
    64                _LOGGER.debug(f"Providing update for {sensor.nickname}")
    65                try:
    66                    callback(asyncio.run_coroutine_threadsafe(self.update(sensor), loop).result())
    67                except UnknownApiError as e:
    68                    _LOGGER.warning(f"The update method detected an UnknownApiError: {e}")
    69                except ClientOSError as e:
    70                    _LOGGER.error(f"A network error was detected: {e}")
    71                except ContentTypeError as e:
    72                    _LOGGER.error(f"Server returned unexpected ContentType: {e}")

async def get_sensors(self) -> List[Sensor]: View Source

    74    async def get_sensors(self) -> List[Sensor]:
    75        if self._devices is None:
    76            self._devices = await self.get_object_list()
    77
    78        sensors = [Sensor(device.raw_dict) for device in self._devices if
    79                   device.type is DeviceTypes.MOTION_SENSOR or
    80                   device.type is DeviceTypes.CONTACT_SENSOR]
    81        return [Sensor(sensor.raw_dict) for sensor in sensors]

##### Inherited Members

wyzeapy.services.base_service.BaseService
  BaseService
  start_update_manager
  register_updater
  unregister_updater
  set_push_info
  get_user_profile
  get_object_list
  get_updated_params