wyzeapy.services.bulb_service API documentation

# wyzeapy.services.bulb_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 logging
      7import re
      8from typing import Any, Dict, Optional, List
      9
     10from .base_service import BaseService
     11from ..types import Device, PropertyIDs, DeviceTypes
     12from ..utils import create_pid_pair
     13
     14_LOGGER = logging.getLogger(__name__)
     15
     16
     17class Bulb(Device):
     18    _brightness: int = 0
     19    _color_temp: int = 1800
     20    _color: Optional[str]
     21    enr: str
     22
     23    on: bool = False
     24    cloud_fallback = False
     25
     26    def __init__(self, dictionary: Dict[Any, Any]):
     27        super().__init__(dictionary)
     28
     29        self.ip = self.device_params["ip"]
     30
     31        if (
     32            self.type is DeviceTypes.MESH_LIGHT
     33            or self.type is DeviceTypes.LIGHTSTRIP
     34        ):
     35            self._color = "000000"
     36
     37    @property
     38    def brightness(self) -> int:
     39        return self._brightness
     40
     41    @brightness.setter
     42    def brightness(self, value: int) -> None:
     43        assert value <= 100
     44        assert value >= 0
     45        self._brightness = value
     46
     47    @property
     48    def color_temp(self) -> int:
     49        return self._color_temp
     50
     51    @color_temp.setter
     52    def color_temp(self, value: int) -> None:
     53        self._color_temp = value
     54
     55    @property
     56    def color(self) -> Optional[str]:
     57        return self._color
     58
     59    @color.setter
     60    def color(self, value) -> None:
     61        assert re.match(r"^([A-Fa-f\d]{6}|[A-Fa-f\d]{3})$", value) is not None
     62        self._color = value
     63
     64
     65class BulbService(BaseService):
     66    async def update(self, bulb: Bulb) -> Bulb:
     67        # Get updated device_params
     68        async with BaseService._update_lock:
     69            bulb.device_params = await self.get_updated_params(bulb.mac)
     70
     71        device_info = await self._get_property_list(bulb)
     72        for property_id, value in device_info:
     73            if property_id == PropertyIDs.BRIGHTNESS:
     74                bulb.brightness = int(float(value))
     75            elif property_id == PropertyIDs.COLOR_TEMP:
     76                try:
     77                    bulb.color_temp = int(value)
     78                except ValueError:
     79                    bulb.color_temp = 2700
     80            elif property_id == PropertyIDs.ON:
     81                bulb.on = value == "1"
     82            elif property_id == PropertyIDs.AVAILABLE:
     83                bulb.available = value == "1"
     84            elif (
     85                property_id == PropertyIDs.COLOR
     86                and bulb.type in [DeviceTypes.LIGHTSTRIP, DeviceTypes.MESH_LIGHT]
     87            ):
     88                bulb.color = value
     89            elif property_id == PropertyIDs.COLOR_MODE:
     90                bulb.color_mode = value
     91            elif property_id == PropertyIDs.SUN_MATCH:
     92                bulb.sun_match = value == "1"
     93            elif property_id == PropertyIDs.LIGHTSTRIP_EFFECTS:
     94                bulb.effects = value
     95            elif property_id == PropertyIDs.LIGHTSTRIP_MUSIC_MODE:
     96                bulb.music_mode = value == "1"
     97
     98        return bulb
     99
    100    async def get_bulbs(self) -> List[Bulb]:
    101        if self._devices is None:
    102            self._devices = await self.get_object_list()
    103
    104        bulbs = [
    105            device
    106            for device in self._devices
    107            if device.type in [DeviceTypes.LIGHT,
    108                               DeviceTypes.MESH_LIGHT,
    109                               DeviceTypes.LIGHTSTRIP]
    110        ]
    111
    112        return [Bulb(bulb.raw_dict) for bulb in bulbs]
    113
    114    async def turn_on(self, bulb: Bulb, local_control, options=None):
    115        plist = [
    116            create_pid_pair(PropertyIDs.ON, "1")
    117        ]
    118
    119        if options is not None:
    120            plist.extend(options)
    121
    122        if bulb.type is DeviceTypes.LIGHT:
    123            await self._set_property_list(bulb, plist)
    124
    125        elif (
    126            bulb.type in [DeviceTypes.MESH_LIGHT, DeviceTypes.LIGHTSTRIP]
    127        ):
    128            # Local Control
    129            if local_control and not bulb.cloud_fallback:
    130                await self._local_bulb_command(bulb, plist)
    131
    132            # Cloud Control
    133            elif bulb.type is DeviceTypes.MESH_LIGHT:  # Sun match for mesh bulbs needs to be set on a different endpoint for some reason
    134                for item in plist:
    135                    if item["pid"] == PropertyIDs.SUN_MATCH.value:
    136                        await self._set_property_list(bulb, [item])
    137                        plist.remove(item)
    138                await self._run_action_list(bulb, plist)
    139            else:
    140                await self._run_action_list(bulb, plist)  # Lightstrips
    141
    142    async def turn_off(self, bulb: Bulb, local_control):
    143        plist = [
    144            create_pid_pair(PropertyIDs.ON, "0")
    145        ]
    146
    147        if bulb.type in [
    148            DeviceTypes.LIGHT
    149        ]:
    150            await self._set_property_list(bulb, plist)
    151        elif (
    152            bulb.type in [DeviceTypes.MESH_LIGHT, DeviceTypes.LIGHTSTRIP]
    153        ):
    154            if local_control and not bulb.cloud_fallback:
    155                await self._local_bulb_command(bulb, plist)
    156            else:
    157                await self._run_action_list(bulb, plist)
    158
    159    async def set_color_temp(self, bulb: Bulb, color_temp: int):
    160        plist = [
    161            create_pid_pair(PropertyIDs.COLOR_TEMP, str(color_temp))
    162        ]
    163
    164        if bulb.type in [
    165            DeviceTypes.LIGHT
    166        ]:
    167            await self._set_property_list(bulb, plist)
    168        elif bulb.type in [
    169            DeviceTypes.MESH_LIGHT
    170        ]:
    171            await self._local_bulb_command(bulb, plist)
    172
    173    async def set_color(self, bulb: Bulb, color: str, local_control):
    174        plist = [
    175            create_pid_pair(PropertyIDs.COLOR, str(color))
    176        ]
    177        if bulb.type in [
    178            DeviceTypes.MESH_LIGHT
    179        ]:
    180            if local_control and not bulb.cloud_fallback:
    181                await self._local_bulb_command(bulb, plist)
    182            else:
    183                await self._run_action_list(bulb, plist)
    184
    185    async def set_brightness(self, bulb: Device, brightness: int):
    186        plist = [
    187            create_pid_pair(PropertyIDs.BRIGHTNESS, str(brightness))
    188        ]
    189
    190        if bulb.type in [
    191            DeviceTypes.LIGHT
    192        ]:
    193            await self._set_property_list(bulb, plist)
    194        if bulb.type in [
    195            DeviceTypes.MESH_LIGHT
    196        ]:
    197            await self._local_bulb_command(bulb, plist)
    198
    199    async def music_mode_on(self, bulb: Device):
    200        plist = [
    201            create_pid_pair(PropertyIDs.LIGHTSTRIP_MUSIC_MODE, "1")
    202        ]
    203
    204        await self._run_action_list(bulb, plist)
    205
    206    async def music_mode_off(self, bulb: Device):
    207        plist = [
    208            create_pid_pair(PropertyIDs.LIGHTSTRIP_MUSIC_MODE, "0")
    209        ]
    210
    211        await self._run_action_list(bulb, plist)

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

    18class Bulb(Device):
    19    _brightness: int = 0
    20    _color_temp: int = 1800
    21    _color: Optional[str]
    22    enr: str
    23
    24    on: bool = False
    25    cloud_fallback = False
    26
    27    def __init__(self, dictionary: Dict[Any, Any]):
    28        super().__init__(dictionary)
    29
    30        self.ip = self.device_params["ip"]
    31
    32        if (
    33            self.type is DeviceTypes.MESH_LIGHT
    34            or self.type is DeviceTypes.LIGHTSTRIP
    35        ):
    36            self._color = "000000"
    37
    38    @property
    39    def brightness(self) -> int:
    40        return self._brightness
    41
    42    @brightness.setter
    43    def brightness(self, value: int) -> None:
    44        assert value <= 100
    45        assert value >= 0
    46        self._brightness = value
    47
    48    @property
    49    def color_temp(self) -> int:
    50        return self._color_temp
    51
    52    @color_temp.setter
    53    def color_temp(self, value: int) -> None:
    54        self._color_temp = value
    55
    56    @property
    57    def color(self) -> Optional[str]:
    58        return self._color
    59
    60    @color.setter
    61    def color(self, value) -> None:
    62        assert re.match(r"^([A-Fa-f\d]{6}|[A-Fa-f\d]{3})$", value) is not None
    63        self._color = value

Bulb(dictionary: Dict[Any, Any]) View Source

    27    def __init__(self, dictionary: Dict[Any, Any]):
    28        super().__init__(dictionary)
    29
    30        self.ip = self.device_params["ip"]
    31
    32        if (
    33            self.type is DeviceTypes.MESH_LIGHT
    34            or self.type is DeviceTypes.LIGHTSTRIP
    35        ):
    36            self._color = "000000"

enr: str
on: bool = False
cloud_fallback = False
ip
brightness: int View Source

    38    @property
    39    def brightness(self) -> int:
    40        return self._brightness

color_temp: int View Source

    48    @property
    49    def color_temp(self) -> int:
    50        return self._color_temp

color: Optional[str] View Source

    56    @property
    57    def color(self) -> Optional[str]:
    58        return self._color

##### Inherited Members

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

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

     66class BulbService(BaseService):
     67    async def update(self, bulb: Bulb) -> Bulb:
     68        # Get updated device_params
     69        async with BaseService._update_lock:
     70            bulb.device_params = await self.get_updated_params(bulb.mac)
     71
     72        device_info = await self._get_property_list(bulb)
     73        for property_id, value in device_info:
     74            if property_id == PropertyIDs.BRIGHTNESS:
     75                bulb.brightness = int(float(value))
     76            elif property_id == PropertyIDs.COLOR_TEMP:
     77                try:
     78                    bulb.color_temp = int(value)
     79                except ValueError:
     80                    bulb.color_temp = 2700
     81            elif property_id == PropertyIDs.ON:
     82                bulb.on = value == "1"
     83            elif property_id == PropertyIDs.AVAILABLE:
     84                bulb.available = value == "1"
     85            elif (
     86                property_id == PropertyIDs.COLOR
     87                and bulb.type in [DeviceTypes.LIGHTSTRIP, DeviceTypes.MESH_LIGHT]
     88            ):
     89                bulb.color = value
     90            elif property_id == PropertyIDs.COLOR_MODE:
     91                bulb.color_mode = value
     92            elif property_id == PropertyIDs.SUN_MATCH:
     93                bulb.sun_match = value == "1"
     94            elif property_id == PropertyIDs.LIGHTSTRIP_EFFECTS:
     95                bulb.effects = value
     96            elif property_id == PropertyIDs.LIGHTSTRIP_MUSIC_MODE:
     97                bulb.music_mode = value == "1"
     98
     99        return bulb
    100
    101    async def get_bulbs(self) -> List[Bulb]:
    102        if self._devices is None:
    103            self._devices = await self.get_object_list()
    104
    105        bulbs = [
    106            device
    107            for device in self._devices
    108            if device.type in [DeviceTypes.LIGHT,
    109                               DeviceTypes.MESH_LIGHT,
    110                               DeviceTypes.LIGHTSTRIP]
    111        ]
    112
    113        return [Bulb(bulb.raw_dict) for bulb in bulbs]
    114
    115    async def turn_on(self, bulb: Bulb, local_control, options=None):
    116        plist = [
    117            create_pid_pair(PropertyIDs.ON, "1")
    118        ]
    119
    120        if options is not None:
    121            plist.extend(options)
    122
    123        if bulb.type is DeviceTypes.LIGHT:
    124            await self._set_property_list(bulb, plist)
    125
    126        elif (
    127            bulb.type in [DeviceTypes.MESH_LIGHT, DeviceTypes.LIGHTSTRIP]
    128        ):
    129            # Local Control
    130            if local_control and not bulb.cloud_fallback:
    131                await self._local_bulb_command(bulb, plist)
    132
    133            # Cloud Control
    134            elif bulb.type is DeviceTypes.MESH_LIGHT:  # Sun match for mesh bulbs needs to be set on a different endpoint for some reason
    135                for item in plist:
    136                    if item["pid"] == PropertyIDs.SUN_MATCH.value:
    137                        await self._set_property_list(bulb, [item])
    138                        plist.remove(item)
    139                await self._run_action_list(bulb, plist)
    140            else:
    141                await self._run_action_list(bulb, plist)  # Lightstrips
    142
    143    async def turn_off(self, bulb: Bulb, local_control):
    144        plist = [
    145            create_pid_pair(PropertyIDs.ON, "0")
    146        ]
    147
    148        if bulb.type in [
    149            DeviceTypes.LIGHT
    150        ]:
    151            await self._set_property_list(bulb, plist)
    152        elif (
    153            bulb.type in [DeviceTypes.MESH_LIGHT, DeviceTypes.LIGHTSTRIP]
    154        ):
    155            if local_control and not bulb.cloud_fallback:
    156                await self._local_bulb_command(bulb, plist)
    157            else:
    158                await self._run_action_list(bulb, plist)
    159
    160    async def set_color_temp(self, bulb: Bulb, color_temp: int):
    161        plist = [
    162            create_pid_pair(PropertyIDs.COLOR_TEMP, str(color_temp))
    163        ]
    164
    165        if bulb.type in [
    166            DeviceTypes.LIGHT
    167        ]:
    168            await self._set_property_list(bulb, plist)
    169        elif bulb.type in [
    170            DeviceTypes.MESH_LIGHT
    171        ]:
    172            await self._local_bulb_command(bulb, plist)
    173
    174    async def set_color(self, bulb: Bulb, color: str, local_control):
    175        plist = [
    176            create_pid_pair(PropertyIDs.COLOR, str(color))
    177        ]
    178        if bulb.type in [
    179            DeviceTypes.MESH_LIGHT
    180        ]:
    181            if local_control and not bulb.cloud_fallback:
    182                await self._local_bulb_command(bulb, plist)
    183            else:
    184                await self._run_action_list(bulb, plist)
    185
    186    async def set_brightness(self, bulb: Device, brightness: int):
    187        plist = [
    188            create_pid_pair(PropertyIDs.BRIGHTNESS, str(brightness))
    189        ]
    190
    191        if bulb.type in [
    192            DeviceTypes.LIGHT
    193        ]:
    194            await self._set_property_list(bulb, plist)
    195        if bulb.type in [
    196            DeviceTypes.MESH_LIGHT
    197        ]:
    198            await self._local_bulb_command(bulb, plist)
    199
    200    async def music_mode_on(self, bulb: Device):
    201        plist = [
    202            create_pid_pair(PropertyIDs.LIGHTSTRIP_MUSIC_MODE, "1")
    203        ]
    204
    205        await self._run_action_list(bulb, plist)
    206
    207    async def music_mode_off(self, bulb: Device):
    208        plist = [
    209            create_pid_pair(PropertyIDs.LIGHTSTRIP_MUSIC_MODE, "0")
    210        ]
    211
    212        await self._run_action_list(bulb, plist)

Base service class for interacting with Wyze devices.

async def update( self, bulb: Bulb) -> Bulb: View Source

    67    async def update(self, bulb: Bulb) -> Bulb:
    68        # Get updated device_params
    69        async with BaseService._update_lock:
    70            bulb.device_params = await self.get_updated_params(bulb.mac)
    71
    72        device_info = await self._get_property_list(bulb)
    73        for property_id, value in device_info:
    74            if property_id == PropertyIDs.BRIGHTNESS:
    75                bulb.brightness = int(float(value))
    76            elif property_id == PropertyIDs.COLOR_TEMP:
    77                try:
    78                    bulb.color_temp = int(value)
    79                except ValueError:
    80                    bulb.color_temp = 2700
    81            elif property_id == PropertyIDs.ON:
    82                bulb.on = value == "1"
    83            elif property_id == PropertyIDs.AVAILABLE:
    84                bulb.available = value == "1"
    85            elif (
    86                property_id == PropertyIDs.COLOR
    87                and bulb.type in [DeviceTypes.LIGHTSTRIP, DeviceTypes.MESH_LIGHT]
    88            ):
    89                bulb.color = value
    90            elif property_id == PropertyIDs.COLOR_MODE:
    91                bulb.color_mode = value
    92            elif property_id == PropertyIDs.SUN_MATCH:
    93                bulb.sun_match = value == "1"
    94            elif property_id == PropertyIDs.LIGHTSTRIP_EFFECTS:
    95                bulb.effects = value
    96            elif property_id == PropertyIDs.LIGHTSTRIP_MUSIC_MODE:
    97                bulb.music_mode = value == "1"
    98
    99        return bulb

async def get_bulbs(self) -> List[Bulb]: View Source

    101    async def get_bulbs(self) -> List[Bulb]:
    102        if self._devices is None:
    103            self._devices = await self.get_object_list()
    104
    105        bulbs = [
    106            device
    107            for device in self._devices
    108            if device.type in [DeviceTypes.LIGHT,
    109                               DeviceTypes.MESH_LIGHT,
    110                               DeviceTypes.LIGHTSTRIP]
    111        ]
    112
    113        return [Bulb(bulb.raw_dict) for bulb in bulbs]

async def turn_on( self, bulb: Bulb, local_control, options=None): View Source

    115    async def turn_on(self, bulb: Bulb, local_control, options=None):
    116        plist = [
    117            create_pid_pair(PropertyIDs.ON, "1")
    118        ]
    119
    120        if options is not None:
    121            plist.extend(options)
    122
    123        if bulb.type is DeviceTypes.LIGHT:
    124            await self._set_property_list(bulb, plist)
    125
    126        elif (
    127            bulb.type in [DeviceTypes.MESH_LIGHT, DeviceTypes.LIGHTSTRIP]
    128        ):
    129            # Local Control
    130            if local_control and not bulb.cloud_fallback:
    131                await self._local_bulb_command(bulb, plist)
    132
    133            # Cloud Control
    134            elif bulb.type is DeviceTypes.MESH_LIGHT:  # Sun match for mesh bulbs needs to be set on a different endpoint for some reason
    135                for item in plist:
    136                    if item["pid"] == PropertyIDs.SUN_MATCH.value:
    137                        await self._set_property_list(bulb, [item])
    138                        plist.remove(item)
    139                await self._run_action_list(bulb, plist)
    140            else:
    141                await self._run_action_list(bulb, plist)  # Lightstrips

async def turn_off(self, bulb: Bulb, local_control): View Source

    143    async def turn_off(self, bulb: Bulb, local_control):
    144        plist = [
    145            create_pid_pair(PropertyIDs.ON, "0")
    146        ]
    147
    148        if bulb.type in [
    149            DeviceTypes.LIGHT
    150        ]:
    151            await self._set_property_list(bulb, plist)
    152        elif (
    153            bulb.type in [DeviceTypes.MESH_LIGHT, DeviceTypes.LIGHTSTRIP]
    154        ):
    155            if local_control and not bulb.cloud_fallback:
    156                await self._local_bulb_command(bulb, plist)
    157            else:
    158                await self._run_action_list(bulb, plist)

async def set_color_temp(self, bulb: Bulb, color_temp: int): View Source

    160    async def set_color_temp(self, bulb: Bulb, color_temp: int):
    161        plist = [
    162            create_pid_pair(PropertyIDs.COLOR_TEMP, str(color_temp))
    163        ]
    164
    165        if bulb.type in [
    166            DeviceTypes.LIGHT
    167        ]:
    168            await self._set_property_list(bulb, plist)
    169        elif bulb.type in [
    170            DeviceTypes.MESH_LIGHT
    171        ]:
    172            await self._local_bulb_command(bulb, plist)

async def set_color( self, bulb: Bulb, color: str, local_control): View Source

    174    async def set_color(self, bulb: Bulb, color: str, local_control):
    175        plist = [
    176            create_pid_pair(PropertyIDs.COLOR, str(color))
    177        ]
    178        if bulb.type in [
    179            DeviceTypes.MESH_LIGHT
    180        ]:
    181            if local_control and not bulb.cloud_fallback:
    182                await self._local_bulb_command(bulb, plist)
    183            else:
    184                await self._run_action_list(bulb, plist)

async def set_brightness(self, bulb: wyzeapy.types.Device, brightness: int): View Source

    186    async def set_brightness(self, bulb: Device, brightness: int):
    187        plist = [
    188            create_pid_pair(PropertyIDs.BRIGHTNESS, str(brightness))
    189        ]
    190
    191        if bulb.type in [
    192            DeviceTypes.LIGHT
    193        ]:
    194            await self._set_property_list(bulb, plist)
    195        if bulb.type in [
    196            DeviceTypes.MESH_LIGHT
    197        ]:
    198            await self._local_bulb_command(bulb, plist)

async def music_mode_on(self, bulb: wyzeapy.types.Device): View Source

    200    async def music_mode_on(self, bulb: Device):
    201        plist = [
    202            create_pid_pair(PropertyIDs.LIGHTSTRIP_MUSIC_MODE, "1")
    203        ]
    204
    205        await self._run_action_list(bulb, plist)

async def music_mode_off(self, bulb: wyzeapy.types.Device): View Source

    207    async def music_mode_off(self, bulb: Device):
    208        plist = [
    209            create_pid_pair(PropertyIDs.LIGHTSTRIP_MUSIC_MODE, "0")
    210        ]
    211
    212        await self._run_action_list(bulb, plist)

##### 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