From b5b1d72ab6d6d7ef782b62ceb886861826e4a2fb Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 1 Feb 2017 23:55:16 +0100 Subject: [PATCH] Fix bug for UNREACH devices / Variable handling and update. (#5689) * Fix bug for UNREACH devices / Variable handling and update. * fix track_time * update after data after creation * add message output * change unreach * change unreach code * Revert "change unreach code" This reverts commit f58430de3cb854d5f6f886bfe4d59899c1efadbf. * update pyhomematic --- homeassistant/components/homematic.py | 201 ++++++++++--------------- homeassistant/components/services.yaml | 8 +- requirements_all.txt | 2 +- 3 files changed, 88 insertions(+), 123 deletions(-) diff --git a/homeassistant/components/homematic.py b/homeassistant/components/homematic.py index 9b38bb0efea..ce1df98d727 100644 --- a/homeassistant/components/homematic.py +++ b/homeassistant/components/homematic.py @@ -16,17 +16,16 @@ import homeassistant.helpers.config_validation as cv from homeassistant.const import ( EVENT_HOMEASSISTANT_STOP, STATE_UNKNOWN, CONF_USERNAME, CONF_PASSWORD, CONF_PLATFORM, CONF_HOSTS, CONF_NAME, ATTR_ENTITY_ID) -from homeassistant.helpers.entity import Entity -from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers import discovery +from homeassistant.helpers.entity import Entity +from homeassistant.helpers.event import track_time_interval from homeassistant.config import load_yaml_config_file -from homeassistant.util import Throttle DOMAIN = 'homematic' -REQUIREMENTS = ["pyhomematic==0.1.20"] +REQUIREMENTS = ["pyhomematic==0.1.21"] -MIN_TIME_BETWEEN_UPDATE_HUB = timedelta(seconds=300) -SCAN_INTERVAL = timedelta(seconds=30) +SCAN_INTERVAL_HUB = timedelta(seconds=300) +SCAN_INTERVAL_VARIABLES = timedelta(seconds=30) DISCOVER_SWITCHES = 'homematic.switch' DISCOVER_LIGHTS = 'homematic.light' @@ -176,8 +175,9 @@ SCHEMA_SERVICE_VIRTUALKEY = vol.Schema({ }) SCHEMA_SERVICE_SET_VAR_VALUE = vol.Schema({ - vol.Required(ATTR_ENTITY_ID): cv.entity_ids, + vol.Required(ATTR_NAME): cv.string, vol.Required(ATTR_VALUE): cv.match_all, + vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, }) SCHEMA_SERVICE_SET_DEV_VALUE = vol.Schema({ @@ -236,8 +236,6 @@ def setup(hass, config): """Setup the Homematic component.""" from pyhomematic import HMConnection - component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) - hass.data[DATA_DELAY] = config[DOMAIN].get(CONF_DELAY) hass.data[DATA_DEVINIT] = {} hass.data[DATA_STORE] = [] @@ -281,11 +279,10 @@ def setup(hass, config): hass.config.components.append(DOMAIN) # init homematic hubs - hub_entities = [] + entity_hubs = [] for _, hub_data in hosts.items(): - hub_entities.append(HMHub(hass, component, hub_data[CONF_NAME], - hub_data[CONF_VARIABLES])) - component.add_entities(hub_entities) + entity_hubs.append(HMHub( + hass, hub_data[CONF_NAME], hub_data[CONF_VARIABLES])) # regeister homematic services descriptions = load_yaml_config_file( @@ -323,14 +320,23 @@ def setup(hass, config): schema=SCHEMA_SERVICE_VIRTUALKEY) def _service_handle_value(service): - """Set value on homematic variable object.""" - variable_list = component.extract_from_service(service) - + """Set value on homematic variable.""" + entity_ids = service.data.get(ATTR_ENTITY_ID) + name = service.data[ATTR_NAME] value = service.data[ATTR_VALUE] - for hm_variable in variable_list: - if isinstance(hm_variable, HMVariable): - hm_variable.hm_set(value) + if entity_ids: + entities = [entity for entity in entity_hubs if + entity.entity_id in entity_ids] + else: + entities = entity_hubs + + if not entities: + _LOGGER.error("Homematic controller not found!") + return + + for hub in entities: + hub.hm_set_variable(name, value) hass.services.register( DOMAIN, SERVICE_SET_VAR_VALUE, _service_handle_value, @@ -579,132 +585,87 @@ def _device_from_servicecall(hass, service): class HMHub(Entity): """The Homematic hub. I.e. CCU2/HomeGear.""" - def __init__(self, hass, component, name, use_variables): + def __init__(self, hass, name, use_variables): """Initialize Homematic hub.""" self.hass = hass + self.entity_id = "{}.{}".format(DOMAIN, name.lower()) self._homematic = hass.data[DATA_HOMEMATIC] - self._component = component + self._variables = {} self._name = name self._state = STATE_UNKNOWN - self._store = {} self._use_variables = use_variables # load data - self._update_hub_state() - self._init_variables() + track_time_interval(hass, self._update_hub, SCAN_INTERVAL_HUB) + self._update_hub(None) + + if self._use_variables: + track_time_interval( + hass, self._update_variables, SCAN_INTERVAL_VARIABLES) + self._update_variables(None) @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 device_state_attributes(self): - """Return device specific state attributes.""" - return {} - - @property - def icon(self): - """Return the icon to use in the frontend, if any.""" - return "mdi:gradient" - - def update(self): - """Update Hub data and all HM variables.""" - self._update_hub_state() - self._update_variables_state() - - @Throttle(MIN_TIME_BETWEEN_UPDATE_HUB) - def _update_hub_state(self): - """Retrieve latest state.""" - state = self._homematic.getServiceMessages(self._name) - self._state = STATE_UNKNOWN if state is None else len(state) - - def _update_variables_state(self): - """Retrive all variable data and update hmvariable states.""" - if not self._use_variables: - return - - variables = self._homematic.getAllSystemVariables(self._name) - if variables is None: - return - - for key, value in variables.items(): - if key in self._store: - self._store.get(key).hm_update(value) - - def _init_variables(self): - """Load variables from hub.""" - if not self._use_variables: - return - - variables = self._homematic.getAllSystemVariables(self._name) - if variables is None: - return - - entities = [] - for key, value in variables.items(): - entities.append(HMVariable(self.hass, self._name, key, value)) - self._component.add_entities(entities) - - -class HMVariable(Entity): - """The Homematic system variable.""" - - def __init__(self, hass, hub_name, name, state): - """Initialize Homematic hub.""" - self.hass = hass - self._homematic = hass.data[DATA_HOMEMATIC] - self._state = state - self._name = name - self._hub_name = hub_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 Hub object update variable.""" return False @property - def device_state_attributes(self): - """Return device specific state attributes.""" - attr = { - 'hub': self._hub_name, - } + def state(self): + """Return the state of the entity.""" + return self._state + + @property + def state_attributes(self): + """Return the state attributes.""" + attr = self._variables.copy() return attr - def hm_update(self, value): - """Update variable over Hub object.""" - if value != self._state: - self._state = value + @property + def icon(self): + """Return the icon to use in the frontend, if any.""" + return "mdi:gradient" + + def _update_hub(self, now): + """Retrieve latest state.""" + state = self._homematic.getServiceMessages(self._name) + self._state = STATE_UNKNOWN if state is None else len(state) + self.schedule_update_ha_state() + + def _update_variables(self, now): + """Retrive all variable data and update hmvariable states.""" + variables = self._homematic.getAllSystemVariables(self._name) + if variables is None: + return + + state_change = False + for key, value in variables.items(): + if key in self._variables and value == self._variables[key]: + continue + + state_change = True + self._variables.update({key: value}) + + if state_change: self.schedule_update_ha_state() - def hm_set(self, value): + def hm_set_variable(self, name, value): """Set variable on homematic controller.""" - if isinstance(self._state, bool): + if name not in self._variables: + _LOGGER.error("Variable %s not found on %s", name, self.name) + return + old_value = self._variables.get(name) + if isinstance(old_value, bool): value = cv.boolean(value) else: value = float(value) - self._homematic.setSystemVariable(self._hub_name, self._name, value) - self._state = value + self._homematic.setSystemVariable(self.name, name, value) + + self._variables.update({name: value}) self.schedule_update_ha_state() @@ -817,7 +778,7 @@ class HMDevice(Entity): have_change = True # If available it has changed - if attribute is 'UNREACH': + if attribute == 'UNREACH': self._available = bool(value) have_change = True @@ -829,7 +790,7 @@ class HMDevice(Entity): def _subscribe_homematic_events(self): """Subscribe all required events to handle job.""" - channels_to_sub = {} + channels_to_sub = {0: True} # add channel 0 for UNREACH # Push data to channels_to_sub from hmdevice metadata for metadata in (self._hmdevice.SENSORNODE, self._hmdevice.BINARYNODE, @@ -856,7 +817,7 @@ class HMDevice(Entity): # Set callbacks for channel in channels_to_sub: _LOGGER.debug( - "Subscribe channel %s from %s", str(channel), self._name) + "Subscribe channel %d from %s", channel, self._name) self._hmdevice.setEventCallback( callback=self._hm_event_callback, bequeath=False, channel=channel) diff --git a/homeassistant/components/services.yaml b/homeassistant/components/services.yaml index 45cc36e90be..c6057dcd2a8 100644 --- a/homeassistant/components/services.yaml +++ b/homeassistant/components/services.yaml @@ -99,8 +99,12 @@ homematic: fields: entity_id: - description: Name(s) of entities to set value - example: 'homematic.my_variable' + description: Name(s) of homematic central to set value + example: 'homematic.ccu2' + + name: + description: Name of the varaible to set + example: 'testvariable' value: description: New value diff --git a/requirements_all.txt b/requirements_all.txt index 206b2a9a525..055e0a4292c 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -444,7 +444,7 @@ pyharmony==1.0.12 pyhik==0.0.7 # homeassistant.components.homematic -pyhomematic==0.1.20 +pyhomematic==0.1.21 # homeassistant.components.device_tracker.icloud pyicloud==0.9.1