Source code for fauxmo.plugins

"""fauxmo.plugins :: Provide ABC for Fauxmo plugins."""

import abc
from typing import Callable


[docs]class FauxmoPlugin(abc.ABC): """Provide ABC for Fauxmo plugins. This will become the `plugin` attribute of a `Fauxmo` instance. Its `on` and `off` methods will be called when Alexa turns something `on` or `off`. All keys (other than the list of `DEVICES`) from the config will be passed into FauxmoPlugin as kwargs at initialization, which should let users do some interesting things. However, that means users employing custom config keys will need to override `__init__` and either set the `name` and "private" `_port` attributes manually or pass the appropriate args to `super().__init__()`. """
[docs] def __init__(self, *, name: str, port: int) -> None: """Initialize FauxmoPlugin. Keyword Args: name: Required, device name port: Required, port that the Fauxmo associated with this plugin should run on Note about `port`: if not given in config, it will be set to an apparently free port in `fauxmo.fauxmo` before FauxmoPlugin initialization. This attribute serves no default purpose in the FauxmoPlugin but is passed in to be accessible by user code (i.e. for logging / debugging). Alternatively, one could accept and throw away the passed in `port` value and generate their own port in a plugin, since the Fauxmo device determines its port from the plugin's instance attribute. The `_latest_action` attribute stores the most recent successful action, which is set by the `__getattribute__` hackery for successful `.on()` and `.off()` commands. """ self._name = name self._port = port self._latest_action = "off"
def __getattribute__(self, name: str) -> Callable: """Intercept `.on()` and `.off()` to set `_latest_action` attribute.""" if name in ["on", "off"]: success = object.__getattribute__(self, name)() if success is True: self._latest_action = name return lambda: success else: return object.__getattribute__(self, name) @property def port(self) -> int: """Return port attribute in read-only manner.""" return self._port @property def name(self) -> str: """Return name attribute in read-only manner.""" return self._name
[docs] @abc.abstractmethod def on(self) -> bool: """Run function when Alexa turns this Fauxmo device on.""" pass
[docs] @abc.abstractmethod def off(self) -> bool: """Run function when Alexa turns this Fauxmo device off.""" pass
[docs] @abc.abstractmethod def get_state(self) -> str: """Run function when Alexa requests device state. Should return "on" or "off" if it can be determined, or "unknown" if there is no mechanism for determining the device state, in which case Alexa will complain that the device is not responding. If state cannot be determined, a plugin can opt into this implementation, which falls back on the `_latest_action` attribute. It is intentionally left as an abstract method so that plugins cannot omit a `get_state` method completely, which could lead to unexpected behavior; instead, they should explicitly `return super().get_state()`. """ return self.latest_action
[docs] def close(self) -> None: """Run when shutting down; allows plugin to clean up state.""" pass
@property def latest_action(self) -> str: """Return latest action in read-only manner. Must be a function instead of e.g. property because it overrides `get_state`, and therefore must be callable. """ return self._latest_action