Full homematic system variable support (#2986)

This commit is contained in:
Pascal Vizeli 2016-08-26 10:25:56 +02:00 committed by GitHub
parent 877dc9c7b5
commit 95b98f6752
2 changed files with 140 additions and 39 deletions

View File

@ -7,24 +7,29 @@ https://home-assistant.io/components/homematic/
import os import os
import time import time
import logging import logging
from datetime import timedelta
from functools import partial from functools import partial
import voluptuous as vol import voluptuous as vol
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.const import (EVENT_HOMEASSISTANT_STOP, STATE_UNKNOWN, from homeassistant.const import (EVENT_HOMEASSISTANT_STOP, STATE_UNKNOWN,
CONF_USERNAME, CONF_PASSWORD, CONF_PLATFORM) CONF_USERNAME, CONF_PASSWORD, CONF_PLATFORM,
ATTR_ENTITY_ID)
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
from homeassistant.config import load_yaml_config_file from homeassistant.config import load_yaml_config_file
from homeassistant.util import Throttle
DOMAIN = 'homematic' DOMAIN = 'homematic'
REQUIREMENTS = ["pyhomematic==0.1.13"] REQUIREMENTS = ["pyhomematic==0.1.13"]
ENTITY_ID_FORMAT = DOMAIN + '.{}'
HOMEMATIC = None HOMEMATIC = None
HOMEMATIC_LINK_DELAY = 0.5 HOMEMATIC_LINK_DELAY = 0.5
HOMEMATIC_VAR = {}
MIN_TIME_BETWEEN_UPDATE_HUB = timedelta(seconds=300)
DISCOVER_SWITCHES = 'homematic.switch' DISCOVER_SWITCHES = 'homematic.switch'
DISCOVER_LIGHTS = 'homematic.light' DISCOVER_LIGHTS = 'homematic.light'
@ -38,11 +43,13 @@ ATTR_PARAM = 'param'
ATTR_CHANNEL = 'channel' ATTR_CHANNEL = 'channel'
ATTR_NAME = 'name' ATTR_NAME = 'name'
ATTR_ADDRESS = 'address' ATTR_ADDRESS = 'address'
ATTR_VALUE = 'value'
EVENT_KEYPRESS = 'homematic.keypress' EVENT_KEYPRESS = 'homematic.keypress'
EVENT_IMPULSE = 'homematic.impulse' EVENT_IMPULSE = 'homematic.impulse'
SERVICE_VIRTUALKEY = 'virtualkey' SERVICE_VIRTUALKEY = 'virtualkey'
SERVICE_SET_VALUE = 'set_value'
HM_DEVICE_TYPES = { HM_DEVICE_TYPES = {
DISCOVER_SWITCHES: ['Switch', 'SwitchPowermeter'], DISCOVER_SWITCHES: ['Switch', 'SwitchPowermeter'],
@ -132,15 +139,40 @@ SCHEMA_SERVICE_VIRTUALKEY = vol.Schema({
vol.Required(ATTR_PARAM): cv.string, vol.Required(ATTR_PARAM): cv.string,
}) })
SCHEMA_SERVICE_SET_VALUE = vol.Schema({
vol.Required(ATTR_ENTITY_ID): cv.entity_ids,
vol.Required(ATTR_VALUE): vol.Coerce(float),
})
# pylint: disable=unused-argument
def virtualkey(hass, address, channel, param):
"""Send virtual keypress to homematic controlller."""
data = {
ATTR_ADDRESS: address,
ATTR_CHANNEL: channel,
ATTR_PARAM: param,
}
hass.services.call(DOMAIN, SERVICE_VIRTUALKEY, data)
def set_value(hass, entity_id, value):
"""Change value of homematic system variable."""
data = {
ATTR_ENTITY_ID: entity_id,
ATTR_VALUE: value,
}
hass.services.call(DOMAIN, SERVICE_SET_VALUE, data)
# pylint: disable=unused-argument,too-many-locals
def setup(hass, config): def setup(hass, config):
"""Setup the Homematic component.""" """Setup the Homematic component."""
global HOMEMATIC, HOMEMATIC_LINK_DELAY global HOMEMATIC, HOMEMATIC_LINK_DELAY
from pyhomematic import HMConnection from pyhomematic import HMConnection
component = EntityComponent(_LOGGER, DOMAIN, hass) component = EntityComponent(_LOGGER, DOMAIN, hass)
hm_hub = HMHub()
local_ip = config[DOMAIN].get(CONF_LOCAL_IP) local_ip = config[DOMAIN].get(CONF_LOCAL_IP)
local_port = config[DOMAIN].get(CONF_LOCAL_PORT) local_port = config[DOMAIN].get(CONF_LOCAL_PORT)
@ -157,12 +189,11 @@ def setup(hass, config):
# Create server thread # Create server thread
bound_system_callback = partial(_system_callback_handler, hass, config) bound_system_callback = partial(_system_callback_handler, hass, config)
bound_event_callback = partial(_event_callback_handler, hm_hub)
HOMEMATIC = HMConnection(local=local_ip, HOMEMATIC = HMConnection(local=local_ip,
localport=local_port, localport=local_port,
remote=remote_ip, remote=remote_ip,
remoteport=remote_port, remoteport=remote_port,
eventcallback=bound_event_callback, eventcallback=_event_callback_handler,
systemcallback=bound_system_callback, systemcallback=bound_system_callback,
resolvenames=resolvenames, resolvenames=resolvenames,
rpcusername=username, rpcusername=username,
@ -183,17 +214,50 @@ def setup(hass, config):
hass.services.register(DOMAIN, SERVICE_VIRTUALKEY, hass.services.register(DOMAIN, SERVICE_VIRTUALKEY,
_hm_service_virtualkey, _hm_service_virtualkey,
descriptions[DOMAIN][SERVICE_VIRTUALKEY], descriptions[DOMAIN][SERVICE_VIRTUALKEY],
SCHEMA_SERVICE_VIRTUALKEY) schema=SCHEMA_SERVICE_VIRTUALKEY)
entities = []
##
# init HM variable
variables = HOMEMATIC.getAllSystemVariables()
if variables is not None:
for key, value in variables.items():
hm_var = HMVariable(key, value)
HOMEMATIC_VAR.update({key: hm_var})
entities.append(hm_var)
# add homematic entites
entities.append(HMHub())
component.add_entities(entities)
##
# register set_value service if exists variables
if not HOMEMATIC_VAR:
return True
def _service_handle_value(service):
"""Set value on homematic variable object."""
variable_list = component.extract_from_service(service)
value = service.data[ATTR_VALUE]
for hm_variable in variable_list:
hm_variable.hm_set(value)
hass.services.register(DOMAIN, SERVICE_SET_VALUE,
_service_handle_value,
descriptions[DOMAIN][SERVICE_SET_VALUE],
schema=SCHEMA_SERVICE_SET_VALUE)
hm_hub.init_data()
component.add_entities([hm_hub])
return True return True
def _event_callback_handler(hm_hub, interface_id, address, value_key, value): def _event_callback_handler(interface_id, address, value_key, value):
"""Callback handler for events.""" """Callback handler for events."""
if not address: if not address:
hm_hub.update_hm_variable(value_key, value) if value_key in HOMEMATIC_VAR:
HOMEMATIC_VAR[value_key].hm_update(value)
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
@ -444,7 +508,7 @@ class HMHub(Entity):
def __init__(self): def __init__(self):
"""Initialize Homematic hub.""" """Initialize Homematic hub."""
self._data = {} self._state = STATE_UNKNOWN
@property @property
def name(self): def name(self):
@ -454,47 +518,72 @@ class HMHub(Entity):
@property @property
def state(self): def state(self):
"""Return the state of the entity.""" """Return the state of the entity."""
state = HOMEMATIC.getServiceMessages() return self._state
if state is None:
return STATE_UNKNOWN
return len(state)
@property @property
def device_state_attributes(self): def device_state_attributes(self):
"""Return device specific state attributes.""" """Return device specific state attributes."""
return self._data return {}
def init_data(self): @property
"""Init variable to object.""" def icon(self):
hm_var = HOMEMATIC.getAllSystemVariables() """Return the icon to use in the frontend, if any."""
for var, val in hm_var: return "mdi:gradient"
self._data[var] = val
def update_hm_variable(self, variable, value): @property
"""Update homematic variable from Homematic.""" def available(self):
if variable not in self._data: """Return true if device is available."""
return True if HOMEMATIC is not None else False
@Throttle(MIN_TIME_BETWEEN_UPDATE_HUB)
def update(self):
"""Retrieve latest state."""
if HOMEMATIC is None:
return return
state = HOMEMATIC.getServiceMessages()
self._state = STATE_UNKNOWN if state is None else len(state)
# if value have change, update HASS
if self._data[variable] != value: class HMVariable(Entity):
self._data[variable] = value """The Homematic system variable."""
self.update_ha_state()
def __init__(self, name, state):
"""Initialize Homematic hub."""
self._state = state
self._name = name
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def state(self):
"""Return the state of the entity."""
return self._state
@property
def icon(self):
"""Return the icon to use in the frontend, if any."""
return "mdi:code-string"
@property @property
def should_poll(self): def should_poll(self):
"""Return false. Homematic states are pushed by the XML RPC Server.""" """Return false. Homematic states are pushed by the XML RPC Server."""
return False return False
@property def hm_update(self, value):
def unit_of_measurement(self): """Update variable value from event callback."""
"""Return the unit of measurement of this entity, if any.""" self._state = value
return '#' self.update_ha_state()
@property def hm_set(self, value):
def icon(self): """Set variable on homematic controller."""
"""Return the icon to use in the frontend, if any.""" if HOMEMATIC is not None:
return "mdi:gradient" HOMEMATIC.setSystemVariable(self._name, value)
# CCU don't send variable updates from own
self.hm_update(value)
class HMDevice(Entity): class HMDevice(Entity):

View File

@ -73,6 +73,18 @@ homematic:
description: Event to send i.e. PRESS_LONG, PRESS_SHORT description: Event to send i.e. PRESS_LONG, PRESS_SHORT
example: PRESS_LONG example: PRESS_LONG
set_value:
description: Set the name of a node.
fields:
entity_id:
description: Name(s) of entities to set value
example: 'homematic.my_variable'
value:
description: New value
example: 1
zwave: zwave:
add_node: add_node:
description: Add a new node to the zwave network. Refer to OZW.log for details. description: Add a new node to the zwave network. Refer to OZW.log for details.