diff --git a/.coveragerc b/.coveragerc index ea9f302fbb1..c443b33cc4d 100644 --- a/.coveragerc +++ b/.coveragerc @@ -36,6 +36,9 @@ omit = homeassistant/components/rfxtrx.py homeassistant/components/*/rfxtrx.py + homeassistant/components/mysensors.py + homeassistant/components/*/mysensors.py + homeassistant/components/binary_sensor/arest.py homeassistant/components/binary_sensor/rest.py homeassistant/components/browser.py @@ -92,7 +95,6 @@ omit = homeassistant/components/sensor/eliqonline.py homeassistant/components/sensor/forecast.py homeassistant/components/sensor/glances.py - homeassistant/components/sensor/mysensors.py homeassistant/components/sensor/openweathermap.py homeassistant/components/sensor/rest.py homeassistant/components/sensor/rpi_gpio.py diff --git a/homeassistant/components/mysensors.py b/homeassistant/components/mysensors.py new file mode 100644 index 00000000000..7fb1a7cb1d7 --- /dev/null +++ b/homeassistant/components/mysensors.py @@ -0,0 +1,230 @@ +""" +homeassistant.components.mysensors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +MySensors component that connects to a MySensors gateway via pymysensors +API. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.mysensors.html + + +New features: + +New MySensors component. +Updated MySensors Sensor platform. +New MySensors Switch platform. Currently only in optimistic mode (compare +with MQTT). +Multiple gateways are now supported. + +Configuration.yaml: + +mysensors: + gateways: + - port: '/dev/ttyUSB0' + persistence_file: 'path/mysensors.json' + - port: '/dev/ttyACM1' + persistence_file: 'path/mysensors2.json' + debug: true + persistence: true + version: '1.5' +""" +import logging + +from homeassistant.helpers import validate_config +import homeassistant.bootstrap as bootstrap + +from homeassistant.const import ( + EVENT_HOMEASSISTANT_START, + EVENT_HOMEASSISTANT_STOP, + EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE, ATTR_DISCOVERED, + TEMP_CELCIUS,) + +CONF_GATEWAYS = 'gateways' +CONF_PORT = 'port' +CONF_DEBUG = 'debug' +CONF_PERSISTENCE = 'persistence' +CONF_PERSISTENCE_FILE = 'persistence_file' +CONF_VERSION = 'version' +DEFAULT_VERSION = '1.4' + +DOMAIN = 'mysensors' +DEPENDENCIES = [] +REQUIREMENTS = [ + 'https://github.com/theolind/pymysensors/archive/' + '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 + +DISCOVER_SENSORS = "mysensors.sensors" +DISCOVER_SWITCHES = "mysensors.switches" + +# Maps discovered services to their platforms +DISCOVERY_COMPONENTS = [ + ('sensor', DISCOVER_SENSORS), + ('switch', DISCOVER_SWITCHES), +] + + +def setup(hass, config): + """Setup the MySensors component.""" + # pylint: disable=too-many-locals + + if not validate_config(config, + {DOMAIN: [CONF_GATEWAYS]}, + _LOGGER): + return False + + 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 = 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.""" + gateway.start() + hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, + lambda event: gateway.stop()) + if persistence: + for node_id in gateway.sensors: + gateway.event_callback('persistence', node_id) + + hass.bus.listen_once(EVENT_HOMEASSISTANT_START, gw_start) + + return gateway + + # Setup all ports from config + global GATEWAYS + GATEWAYS = {} + conf_gateways = config[DOMAIN][CONF_GATEWAYS] + if isinstance(conf_gateways, dict): + conf_gateways = [conf_gateways] + persistence = config[DOMAIN].get(CONF_PERSISTENCE, True) + + for index, gway in enumerate(conf_gateways): + port = gway[CONF_PORT] + persistence_file = gway.get( + CONF_PERSISTENCE_FILE, + hass.config.path('mysensors{}.pickle'.format(index + 1))) + GATEWAYS[port] = setup_gateway( + port, persistence, persistence_file, version) + + for (component, discovery_service) in DISCOVERY_COMPONENTS: + # Ensure component is loaded + if not bootstrap.setup_component(hass, component, config): + return False + # Fire discovery event + hass.bus.fire(EVENT_PLATFORM_DISCOVERED, { + ATTR_SERVICE: discovery_service, + ATTR_DISCOVERED: {}}) + + return True + + +def pf_callback_factory( + s_types, v_types, devices, add_devices, entity_class): + """Return a new callback for the platform.""" + def mysensors_callback(gateway, node_id): + """Callback for mysensors platform.""" + if gateway.sensors[node_id].sketch_name is None: + _LOGGER.info('No sketch_name: node %s', node_id) + return + # previously discovered, just update state with latest info + if node_id in devices: + for entity in devices[node_id]: + entity.update_ha_state(True) + return + + # First time we see this node, detect sensors + for child in gateway.sensors[node_id].children.values(): + name = '{} {}.{}'.format( + gateway.sensors[node_id].sketch_name, node_id, child.id) + + for value_type in child.values.keys(): + if child.type not in s_types or value_type not in v_types: + continue + + devices[node_id].append( + entity_class(gateway, node_id, child.id, name, value_type)) + if devices[node_id]: + _LOGGER.info('adding new devices: %s', devices[node_id]) + add_devices(devices[node_id]) + for entity in devices[node_id]: + entity.update_ha_state(True) + return mysensors_callback + + +class GatewayWrapper(object): + """Gateway wrapper class, by subclassing serial gateway.""" + + def __init__(self, gateway, version): + """Setup class attributes on instantiation. + + Args: + 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. + """ + 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.""" + if self.version == '1.5': + import mysensors.const_15 as const + else: + import mysensors.const_14 as const + return const + + def callback_factory(self): + """Return a new callback function.""" + def node_update(update_type, node_id): + """Callback for node updates from the MySensors gateway.""" + _LOGGER.info('update %s: node %s', update_type, node_id) + for callback in self.platform_callbacks: + callback(self, node_id) + + return node_update diff --git a/homeassistant/components/sensor/__init__.py b/homeassistant/components/sensor/__init__.py index 9a6456857b8..88071c0b5fb 100644 --- a/homeassistant/components/sensor/__init__.py +++ b/homeassistant/components/sensor/__init__.py @@ -9,8 +9,8 @@ https://home-assistant.io/components/sensor/ import logging from homeassistant.helpers.entity_component import EntityComponent -from homeassistant.components import (wink, zwave, isy994, - verisure, ecobee, tellduslive) +from homeassistant.components import ( + wink, zwave, isy994, verisure, ecobee, tellduslive, mysensors) DOMAIN = 'sensor' SCAN_INTERVAL = 30 @@ -25,6 +25,7 @@ DISCOVERY_PLATFORMS = { verisure.DISCOVER_SENSORS: 'verisure', ecobee.DISCOVER_SENSORS: 'ecobee', tellduslive.DISCOVER_SENSORS: 'tellduslive', + mysensors.DISCOVER_SENSORS: 'mysensors', } diff --git a/homeassistant/components/sensor/mysensors.py b/homeassistant/components/sensor/mysensors.py index fb61173d8ee..3562af1949d 100644 --- a/homeassistant/components/sensor/mysensors.py +++ b/homeassistant/components/sensor/mysensors.py @@ -7,150 +7,177 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.mysensors/ """ import logging +from collections import defaultdict from homeassistant.helpers.entity import Entity from homeassistant.const import ( - ATTR_BATTERY_LEVEL, EVENT_HOMEASSISTANT_STOP, + ATTR_BATTERY_LEVEL, TEMP_CELCIUS, TEMP_FAHRENHEIT, STATE_ON, STATE_OFF) -CONF_PORT = "port" -CONF_DEBUG = "debug" -CONF_PERSISTENCE = "persistence" -CONF_PERSISTENCE_FILE = "persistence_file" -CONF_VERSION = "version" - -ATTR_NODE_ID = "node_id" -ATTR_CHILD_ID = "child_id" +import homeassistant.components.mysensors as mysensors _LOGGER = logging.getLogger(__name__) -REQUIREMENTS = ['https://github.com/theolind/pymysensors/archive/' - 'd4b809c2167650691058d1e29bfd2c4b1792b4b0.zip' - '#pymysensors==0.3'] +DEPENDENCIES = [] def setup_platform(hass, config, add_devices, discovery_info=None): - """ Setup the mysensors platform. """ + """Setup the mysensors platform for sensors.""" + # Only act if loaded via mysensors by discovery event. + # Otherwise gateway is not setup. + if discovery_info is None: + return - import mysensors.mysensors as mysensors - import mysensors.const_14 as const + for gateway in mysensors.GATEWAYS.values(): + # Define the S_TYPES and V_TYPES that the platform should handle as + # states. + s_types = [ + gateway.const.Presentation.S_TEMP, + gateway.const.Presentation.S_HUM, + gateway.const.Presentation.S_BARO, + gateway.const.Presentation.S_WIND, + gateway.const.Presentation.S_RAIN, + gateway.const.Presentation.S_UV, + gateway.const.Presentation.S_WEIGHT, + gateway.const.Presentation.S_POWER, + gateway.const.Presentation.S_DISTANCE, + gateway.const.Presentation.S_LIGHT_LEVEL, + gateway.const.Presentation.S_IR, + gateway.const.Presentation.S_WATER, + gateway.const.Presentation.S_AIR_QUALITY, + gateway.const.Presentation.S_CUSTOM, + gateway.const.Presentation.S_DUST, + gateway.const.Presentation.S_SCENE_CONTROLLER, + ] + not_v_types = [ + gateway.const.SetReq.V_ARMED, + gateway.const.SetReq.V_LIGHT, + gateway.const.SetReq.V_LOCK_STATUS, + ] + if float(gateway.version) >= 1.5: + s_types.extend([ + gateway.const.Presentation.S_COLOR_SENSOR, + gateway.const.Presentation.S_MULTIMETER, + ]) + not_v_types.extend([gateway.const.SetReq.V_STATUS, ]) + v_types = [member for member in gateway.const.SetReq + if member.value not in not_v_types] - devices = {} # keep track of devices added to HA - # Just assume celcius means that the user wants metric for now. - # It may make more sense to make this a global config option in the future. - is_metric = (hass.config.temperature_unit == TEMP_CELCIUS) - - def sensor_update(update_type, nid): - """ Callback for sensor updates from the MySensors gateway. """ - _LOGGER.info("sensor_update %s: node %s", update_type, nid) - sensor = gateway.sensors[nid] - if sensor.sketch_name is None: - return - if nid not in devices: - devices[nid] = {} - - node = devices[nid] - new_devices = [] - for child_id, child in sensor.children.items(): - if child_id not in node: - node[child_id] = {} - for value_type, value in child.values.items(): - if value_type not in node[child_id]: - name = '{} {}.{}'.format(sensor.sketch_name, nid, child.id) - node[child_id][value_type] = \ - MySensorsNodeValue( - nid, child_id, name, value_type, is_metric, const) - new_devices.append(node[child_id][value_type]) - else: - node[child_id][value_type].update_sensor( - value, sensor.battery_level) - - if new_devices: - _LOGGER.info("adding new devices: %s", new_devices) - add_devices(new_devices) - - port = config.get(CONF_PORT) - if port is None: - _LOGGER.error("Missing required key 'port'") - return False - - persistence = config.get(CONF_PERSISTENCE, True) - persistence_file = config.get(CONF_PERSISTENCE_FILE, - hass.config.path('mysensors.pickle')) - version = config.get(CONF_VERSION, '1.4') - - gateway = mysensors.SerialGateway(port, sensor_update, - persistence=persistence, - persistence_file=persistence_file, - protocol_version=version) - gateway.metric = is_metric - gateway.debug = config.get(CONF_DEBUG, False) - gateway.start() - - if persistence: - for nid in gateway.sensors: - sensor_update('sensor_update', nid) - - hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, - lambda event: gateway.stop()) + devices = defaultdict(list) + gateway.platform_callbacks.append(mysensors.pf_callback_factory( + s_types, v_types, devices, add_devices, MySensorsSensor)) -class MySensorsNodeValue(Entity): - """ Represents the value of a MySensors child node. """ - # pylint: disable=too-many-arguments, too-many-instance-attributes - def __init__(self, node_id, child_id, name, value_type, metric, const): - self._name = name +class MySensorsSensor(Entity): + """Represent the value of a MySensors child node.""" + + # pylint: disable=too-many-arguments + + def __init__(self, gateway, node_id, child_id, name, value_type): + """Setup class attributes on instantiation. + + Args: + 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 (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. + battery_level (int): Node battery level. + _values (dict): Child values. Non state values set as state attributes. + """ + self.gateway = gateway self.node_id = node_id self.child_id = child_id - self.battery_level = 0 + self._name = name self.value_type = value_type - self.metric = metric - self._value = '' - self.const = const + self.battery_level = 0 + self._values = {} @property def should_poll(self): - """ MySensor gateway pushes its state to HA. """ + """MySensor gateway pushes its state to HA.""" return False @property def name(self): - """ The name of this sensor. """ + """The name of this entity.""" return self._name @property def state(self): - """ Returns the state of the device. """ - return self._value + """Return the state of the device.""" + if not self._values: + return '' + return self._values[self.value_type] @property def unit_of_measurement(self): - """ Unit of measurement of this entity. """ - if self.value_type == self.const.SetReq.V_TEMP: - return TEMP_CELCIUS if self.metric else TEMP_FAHRENHEIT - elif self.value_type == self.const.SetReq.V_HUM or \ - self.value_type == self.const.SetReq.V_DIMMER or \ - self.value_type == self.const.SetReq.V_LIGHT_LEVEL: + """Unit of measurement of this entity.""" + # pylint:disable=too-many-return-statements + if self.value_type == self.gateway.const.SetReq.V_TEMP: + return TEMP_CELCIUS if self.gateway.metric else TEMP_FAHRENHEIT + elif self.value_type == self.gateway.const.SetReq.V_HUM or \ + self.value_type == self.gateway.const.SetReq.V_DIMMER or \ + self.value_type == self.gateway.const.SetReq.V_PERCENTAGE or \ + self.value_type == self.gateway.const.SetReq.V_LIGHT_LEVEL: return '%' + elif self.value_type == self.gateway.const.SetReq.V_WATT: + return 'W' + elif self.value_type == self.gateway.const.SetReq.V_KWH: + return 'kWh' + elif self.value_type == self.gateway.const.SetReq.V_VOLTAGE: + return 'V' + elif self.value_type == self.gateway.const.SetReq.V_CURRENT: + return 'A' + elif self.value_type == self.gateway.const.SetReq.V_IMPEDANCE: + return 'ohm' + elif self.gateway.const.SetReq.V_UNIT_PREFIX in self._values: + return self._values[self.gateway.const.SetReq.V_UNIT_PREFIX] return None + @property + def device_state_attributes(self): + """Return device specific state attributes.""" + device_attr = dict(self._values) + device_attr.pop(self.value_type, None) + return device_attr + @property def state_attributes(self): - """ Returns the state attributes. """ - return { - ATTR_NODE_ID: self.node_id, - ATTR_CHILD_ID: self.child_id, + """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, } - def update_sensor(self, value, battery_level): - """ Update a sensor with the latest value from the controller. """ - _LOGGER.info("%s value = %s", self._name, value) - if self.value_type == self.const.SetReq.V_TRIPPED or \ - self.value_type == self.const.SetReq.V_ARMED: - self._value = STATE_ON if int(value) == 1 else STATE_OFF - else: - self._value = value - self.battery_level = battery_level - self.update_ha_state() + device_attr = self.device_state_attributes + + if device_attr is not None: + data.update(device_attr) + + return data + + def update(self): + """Update the controller with the latest values from a sensor.""" + node = self.gateway.sensors[self.node_id] + child = node.children[self.child_id] + for value_type, value in child.values.items(): + _LOGGER.info( + "%s: value_type %s, value = %s", self._name, value_type, value) + if value_type == self.gateway.const.SetReq.V_TRIPPED: + self._values[value_type] = STATE_ON if int( + value) == 1 else STATE_OFF + else: + self._values[value_type] = value + + self.battery_level = node.battery_level diff --git a/homeassistant/components/switch/__init__.py b/homeassistant/components/switch/__init__.py index e2fbb256fb5..a05a673c3dd 100644 --- a/homeassistant/components/switch/__init__.py +++ b/homeassistant/components/switch/__init__.py @@ -17,7 +17,7 @@ from homeassistant.helpers.entity import ToggleEntity from homeassistant.const import ( STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID) from homeassistant.components import ( - group, discovery, wink, isy994, verisure, zwave, tellduslive) + group, discovery, wink, isy994, verisure, zwave, tellduslive, mysensors) DOMAIN = 'switch' SCAN_INTERVAL = 30 @@ -41,6 +41,7 @@ DISCOVERY_PLATFORMS = { verisure.DISCOVER_SWITCHES: 'verisure', zwave.DISCOVER_SWITCHES: 'zwave', tellduslive.DISCOVER_SWITCHES: 'tellduslive', + mysensors.DISCOVER_SWITCHES: 'mysensors', } PROP_TO_ATTR = { diff --git a/homeassistant/components/switch/mysensors.py b/homeassistant/components/switch/mysensors.py new file mode 100644 index 00000000000..d8d7d4d2473 --- /dev/null +++ b/homeassistant/components/switch/mysensors.py @@ -0,0 +1,164 @@ +""" +homeassistant.components.switch.mysensors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Support for MySensors switches. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.mysensors.html +""" +import logging +from collections import defaultdict + +from homeassistant.components.switch import SwitchDevice + +from homeassistant.const import ( + ATTR_BATTERY_LEVEL, + STATE_ON, STATE_OFF) + +import homeassistant.components.mysensors as mysensors + +_LOGGER = logging.getLogger(__name__) +DEPENDENCIES = [] + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the mysensors platform for switches.""" + # Only act if loaded via mysensors by discovery event. + # Otherwise gateway is not setup. + if discovery_info is None: + return + + for gateway in mysensors.GATEWAYS.values(): + # Define the S_TYPES and V_TYPES that the platform should handle as + # states. + s_types = [ + gateway.const.Presentation.S_DOOR, + gateway.const.Presentation.S_MOTION, + gateway.const.Presentation.S_SMOKE, + gateway.const.Presentation.S_LIGHT, + gateway.const.Presentation.S_LOCK, + ] + v_types = [ + gateway.const.SetReq.V_ARMED, + gateway.const.SetReq.V_LIGHT, + gateway.const.SetReq.V_LOCK_STATUS, + ] + 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, + gateway.const.Presentation.S_VIBRATION, + gateway.const.Presentation.S_MOISTURE, + ]) + v_types.extend([gateway.const.SetReq.V_STATUS, ]) + + devices = defaultdict(list) + gateway.platform_callbacks.append(mysensors.pf_callback_factory( + s_types, v_types, devices, add_devices, MySensorsSwitch)) + + +class MySensorsSwitch(SwitchDevice): + """Represent the value of a MySensors child node.""" + + # pylint: disable=too-many-arguments + + def __init__(self, gateway, node_id, child_id, name, value_type): + """Setup class attributes on instantiation. + + Args: + 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 (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. + battery_level (int): Node battery level. + _values (dict): Child values. Non state values set as state attributes. + """ + self.gateway = gateway + self.node_id = node_id + self.child_id = child_id + self._name = name + self.value_type = value_type + self.battery_level = 0 + self._values = {} + + @property + def should_poll(self): + """MySensor gateway pushes its state to HA.""" + return False + + @property + def name(self): + """The name of this entity.""" + return self._name + + @property + def device_state_attributes(self): + """Return device specific state attributes.""" + device_attr = dict(self._values) + device_attr.pop(self.value_type, None) + return device_attr + + @property + 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, + } + + device_attr = self.device_state_attributes + + if device_attr is not None: + data.update(device_attr) + + return data + + @property + def is_on(self): + """Return True if switch is on.""" + if self.value_type in self._values: + return self._values[self.value_type] == STATE_ON + return False + + def turn_on(self): + """Turn the switch on.""" + self.gateway.set_child_value( + self.node_id, self.child_id, self.value_type, 1) + self._values[self.value_type] = STATE_ON + self.update_ha_state() + + def turn_off(self): + """Turn the switch off.""" + self.gateway.set_child_value( + self.node_id, self.child_id, self.value_type, 0) + self._values[self.value_type] = STATE_OFF + self.update_ha_state() + + def update(self): + """Update the controller with the latest value from a sensor.""" + node = self.gateway.sensors[self.node_id] + child = node.children[self.child_id] + for value_type, value in child.values.items(): + _LOGGER.info( + "%s: value_type %s, value = %s", self._name, value_type, value) + if value_type == self.gateway.const.SetReq.V_ARMED or \ + value_type == self.gateway.const.SetReq.V_STATUS or \ + value_type == self.gateway.const.SetReq.V_LIGHT or \ + value_type == self.gateway.const.SetReq.V_LOCK_STATUS: + self._values[value_type] = ( + STATE_ON if int(value) == 1 else STATE_OFF) + else: + self._values[value_type] = value + self.battery_level = node.battery_level diff --git a/requirements_all.txt b/requirements_all.txt index f320408f138..356c751a40f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -89,6 +89,9 @@ https://github.com/bashwork/pymodbus/archive/d7fc4f1cc975631e0a9011390e8017f64b6 # homeassistant.components.mqtt paho-mqtt==1.1 +# homeassistant.components.mysensors +https://github.com/theolind/pymysensors/archive/005bff4c5ca7a56acd30e816bc3bcdb5cb2d46fd.zip#pymysensors==0.4 + # homeassistant.components.notify.pushbullet pushbullet.py==0.9.0 @@ -131,9 +134,6 @@ eliqonline==1.0.11 # homeassistant.components.sensor.forecast python-forecastio==1.3.3 -# homeassistant.components.sensor.mysensors -https://github.com/theolind/pymysensors/archive/d4b809c2167650691058d1e29bfd2c4b1792b4b0.zip#pymysensors==0.3 - # homeassistant.components.sensor.openweathermap pyowm==2.3.0