Merge pull request #1110 from lukas-hetzenecker/feature-zwave-poll-and-scene

Z-Wave: Scene activation & Polling
This commit is contained in:
Paulus Schoutsen 2016-02-04 20:51:52 -08:00
commit 1a6539ad41

View File

@ -10,12 +10,12 @@ import sys
import os.path import os.path
from pprint import pprint from pprint import pprint
from homeassistant.util import slugify from homeassistant.util import slugify, convert
from homeassistant import bootstrap from homeassistant import bootstrap
from homeassistant.const import ( from homeassistant.const import (
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE, ATTR_DISCOVERED, EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE, ATTR_DISCOVERED,
ATTR_BATTERY_LEVEL, ATTR_LOCATION) ATTR_BATTERY_LEVEL, ATTR_LOCATION, ATTR_ENTITY_ID, CONF_CUSTOMIZE)
DOMAIN = "zwave" DOMAIN = "zwave"
@ -25,6 +25,7 @@ CONF_USB_STICK_PATH = "usb_path"
DEFAULT_CONF_USB_STICK_PATH = "/zwaveusbstick" DEFAULT_CONF_USB_STICK_PATH = "/zwaveusbstick"
CONF_DEBUG = "debug" CONF_DEBUG = "debug"
CONF_POLLING_INTERVAL = "polling_interval" CONF_POLLING_INTERVAL = "polling_interval"
CONF_POLLING_INTENSITY = "polling_intensity"
DEFAULT_ZWAVE_CONFIG_PATH = os.path.join(sys.prefix, 'share', DEFAULT_ZWAVE_CONFIG_PATH = os.path.join(sys.prefix, 'share',
'python-openzwave', 'config') 'python-openzwave', 'config')
@ -35,6 +36,8 @@ DISCOVER_SENSORS = "zwave.sensors"
DISCOVER_SWITCHES = "zwave.switch" DISCOVER_SWITCHES = "zwave.switch"
DISCOVER_LIGHTS = "zwave.light" DISCOVER_LIGHTS = "zwave.light"
EVENT_SCENE_ACTIVATED = "zwave.scene_activated"
COMMAND_CLASS_SWITCH_MULTILEVEL = 38 COMMAND_CLASS_SWITCH_MULTILEVEL = 38
COMMAND_CLASS_SWITCH_BINARY = 37 COMMAND_CLASS_SWITCH_BINARY = 37
@ -78,6 +81,8 @@ DISCOVERY_COMPONENTS = [
ATTR_NODE_ID = "node_id" ATTR_NODE_ID = "node_id"
ATTR_VALUE_ID = "value_id" ATTR_VALUE_ID = "value_id"
ATTR_SCENE_ID = "scene_id"
NETWORK = None NETWORK = None
@ -88,6 +93,32 @@ def _obj_to_dict(obj):
if key[0] != '_' and not hasattr(getattr(obj, key), '__call__')} if key[0] != '_' and not hasattr(getattr(obj, key), '__call__')}
def _node_name(node):
""" Returns the name of the node. """
return node.name or "{} {}".format(
node.manufacturer_name, node.product_name)
def _value_name(value):
""" Returns the name of the value. """
return "{} {}".format(_node_name(value.node), value.label)
def _object_id(value):
""" Returns the object_id of the device value.
The object_id contains node_id and value instance id
to not collide with other entity_ids"""
object_id = "{}_{}".format(slugify(_value_name(value)),
value.node.node_id)
# Add the instance id if there is more than one instance for the value
if value.instance > 1:
return "{}_{}".format(object_id, value.instance)
return object_id
def nice_print_node(node): def nice_print_node(node):
""" Prints a nice formatted node to the output (debug method). """ """ Prints a nice formatted node to the output (debug method). """
node_dict = _obj_to_dict(node) node_dict = _obj_to_dict(node)
@ -126,7 +157,9 @@ def setup(hass, config):
from openzwave.option import ZWaveOption from openzwave.option import ZWaveOption
from openzwave.network import ZWaveNetwork from openzwave.network import ZWaveNetwork
# Load configuration
use_debug = str(config[DOMAIN].get(CONF_DEBUG)) == '1' use_debug = str(config[DOMAIN].get(CONF_DEBUG)) == '1'
customize = config[DOMAIN].get(CONF_CUSTOMIZE, {})
# Setup options # Setup options
options = ZWaveOption( options = ZWaveOption(
@ -148,6 +181,7 @@ def setup(hass, config):
if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED, if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED,
ZWaveNetwork.SIGNAL_VALUE_ADDED): ZWaveNetwork.SIGNAL_VALUE_ADDED):
pprint(_obj_to_dict(value)) pprint(_obj_to_dict(value))
print("") print("")
dispatcher.connect(log_all, weak=False) dispatcher.connect(log_all, weak=False)
@ -171,6 +205,15 @@ def setup(hass, config):
# Ensure component is loaded # Ensure component is loaded
bootstrap.setup_component(hass, component, config) bootstrap.setup_component(hass, component, config)
# Configure node
name = "{}.{}".format(component, _object_id(value))
node_config = customize.get(name, {})
polling_intensity = convert(
node_config.get(CONF_POLLING_INTENSITY), int)
if polling_intensity is not None:
value.enable_poll(polling_intensity)
# Fire discovery event # Fire discovery event
hass.bus.fire(EVENT_PLATFORM_DISCOVERED, { hass.bus.fire(EVENT_PLATFORM_DISCOVERED, {
ATTR_SERVICE: discovery_service, ATTR_SERVICE: discovery_service,
@ -180,8 +223,20 @@ def setup(hass, config):
} }
}) })
def scene_activated(node, scene_id):
""" Called when a scene is activated on any node in the network. """
name = _node_name(node)
object_id = "{}_{}".format(slugify(name), node.node_id)
hass.bus.fire(EVENT_SCENE_ACTIVATED, {
ATTR_ENTITY_ID: object_id,
ATTR_SCENE_ID: scene_id
})
dispatcher.connect( dispatcher.connect(
value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False) value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False)
dispatcher.connect(
scene_activated, ZWaveNetwork.SIGNAL_SCENE_EVENT, weak=False)
def add_node(event): def add_node(event):
""" Switch into inclusion mode """ """ Switch into inclusion mode """
@ -199,9 +254,10 @@ def setup(hass, config):
""" Called when Home Assistant starts up. """ """ Called when Home Assistant starts up. """
NETWORK.start() NETWORK.start()
polling_interval = config[DOMAIN].get(CONF_POLLING_INTERVAL, None) polling_interval = convert(
config[DOMAIN].get(CONF_POLLING_INTERVAL), int)
if polling_interval is not None: if polling_interval is not None:
NETWORK.setPollInterval(polling_interval) NETWORK.set_poll_interval(polling_interval, False)
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zwave) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zwave)
@ -235,24 +291,14 @@ class ZWaveDeviceEntity:
@property @property
def name(self): def name(self):
""" Returns the name of the device. """ """ Returns the name of the device. """
name = self._value.node.name or "{} {}".format( return _value_name(self._value)
self._value.node.manufacturer_name, self._value.node.product_name)
return "{} {}".format(name, self._value.label)
def _object_id(self): def _object_id(self):
""" Returns the object_id of the device value. """ Returns the object_id of the device value.
The object_id contains node_id and value instance id The object_id contains node_id and value instance id
to not collide with other entity_ids""" to not collide with other entity_ids"""
object_id = "{}_{}".format(slugify(self.name), return _object_id(self._value)
self._value.node.node_id)
# Add the instance id if there is more than one instance for the value
if self._value.instance > 1:
return "{}_{}".format(object_id, self._value.instance)
return object_id
@property @property
def device_state_attributes(self): def device_state_attributes(self):