wyzeapy
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 7from inspect import iscoroutinefunction 8from typing import List, Optional, Set, Callable 9 10from .const import PHONE_SYSTEM_TYPE, APP_VERSION, SC, APP_VER, SV, PHONE_ID, APP_NAME, OLIVE_APP_ID, APP_INFO 11from .crypto import olive_create_signature 12from .exceptions import TwoFactorAuthenticationEnabled 13from .payload_factory import olive_create_user_info_payload 14from .services.base_service import BaseService 15from .services.bulb_service import BulbService 16from .services.camera_service import CameraService 17from .services.hms_service import HMSService 18from .services.lock_service import LockService 19from .services.sensor_service import SensorService 20from .services.switch_service import SwitchService, SwitchUsageService 21from .services.thermostat_service import ThermostatService 22from .services.wall_switch_service import WallSwitchService 23from .wyze_auth_lib import WyzeAuthLib, Token 24 25_LOGGER = logging.getLogger(__name__) 26 27 28class Wyzeapy: 29 """A Python module to assist developers in interacting with the Wyze service API. 30 31 This class provides methods for authentication, device management, and accessing 32 various Wyze device services including: 33 34 * **Bulbs** - Control brightness, color, and power state 35 * **Switches** - Toggle power and monitor usage 36 * **Cameras** - Access video streams and control settings 37 * **Thermostats** - Manage temperature settings and modes 38 * **Locks** - Control and monitor door locks 39 * **Sensors** - Monitor motion, contact, and environmental sensors 40 * **HMS** - Manage home monitoring system 41 42 Most interactions with Wyze devices should go through this class. 43 """ 44 # _client: Client 45 _auth_lib: WyzeAuthLib 46 47 def __init__(self): 48 self._bulb_service = None 49 self._switch_service = None 50 self._camera_service = None 51 self._thermostat_service = None 52 self._hms_service = None 53 self._lock_service = None 54 self._sensor_service = None 55 self._wall_switch_service = None 56 self._switch_usage_service = None 57 self._email = None 58 self._password = None 59 self._key_id = None 60 self._api_key = None 61 self._service: Optional[BaseService] = None 62 self._token_callbacks: List[Callable] = [] 63 64 @classmethod 65 async def create(cls): 66 """ 67 Creates and initializes the Wyzeapy class asynchronously. 68 69 This factory method provides a way to instantiate the class using async/await syntax, 70 though it's currently a simple implementation that may be expanded in the future. 71 72 **Returns:** 73 `Wyzeapy`: A new instance of the Wyzeapy class ready for authentication. 74 """ 75 self = cls() 76 return self 77 78 async def login( 79 self, email, password, key_id, api_key, token: Optional[Token] = None 80 ): 81 """ 82 Authenticates with the Wyze API and retrieves the user's access token. 83 84 This method handles the authentication process, including token management 85 and service initialization. If two-factor authentication is enabled on the account, 86 it will raise an exception requiring the use of `login_with_2fa()` instead. 87 88 **Args:** 89 * `email` (str): User's email address for Wyze account 90 * `password` (str): User's password for Wyze account 91 * `key_id` (str): Key ID for third-party API access 92 * `api_key` (str): API Key for third-party API access 93 * `token` (Optional[Token], optional): Existing token from a previous session. Defaults to None. 94 95 **Raises:** 96 * `TwoFactorAuthenticationEnabled`: When the account has 2FA enabled and requires verification 97 """ 98 99 self._email = email 100 self._password = password 101 self._key_id = key_id 102 self._api_key = api_key 103 104 try: 105 self._auth_lib = await WyzeAuthLib.create( 106 email, password, key_id, api_key, token, self.execute_token_callbacks 107 ) 108 if token: 109 # User token supplied, refresh on startup 110 await self._auth_lib.refresh() 111 else: 112 await self._auth_lib.get_token_with_username_password( 113 email, password, key_id, api_key 114 ) 115 self._service = BaseService(self._auth_lib) 116 except TwoFactorAuthenticationEnabled as error: 117 raise error 118 119 async def login_with_2fa(self, verification_code) -> Token: 120 """ 121 Completes the login process for accounts with two-factor authentication enabled. 122 123 This method should be called after receiving a `TwoFactorAuthenticationEnabled` 124 exception from the `login()` method. It completes the authentication process 125 using the verification code sent to the user. 126 127 **Args:** 128 * `verification_code` (str): The 2FA verification code received by the user 129 130 **Returns:** 131 * `Token`: The authenticated user token object 132 """ 133 134 _LOGGER.debug(f"Verification Code: {verification_code}") 135 136 await self._auth_lib.get_token_with_2fa(verification_code) 137 self._service = BaseService(self._auth_lib) 138 return self._auth_lib.token 139 140 async def execute_token_callbacks(self, token: Token): 141 """ 142 Sends the token to all registered callback functions. 143 144 This method is called internally whenever the token is refreshed or updated, 145 allowing external components to stay in sync with token changes. 146 147 **Args:** 148 * `token` (Token): The current user token object 149 """ 150 for callback in self._token_callbacks: 151 if iscoroutinefunction(callback): 152 await callback(token) 153 else: 154 callback(token) 155 156 def register_for_token_callback(self, callback_function): 157 """ 158 Registers a callback function to be called whenever the user's token is modified. 159 160 This allows external components to be notified of token changes for persistence 161 or other token-dependent operations. 162 163 **Args:** 164 * `callback_function`: A function that accepts a Token object as its parameter 165 166 **Example:** 167 ```python 168 def token_updated(token): 169 print(f"Token refreshed: {token.access_token[:10]}...") 170 171 wyze = Wyzeapy() 172 wyze.register_for_token_callback(token_updated) 173 ``` 174 """ 175 self._token_callbacks.append(callback_function) 176 177 def unregister_for_token_callback(self, callback_function): 178 """ 179 Removes a previously registered token callback function. 180 181 This stops the specified callback from receiving token updates. 182 183 **Args:** 184 * `callback_function`: The callback function to remove from the notification list 185 """ 186 self._token_callbacks.remove(callback_function) 187 188 @property 189 async def unique_device_ids(self) -> Set[str]: 190 """ 191 Retrieves a set of all unique device IDs known to the Wyze server. 192 193 This property fetches all devices associated with the account and 194 extracts their MAC addresses as unique identifiers. 195 196 **Returns:** 197 * `Set[str]`: A set containing all unique device IDs (MAC addresses) 198 199 **Example:** 200 ```python 201 device_ids = await wyze.unique_device_ids 202 print(f"Found {len(device_ids)} devices") 203 ``` 204 """ 205 206 devices = await self._service.get_object_list() 207 device_ids = set() 208 for device in devices: 209 device_ids.add(device.mac) 210 211 return device_ids 212 213 @property 214 async def notifications_are_on(self) -> bool: 215 """ 216 Checks if push notifications are enabled for the account. 217 218 This property queries the user profile to determine the current 219 notification settings status. 220 221 **Returns:** 222 * `bool`: True if notifications are enabled, False otherwise 223 """ 224 225 response_json = await self._service.get_user_profile() 226 return response_json['data']['notification'] 227 228 async def enable_notifications(self): 229 """Enables push notifications for the Wyze account. 230 231 This method updates the user's profile to turn on push notifications 232 for all supported devices and events. 233 234 **Example:** 235 ```python 236 # Turn on notifications 237 await wyze.enable_notifications() 238 ``` 239 """ 240 241 await self._service.set_push_info(True) 242 243 async def disable_notifications(self): 244 """Disables push notifications for the Wyze account. 245 246 This method updates the user's profile to turn off push notifications 247 for all devices and events. 248 249 **Example:** 250 ```python 251 # Turn off notifications 252 await wyze.disable_notifications() 253 ``` 254 """ 255 256 await self._service.set_push_info(False) 257 258 @classmethod 259 async def valid_login( 260 cls, email: str, password: str, key_id: str, api_key: str 261 ) -> bool: 262 """ 263 Validates if the provided credentials can successfully authenticate with the Wyze API. 264 265 This method attempts to log in with the provided credentials and returns whether 266 the authentication was successful. It's useful for validating credentials without 267 needing to handle the full login process. 268 269 **Args:** 270 * `email` (str): The user's email address 271 * `password` (str): The user's password 272 * `key_id` (str): Key ID for third-party API access 273 * `api_key` (str): API Key for third-party API access 274 275 **Returns:** 276 * `bool`: True if the credentials are valid and authentication succeeded 277 278 **Example:** 279 ```python 280 is_valid = await Wyzeapy.valid_login("user@example.com", "password123", "key_id", "api_key") 281 if is_valid: 282 print("Credentials are valid") 283 else: 284 print("Invalid credentials") 285 ``` 286 """ 287 288 self = cls() 289 await self.login(email, password, key_id, api_key) 290 291 return not self._auth_lib.should_refresh 292 293 @property 294 async def bulb_service(self) -> BulbService: 295 """Provides access to the Wyze Bulb service. 296 297 This property lazily initializes and returns a BulbService instance 298 for controlling and monitoring Wyze bulbs. 299 300 **Returns:** 301 * `BulbService`: An instance of the bulb service for interacting with Wyze bulbs 302 303 **Example:** 304 ```python 305 # Get all bulbs 306 bulb_service = await wyze.bulb_service 307 bulbs = await bulb_service.get_bulbs() 308 ``` 309 """ 310 311 if self._bulb_service is None: 312 self._bulb_service = BulbService(self._auth_lib) 313 return self._bulb_service 314 315 @property 316 async def switch_service(self) -> SwitchService: 317 """Provides access to the Wyze Switch service. 318 319 This property lazily initializes and returns a SwitchService instance 320 for controlling and monitoring Wyze plugs and switches. 321 322 **Returns:** 323 * `SwitchService`: An instance of the switch service for interacting with Wyze switches 324 325 **Example:** 326 ```python 327 # Get all switches 328 switch_service = await wyze.switch_service 329 switches = await switch_service.get_switches() 330 ``` 331 """ 332 333 if self._switch_service is None: 334 self._switch_service = SwitchService(self._auth_lib) 335 return self._switch_service 336 337 @property 338 async def camera_service(self) -> CameraService: 339 """Provides access to the Wyze Camera service. 340 341 This property lazily initializes and returns a CameraService instance 342 for controlling and monitoring Wyze cameras. 343 344 **Returns:** 345 * `CameraService`: An instance of the camera service for interacting with Wyze cameras 346 347 **Example:** 348 ```python 349 # Get all cameras 350 camera_service = await wyze.camera_service 351 cameras = await camera_service.get_cameras() 352 ``` 353 """ 354 355 if self._camera_service is None: 356 self._camera_service = CameraService(self._auth_lib) 357 return self._camera_service 358 359 @property 360 async def thermostat_service(self) -> ThermostatService: 361 """Provides access to the Wyze Thermostat service. 362 363 This property lazily initializes and returns a ThermostatService instance 364 for controlling and monitoring Wyze thermostats. 365 366 **Returns:** 367 * `ThermostatService`: An instance of the thermostat service for interacting with Wyze thermostats 368 369 **Example:** 370 ```python 371 # Get all thermostats 372 thermostat_service = await wyze.thermostat_service 373 thermostats = await thermostat_service.get_thermostats() 374 ``` 375 """ 376 377 if self._thermostat_service is None: 378 self._thermostat_service = ThermostatService(self._auth_lib) 379 return self._thermostat_service 380 381 @property 382 async def hms_service(self) -> HMSService: 383 """Provides access to the Wyze Home Monitoring Service (HMS). 384 385 This property lazily initializes and returns an HMSService instance 386 for controlling and monitoring the Wyze home security system. 387 388 **Returns:** 389 * `HMSService`: An instance of the HMS service for interacting with Wyze home monitoring 390 391 **Example:** 392 ```python 393 # Get HMS status 394 hms_service = await wyze.hms_service 395 status = await hms_service.get_hms_status() 396 ``` 397 """ 398 399 if self._hms_service is None: 400 self._hms_service = await HMSService.create(self._auth_lib) 401 return self._hms_service 402 403 @property 404 async def lock_service(self) -> LockService: 405 """Provides access to the Wyze Lock service. 406 407 This property lazily initializes and returns a LockService instance 408 for controlling and monitoring Wyze locks. 409 410 **Returns:** 411 * `LockService`: An instance of the lock service for interacting with Wyze locks 412 413 **Example:** 414 ```python 415 # Get all locks 416 lock_service = await wyze.lock_service 417 locks = await lock_service.get_locks() 418 ``` 419 """ 420 421 if self._lock_service is None: 422 self._lock_service = LockService(self._auth_lib) 423 return self._lock_service 424 425 @property 426 async def sensor_service(self) -> SensorService: 427 """Provides access to the Wyze Sensor service. 428 429 This property lazily initializes and returns a SensorService instance 430 for monitoring Wyze sensors such as contact sensors, motion sensors, etc. 431 432 **Returns:** 433 * `SensorService`: An instance of the sensor service for interacting with Wyze sensors 434 435 **Example:** 436 ```python 437 # Get all sensors 438 sensor_service = await wyze.sensor_service 439 sensors = await sensor_service.get_sensors() 440 ``` 441 """ 442 443 if self._sensor_service is None: 444 self._sensor_service = SensorService(self._auth_lib) 445 return self._sensor_service 446 447 @property 448 async def wall_switch_service(self) -> WallSwitchService: 449 """Provides access to the Wyze Wall Switch service. 450 451 This property lazily initializes and returns a WallSwitchService instance 452 for controlling and monitoring Wyze wall switches. 453 454 **Returns:** 455 * `WallSwitchService`: An instance of the wall switch service for interacting with Wyze wall switches 456 457 **Example:** 458 ```python 459 # Get all wall switches 460 wall_switch_service = await wyze.wall_switch_service 461 switches = await wall_switch_service.get_wall_switches() 462 ``` 463 """ 464 465 if self._wall_switch_service is None: 466 self._wall_switch_service = WallSwitchService(self._auth_lib) 467 return self._wall_switch_service 468 469 @property 470 async def switch_usage_service(self) -> SwitchUsageService: 471 """Provides access to the Wyze Switch Usage service. 472 473 This property lazily initializes and returns a SwitchUsageService instance 474 for retrieving usage statistics from Wyze switches and plugs. 475 476 **Returns:** 477 * `SwitchUsageService`: An instance of the switch usage service for accessing Wyze switch usage data 478 479 **Example:** 480 ```python 481 # Get usage data for a switch 482 usage_service = await wyze.switch_usage_service 483 usage = await usage_service.get_usage_records(switch_mac) 484 ``` 485 """ 486 if self._switch_usage_service is None: 487 self._switch_usage_service = SwitchUsageService(self._auth_lib) 488 return self._switch_usage_service
29class Wyzeapy: 30 """A Python module to assist developers in interacting with the Wyze service API. 31 32 This class provides methods for authentication, device management, and accessing 33 various Wyze device services including: 34 35 * **Bulbs** - Control brightness, color, and power state 36 * **Switches** - Toggle power and monitor usage 37 * **Cameras** - Access video streams and control settings 38 * **Thermostats** - Manage temperature settings and modes 39 * **Locks** - Control and monitor door locks 40 * **Sensors** - Monitor motion, contact, and environmental sensors 41 * **HMS** - Manage home monitoring system 42 43 Most interactions with Wyze devices should go through this class. 44 """ 45 # _client: Client 46 _auth_lib: WyzeAuthLib 47 48 def __init__(self): 49 self._bulb_service = None 50 self._switch_service = None 51 self._camera_service = None 52 self._thermostat_service = None 53 self._hms_service = None 54 self._lock_service = None 55 self._sensor_service = None 56 self._wall_switch_service = None 57 self._switch_usage_service = None 58 self._email = None 59 self._password = None 60 self._key_id = None 61 self._api_key = None 62 self._service: Optional[BaseService] = None 63 self._token_callbacks: List[Callable] = [] 64 65 @classmethod 66 async def create(cls): 67 """ 68 Creates and initializes the Wyzeapy class asynchronously. 69 70 This factory method provides a way to instantiate the class using async/await syntax, 71 though it's currently a simple implementation that may be expanded in the future. 72 73 **Returns:** 74 `Wyzeapy`: A new instance of the Wyzeapy class ready for authentication. 75 """ 76 self = cls() 77 return self 78 79 async def login( 80 self, email, password, key_id, api_key, token: Optional[Token] = None 81 ): 82 """ 83 Authenticates with the Wyze API and retrieves the user's access token. 84 85 This method handles the authentication process, including token management 86 and service initialization. If two-factor authentication is enabled on the account, 87 it will raise an exception requiring the use of `login_with_2fa()` instead. 88 89 **Args:** 90 * `email` (str): User's email address for Wyze account 91 * `password` (str): User's password for Wyze account 92 * `key_id` (str): Key ID for third-party API access 93 * `api_key` (str): API Key for third-party API access 94 * `token` (Optional[Token], optional): Existing token from a previous session. Defaults to None. 95 96 **Raises:** 97 * `TwoFactorAuthenticationEnabled`: When the account has 2FA enabled and requires verification 98 """ 99 100 self._email = email 101 self._password = password 102 self._key_id = key_id 103 self._api_key = api_key 104 105 try: 106 self._auth_lib = await WyzeAuthLib.create( 107 email, password, key_id, api_key, token, self.execute_token_callbacks 108 ) 109 if token: 110 # User token supplied, refresh on startup 111 await self._auth_lib.refresh() 112 else: 113 await self._auth_lib.get_token_with_username_password( 114 email, password, key_id, api_key 115 ) 116 self._service = BaseService(self._auth_lib) 117 except TwoFactorAuthenticationEnabled as error: 118 raise error 119 120 async def login_with_2fa(self, verification_code) -> Token: 121 """ 122 Completes the login process for accounts with two-factor authentication enabled. 123 124 This method should be called after receiving a `TwoFactorAuthenticationEnabled` 125 exception from the `login()` method. It completes the authentication process 126 using the verification code sent to the user. 127 128 **Args:** 129 * `verification_code` (str): The 2FA verification code received by the user 130 131 **Returns:** 132 * `Token`: The authenticated user token object 133 """ 134 135 _LOGGER.debug(f"Verification Code: {verification_code}") 136 137 await self._auth_lib.get_token_with_2fa(verification_code) 138 self._service = BaseService(self._auth_lib) 139 return self._auth_lib.token 140 141 async def execute_token_callbacks(self, token: Token): 142 """ 143 Sends the token to all registered callback functions. 144 145 This method is called internally whenever the token is refreshed or updated, 146 allowing external components to stay in sync with token changes. 147 148 **Args:** 149 * `token` (Token): The current user token object 150 """ 151 for callback in self._token_callbacks: 152 if iscoroutinefunction(callback): 153 await callback(token) 154 else: 155 callback(token) 156 157 def register_for_token_callback(self, callback_function): 158 """ 159 Registers a callback function to be called whenever the user's token is modified. 160 161 This allows external components to be notified of token changes for persistence 162 or other token-dependent operations. 163 164 **Args:** 165 * `callback_function`: A function that accepts a Token object as its parameter 166 167 **Example:** 168 ```python 169 def token_updated(token): 170 print(f"Token refreshed: {token.access_token[:10]}...") 171 172 wyze = Wyzeapy() 173 wyze.register_for_token_callback(token_updated) 174 ``` 175 """ 176 self._token_callbacks.append(callback_function) 177 178 def unregister_for_token_callback(self, callback_function): 179 """ 180 Removes a previously registered token callback function. 181 182 This stops the specified callback from receiving token updates. 183 184 **Args:** 185 * `callback_function`: The callback function to remove from the notification list 186 """ 187 self._token_callbacks.remove(callback_function) 188 189 @property 190 async def unique_device_ids(self) -> Set[str]: 191 """ 192 Retrieves a set of all unique device IDs known to the Wyze server. 193 194 This property fetches all devices associated with the account and 195 extracts their MAC addresses as unique identifiers. 196 197 **Returns:** 198 * `Set[str]`: A set containing all unique device IDs (MAC addresses) 199 200 **Example:** 201 ```python 202 device_ids = await wyze.unique_device_ids 203 print(f"Found {len(device_ids)} devices") 204 ``` 205 """ 206 207 devices = await self._service.get_object_list() 208 device_ids = set() 209 for device in devices: 210 device_ids.add(device.mac) 211 212 return device_ids 213 214 @property 215 async def notifications_are_on(self) -> bool: 216 """ 217 Checks if push notifications are enabled for the account. 218 219 This property queries the user profile to determine the current 220 notification settings status. 221 222 **Returns:** 223 * `bool`: True if notifications are enabled, False otherwise 224 """ 225 226 response_json = await self._service.get_user_profile() 227 return response_json['data']['notification'] 228 229 async def enable_notifications(self): 230 """Enables push notifications for the Wyze account. 231 232 This method updates the user's profile to turn on push notifications 233 for all supported devices and events. 234 235 **Example:** 236 ```python 237 # Turn on notifications 238 await wyze.enable_notifications() 239 ``` 240 """ 241 242 await self._service.set_push_info(True) 243 244 async def disable_notifications(self): 245 """Disables push notifications for the Wyze account. 246 247 This method updates the user's profile to turn off push notifications 248 for all devices and events. 249 250 **Example:** 251 ```python 252 # Turn off notifications 253 await wyze.disable_notifications() 254 ``` 255 """ 256 257 await self._service.set_push_info(False) 258 259 @classmethod 260 async def valid_login( 261 cls, email: str, password: str, key_id: str, api_key: str 262 ) -> bool: 263 """ 264 Validates if the provided credentials can successfully authenticate with the Wyze API. 265 266 This method attempts to log in with the provided credentials and returns whether 267 the authentication was successful. It's useful for validating credentials without 268 needing to handle the full login process. 269 270 **Args:** 271 * `email` (str): The user's email address 272 * `password` (str): The user's password 273 * `key_id` (str): Key ID for third-party API access 274 * `api_key` (str): API Key for third-party API access 275 276 **Returns:** 277 * `bool`: True if the credentials are valid and authentication succeeded 278 279 **Example:** 280 ```python 281 is_valid = await Wyzeapy.valid_login("user@example.com", "password123", "key_id", "api_key") 282 if is_valid: 283 print("Credentials are valid") 284 else: 285 print("Invalid credentials") 286 ``` 287 """ 288 289 self = cls() 290 await self.login(email, password, key_id, api_key) 291 292 return not self._auth_lib.should_refresh 293 294 @property 295 async def bulb_service(self) -> BulbService: 296 """Provides access to the Wyze Bulb service. 297 298 This property lazily initializes and returns a BulbService instance 299 for controlling and monitoring Wyze bulbs. 300 301 **Returns:** 302 * `BulbService`: An instance of the bulb service for interacting with Wyze bulbs 303 304 **Example:** 305 ```python 306 # Get all bulbs 307 bulb_service = await wyze.bulb_service 308 bulbs = await bulb_service.get_bulbs() 309 ``` 310 """ 311 312 if self._bulb_service is None: 313 self._bulb_service = BulbService(self._auth_lib) 314 return self._bulb_service 315 316 @property 317 async def switch_service(self) -> SwitchService: 318 """Provides access to the Wyze Switch service. 319 320 This property lazily initializes and returns a SwitchService instance 321 for controlling and monitoring Wyze plugs and switches. 322 323 **Returns:** 324 * `SwitchService`: An instance of the switch service for interacting with Wyze switches 325 326 **Example:** 327 ```python 328 # Get all switches 329 switch_service = await wyze.switch_service 330 switches = await switch_service.get_switches() 331 ``` 332 """ 333 334 if self._switch_service is None: 335 self._switch_service = SwitchService(self._auth_lib) 336 return self._switch_service 337 338 @property 339 async def camera_service(self) -> CameraService: 340 """Provides access to the Wyze Camera service. 341 342 This property lazily initializes and returns a CameraService instance 343 for controlling and monitoring Wyze cameras. 344 345 **Returns:** 346 * `CameraService`: An instance of the camera service for interacting with Wyze cameras 347 348 **Example:** 349 ```python 350 # Get all cameras 351 camera_service = await wyze.camera_service 352 cameras = await camera_service.get_cameras() 353 ``` 354 """ 355 356 if self._camera_service is None: 357 self._camera_service = CameraService(self._auth_lib) 358 return self._camera_service 359 360 @property 361 async def thermostat_service(self) -> ThermostatService: 362 """Provides access to the Wyze Thermostat service. 363 364 This property lazily initializes and returns a ThermostatService instance 365 for controlling and monitoring Wyze thermostats. 366 367 **Returns:** 368 * `ThermostatService`: An instance of the thermostat service for interacting with Wyze thermostats 369 370 **Example:** 371 ```python 372 # Get all thermostats 373 thermostat_service = await wyze.thermostat_service 374 thermostats = await thermostat_service.get_thermostats() 375 ``` 376 """ 377 378 if self._thermostat_service is None: 379 self._thermostat_service = ThermostatService(self._auth_lib) 380 return self._thermostat_service 381 382 @property 383 async def hms_service(self) -> HMSService: 384 """Provides access to the Wyze Home Monitoring Service (HMS). 385 386 This property lazily initializes and returns an HMSService instance 387 for controlling and monitoring the Wyze home security system. 388 389 **Returns:** 390 * `HMSService`: An instance of the HMS service for interacting with Wyze home monitoring 391 392 **Example:** 393 ```python 394 # Get HMS status 395 hms_service = await wyze.hms_service 396 status = await hms_service.get_hms_status() 397 ``` 398 """ 399 400 if self._hms_service is None: 401 self._hms_service = await HMSService.create(self._auth_lib) 402 return self._hms_service 403 404 @property 405 async def lock_service(self) -> LockService: 406 """Provides access to the Wyze Lock service. 407 408 This property lazily initializes and returns a LockService instance 409 for controlling and monitoring Wyze locks. 410 411 **Returns:** 412 * `LockService`: An instance of the lock service for interacting with Wyze locks 413 414 **Example:** 415 ```python 416 # Get all locks 417 lock_service = await wyze.lock_service 418 locks = await lock_service.get_locks() 419 ``` 420 """ 421 422 if self._lock_service is None: 423 self._lock_service = LockService(self._auth_lib) 424 return self._lock_service 425 426 @property 427 async def sensor_service(self) -> SensorService: 428 """Provides access to the Wyze Sensor service. 429 430 This property lazily initializes and returns a SensorService instance 431 for monitoring Wyze sensors such as contact sensors, motion sensors, etc. 432 433 **Returns:** 434 * `SensorService`: An instance of the sensor service for interacting with Wyze sensors 435 436 **Example:** 437 ```python 438 # Get all sensors 439 sensor_service = await wyze.sensor_service 440 sensors = await sensor_service.get_sensors() 441 ``` 442 """ 443 444 if self._sensor_service is None: 445 self._sensor_service = SensorService(self._auth_lib) 446 return self._sensor_service 447 448 @property 449 async def wall_switch_service(self) -> WallSwitchService: 450 """Provides access to the Wyze Wall Switch service. 451 452 This property lazily initializes and returns a WallSwitchService instance 453 for controlling and monitoring Wyze wall switches. 454 455 **Returns:** 456 * `WallSwitchService`: An instance of the wall switch service for interacting with Wyze wall switches 457 458 **Example:** 459 ```python 460 # Get all wall switches 461 wall_switch_service = await wyze.wall_switch_service 462 switches = await wall_switch_service.get_wall_switches() 463 ``` 464 """ 465 466 if self._wall_switch_service is None: 467 self._wall_switch_service = WallSwitchService(self._auth_lib) 468 return self._wall_switch_service 469 470 @property 471 async def switch_usage_service(self) -> SwitchUsageService: 472 """Provides access to the Wyze Switch Usage service. 473 474 This property lazily initializes and returns a SwitchUsageService instance 475 for retrieving usage statistics from Wyze switches and plugs. 476 477 **Returns:** 478 * `SwitchUsageService`: An instance of the switch usage service for accessing Wyze switch usage data 479 480 **Example:** 481 ```python 482 # Get usage data for a switch 483 usage_service = await wyze.switch_usage_service 484 usage = await usage_service.get_usage_records(switch_mac) 485 ``` 486 """ 487 if self._switch_usage_service is None: 488 self._switch_usage_service = SwitchUsageService(self._auth_lib) 489 return self._switch_usage_service
A Python module to assist developers in interacting with the Wyze service API.
This class provides methods for authentication, device management, and accessing various Wyze device services including:
- Bulbs - Control brightness, color, and power state
- Switches - Toggle power and monitor usage
- Cameras - Access video streams and control settings
- Thermostats - Manage temperature settings and modes
- Locks - Control and monitor door locks
- Sensors - Monitor motion, contact, and environmental sensors
- HMS - Manage home monitoring system
Most interactions with Wyze devices should go through this class.
65 @classmethod 66 async def create(cls): 67 """ 68 Creates and initializes the Wyzeapy class asynchronously. 69 70 This factory method provides a way to instantiate the class using async/await syntax, 71 though it's currently a simple implementation that may be expanded in the future. 72 73 **Returns:** 74 `Wyzeapy`: A new instance of the Wyzeapy class ready for authentication. 75 """ 76 self = cls() 77 return self
Creates and initializes the Wyzeapy class asynchronously.
This factory method provides a way to instantiate the class using async/await syntax, though it's currently a simple implementation that may be expanded in the future.
Returns:
Wyzeapy: A new instance of the Wyzeapy class ready for authentication.
79 async def login( 80 self, email, password, key_id, api_key, token: Optional[Token] = None 81 ): 82 """ 83 Authenticates with the Wyze API and retrieves the user's access token. 84 85 This method handles the authentication process, including token management 86 and service initialization. If two-factor authentication is enabled on the account, 87 it will raise an exception requiring the use of `login_with_2fa()` instead. 88 89 **Args:** 90 * `email` (str): User's email address for Wyze account 91 * `password` (str): User's password for Wyze account 92 * `key_id` (str): Key ID for third-party API access 93 * `api_key` (str): API Key for third-party API access 94 * `token` (Optional[Token], optional): Existing token from a previous session. Defaults to None. 95 96 **Raises:** 97 * `TwoFactorAuthenticationEnabled`: When the account has 2FA enabled and requires verification 98 """ 99 100 self._email = email 101 self._password = password 102 self._key_id = key_id 103 self._api_key = api_key 104 105 try: 106 self._auth_lib = await WyzeAuthLib.create( 107 email, password, key_id, api_key, token, self.execute_token_callbacks 108 ) 109 if token: 110 # User token supplied, refresh on startup 111 await self._auth_lib.refresh() 112 else: 113 await self._auth_lib.get_token_with_username_password( 114 email, password, key_id, api_key 115 ) 116 self._service = BaseService(self._auth_lib) 117 except TwoFactorAuthenticationEnabled as error: 118 raise error
Authenticates with the Wyze API and retrieves the user's access token.
This method handles the authentication process, including token management
and service initialization. If two-factor authentication is enabled on the account,
it will raise an exception requiring the use of login_with_2fa() instead.
Args:
email(str): User's email address for Wyze accountpassword(str): User's password for Wyze accountkey_id(str): Key ID for third-party API accessapi_key(str): API Key for third-party API accesstoken(Optional[Token], optional): Existing token from a previous session. Defaults to None.
Raises:
TwoFactorAuthenticationEnabled: When the account has 2FA enabled and requires verification
120 async def login_with_2fa(self, verification_code) -> Token: 121 """ 122 Completes the login process for accounts with two-factor authentication enabled. 123 124 This method should be called after receiving a `TwoFactorAuthenticationEnabled` 125 exception from the `login()` method. It completes the authentication process 126 using the verification code sent to the user. 127 128 **Args:** 129 * `verification_code` (str): The 2FA verification code received by the user 130 131 **Returns:** 132 * `Token`: The authenticated user token object 133 """ 134 135 _LOGGER.debug(f"Verification Code: {verification_code}") 136 137 await self._auth_lib.get_token_with_2fa(verification_code) 138 self._service = BaseService(self._auth_lib) 139 return self._auth_lib.token
Completes the login process for accounts with two-factor authentication enabled.
This method should be called after receiving a TwoFactorAuthenticationEnabled
exception from the login() method. It completes the authentication process
using the verification code sent to the user.
Args:
verification_code(str): The 2FA verification code received by the user
Returns:
Token: The authenticated user token object
141 async def execute_token_callbacks(self, token: Token): 142 """ 143 Sends the token to all registered callback functions. 144 145 This method is called internally whenever the token is refreshed or updated, 146 allowing external components to stay in sync with token changes. 147 148 **Args:** 149 * `token` (Token): The current user token object 150 """ 151 for callback in self._token_callbacks: 152 if iscoroutinefunction(callback): 153 await callback(token) 154 else: 155 callback(token)
Sends the token to all registered callback functions.
This method is called internally whenever the token is refreshed or updated, allowing external components to stay in sync with token changes.
Args:
token(Token): The current user token object
157 def register_for_token_callback(self, callback_function): 158 """ 159 Registers a callback function to be called whenever the user's token is modified. 160 161 This allows external components to be notified of token changes for persistence 162 or other token-dependent operations. 163 164 **Args:** 165 * `callback_function`: A function that accepts a Token object as its parameter 166 167 **Example:** 168 ```python 169 def token_updated(token): 170 print(f"Token refreshed: {token.access_token[:10]}...") 171 172 wyze = Wyzeapy() 173 wyze.register_for_token_callback(token_updated) 174 ``` 175 """ 176 self._token_callbacks.append(callback_function)
Registers a callback function to be called whenever the user's token is modified.
This allows external components to be notified of token changes for persistence or other token-dependent operations.
Args:
callback_function: A function that accepts a Token object as its parameter
Example:
def token_updated(token):
print(f"Token refreshed: {token.access_token[:10]}...")
wyze = Wyzeapy()
wyze.register_for_token_callback(token_updated)
178 def unregister_for_token_callback(self, callback_function): 179 """ 180 Removes a previously registered token callback function. 181 182 This stops the specified callback from receiving token updates. 183 184 **Args:** 185 * `callback_function`: The callback function to remove from the notification list 186 """ 187 self._token_callbacks.remove(callback_function)
Removes a previously registered token callback function.
This stops the specified callback from receiving token updates.
Args:
callback_function: The callback function to remove from the notification list
189 @property 190 async def unique_device_ids(self) -> Set[str]: 191 """ 192 Retrieves a set of all unique device IDs known to the Wyze server. 193 194 This property fetches all devices associated with the account and 195 extracts their MAC addresses as unique identifiers. 196 197 **Returns:** 198 * `Set[str]`: A set containing all unique device IDs (MAC addresses) 199 200 **Example:** 201 ```python 202 device_ids = await wyze.unique_device_ids 203 print(f"Found {len(device_ids)} devices") 204 ``` 205 """ 206 207 devices = await self._service.get_object_list() 208 device_ids = set() 209 for device in devices: 210 device_ids.add(device.mac) 211 212 return device_ids
Retrieves a set of all unique device IDs known to the Wyze server.
This property fetches all devices associated with the account and extracts their MAC addresses as unique identifiers.
Returns:
Set[str]: A set containing all unique device IDs (MAC addresses)
Example:
device_ids = await wyze.unique_device_ids
print(f"Found {len(device_ids)} devices")
214 @property 215 async def notifications_are_on(self) -> bool: 216 """ 217 Checks if push notifications are enabled for the account. 218 219 This property queries the user profile to determine the current 220 notification settings status. 221 222 **Returns:** 223 * `bool`: True if notifications are enabled, False otherwise 224 """ 225 226 response_json = await self._service.get_user_profile() 227 return response_json['data']['notification']
Checks if push notifications are enabled for the account.
This property queries the user profile to determine the current notification settings status.
Returns:
bool: True if notifications are enabled, False otherwise
229 async def enable_notifications(self): 230 """Enables push notifications for the Wyze account. 231 232 This method updates the user's profile to turn on push notifications 233 for all supported devices and events. 234 235 **Example:** 236 ```python 237 # Turn on notifications 238 await wyze.enable_notifications() 239 ``` 240 """ 241 242 await self._service.set_push_info(True)
Enables push notifications for the Wyze account.
This method updates the user's profile to turn on push notifications for all supported devices and events.
Example:
# Turn on notifications
await wyze.enable_notifications()
244 async def disable_notifications(self): 245 """Disables push notifications for the Wyze account. 246 247 This method updates the user's profile to turn off push notifications 248 for all devices and events. 249 250 **Example:** 251 ```python 252 # Turn off notifications 253 await wyze.disable_notifications() 254 ``` 255 """ 256 257 await self._service.set_push_info(False)
Disables push notifications for the Wyze account.
This method updates the user's profile to turn off push notifications for all devices and events.
Example:
# Turn off notifications
await wyze.disable_notifications()
259 @classmethod 260 async def valid_login( 261 cls, email: str, password: str, key_id: str, api_key: str 262 ) -> bool: 263 """ 264 Validates if the provided credentials can successfully authenticate with the Wyze API. 265 266 This method attempts to log in with the provided credentials and returns whether 267 the authentication was successful. It's useful for validating credentials without 268 needing to handle the full login process. 269 270 **Args:** 271 * `email` (str): The user's email address 272 * `password` (str): The user's password 273 * `key_id` (str): Key ID for third-party API access 274 * `api_key` (str): API Key for third-party API access 275 276 **Returns:** 277 * `bool`: True if the credentials are valid and authentication succeeded 278 279 **Example:** 280 ```python 281 is_valid = await Wyzeapy.valid_login("user@example.com", "password123", "key_id", "api_key") 282 if is_valid: 283 print("Credentials are valid") 284 else: 285 print("Invalid credentials") 286 ``` 287 """ 288 289 self = cls() 290 await self.login(email, password, key_id, api_key) 291 292 return not self._auth_lib.should_refresh
Validates if the provided credentials can successfully authenticate with the Wyze API.
This method attempts to log in with the provided credentials and returns whether the authentication was successful. It's useful for validating credentials without needing to handle the full login process.
Args:
email(str): The user's email addresspassword(str): The user's passwordkey_id(str): Key ID for third-party API accessapi_key(str): API Key for third-party API access
Returns:
bool: True if the credentials are valid and authentication succeeded
Example:
is_valid = await Wyzeapy.valid_login("user@example.com", "password123", "key_id", "api_key")
if is_valid:
print("Credentials are valid")
else:
print("Invalid credentials")
294 @property 295 async def bulb_service(self) -> BulbService: 296 """Provides access to the Wyze Bulb service. 297 298 This property lazily initializes and returns a BulbService instance 299 for controlling and monitoring Wyze bulbs. 300 301 **Returns:** 302 * `BulbService`: An instance of the bulb service for interacting with Wyze bulbs 303 304 **Example:** 305 ```python 306 # Get all bulbs 307 bulb_service = await wyze.bulb_service 308 bulbs = await bulb_service.get_bulbs() 309 ``` 310 """ 311 312 if self._bulb_service is None: 313 self._bulb_service = BulbService(self._auth_lib) 314 return self._bulb_service
Provides access to the Wyze Bulb service.
This property lazily initializes and returns a BulbService instance for controlling and monitoring Wyze bulbs.
Returns:
BulbService: An instance of the bulb service for interacting with Wyze bulbs
Example:
# Get all bulbs
bulb_service = await wyze.bulb_service
bulbs = await bulb_service.get_bulbs()
316 @property 317 async def switch_service(self) -> SwitchService: 318 """Provides access to the Wyze Switch service. 319 320 This property lazily initializes and returns a SwitchService instance 321 for controlling and monitoring Wyze plugs and switches. 322 323 **Returns:** 324 * `SwitchService`: An instance of the switch service for interacting with Wyze switches 325 326 **Example:** 327 ```python 328 # Get all switches 329 switch_service = await wyze.switch_service 330 switches = await switch_service.get_switches() 331 ``` 332 """ 333 334 if self._switch_service is None: 335 self._switch_service = SwitchService(self._auth_lib) 336 return self._switch_service
Provides access to the Wyze Switch service.
This property lazily initializes and returns a SwitchService instance for controlling and monitoring Wyze plugs and switches.
Returns:
SwitchService: An instance of the switch service for interacting with Wyze switches
Example:
# Get all switches
switch_service = await wyze.switch_service
switches = await switch_service.get_switches()
338 @property 339 async def camera_service(self) -> CameraService: 340 """Provides access to the Wyze Camera service. 341 342 This property lazily initializes and returns a CameraService instance 343 for controlling and monitoring Wyze cameras. 344 345 **Returns:** 346 * `CameraService`: An instance of the camera service for interacting with Wyze cameras 347 348 **Example:** 349 ```python 350 # Get all cameras 351 camera_service = await wyze.camera_service 352 cameras = await camera_service.get_cameras() 353 ``` 354 """ 355 356 if self._camera_service is None: 357 self._camera_service = CameraService(self._auth_lib) 358 return self._camera_service
Provides access to the Wyze Camera service.
This property lazily initializes and returns a CameraService instance for controlling and monitoring Wyze cameras.
Returns:
CameraService: An instance of the camera service for interacting with Wyze cameras
Example:
# Get all cameras
camera_service = await wyze.camera_service
cameras = await camera_service.get_cameras()
360 @property 361 async def thermostat_service(self) -> ThermostatService: 362 """Provides access to the Wyze Thermostat service. 363 364 This property lazily initializes and returns a ThermostatService instance 365 for controlling and monitoring Wyze thermostats. 366 367 **Returns:** 368 * `ThermostatService`: An instance of the thermostat service for interacting with Wyze thermostats 369 370 **Example:** 371 ```python 372 # Get all thermostats 373 thermostat_service = await wyze.thermostat_service 374 thermostats = await thermostat_service.get_thermostats() 375 ``` 376 """ 377 378 if self._thermostat_service is None: 379 self._thermostat_service = ThermostatService(self._auth_lib) 380 return self._thermostat_service
Provides access to the Wyze Thermostat service.
This property lazily initializes and returns a ThermostatService instance for controlling and monitoring Wyze thermostats.
Returns:
ThermostatService: An instance of the thermostat service for interacting with Wyze thermostats
Example:
# Get all thermostats
thermostat_service = await wyze.thermostat_service
thermostats = await thermostat_service.get_thermostats()
382 @property 383 async def hms_service(self) -> HMSService: 384 """Provides access to the Wyze Home Monitoring Service (HMS). 385 386 This property lazily initializes and returns an HMSService instance 387 for controlling and monitoring the Wyze home security system. 388 389 **Returns:** 390 * `HMSService`: An instance of the HMS service for interacting with Wyze home monitoring 391 392 **Example:** 393 ```python 394 # Get HMS status 395 hms_service = await wyze.hms_service 396 status = await hms_service.get_hms_status() 397 ``` 398 """ 399 400 if self._hms_service is None: 401 self._hms_service = await HMSService.create(self._auth_lib) 402 return self._hms_service
Provides access to the Wyze Home Monitoring Service (HMS).
This property lazily initializes and returns an HMSService instance for controlling and monitoring the Wyze home security system.
Returns:
HMSService: An instance of the HMS service for interacting with Wyze home monitoring
Example:
# Get HMS status
hms_service = await wyze.hms_service
status = await hms_service.get_hms_status()
404 @property 405 async def lock_service(self) -> LockService: 406 """Provides access to the Wyze Lock service. 407 408 This property lazily initializes and returns a LockService instance 409 for controlling and monitoring Wyze locks. 410 411 **Returns:** 412 * `LockService`: An instance of the lock service for interacting with Wyze locks 413 414 **Example:** 415 ```python 416 # Get all locks 417 lock_service = await wyze.lock_service 418 locks = await lock_service.get_locks() 419 ``` 420 """ 421 422 if self._lock_service is None: 423 self._lock_service = LockService(self._auth_lib) 424 return self._lock_service
Provides access to the Wyze Lock service.
This property lazily initializes and returns a LockService instance for controlling and monitoring Wyze locks.
Returns:
LockService: An instance of the lock service for interacting with Wyze locks
Example:
# Get all locks
lock_service = await wyze.lock_service
locks = await lock_service.get_locks()
426 @property 427 async def sensor_service(self) -> SensorService: 428 """Provides access to the Wyze Sensor service. 429 430 This property lazily initializes and returns a SensorService instance 431 for monitoring Wyze sensors such as contact sensors, motion sensors, etc. 432 433 **Returns:** 434 * `SensorService`: An instance of the sensor service for interacting with Wyze sensors 435 436 **Example:** 437 ```python 438 # Get all sensors 439 sensor_service = await wyze.sensor_service 440 sensors = await sensor_service.get_sensors() 441 ``` 442 """ 443 444 if self._sensor_service is None: 445 self._sensor_service = SensorService(self._auth_lib) 446 return self._sensor_service
Provides access to the Wyze Sensor service.
This property lazily initializes and returns a SensorService instance for monitoring Wyze sensors such as contact sensors, motion sensors, etc.
Returns:
SensorService: An instance of the sensor service for interacting with Wyze sensors
Example:
# Get all sensors
sensor_service = await wyze.sensor_service
sensors = await sensor_service.get_sensors()
448 @property 449 async def wall_switch_service(self) -> WallSwitchService: 450 """Provides access to the Wyze Wall Switch service. 451 452 This property lazily initializes and returns a WallSwitchService instance 453 for controlling and monitoring Wyze wall switches. 454 455 **Returns:** 456 * `WallSwitchService`: An instance of the wall switch service for interacting with Wyze wall switches 457 458 **Example:** 459 ```python 460 # Get all wall switches 461 wall_switch_service = await wyze.wall_switch_service 462 switches = await wall_switch_service.get_wall_switches() 463 ``` 464 """ 465 466 if self._wall_switch_service is None: 467 self._wall_switch_service = WallSwitchService(self._auth_lib) 468 return self._wall_switch_service
Provides access to the Wyze Wall Switch service.
This property lazily initializes and returns a WallSwitchService instance for controlling and monitoring Wyze wall switches.
Returns:
WallSwitchService: An instance of the wall switch service for interacting with Wyze wall switches
Example:
# Get all wall switches
wall_switch_service = await wyze.wall_switch_service
switches = await wall_switch_service.get_wall_switches()
470 @property 471 async def switch_usage_service(self) -> SwitchUsageService: 472 """Provides access to the Wyze Switch Usage service. 473 474 This property lazily initializes and returns a SwitchUsageService instance 475 for retrieving usage statistics from Wyze switches and plugs. 476 477 **Returns:** 478 * `SwitchUsageService`: An instance of the switch usage service for accessing Wyze switch usage data 479 480 **Example:** 481 ```python 482 # Get usage data for a switch 483 usage_service = await wyze.switch_usage_service 484 usage = await usage_service.get_usage_records(switch_mac) 485 ``` 486 """ 487 if self._switch_usage_service is None: 488 self._switch_usage_service = SwitchUsageService(self._auth_lib) 489 return self._switch_usage_service
Provides access to the Wyze Switch Usage service.
This property lazily initializes and returns a SwitchUsageService instance for retrieving usage statistics from Wyze switches and plugs.
Returns:
SwitchUsageService: An instance of the switch usage service for accessing Wyze switch usage data
Example:
# Get usage data for a switch
usage_service = await wyze.switch_usage_service
usage = await usage_service.get_usage_records(switch_mac)