Full homematic system variable support (#2986)
parent
877dc9c7b5
commit
95b98f6752
|
@ -7,24 +7,29 @@ https://home-assistant.io/components/homematic/
|
|||
import os
|
||||
import time
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
from functools import partial
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
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_component import EntityComponent
|
||||
from homeassistant.helpers import discovery
|
||||
from homeassistant.config import load_yaml_config_file
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
DOMAIN = 'homematic'
|
||||
REQUIREMENTS = ["pyhomematic==0.1.13"]
|
||||
|
||||
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
||||
|
||||
HOMEMATIC = None
|
||||
HOMEMATIC_LINK_DELAY = 0.5
|
||||
HOMEMATIC_VAR = {}
|
||||
|
||||
MIN_TIME_BETWEEN_UPDATE_HUB = timedelta(seconds=300)
|
||||
|
||||
DISCOVER_SWITCHES = 'homematic.switch'
|
||||
DISCOVER_LIGHTS = 'homematic.light'
|
||||
|
@ -38,11 +43,13 @@ ATTR_PARAM = 'param'
|
|||
ATTR_CHANNEL = 'channel'
|
||||
ATTR_NAME = 'name'
|
||||
ATTR_ADDRESS = 'address'
|
||||
ATTR_VALUE = 'value'
|
||||
|
||||
EVENT_KEYPRESS = 'homematic.keypress'
|
||||
EVENT_IMPULSE = 'homematic.impulse'
|
||||
|
||||
SERVICE_VIRTUALKEY = 'virtualkey'
|
||||
SERVICE_SET_VALUE = 'set_value'
|
||||
|
||||
HM_DEVICE_TYPES = {
|
||||
DISCOVER_SWITCHES: ['Switch', 'SwitchPowermeter'],
|
||||
|
@ -132,15 +139,40 @@ SCHEMA_SERVICE_VIRTUALKEY = vol.Schema({
|
|||
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):
|
||||
"""Setup the Homematic component."""
|
||||
global HOMEMATIC, HOMEMATIC_LINK_DELAY
|
||||
from pyhomematic import HMConnection
|
||||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
hm_hub = HMHub()
|
||||
|
||||
local_ip = config[DOMAIN].get(CONF_LOCAL_IP)
|
||||
local_port = config[DOMAIN].get(CONF_LOCAL_PORT)
|
||||
|
@ -157,12 +189,11 @@ def setup(hass, config):
|
|||
|
||||
# Create server thread
|
||||
bound_system_callback = partial(_system_callback_handler, hass, config)
|
||||
bound_event_callback = partial(_event_callback_handler, hm_hub)
|
||||
HOMEMATIC = HMConnection(local=local_ip,
|
||||
localport=local_port,
|
||||
remote=remote_ip,
|
||||
remoteport=remote_port,
|
||||
eventcallback=bound_event_callback,
|
||||
eventcallback=_event_callback_handler,
|
||||
systemcallback=bound_system_callback,
|
||||
resolvenames=resolvenames,
|
||||
rpcusername=username,
|
||||
|
@ -183,17 +214,50 @@ def setup(hass, config):
|
|||
hass.services.register(DOMAIN, SERVICE_VIRTUALKEY,
|
||||
_hm_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
|
||||
|
||||
|
||||
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."""
|
||||
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
|
||||
|
@ -444,7 +508,7 @@ class HMHub(Entity):
|
|||
|
||||
def __init__(self):
|
||||
"""Initialize Homematic hub."""
|
||||
self._data = {}
|
||||
self._state = STATE_UNKNOWN
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@ -454,47 +518,72 @@ class HMHub(Entity):
|
|||
@property
|
||||
def state(self):
|
||||
"""Return the state of the entity."""
|
||||
state = HOMEMATIC.getServiceMessages()
|
||||
if state is None:
|
||||
return STATE_UNKNOWN
|
||||
|
||||
return len(state)
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return device specific state attributes."""
|
||||
return self._data
|
||||
return {}
|
||||
|
||||
def init_data(self):
|
||||
"""Init variable to object."""
|
||||
hm_var = HOMEMATIC.getAllSystemVariables()
|
||||
for var, val in hm_var:
|
||||
self._data[var] = val
|
||||
@property
|
||||
def icon(self):
|
||||
"""Return the icon to use in the frontend, if any."""
|
||||
return "mdi:gradient"
|
||||
|
||||
def update_hm_variable(self, variable, value):
|
||||
"""Update homematic variable from Homematic."""
|
||||
if variable not in self._data:
|
||||
@property
|
||||
def available(self):
|
||||
"""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
|
||||
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:
|
||||
self._data[variable] = value
|
||||
self.update_ha_state()
|
||||
|
||||
class HMVariable(Entity):
|
||||
"""The Homematic system variable."""
|
||||
|
||||
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
|
||||
def should_poll(self):
|
||||
"""Return false. Homematic states are pushed by the XML RPC Server."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit of measurement of this entity, if any."""
|
||||
return '#'
|
||||
def hm_update(self, value):
|
||||
"""Update variable value from event callback."""
|
||||
self._state = value
|
||||
self.update_ha_state()
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Return the icon to use in the frontend, if any."""
|
||||
return "mdi:gradient"
|
||||
def hm_set(self, value):
|
||||
"""Set variable on homematic controller."""
|
||||
if HOMEMATIC is not None:
|
||||
HOMEMATIC.setSystemVariable(self._name, value)
|
||||
|
||||
# CCU don't send variable updates from own
|
||||
self.hm_update(value)
|
||||
|
||||
|
||||
class HMDevice(Entity):
|
||||
|
|
|
@ -73,6 +73,18 @@ homematic:
|
|||
description: Event to send i.e. PRESS_LONG, PRESS_SHORT
|
||||
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:
|
||||
add_node:
|
||||
description: Add a new node to the zwave network. Refer to OZW.log for details.
|
||||
|
|
Loading…
Reference in New Issue