"""This is a WIP, not implemented yet.""" from __future__ import annotations import asyncio import logging from dataclasses import fields from typing import TYPE_CHECKING from pyvesync.models.home_models import ( IntResponseHomeListModel, IntResponseHomeResultModel, RequestHomeModel, ResponseHomeModel, ) from pyvesync.utils.errors import ErrorCodes, VeSyncAPIResponseError from pyvesync.utils.helpers import Helpers if TYPE_CHECKING: from pyvesync.base_devices import VeSyncBaseDevice from pyvesync.models.base_models import RequestBaseModel from pyvesync.vesync import VeSync _LOGGER = logging.getLogger(__name__) class VeSyncHome: """Class to handle home-related operations in VeSync.""" def __init__(self, home_id: int, name: str, nickname: str | None = None) -> None: """Initialize the VeSyncHome instance.""" self.home_id: int = home_id self.name: str = name self.nickname: str | None = nickname self.rooms: list[VeSyncRoom] = [] @property def devices(self) -> list[VeSyncBaseDevice]: """Return a list of all devices in the home.""" devices = [] for room in self.rooms: devices.extend(room.devices) return devices async def update_devices(self, devices: list[VeSyncBaseDevice]) -> None: """Update the devices in the home.""" update_tasks = [device.update() for device in devices] for update_coro in asyncio.as_completed(update_tasks): try: await update_coro except Exception as e: # pylint: disable=broad-except _LOGGER.debug('Error updating device %s', e) @staticmethod def _build_request_model( manager: VeSync, request_model: type[RequestBaseModel] ) -> RequestBaseModel: """Build the request model for home data.""" req_fields = tuple(field.name for field in fields(request_model) if field.init) body = Helpers.get_defaultvalues_attributes(req_fields) body.update(Helpers.get_manager_attributes(manager, req_fields)) return request_model(**body) @classmethod def _process_home_list( cls, home_list: list[IntResponseHomeListModel] ) -> list[VeSyncHome]: """Process the home list and return a list of VeSyncHome instances.""" homes = [] for home in home_list: if not isinstance(home, IntResponseHomeListModel): msg = ( 'Invalid home list item type.' f'Expected IntResponseHomeListModel, got {home}' ) raise VeSyncAPIResponseError(msg) homes.append(VeSyncHome(home.homeId, home.homeName, home.nickname)) return homes @classmethod async def build_homes(cls, manager: VeSync) -> bool: """Get home information. This method retrieves the home list from the VeSync API and populates the VeSyncHome instances in the manager. The objects are stored in `manager.homes` attribute as a list. Args: manager (VeSync): The VeSync instance to use for the API call. Returns: bool: True if the home list was successfully retrieved and populated. Raises: VeSyncAPIResponseError: If the API response contains an error or if the home list is empty. """ body = cls._build_request_model(manager, RequestHomeModel) response, _ = await manager.async_call_api( '/cloud/v1/homeManaged/getHomeList', method='post', json_object=body ) if response is None: raise VeSyncAPIResponseError( 'Response is None, enable debugging to see more information.' ) resp_model = ResponseHomeModel.from_dict(response) if resp_model.code != 0: error = ErrorCodes.get_error_info(resp_model.code) if resp_model.msg is not None: error.message = f'{resp_model.msg} ({error.message})' msg = f'Failed to get home list with error: {error.to_json()}' raise VeSyncAPIResponseError(msg) result = resp_model.result if not isinstance(result, IntResponseHomeResultModel): msg = ( 'Error in home list API response.' f'Expected IntResponseHomeResultModel, got {result}' ) raise VeSyncAPIResponseError(msg) home_list = result.homeList if not home_list: raise VeSyncAPIResponseError('No homes found in the response.') for home in home_list: if not isinstance(home, IntResponseHomeListModel): msg = ( 'Invalid home list item type.' f'Expected IntResponseHomeListModel, got {home}' ) raise VeSyncAPIResponseError(msg) return True class VeSyncRoom: """Class to handle room-related operations in VeSync.""" def __init__(self, room_id: str, name: str) -> None: """Initialize the VeSyncRoom instance.""" self.room_id: str = room_id self.name: str = name self.devices: list[VeSyncBaseDevice] = [] @staticmethod def _build_request_model( manager: VeSync, request_model: type[RequestBaseModel] ) -> RequestBaseModel: """Build the request model for room data.""" req_fields = tuple(field.name for field in fields(request_model) if field.init) body = Helpers.get_defaultvalues_attributes(req_fields) body.update(Helpers.get_manager_attributes(manager, req_fields)) return request_model(**body)