Big Homematic update (#3677)

* Update homeassistant with new pyhomematic layout

* fix linter
This commit is contained in:
Pascal Vizeli 2016-10-03 23:21:53 +02:00 committed by GitHub
parent c3ea04f2dd
commit 625319846c
4 changed files with 81 additions and 98 deletions

View file

@ -16,6 +16,7 @@ DEPENDENCIES = ['homematic']
SENSOR_TYPES_CLASS = { SENSOR_TYPES_CLASS = {
"Remote": None, "Remote": None,
"ShutterContact": "opening", "ShutterContact": "opening",
"IPShutterContact": "opening",
"Smoke": "smoke", "Smoke": "smoke",
"SmokeV2": "smoke", "SmokeV2": "smoke",
"Motion": "motion", "Motion": "motion",

View file

@ -23,7 +23,7 @@ from homeassistant.config import load_yaml_config_file
from homeassistant.util import Throttle from homeassistant.util import Throttle
DOMAIN = 'homematic' DOMAIN = 'homematic'
REQUIREMENTS = ["pyhomematic==0.1.14"] REQUIREMENTS = ["pyhomematic==0.1.16"]
HOMEMATIC = None HOMEMATIC = None
HOMEMATIC_LINK_DELAY = 0.5 HOMEMATIC_LINK_DELAY = 0.5
@ -52,17 +52,22 @@ SERVICE_VIRTUALKEY = 'virtualkey'
SERVICE_SET_VALUE = 'set_value' SERVICE_SET_VALUE = 'set_value'
HM_DEVICE_TYPES = { HM_DEVICE_TYPES = {
DISCOVER_SWITCHES: ['Switch', 'SwitchPowermeter'], DISCOVER_SWITCHES: [
DISCOVER_LIGHTS: ['Dimmer'], 'Switch', 'SwitchPowermeter', 'IOSwitch', 'IPSwitch',
DISCOVER_SENSORS: ['SwitchPowermeter', 'Motion', 'MotionV2', 'IPSwitchPowermeter', 'KeyMatic'],
'RemoteMotion', 'ThermostatWall', 'AreaThermostat', DISCOVER_LIGHTS: ['Dimmer', 'KeyDimmer'],
'RotaryHandleSensor', 'WaterSensor', 'PowermeterGas', DISCOVER_SENSORS: [
'LuxSensor', 'WeatherSensor', 'WeatherStation'], 'SwitchPowermeter', 'Motion', 'MotionV2', 'RemoteMotion',
DISCOVER_CLIMATE: ['Thermostat', 'ThermostatWall', 'MAXThermostat'], 'ThermostatWall', 'AreaThermostat', 'RotaryHandleSensor',
DISCOVER_BINARY_SENSORS: ['ShutterContact', 'Smoke', 'SmokeV2', 'Motion', 'WaterSensor', 'PowermeterGas', 'LuxSensor', 'WeatherSensor',
'MotionV2', 'RemoteMotion', 'WeatherSensor', 'WeatherStation', 'ThermostatWall2', 'TemperatureDiffSensor',
'TiltSensor'], 'TemperatureSensor', 'CO2Sensor'],
DISCOVER_COVER: ['Blind'] DISCOVER_CLIMATE: [
'Thermostat', 'ThermostatWall', 'MAXThermostat', 'ThermostatWall2'],
DISCOVER_BINARY_SENSORS: [
'ShutterContact', 'Smoke', 'SmokeV2', 'Motion', 'MotionV2',
'RemoteMotion', 'WeatherSensor', 'TiltSensor', 'IPShutterContact'],
DISCOVER_COVER: ['Blind', 'KeyBlind']
} }
HM_IGNORE_DISCOVERY_NODE = [ HM_IGNORE_DISCOVERY_NODE = [
@ -87,11 +92,12 @@ HM_PRESS_EVENTS = [
'PRESS_SHORT', 'PRESS_SHORT',
'PRESS_LONG', 'PRESS_LONG',
'PRESS_CONT', 'PRESS_CONT',
'PRESS_LONG_RELEASE' 'PRESS_LONG_RELEASE',
'PRESS',
] ]
HM_IMPULSE_EVENTS = [ HM_IMPULSE_EVENTS = [
'SEQUENCE_OK' 'SEQUENCE_OK',
] ]
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -111,6 +117,15 @@ CONF_RESOLVENAMES = 'resolvenames'
CONF_DELAY = 'delay' CONF_DELAY = 'delay'
CONF_VARIABLES = 'variables' CONF_VARIABLES = 'variables'
DEFAULT_LOCAL_IP = "0.0.0.0"
DEFAULT_LOCAL_PORT = 0
DEFAULT_RESOLVENAMES = False
DEFAULT_REMOTE_PORT = 2001
DEFAULT_USERNAME = "Admin"
DEFAULT_PASSWORD = ""
DEFAULT_VARIABLES = False
DEFAULT_DELAY = 0.5
DEVICE_SCHEMA = vol.Schema({ DEVICE_SCHEMA = vol.Schema({
vol.Required(CONF_PLATFORM): "homematic", vol.Required(CONF_PLATFORM): "homematic",
@ -122,16 +137,16 @@ DEVICE_SCHEMA = vol.Schema({
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: vol.Schema({
vol.Required(CONF_LOCAL_IP): cv.string,
vol.Optional(CONF_LOCAL_PORT, default=8943): cv.port,
vol.Required(CONF_REMOTE_IP): cv.string, vol.Required(CONF_REMOTE_IP): cv.string,
vol.Optional(CONF_REMOTE_PORT, default=2001): cv.port, vol.Optional(CONF_LOCAL_IP, default=DEFAULT_LOCAL_IP): cv.string,
vol.Optional(CONF_RESOLVENAMES, default=False): vol.Optional(CONF_LOCAL_PORT, default=DEFAULT_LOCAL_PORT): cv.port,
vol.Optional(CONF_REMOTE_PORT, default=DEFAULT_REMOTE_PORT): cv.port,
vol.Optional(CONF_RESOLVENAMES, default=DEFAULT_RESOLVENAMES):
vol.In(CONF_RESOLVENAMES_OPTIONS), vol.In(CONF_RESOLVENAMES_OPTIONS),
vol.Optional(CONF_USERNAME, default="Admin"): cv.string, vol.Optional(CONF_USERNAME, default=DEFAULT_USERNAME): cv.string,
vol.Optional(CONF_PASSWORD, default=""): cv.string, vol.Optional(CONF_PASSWORD, default=DEFAULT_PASSWORD): cv.string,
vol.Optional(CONF_DELAY, default=0.5): vol.Coerce(float), vol.Optional(CONF_DELAY, default=DEFAULT_DELAY): vol.Coerce(float),
vol.Optional(CONF_VARIABLES, default=False): cv.boolean, vol.Optional(CONF_VARIABLES, default=DEFAULT_VARIABLES): cv.boolean,
}), }),
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)
@ -323,14 +338,18 @@ def _get_devices(device_type, keys):
metadata.update(device.SENSORNODE) metadata.update(device.SENSORNODE)
elif device_type == DISCOVER_BINARY_SENSORS: elif device_type == DISCOVER_BINARY_SENSORS:
metadata.update(device.BINARYNODE) metadata.update(device.BINARYNODE)
else:
metadata.update({None: device.ELEMENT})
params = _create_params_list(device, metadata, device_type) if metadata:
if params:
# Generate options for 1...n elements with 1...n params # Generate options for 1...n elements with 1...n params
for channel in range(1, device.ELEMENT + 1): for param, channels in metadata.items():
_LOGGER.debug("Handling %s:%i", key, channel) if param in HM_IGNORE_DISCOVERY_NODE:
if channel in params: continue
for param in params[channel]:
# add devices
_LOGGER.debug("Handling %s: %s", param, channels)
for channel in channels:
name = _create_ha_name( name = _create_ha_name(
name=device.NAME, name=device.NAME,
channel=channel, channel=channel,
@ -343,7 +362,7 @@ def _get_devices(device_type, keys):
ATTR_CHANNEL: channel ATTR_CHANNEL: channel
} }
if param is not None: if param is not None:
device_dict.update({ATTR_PARAM: param}) device_dict[ATTR_PARAM] = param
# Add new device # Add new device
try: try:
@ -352,54 +371,12 @@ def _get_devices(device_type, keys):
except vol.MultipleInvalid as err: except vol.MultipleInvalid as err:
_LOGGER.error("Invalid device config: %s", _LOGGER.error("Invalid device config: %s",
str(err)) str(err))
else:
_LOGGER.debug("Channel %i not in params", channel)
else: else:
_LOGGER.debug("Got no params for %s", key) _LOGGER.debug("Got no params for %s", key)
_LOGGER.debug("%s autodiscovery: %s", device_type, str(device_arr)) _LOGGER.debug("%s autodiscovery: %s", device_type, str(device_arr))
return device_arr return device_arr
def _create_params_list(hmdevice, metadata, device_type):
"""Create a list from HMDevice with all possible parameters in config."""
params = {}
merge = False
# use merge?
if device_type in (DISCOVER_SENSORS, DISCOVER_BINARY_SENSORS):
merge = True
# Search in sensor and binary metadata per elements
for channel in range(1, hmdevice.ELEMENT + 1):
param_chan = []
for node, meta_chan in metadata.items():
try:
# Is this attribute ignored?
if node in HM_IGNORE_DISCOVERY_NODE:
continue
if meta_chan == 'c' or meta_chan is None:
# Only channel linked data
param_chan.append(node)
elif channel == 1:
# First channel can have other data channel
param_chan.append(node)
except (TypeError, ValueError):
_LOGGER.error("Exception generating %s (%s)",
hmdevice.ADDRESS, str(metadata))
# default parameter is merge is off
if len(param_chan) == 0 and not merge:
param_chan.append(None)
# Add to channel
if len(param_chan) > 0:
params.update({channel: param_chan})
_LOGGER.debug("Create param list for %s with: %s", hmdevice.ADDRESS,
str(params))
return params
def _create_ha_name(name, channel, param): def _create_ha_name(name, channel, param):
"""Generate a unique object name.""" """Generate a unique object name."""
# HMDevice is a simple device # HMDevice is a simple device
@ -484,12 +461,12 @@ def _hm_service_virtualkey(call):
hmdevice = HOMEMATIC.devices.get(address) hmdevice = HOMEMATIC.devices.get(address)
# if param exists for this device # if param exists for this device
if param not in hmdevice.ACTIONNODE: if hmdevice is None or param not in hmdevice.ACTIONNODE:
_LOGGER.error("%s not datapoint in hm device %s", param, address) _LOGGER.error("%s not datapoint in hm device %s", param, address)
return return
# channel exists? # channel exists?
if channel > hmdevice.ELEMENT: if channel in hmdevice.ACTIONNODE[param]:
_LOGGER.error("%i is not a channel in hm device %s", channel, address) _LOGGER.error("%i is not a channel in hm device %s", channel, address)
return return
@ -743,18 +720,21 @@ class HMDevice(Entity):
self._hmdevice.ATTRIBUTENODE, self._hmdevice.ATTRIBUTENODE,
self._hmdevice.WRITENODE, self._hmdevice.EVENTNODE, self._hmdevice.WRITENODE, self._hmdevice.EVENTNODE,
self._hmdevice.ACTIONNODE): self._hmdevice.ACTIONNODE):
for node, channel in metadata.items(): for node, channels in metadata.items():
# Data is needed for this instance # Data is needed for this instance
if node in self._data: if node in self._data:
# chan is current channel # chan is current channel
if channel == 'c' or channel is None: if len(channels) == 1:
channel = channels[0]
else:
channel = self._channel channel = self._channel
# Prepare for subscription # Prepare for subscription
try: try:
if int(channel) >= 0: if int(channel) >= 0:
channels_to_sub.update({int(channel): True}) channels_to_sub.update({int(channel): True})
except (ValueError, TypeError): except (ValueError, TypeError):
_LOGGER("Invalid channel in metadata from %s", _LOGGER.error("Invalid channel in metadata from %s",
self._name) self._name)
# Set callbacks # Set callbacks

View file

@ -18,7 +18,8 @@ DEPENDENCIES = ['homematic']
HM_STATE_HA_CAST = { HM_STATE_HA_CAST = {
"RotaryHandleSensor": {0: "closed", 1: "tilted", 2: "open"}, "RotaryHandleSensor": {0: "closed", 1: "tilted", 2: "open"},
"WaterSensor": {0: "dry", 1: "wet", 2: "water"} "WaterSensor": {0: "dry", 1: "wet", 2: "water"},
"CO2Sensor": {0: "normal", 1: "added", 2: "strong"},
} }
HM_UNIT_HA_CAST = { HM_UNIT_HA_CAST = {
@ -38,6 +39,7 @@ HM_UNIT_HA_CAST = {
"WIND_DIRECTION_RANGE": "°", "WIND_DIRECTION_RANGE": "°",
"SUNSHINEDURATION": "#", "SUNSHINEDURATION": "#",
"AIR_PRESSURE": "hPa", "AIR_PRESSURE": "hPa",
"FREQUENCY": "Hz",
} }

View file

@ -336,7 +336,7 @@ pyenvisalink==1.7
pyfttt==0.3 pyfttt==0.3
# homeassistant.components.homematic # homeassistant.components.homematic
pyhomematic==0.1.14 pyhomematic==0.1.16
# homeassistant.components.device_tracker.icloud # homeassistant.components.device_tracker.icloud
pyicloud==0.9.1 pyicloud==0.9.1