mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-10-14 19:38:02 +00:00
add typing hints to make it easier for 3rd party developers to use the library (#90)
* add typing hints to make it easier for 3rd party developers to use the library * remove unused devicetype enum to support python3.3 * add python 3.3 to travis and tox, install typing module in setup.py
This commit is contained in:
@@ -18,6 +18,7 @@ import logging
|
||||
import socket
|
||||
import warnings
|
||||
from collections import defaultdict
|
||||
from typing import Any, Dict, List, Tuple, Optional
|
||||
|
||||
from .types import SmartDeviceException
|
||||
from .protocol import TPLinkSmartHomeProtocol
|
||||
@@ -32,7 +33,9 @@ class SmartDevice(object):
|
||||
|
||||
ALL_FEATURES = (FEATURE_ENERGY_METER, FEATURE_TIMER)
|
||||
|
||||
def __init__(self, ip_address, protocol=None):
|
||||
def __init__(self,
|
||||
ip_address: str,
|
||||
protocol: Optional[TPLinkSmartHomeProtocol] = None) -> None:
|
||||
"""
|
||||
Create a new SmartDevice instance, identified through its IP address.
|
||||
|
||||
@@ -43,8 +46,13 @@ class SmartDevice(object):
|
||||
if not protocol:
|
||||
protocol = TPLinkSmartHomeProtocol()
|
||||
self.protocol = protocol
|
||||
self.emeter_type = "emeter" # type: str
|
||||
self.emeter_units = False
|
||||
|
||||
def _query_helper(self, target, cmd, arg=None):
|
||||
def _query_helper(self,
|
||||
target: str,
|
||||
cmd: str,
|
||||
arg: Optional[Dict] = None) -> Any:
|
||||
"""
|
||||
Helper returning unwrapped result object and doing error handling.
|
||||
|
||||
@@ -80,7 +88,7 @@ class SmartDevice(object):
|
||||
return result
|
||||
|
||||
@property
|
||||
def features(self):
|
||||
def features(self) -> List[str]:
|
||||
"""
|
||||
Returns features of the devices
|
||||
|
||||
@@ -95,7 +103,7 @@ class SmartDevice(object):
|
||||
)
|
||||
warnings.simplefilter('default', DeprecationWarning)
|
||||
if "feature" not in self.sys_info:
|
||||
return None
|
||||
return []
|
||||
|
||||
features = self.sys_info['feature'].split(':')
|
||||
|
||||
@@ -107,7 +115,7 @@ class SmartDevice(object):
|
||||
return features
|
||||
|
||||
@property
|
||||
def has_emeter(self):
|
||||
def has_emeter(self) -> bool:
|
||||
"""
|
||||
Checks feature list for energey meter support.
|
||||
|
||||
@@ -117,7 +125,7 @@ class SmartDevice(object):
|
||||
return SmartDevice.FEATURE_ENERGY_METER in self.features
|
||||
|
||||
@property
|
||||
def sys_info(self):
|
||||
def sys_info(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Returns the complete system information from the device.
|
||||
|
||||
@@ -126,7 +134,7 @@ class SmartDevice(object):
|
||||
"""
|
||||
return defaultdict(lambda: None, self.get_sysinfo())
|
||||
|
||||
def get_sysinfo(self):
|
||||
def get_sysinfo(self) -> Dict:
|
||||
"""
|
||||
Retrieve system information.
|
||||
|
||||
@@ -136,7 +144,7 @@ class SmartDevice(object):
|
||||
"""
|
||||
return self._query_helper("system", "get_sysinfo")
|
||||
|
||||
def identify(self):
|
||||
def identify(self) -> Tuple[str, str, Any]:
|
||||
"""
|
||||
Query device information to identify model and featureset
|
||||
|
||||
@@ -157,7 +165,7 @@ class SmartDevice(object):
|
||||
return info["alias"], info["model"], self.features
|
||||
|
||||
@property
|
||||
def model(self):
|
||||
def model(self) -> str:
|
||||
"""
|
||||
Get model of the device
|
||||
|
||||
@@ -165,20 +173,20 @@ class SmartDevice(object):
|
||||
:rtype: str
|
||||
:raises SmartDeviceException: on error
|
||||
"""
|
||||
return self.sys_info['model']
|
||||
return str(self.sys_info['model'])
|
||||
|
||||
@property
|
||||
def alias(self):
|
||||
def alias(self) -> str:
|
||||
"""
|
||||
Get current device alias (name)
|
||||
|
||||
:return: Device name aka alias.
|
||||
:rtype: str
|
||||
"""
|
||||
return self.sys_info['alias']
|
||||
return str(self.sys_info['alias'])
|
||||
|
||||
@alias.setter
|
||||
def alias(self, alias):
|
||||
def alias(self, alias: str) -> None:
|
||||
"""
|
||||
Sets the device name aka alias.
|
||||
|
||||
@@ -188,7 +196,7 @@ class SmartDevice(object):
|
||||
self._query_helper("system", "set_dev_alias", {"alias": alias})
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
def icon(self) -> Dict:
|
||||
"""
|
||||
Returns device icon
|
||||
|
||||
@@ -201,7 +209,7 @@ class SmartDevice(object):
|
||||
return self._query_helper("system", "get_dev_icon")
|
||||
|
||||
@icon.setter
|
||||
def icon(self, icon):
|
||||
def icon(self, icon: str) -> None:
|
||||
"""
|
||||
Content for hash and icon are unknown.
|
||||
|
||||
@@ -216,7 +224,7 @@ class SmartDevice(object):
|
||||
# self.initialize()
|
||||
|
||||
@property
|
||||
def time(self):
|
||||
def time(self) -> Optional[datetime.datetime]:
|
||||
"""
|
||||
Returns current time from the device.
|
||||
|
||||
@@ -232,7 +240,7 @@ class SmartDevice(object):
|
||||
return None
|
||||
|
||||
@time.setter
|
||||
def time(self, ts):
|
||||
def time(self, ts: datetime.datetime) -> None:
|
||||
"""
|
||||
Sets time based on datetime object.
|
||||
Note: this calls set_timezone() for setting.
|
||||
@@ -266,7 +274,7 @@ class SmartDevice(object):
|
||||
"""
|
||||
|
||||
@property
|
||||
def timezone(self):
|
||||
def timezone(self) -> Dict:
|
||||
"""
|
||||
Returns timezone information
|
||||
|
||||
@@ -277,7 +285,7 @@ class SmartDevice(object):
|
||||
return self._query_helper("time", "get_timezone")
|
||||
|
||||
@property
|
||||
def hw_info(self):
|
||||
def hw_info(self) -> Dict:
|
||||
"""
|
||||
Returns information about hardware
|
||||
|
||||
@@ -290,7 +298,7 @@ class SmartDevice(object):
|
||||
return {key: info[key] for key in keys if key in info}
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
def location(self) -> Dict:
|
||||
"""
|
||||
Location of the device, as read from sysinfo
|
||||
|
||||
@@ -313,17 +321,19 @@ class SmartDevice(object):
|
||||
return loc
|
||||
|
||||
@property
|
||||
def rssi(self):
|
||||
def rssi(self) -> Optional[int]:
|
||||
"""
|
||||
Returns WiFi signal strenth (rssi)
|
||||
|
||||
:return: rssi
|
||||
:rtype: int
|
||||
"""
|
||||
return self.sys_info["rssi"]
|
||||
if "rssi" in self.sys_info:
|
||||
return int(self.sys_info["rssi"])
|
||||
return None
|
||||
|
||||
@property
|
||||
def mac(self):
|
||||
def mac(self) -> str:
|
||||
"""
|
||||
Returns mac address
|
||||
|
||||
@@ -333,15 +343,15 @@ class SmartDevice(object):
|
||||
info = self.sys_info
|
||||
|
||||
if 'mac' in info:
|
||||
return info["mac"]
|
||||
return str(info["mac"])
|
||||
elif 'mic_mac' in info:
|
||||
return info['mic_mac']
|
||||
return str(info['mic_mac'])
|
||||
else:
|
||||
raise SmartDeviceException("Unknown mac, please submit a bug"
|
||||
"with sysinfo output.")
|
||||
|
||||
@mac.setter
|
||||
def mac(self, mac):
|
||||
def mac(self, mac: str) -> None:
|
||||
"""
|
||||
Sets new mac address
|
||||
|
||||
@@ -350,7 +360,7 @@ class SmartDevice(object):
|
||||
"""
|
||||
self._query_helper("system", "set_mac_addr", {"mac": mac})
|
||||
|
||||
def get_emeter_realtime(self):
|
||||
def get_emeter_realtime(self) -> Optional[Dict]:
|
||||
"""
|
||||
Retrive current energy readings from device.
|
||||
|
||||
@@ -364,7 +374,9 @@ class SmartDevice(object):
|
||||
|
||||
return self._query_helper(self.emeter_type, "get_realtime")
|
||||
|
||||
def get_emeter_daily(self, year=None, month=None):
|
||||
def get_emeter_daily(self,
|
||||
year: int = None,
|
||||
month: int = None) -> Optional[Dict]:
|
||||
"""
|
||||
Retrieve daily statistics for a given month
|
||||
|
||||
@@ -395,7 +407,7 @@ class SmartDevice(object):
|
||||
return {entry['day']: entry[key]
|
||||
for entry in response['day_list']}
|
||||
|
||||
def get_emeter_monthly(self, year=datetime.datetime.now().year):
|
||||
def get_emeter_monthly(self, year=None) -> Optional[Dict]:
|
||||
"""
|
||||
Retrieve monthly statistics for a given year.
|
||||
|
||||
@@ -408,6 +420,9 @@ class SmartDevice(object):
|
||||
if not self.has_emeter:
|
||||
return None
|
||||
|
||||
if year is None:
|
||||
year = datetime.datetime.now().year
|
||||
|
||||
response = self._query_helper(self.emeter_type, "get_monthstat",
|
||||
{'year': year})
|
||||
|
||||
@@ -419,7 +434,7 @@ class SmartDevice(object):
|
||||
return {entry['month']: entry[key]
|
||||
for entry in response['month_list']}
|
||||
|
||||
def erase_emeter_stats(self):
|
||||
def erase_emeter_stats(self) -> bool:
|
||||
"""
|
||||
Erase energy meter statistics
|
||||
|
||||
@@ -429,7 +444,7 @@ class SmartDevice(object):
|
||||
:raises SmartDeviceException: on error
|
||||
"""
|
||||
if not self.has_emeter:
|
||||
return None
|
||||
return False
|
||||
|
||||
self._query_helper(self.emeter_type, "erase_emeter_stat", None)
|
||||
|
||||
@@ -437,7 +452,7 @@ class SmartDevice(object):
|
||||
# succeeded when we are this far.
|
||||
return True
|
||||
|
||||
def current_consumption(self):
|
||||
def current_consumption(self) -> Optional[float]:
|
||||
"""
|
||||
Get the current power consumption in Watt.
|
||||
|
||||
@@ -450,18 +465,18 @@ class SmartDevice(object):
|
||||
|
||||
response = self.get_emeter_realtime()
|
||||
if self.emeter_units:
|
||||
return response['power_mw']
|
||||
return float(response['power_mw'])
|
||||
else:
|
||||
return response['power']
|
||||
return float(response['power'])
|
||||
|
||||
def turn_off(self):
|
||||
def turn_off(self) -> None:
|
||||
"""
|
||||
Turns the device off.
|
||||
"""
|
||||
raise NotImplementedError("Device subclass needs to implement this.")
|
||||
|
||||
@property
|
||||
def is_off(self):
|
||||
def is_off(self) -> bool:
|
||||
"""
|
||||
Returns whether device is off.
|
||||
|
||||
@@ -470,14 +485,14 @@ class SmartDevice(object):
|
||||
"""
|
||||
return not self.is_on
|
||||
|
||||
def turn_on(self):
|
||||
def turn_on(self) -> None:
|
||||
"""
|
||||
Turns the device on.
|
||||
"""
|
||||
raise NotImplementedError("Device subclass needs to implement this.")
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
def is_on(self) -> bool:
|
||||
"""
|
||||
Returns whether the device is on.
|
||||
|
||||
@@ -488,7 +503,7 @@ class SmartDevice(object):
|
||||
raise NotImplementedError("Device subclass needs to implement this.")
|
||||
|
||||
@property
|
||||
def state_information(self):
|
||||
def state_information(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Returns device-type specific, end-user friendly state information.
|
||||
:return: dict with state information.
|
||||
|
Reference in New Issue
Block a user