"""Base class for all VeSync devices.""" import collections import json import logging from typing import Optional, Union logger = logging.getLogger(__name__) class VeSyncBaseDevice: """Properties shared across all VeSync devices.""" def __init__(self, details: dict, manager): """Initialize VeSync device base class.""" self.manager = manager if "cid" in details and details["cid"] is not None: self.device_name: str = details.get("deviceName", None) self.device_image: Optional[str] = details.get("deviceImg", None) self.cid: str = details.get("cid", None) self.connection_status: str = details.get("connectionStatus", None) self.connection_type: Optional[str] = details.get("connectionType", None) self.device_type: str = details.get("deviceType", None) self.type: str = details.get("type", None) self.uuid: Optional[str] = details.get("uuid", None) self.config_module: str = details.get("configModule", None) self.mac_id: Optional[str] = details.get("macID", None) self.mode: Optional[str] = details.get("mode", None) self.speed: Union[str, int, None] = details.get("speed", None) self.extension = details.get("extension", None) self.current_firm_version = details.get("currentFirmVersion", None) self.sub_device_no = details.get("subDeviceNo", 0) self.config: dict = {} if isinstance(details.get("extension"), dict): ext = details["extension"] self.speed = ext.get("fanSpeedLevel") self.mode = ext.get("mode") if self.connection_status != "online": self.device_status = "off" else: self.device_status = details.get("deviceStatus", None) else: logger.error("No cid found for %s", self.__class__.__name__) def __eq__(self, other): """Use device CID and subdevice number to test equality.""" return bool(other.cid == self.cid and other.sub_device_no == self.sub_device_no) def __hash__(self): """Use CID and sub-device number to make device hash.""" if isinstance(self.sub_device_no, int) and self.sub_device_no > 0: return hash(self.cid + str(self.sub_device_no)) return hash(self.cid) def __str__(self): """Use device info for string represtation of class.""" return f"Device Name: {self.device_name}, \ Device Type: {self.device_type},\ SubDevice No.: {self.sub_device_no},\ Status: {self.device_status}" def __repr__(self): """Representation of device details.""" return f"DevClass: {self.__class__.__name__},\ Name:{self.device_name}, Device No: {self.sub_device_no},\ DevStatus: {self.device_status}, CID: {self.cid}" @property def is_on(self) -> bool: """Return true if device is on.""" if self.device_status == "on": return True return False @property def firmware_update(self) -> bool: """Return True if firmware update available.""" cfv = self.config.get("current_firmware_version") lfv = self.config.get("latest_firmware_version") if cfv is not None and lfv is not None: if cfv != lfv: return True else: logger.debug("Call device.get_config() to get firmware versions") return False def display(self) -> None: """Print formatted device info to stdout.""" disp = [ ("Device Name:", self.device_name), ("Model: ", self.device_type), ("Subdevice No: ", str(self.sub_device_no)), ("Status: ", self.device_status), ("Online: ", self.connection_status), ("Type: ", self.type), ("CID: ", self.cid), ] if self.uuid is not None: disp.append(("UUID: ", self.uuid)) disp1 = collections.OrderedDict(disp) for k, v in disp1.items(): print(f"{k:.<15} {v:<15}") def displayJSON(self) -> str: """JSON API for device details.""" return json.dumps( { "Device Name": self.device_name, "Model": self.device_type, "Subdevice No": str(self.sub_device_no), "Status": self.device_status, "Online": self.connection_status, "Type": self.type, "CID": self.cid, } )