diff --git a/amazon_dash/config.py b/amazon_dash/config.py index 1fbcf95..596979a 100644 --- a/amazon_dash/config.py +++ b/amazon_dash/config.py @@ -6,6 +6,7 @@ from jsonschema import validate, ValidationError +from amazon_dash.device import Device from then.configs.base import LoadConfig from then.configs.components import LoadComponentConfigs from then.configs.templates import LoadTemplates @@ -236,7 +237,10 @@ def read(self): """ then = Then(LoadComponentConfigs(self.file, section='actions')) self.templates = then.templates(LoadTemplates(self.file)) - self.devices = LoadConfig(self.file, 'devices') + devices = LoadConfig(self.file, 'devices') + devices = {device['mac']: device for device in devices.data} if isinstance(devices.data, list) else devices + devices = {key: Device(key, value.get('name'), value.get('actions', [])) for key, value in devices.items()} + self.devices = devices pass # try: # data = load(open(self.file), Loader) diff --git a/amazon_dash/device.py b/amazon_dash/device.py new file mode 100644 index 0000000..6a1835f --- /dev/null +++ b/amazon_dash/device.py @@ -0,0 +1,71 @@ +from amazon_dash.confirmations import get_confirmation +from amazon_dash.exceptions import InvalidConfig +from amazon_dash.execute import ExecuteCmd, ExecuteUrl, ExecuteHomeAssistant, ExecuteOpenHab, ExecuteIFTTT, logger + +EXECUTE_CLS = { + 'cmd': ExecuteCmd, + 'url': ExecuteUrl, + 'homeassistant': ExecuteHomeAssistant, + 'openhab': ExecuteOpenHab, + 'ifttt': ExecuteIFTTT, +} + + +class Device(object): + """Set the execution method for the device + """ + execute_instance = None #: Execute cls instance + + def __init__(self, src, name, actions, config=None): + """ + + :param str src: Mac address + :param data: device data + """ + config = config or {} + + if isinstance(src, Device): + src = src.src + self.src = src.lower() + self.name = name or self.src + self.actions = actions + self.config = config + + def execute(self, root_allowed=False): + """Execute this device + + :param bool root_allowed: Only used for ExecuteCmd + :return: None + """ + logger.debug('%s device executed (mac %s)', self.name, self.src) + if not self.execute_instance: + msg = '%s: There is not execution method in device conf.' + logger.warning(msg, self.name) + self.send_confirmation(msg % self.name, False) + return + try: + result = self.execute_instance.execute(root_allowed) + except Exception as e: + self.send_confirmation('Error executing the device {}: {}'.format(self.name, e), False) + raise + else: + result = 'The {} device has been started and is running right now'.format(self.name) \ + if result is None else result + result = result or 'The {} device has been executed successfully'.format(self.name) + self.send_confirmation(result) + return result + + def send_confirmation(self, message, success=True): + """Send success or error message to configured confirmation + + :param str message: Body message to send + :param bool success: Device executed successfully to personalize message + :return: None + """ + message = message.strip() + if not self.confirmation: + return + try: + self.confirmation.send(message, success) + except Exception as e: + logger.warning('Error sending confirmation on device {}: {}'.format(self.name, e)) diff --git a/amazon_dash/listener.py b/amazon_dash/listener.py index 7867dcb..2d47f7f 100644 --- a/amazon_dash/listener.py +++ b/amazon_dash/listener.py @@ -4,9 +4,9 @@ import threading from amazon_dash.config import Config -from amazon_dash.confirmations import get_confirmation -from amazon_dash.exceptions import InvalidConfig, InvalidDevice -from amazon_dash.execute import logger, ExecuteCmd, ExecuteUrl, ExecuteHomeAssistant, ExecuteOpenHab, ExecuteIFTTT +from amazon_dash.device import Device +from amazon_dash.exceptions import InvalidDevice +from amazon_dash.execute import logger from amazon_dash.scan import scan_devices DEFAULT_DELAY = 10 @@ -14,13 +14,6 @@ On seconds. By default, 10 seconds. Minimum time that must pass between pulsations of the Amazon Dash button. """ -EXECUTE_CLS = { - 'cmd': ExecuteCmd, - 'url': ExecuteUrl, - 'homeassistant': ExecuteHomeAssistant, - 'openhab': ExecuteOpenHab, - 'ifttt': ExecuteIFTTT, -} """ Execute classes registered. """ @@ -31,83 +24,6 @@ """ -class Device(object): - """Set the execution method for the device - """ - execute_instance = None #: Execute cls instance - - def __init__(self, src, data=None, config=None): - """ - - :param str src: Mac address - :param data: device data - """ - data = data or {} - config = config or {} - - if isinstance(src, Device): - src = src.src - self.src = src.lower() - self.data = data - execs = [cls(self.name, data) for name, cls in EXECUTE_CLS.items() if name in self.data] - if len(execs) > 1: - raise InvalidConfig( - extra_body='There can only be one method of execution on a device. The device is {}. '.format(self.name) - ) - elif len(execs): - self.execute_instance = execs[0] - self.execute_instance.validate() - self.confirmation = get_confirmation(src, data, config.get('confirmations', {})) - - @property - def name(self): - """Name on self.data or mac address - - :return: name - :rtype: str - """ - return self.data.get('name', self.src) - - def execute(self, root_allowed=False): - """Execute this device - - :param bool root_allowed: Only used for ExecuteCmd - :return: None - """ - logger.debug('%s device executed (mac %s)', self.name, self.src) - if not self.execute_instance: - msg = '%s: There is not execution method in device conf.' - logger.warning(msg, self.name) - self.send_confirmation(msg % self.name, False) - return - try: - result = self.execute_instance.execute(root_allowed) - except Exception as e: - self.send_confirmation('Error executing the device {}: {}'.format(self.name, e), False) - raise - else: - result = 'The {} device has been started and is running right now'.format(self.name) \ - if result is None else result - result = result or 'The {} device has been executed successfully'.format(self.name) - self.send_confirmation(result) - return result - - def send_confirmation(self, message, success=True): - """Send success or error message to configured confirmation - - :param str message: Body message to send - :param bool success: Device executed successfully to personalize message - :return: None - """ - message = message.strip() - if not self.confirmation: - return - try: - self.confirmation.send(message, success) - except Exception as e: - logger.warning('Error sending confirmation on device {}: {}'.format(self.name, e)) - - class Listener(object): """Start listener daemon for execute on button press """ diff --git a/amazon_dash/tests/test_discovery.py b/amazon_dash/tests/test_discovery.py index 9647b11..51c4f12 100644 --- a/amazon_dash/tests/test_discovery.py +++ b/amazon_dash/tests/test_discovery.py @@ -4,7 +4,7 @@ from ._compat import patch from amazon_dash.discovery import BANNED_DEVICES, pkt_text, AMAZON_DEVICES, mac_id_list, discovery_print -from amazon_dash.listener import Device +from amazon_dash.device import Device class TestDiscovery(unittest.TestCase): diff --git a/amazon_dash/tests/test_listener.py b/amazon_dash/tests/test_listener.py index ab491be..9af17f8 100644 --- a/amazon_dash/tests/test_listener.py +++ b/amazon_dash/tests/test_listener.py @@ -7,7 +7,8 @@ from amazon_dash.confirmations import DisabledConfirmation from amazon_dash.execute import ExecuteCmd from amazon_dash.exceptions import InvalidConfig, InvalidDevice -from amazon_dash.listener import Listener, Device, last_execution, logger, test_device +from amazon_dash.listener import Listener, last_execution, logger, test_device +from amazon_dash.device import Device from amazon_dash.tests.base import ConfigFileMockBase, ExecuteMockBase dirname = os.path.abspath(os.path.dirname(__file__))