From 2d8cf7de447cf4a3fc8b0df65c0ba34066e287f3 Mon Sep 17 00:00:00 2001 From: MartinHjelmare Date: Sun, 10 Jan 2016 04:10:38 +0100 Subject: [PATCH] Fix wrapper and S_BINARY and bump req. version * Wrap existing SerialGateway instance instead of subclassing SerialGatewat class. * Add S_BINARY in switch platform only in version 1.5 of mysenors api. * Use version 0.4 of pymysensors. * Show gateway port as state attribute. --- homeassistant/components/mysensors.py | 62 ++++++++++++-------- homeassistant/components/sensor/mysensors.py | 5 +- homeassistant/components/switch/mysensors.py | 7 ++- requirements_all.txt | 2 +- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/homeassistant/components/mysensors.py b/homeassistant/components/mysensors.py index a0601850fa7..7fb1a7cb1d7 100644 --- a/homeassistant/components/mysensors.py +++ b/homeassistant/components/mysensors.py @@ -12,7 +12,8 @@ New features: New MySensors component. Updated MySensors Sensor platform. -New MySensors Switch platform. +New MySensors Switch platform. Currently only in optimistic mode (compare +with MQTT). Multiple gateways are now supported. Configuration.yaml: @@ -29,11 +30,6 @@ mysensors: """ import logging -try: - import mysensors.mysensors as mysensors -except ImportError: - mysensors = None - from homeassistant.helpers import validate_config import homeassistant.bootstrap as bootstrap @@ -55,10 +51,11 @@ DOMAIN = 'mysensors' DEPENDENCIES = [] REQUIREMENTS = [ 'https://github.com/theolind/pymysensors/archive/' - '2aa8f32908e8c5bb3e5c77c5851db778f8635792.zip#pymysensors==0.3'] + '005bff4c5ca7a56acd30e816bc3bcdb5cb2d46fd.zip#pymysensors==0.4'] _LOGGER = logging.getLogger(__name__) ATTR_NODE_ID = 'node_id' ATTR_CHILD_ID = 'child_id' +ATTR_PORT = 'port' GATEWAYS = None SCAN_INTERVAL = 30 @@ -82,21 +79,22 @@ def setup(hass, config): _LOGGER): return False - global mysensors # pylint: disable=invalid-name - if mysensors is None: - import mysensors.mysensors as _mysensors - mysensors = _mysensors + import mysensors.mysensors as mysensors version = str(config[DOMAIN].get(CONF_VERSION, DEFAULT_VERSION)) is_metric = (hass.config.temperature_unit == TEMP_CELCIUS) def setup_gateway(port, persistence, persistence_file, version): """Return gateway after setup of the gateway.""" - gateway = GatewayWrapper( - port, persistence, persistence_file, version) - # pylint: disable=attribute-defined-outside-init + gateway = mysensors.SerialGateway(port, event_callback=None, + persistence=persistence, + persistence_file=persistence_file, + protocol_version=version) gateway.metric = is_metric gateway.debug = config[DOMAIN].get(CONF_DEBUG, False) + gateway = GatewayWrapper(gateway, version) + # pylint: disable=attribute-defined-outside-init + gateway.event_callback = gateway.callback_factory() def gw_start(event): """Callback to trigger start of gateway and any persistence.""" @@ -172,30 +170,46 @@ def pf_callback_factory( return mysensors_callback -class GatewayWrapper(mysensors.SerialGateway): +class GatewayWrapper(object): """Gateway wrapper class, by subclassing serial gateway.""" - def __init__(self, port, persistence, persistence_file, version): + def __init__(self, gateway, version): """Setup class attributes on instantiation. Args: - port: Port of gateway to wrap. - persistence: Persistence, true or false. - persistence_file: File to store persistence info. - version: Version of mysensors API. + gateway (mysensors.SerialGateway): Gateway to wrap. + version (str): Version of mysensors API. Attributes: + _wrapped_gateway (mysensors.SerialGateway): Wrapped gateway. version (str): Version of mysensors API. platform_callbacks (list): Callback functions, one per platform. const (module): Mysensors API constants. + __initialised (bool): True if GatewayWrapper is initialised. """ - super().__init__(port, event_callback=self.callback_factory(), - persistence=persistence, - persistence_file=persistence_file, - protocol_version=version) + self._wrapped_gateway = gateway self.version = version self.platform_callbacks = [] self.const = self.get_const() + self.__initialised = True + + def __getattr__(self, name): + """See if this object has attribute name.""" + # Do not use hasattr, it goes into infinite recurrsion + if name in self.__dict__: + # this object has it + return getattr(self, name) + # proxy to the wrapped object + return getattr(self._wrapped_gateway, name) + + def __setattr__(self, name, value): + """See if this object has attribute name then set to value.""" + if '_GatewayWrapper__initialised' not in self.__dict__: + return object.__setattr__(self, name, value) + elif name in self.__dict__: + object.__setattr__(self, name, value) + else: + object.__setattr__(self._wrapped_gateway, name, value) def get_const(self): """Get mysensors API constants.""" diff --git a/homeassistant/components/sensor/mysensors.py b/homeassistant/components/sensor/mysensors.py index 3944cf4f982..3562af1949d 100644 --- a/homeassistant/components/sensor/mysensors.py +++ b/homeassistant/components/sensor/mysensors.py @@ -78,14 +78,14 @@ class MySensorsSensor(Entity): """Setup class attributes on instantiation. Args: - gateway (str): Gateway. + gateway (GatewayWrapper): Gateway object. node_id (str): Id of node. child_id (str): Id of child. name (str): Entity name. value_type (str): Value type of child. Value is entity state. Attributes: - gateway (str): Gateway. + gateway (GatewayWrapper): Gateway object. node_id (str): Id of node. child_id (str): Id of child. _name (str): Entity name. @@ -154,6 +154,7 @@ class MySensorsSensor(Entity): def state_attributes(self): """Return the state attributes.""" data = { + mysensors.ATTR_PORT: self.gateway.port, mysensors.ATTR_NODE_ID: self.node_id, mysensors.ATTR_CHILD_ID: self.child_id, ATTR_BATTERY_LEVEL: self.battery_level, diff --git a/homeassistant/components/switch/mysensors.py b/homeassistant/components/switch/mysensors.py index 33c214cda76..d8d7d4d2473 100644 --- a/homeassistant/components/switch/mysensors.py +++ b/homeassistant/components/switch/mysensors.py @@ -36,7 +36,6 @@ def setup_platform(hass, config, add_devices, discovery_info=None): gateway.const.Presentation.S_MOTION, gateway.const.Presentation.S_SMOKE, gateway.const.Presentation.S_LIGHT, - gateway.const.Presentation.S_BINARY, gateway.const.Presentation.S_LOCK, ] v_types = [ @@ -46,6 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ] if float(gateway.version) >= 1.5: s_types.extend([ + gateway.const.Presentation.S_BINARY, gateway.const.Presentation.S_SPRINKLER, gateway.const.Presentation.S_WATER_LEAK, gateway.const.Presentation.S_SOUND, @@ -68,14 +68,14 @@ class MySensorsSwitch(SwitchDevice): """Setup class attributes on instantiation. Args: - port (str): Gateway port. + gateway (GatewayWrapper): Gateway object. node_id (str): Id of node. child_id (str): Id of child. name (str): Entity name. value_type (str): Value type of child. Value is entity state. Attributes: - port (str): Gateway port. + gateway (GatewayWrapper): Gateway object node_id (str): Id of node. child_id (str): Id of child. _name (str): Entity name. @@ -112,6 +112,7 @@ class MySensorsSwitch(SwitchDevice): def state_attributes(self): """Return the state attributes.""" data = { + mysensors.ATTR_PORT: self.gateway.port, mysensors.ATTR_NODE_ID: self.node_id, mysensors.ATTR_CHILD_ID: self.child_id, ATTR_BATTERY_LEVEL: self.battery_level, diff --git a/requirements_all.txt b/requirements_all.txt index e8709c789e3..9bfdd3b62f5 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -90,7 +90,7 @@ https://github.com/bashwork/pymodbus/archive/d7fc4f1cc975631e0a9011390e8017f64b6 paho-mqtt==1.1 # homeassistant.components.mysensors -https://github.com/theolind/pymysensors/archive/2aa8f32908e8c5bb3e5c77c5851db778f8635792.zip#pymysensors==0.3 +https://github.com/theolind/pymysensors/archive/005bff4c5ca7a56acd30e816bc3bcdb5cb2d46fd.zip#pymysensors==0.4 # homeassistant.components.notify.pushbullet pushbullet.py==0.9.0