mirror of
https://github.com/micahqcade/custom_vesync.git
synced 2025-02-11 17:49:00 +01:00
348 lines
12 KiB
Python
348 lines
12 KiB
Python
"""Classes for VeSync Switch Devices."""
|
|
|
|
from abc import ABCMeta, abstractmethod
|
|
import json
|
|
import logging
|
|
from typing import Dict, Union
|
|
|
|
from .helpers import Helpers as helpers
|
|
from .vesyncbasedevice import VeSyncBaseDevice
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
feature_dict: Dict[str, Dict[str, Union[list, str]]] = {
|
|
"ESWL01": {"module": "VeSyncWallSwitch", "features": []},
|
|
"ESWD16": {"module": "VeSyncDimmerSwitch", "features": ["dimmable"]},
|
|
"ESWL03": {"module": "VeSyncWallSwitch", "features": []},
|
|
}
|
|
|
|
switch_modules: dict = {k: v["module"] for k, v in feature_dict.items()}
|
|
|
|
__all__: list = list(switch_modules.values()) + ["switch_modules"]
|
|
|
|
|
|
class VeSyncSwitch(VeSyncBaseDevice):
|
|
"""Etekcity Switch Base Class."""
|
|
|
|
__metaclasss__ = ABCMeta
|
|
|
|
def __init__(self, details, manager):
|
|
"""Initialize Switch Base Class."""
|
|
super().__init__(details, manager)
|
|
self.features = feature_dict.get(self.device_type, {}).get("features")
|
|
if self.features is None:
|
|
logger.error("No configuration set for - %s", self.device_name)
|
|
raise RuntimeError(f"No configuration set for - {self.device_name}")
|
|
self.details = {}
|
|
|
|
def is_dimmable(self) -> bool:
|
|
"""Return True if switch is dimmable."""
|
|
return bool("dimmable" in self.features)
|
|
|
|
@abstractmethod
|
|
def get_details(self) -> None:
|
|
"""Get Device Details."""
|
|
|
|
@abstractmethod
|
|
def turn_on(self) -> bool:
|
|
"""Turn Switch On."""
|
|
|
|
@abstractmethod
|
|
def turn_off(self) -> bool:
|
|
"""Turn switch off."""
|
|
|
|
@abstractmethod
|
|
def get_config(self) -> None:
|
|
"""Get configuration and firmware deatils."""
|
|
|
|
@property
|
|
def active_time(self) -> int:
|
|
"""Get active time of switch."""
|
|
return self.details.get("active_time", 0)
|
|
|
|
def update(self) -> None:
|
|
"""Update device details."""
|
|
self.get_details()
|
|
|
|
|
|
class VeSyncWallSwitch(VeSyncSwitch):
|
|
"""Etekcity standard wall switch class."""
|
|
|
|
def __init__(self, details, manager):
|
|
"""Initialize standard etekcity wall switch class."""
|
|
super().__init__(details, manager)
|
|
|
|
def get_details(self) -> None:
|
|
"""Get switch device details."""
|
|
body = helpers.req_body(self.manager, "devicedetail")
|
|
body["uuid"] = self.uuid
|
|
head = helpers.req_headers(self.manager)
|
|
|
|
r, _ = helpers.call_api(
|
|
"/inwallswitch/v1/device/devicedetail", "post", headers=head, json=body
|
|
)
|
|
|
|
if r is not None and helpers.code_check(r):
|
|
self.device_status = r.get("deviceStatus", self.device_status)
|
|
self.details["active_time"] = r.get("activeTime", 0)
|
|
self.connection_status = r.get("connectionStatus", self.connection_status)
|
|
else:
|
|
logger.debug("Error getting %s details", self.device_name)
|
|
|
|
def get_config(self) -> None:
|
|
"""Get switch device configuration info."""
|
|
body = helpers.req_body(self.manager, "devicedetail")
|
|
body["method"] = "configurations"
|
|
body["uuid"] = self.uuid
|
|
|
|
r, _ = helpers.call_api(
|
|
"/inwallswitch/v1/device/configurations",
|
|
"post",
|
|
headers=helpers.req_headers(self.manager),
|
|
json=body,
|
|
)
|
|
|
|
if helpers.code_check(r):
|
|
self.config = helpers.build_config_dict(r)
|
|
else:
|
|
logger.warning("Unable to get %s config info", self.device_name)
|
|
|
|
def turn_off(self) -> bool:
|
|
"""Turn off switch device."""
|
|
body = helpers.req_body(self.manager, "devicestatus")
|
|
body["status"] = "off"
|
|
body["uuid"] = self.uuid
|
|
head = helpers.req_headers(self.manager)
|
|
|
|
r, _ = helpers.call_api(
|
|
"/inwallswitch/v1/device/devicestatus", "put", headers=head, json=body
|
|
)
|
|
|
|
if r is not None and helpers.code_check(r):
|
|
self.device_status = "off"
|
|
return True
|
|
logger.warning("Error turning %s off", self.device_name)
|
|
return False
|
|
|
|
def turn_on(self) -> bool:
|
|
"""Turn on switch device."""
|
|
body = helpers.req_body(self.manager, "devicestatus")
|
|
body["status"] = "on"
|
|
body["uuid"] = self.uuid
|
|
head = helpers.req_headers(self.manager)
|
|
|
|
r, _ = helpers.call_api(
|
|
"/inwallswitch/v1/device/devicestatus", "put", headers=head, json=body
|
|
)
|
|
|
|
if r is not None and helpers.code_check(r):
|
|
self.device_status = "on"
|
|
return True
|
|
logger.warning("Error turning %s on", self.device_name)
|
|
return False
|
|
|
|
|
|
class VeSyncDimmerSwitch(VeSyncSwitch):
|
|
"""Vesync Dimmer Switch Class with RGB Faceplate."""
|
|
|
|
def __init__(self, details, manager):
|
|
"""Initialize dimmer switch class."""
|
|
super().__init__(details, manager)
|
|
self._brightness = 0
|
|
self._rgb_value = {"red": 0, "blue": 0, "green": 0}
|
|
self._rgb_status = "unknown"
|
|
self._indicator_light = "unknown"
|
|
|
|
def get_details(self) -> None:
|
|
"""Get dimmer switch details."""
|
|
body = helpers.req_body(self.manager, "devicedetail")
|
|
body["uuid"] = self.uuid
|
|
head = helpers.req_headers(self.manager)
|
|
|
|
r, _ = helpers.call_api(
|
|
"/dimmer/v1/device/devicedetail", "post", headers=head, json=body
|
|
)
|
|
|
|
if r is not None and helpers.code_check(r):
|
|
self.device_status = r.get("deviceStatus", self.device_status)
|
|
self.details["active_time"] = r.get("activeTime", 0)
|
|
self.connection_status = r.get("connectionStatus", self.connection_status)
|
|
self._brightness = r.get("brightness")
|
|
self._rgb_status = r.get("rgbStatus")
|
|
self._rgb_value = r.get("rgbValue")
|
|
self._indicator_light = r.get("indicatorlightStatus")
|
|
else:
|
|
logger.debug("Error getting %s details", self.device_name)
|
|
|
|
@property
|
|
def brightness(self) -> float:
|
|
"""Return brightness in percent."""
|
|
return self._brightness
|
|
|
|
@property
|
|
def indicator_light_status(self) -> str:
|
|
"""Faceplate brightness light status."""
|
|
return self._indicator_light
|
|
|
|
@property
|
|
def rgb_light_status(self) -> str:
|
|
"""RGB Faceplate light status."""
|
|
return self._rgb_status
|
|
|
|
@property
|
|
def rgb_light_value(self) -> dict:
|
|
"""RGB Light Values."""
|
|
return self._rgb_value
|
|
|
|
def switch_toggle(self, status: str) -> bool:
|
|
"""Toggle switch status."""
|
|
if status not in ["on", "off"]:
|
|
logger.debug("Invalid status passed to wall switch")
|
|
return False
|
|
body = helpers.req_body(self.manager, "devicestatus")
|
|
body["status"] = status
|
|
body["uuid"] = self.uuid
|
|
head = helpers.req_headers(self.manager)
|
|
|
|
r, _ = helpers.call_api(
|
|
"/dimmer/v1/device/devicestatus", "put", headers=head, json=body
|
|
)
|
|
|
|
if r is not None and helpers.code_check(r):
|
|
self.device_status = status
|
|
return True
|
|
|
|
logger.warning("Error turning %s %s", self.device_name, status)
|
|
return False
|
|
|
|
def turn_on(self) -> bool:
|
|
"""Turn switch on."""
|
|
return self.switch_toggle("on")
|
|
|
|
def turn_off(self) -> bool:
|
|
"""Turn switch off."""
|
|
return self.switch_toggle("off")
|
|
|
|
def indicator_light_toggle(self, status: str) -> bool:
|
|
"""Toggle indicator light."""
|
|
if status not in ["on", "off"]:
|
|
logger.debug("Invalid status for wall switch")
|
|
return False
|
|
body = helpers.req_body(self.manager, "devicestatus")
|
|
body["status"] = status
|
|
body["uuid"] = self.uuid
|
|
head = helpers.req_headers(self.manager)
|
|
|
|
r, _ = helpers.call_api(
|
|
"/dimmer/v1/device/indicatorlightstatus", "put", headers=head, json=body
|
|
)
|
|
|
|
if r is not None and helpers.code_check(r):
|
|
self.device_status = status
|
|
return True
|
|
|
|
logger.warning("Error turning %s indicator light %s", self.device_name, status)
|
|
return False
|
|
|
|
def indicator_light_on(self) -> bool:
|
|
"""Turn Indicator light on."""
|
|
return self.indicator_light_toggle("on")
|
|
|
|
def indicator_light_off(self) -> bool:
|
|
"""Turn indicator light off."""
|
|
return self.indicator_light_toggle("off")
|
|
|
|
def rgb_color_status(
|
|
self, status: str, red: int = None, blue: int = None, green: int = None
|
|
) -> bool:
|
|
"""Set faceplate RGB color."""
|
|
body = helpers.req_body(self.manager, "devicestatus")
|
|
body["status"] = status
|
|
body["uuid"] = self.uuid
|
|
head = helpers.req_headers(self.manager)
|
|
if red is not None and blue is not None and green is not None:
|
|
body["rgbValue"] = {"red": red, "blue": blue, "green": green}
|
|
|
|
r, _ = helpers.call_api(
|
|
"/dimmer/v1/device/devicergbstatus", "put", headers=head, json=body
|
|
)
|
|
|
|
if r is not None and helpers.code_check(r):
|
|
self._rgb_status = status
|
|
if body.get("rgbValue") is not None:
|
|
self._rgb_value = {"red": red, "blue": blue, "green": green}
|
|
return True
|
|
logger.warning("Error turning %s off", self.device_name)
|
|
return False
|
|
|
|
def rgb_color_off(self) -> bool:
|
|
"""Turn RGB Color Off."""
|
|
return self.rgb_color_status("off")
|
|
|
|
def rgb_color_on(self) -> bool:
|
|
"""Turn RGB Color Off."""
|
|
return self.rgb_color_status("on")
|
|
|
|
def rgb_color_set(self, red: int, green: int, blue: int) -> bool:
|
|
"""Set RGB color of faceplate."""
|
|
if isinstance(red, int) and isinstance(green, int) and isinstance(blue, int):
|
|
for color in [red, green, blue]:
|
|
if color < 0 or color > 255:
|
|
logger.warning("Invalid RGB value")
|
|
return False
|
|
|
|
return bool(self.rgb_color_status("on", red, green, blue))
|
|
return False
|
|
|
|
def set_brightness(self, brightness: int) -> bool:
|
|
"""Set brightness of dimmer - 1 - 100."""
|
|
if isinstance(brightness, int) and (brightness > 0 or brightness <= 100):
|
|
|
|
body = helpers.req_body(self.manager, "devicestatus")
|
|
body["brightness"] = brightness
|
|
body["uuid"] = self.uuid
|
|
head = helpers.req_headers(self.manager)
|
|
|
|
r, _ = helpers.call_api(
|
|
"/dimmer/v1/device/updatebrightness", "put", headers=head, json=body
|
|
)
|
|
|
|
if r is not None and helpers.code_check(r):
|
|
self._brightness = brightness
|
|
return True
|
|
logger.warning("Error setting %s brightness", self.device_name)
|
|
else:
|
|
logger.warning("Invalid brightness")
|
|
return False
|
|
|
|
def displayJSON(self) -> str:
|
|
"""JSON API for dimmer switch."""
|
|
sup_val = json.loads(super().displayJSON())
|
|
if self.is_dimmable:
|
|
sup_val.update(
|
|
{
|
|
"Indicator Light": str(self.active_time),
|
|
"Brightness": str(self._brightness),
|
|
"RGB Light": str(self._rgb_status),
|
|
}
|
|
)
|
|
return sup_val
|
|
|
|
def get_config(self) -> None:
|
|
"""Get dimmable switch device configuration info."""
|
|
body = helpers.req_body(self.manager, "devicedetail")
|
|
body["method"] = "configurations"
|
|
body["uuid"] = self.uuid
|
|
|
|
r, _ = helpers.call_api(
|
|
"/dimmer/v1/device/configurations",
|
|
"post",
|
|
headers=helpers.req_headers(self.manager),
|
|
json=body,
|
|
)
|
|
|
|
if helpers.code_check(r):
|
|
self.config = helpers.build_config_dict(r)
|
|
else:
|
|
logger.warning("Unable to get %s config info", self.device_name)
|