Big Homematic update (#3677)
* Update homeassistant with new pyhomematic layout * fix linter
This commit is contained in:
parent
c3ea04f2dd
commit
625319846c
4 changed files with 81 additions and 98 deletions
|
@ -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",
|
||||||
|
|
|
@ -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,83 +338,45 @@ 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]:
|
|
||||||
name = _create_ha_name(
|
|
||||||
name=device.NAME,
|
|
||||||
channel=channel,
|
|
||||||
param=param
|
|
||||||
)
|
|
||||||
device_dict = {
|
|
||||||
CONF_PLATFORM: "homematic",
|
|
||||||
ATTR_ADDRESS: key,
|
|
||||||
ATTR_NAME: name,
|
|
||||||
ATTR_CHANNEL: channel
|
|
||||||
}
|
|
||||||
if param is not None:
|
|
||||||
device_dict.update({ATTR_PARAM: param})
|
|
||||||
|
|
||||||
# Add new device
|
# add devices
|
||||||
try:
|
_LOGGER.debug("Handling %s: %s", param, channels)
|
||||||
DEVICE_SCHEMA(device_dict)
|
for channel in channels:
|
||||||
device_arr.append(device_dict)
|
name = _create_ha_name(
|
||||||
except vol.MultipleInvalid as err:
|
name=device.NAME,
|
||||||
_LOGGER.error("Invalid device config: %s",
|
channel=channel,
|
||||||
str(err))
|
param=param
|
||||||
else:
|
)
|
||||||
_LOGGER.debug("Channel %i not in params", channel)
|
device_dict = {
|
||||||
|
CONF_PLATFORM: "homematic",
|
||||||
|
ATTR_ADDRESS: key,
|
||||||
|
ATTR_NAME: name,
|
||||||
|
ATTR_CHANNEL: channel
|
||||||
|
}
|
||||||
|
if param is not None:
|
||||||
|
device_dict[ATTR_PARAM] = param
|
||||||
|
|
||||||
|
# Add new device
|
||||||
|
try:
|
||||||
|
DEVICE_SCHEMA(device_dict)
|
||||||
|
device_arr.append(device_dict)
|
||||||
|
except vol.MultipleInvalid as err:
|
||||||
|
_LOGGER.error("Invalid device config: %s",
|
||||||
|
str(err))
|
||||||
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,19 +720,22 @@ 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
|
||||||
for channel in channels_to_sub:
|
for channel in channels_to_sub:
|
||||||
|
|
|
@ -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",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue