def trigger(hass, config, action): """ Listen for state changes based on `config`. """ if CONF_AFTER in config: after = dt_util.parse_time_str(config[CONF_AFTER]) if after is None: _error_time(config[CONF_AFTER], CONF_AFTER) return False hours, minutes, seconds = after.hour, after.minute, after.second elif (CONF_HOURS in config or CONF_MINUTES in config or CONF_SECONDS in config): hours = convert(config.get(CONF_HOURS), int) minutes = convert(config.get(CONF_MINUTES), int) seconds = convert(config.get(CONF_SECONDS), int) else: _LOGGER.error('One of %s, %s, %s OR %s needs to be specified', CONF_HOURS, CONF_MINUTES, CONF_SECONDS, CONF_AFTER) return False def time_automation_listener(now): """ Listens for time changes and calls action. """ action() track_time_change(hass, time_automation_listener, hour=hours, minute=minutes, second=seconds) return True
def __init__(self, hass, config): """Initialize the data object.""" self.data = None if not config.get(CONF_MANUAL): track_time_change( hass, self.update, second=config.get(CONF_SECOND), minute=config.get(CONF_MINUTE), hour=config.get(CONF_HOUR))
def __init__(self, hass, config): """Initialize the data object.""" self.data = None track_time_change(hass, self.update, second=config.get(CONF_SECOND, 0), minute=config.get(CONF_MINUTE, 0), hour=config.get(CONF_HOUR, None), day=config.get(CONF_DAY, None))
def __init__(self, hass, config): self.data = None self.hass = hass self.path = hass.config.path track_time_change(self.hass, self.update, minute=config.get(CONF_MINUTE, 0), hour=config.get(CONF_HOUR, None), day=config.get(CONF_DAY, None))
def __init__(self, hass, config): """Initialize the data object.""" self.data = None self._server_id = config.get(CONF_SERVER_ID) track_time_change(hass, self.update, second=config.get(CONF_SECOND), minute=config.get(CONF_MINUTE), hour=config.get(CONF_HOUR), day=config.get(CONF_DAY))
def setup(hass, config): """ Sets up the simple alarms. """ logger = logging.getLogger(__name__) logger.info("Starting laundry automation.") sensors = ["sensor.washer_status", "sensor.dryer_status"] wait_time = config[DOMAIN].get(CONF_WAIT_TIME, 300) def track_complete_status(entity_id, old_state, new_state): """ Called when appliance goes from running to complete. """ actually_complete = True for i in range(1, wait_time): state = hass.states.get(entity_id).state if state == COMPLETE: time.sleep(1) else: actually_complete = False logger.info("LAUNDRY NOT ACTUALLY COMPLETE!!") break if actually_complete: global fluxing fluxing = False if 'dryer' in entity_id: hass.services.call('scene', 'turn_on', {"entity_id":"scene.red"}) message = "The dryer is complete, please empty it!" elif 'washer' in entity_id: hass.services.call('scene', 'turn_on', {"entity_id":"scene.blue"}) message = "The washing machine is complete, please empty it!" logger.info("LAUNDRY ACTUALLY COMPLETE!!") if hass.states.get(LAURENS_DEVICE).state == STATE_HOME: hass.services.call('notify', 'join_lauren', {"message":message}) if hass.states.get(NOLANS_DEVICE).state == STATE_HOME: hass.services.call('notify', 'join', {"message":message}) def appliance_emptied(entity_id, old_state, new_state): """ Called when appliance goes from complete to empty. """ hass.services.call('scene', 'turn_on', {"entity_id":"scene.normal"}) global fluxing fluxing = True def flux_update(service): """ Called every 30 seconds to flux the lights. """ global fluxing ib_flux_state = hass.states.get('input_boolean.flux_automation') if fluxing and ib_flux_state: if ib_flux_state.state == 'on': hass.services.call('switch', 'flux_update') track_state_change( hass, sensors, track_complete_status, RUNNING, COMPLETE) track_state_change( hass, sensors, appliance_emptied, COMPLETE, EMPTY) track_time_change(hass, flux_update, second=[0,30]) return True
def setup(hass, config): """ Sets up the simple alarms. """ logger = logging.getLogger(__name__) logger.info("Starting laundry automation.") sensors = ["sensor.washer_status", "sensor.dryer_status"] wait_time = config[DOMAIN].get(CONF_WAIT_TIME, 300) def track_complete_status(entity_id, old_state, new_state): """ Called when appliance goes from running to complete. """ actually_complete = True for i in range(1, wait_time): state = hass.states.get(entity_id).state if state == COMPLETE: time.sleep(1) else: actually_complete = False logger.info("LAUNDRY NOT ACTUALLY COMPLETE!!") break if actually_complete: global fluxing fluxing = False if 'dryer' in entity_id: hass.services.call('scene', 'turn_on', {"entity_id": "scene.red"}) message = "The dryer is complete, please empty it!" elif 'washer' in entity_id: hass.services.call('scene', 'turn_on', {"entity_id": "scene.blue"}) message = "The washing machine is complete, please empty it!" logger.info("LAUNDRY ACTUALLY COMPLETE!!") if hass.states.get(LAURENS_DEVICE).state == STATE_HOME: hass.services.call('notify', 'join_lauren', {"message": message}) if hass.states.get(NOLANS_DEVICE).state == STATE_HOME: hass.services.call('notify', 'join', {"message": message}) def appliance_emptied(entity_id, old_state, new_state): """ Called when appliance goes from complete to empty. """ hass.services.call('scene', 'turn_on', {"entity_id": "scene.normal"}) global fluxing fluxing = True def flux_update(service): """ Called every 30 seconds to flux the lights. """ global fluxing ib_flux_state = hass.states.get('input_boolean.flux_automation') if fluxing and ib_flux_state: if ib_flux_state.state == 'on': hass.services.call('switch', 'flux_update') track_state_change(hass, sensors, track_complete_status, RUNNING, COMPLETE) track_state_change(hass, sensors, appliance_emptied, COMPLETE, EMPTY) track_time_change(hass, flux_update, second=[0, 30]) return True
def __init__(self, hass, config): """Initialize the data object.""" self.data = None self._server_id = config.get(CONF_SERVER_ID) if not config.get(CONF_MANUAL): track_time_change(hass, self.update, second=config.get(CONF_SECOND), minute=config.get(CONF_MINUTE), hour=config.get(CONF_HOUR), day=config.get(CONF_DAY))
def setup_platform(hass, config, add_devices_callback, discovery_info=None): """Setup the LIFX platform.""" server_addr = config.get(CONF_SERVER, None) broadcast_addr = config.get(CONF_BROADCAST, None) lifx_library = LIFX(add_devices_callback, server_addr, broadcast_addr) # Register our poll service track_time_change(hass, lifx_library.poll, second=[10, 40]) lifx_library.probe()
def track_time_change( self, action, year=None, month=None, day=None, hour=None, minute=None, second=None, utc=False ): """Deprecated method as of 8/4/2015 to track time change.""" # pylint: disable=too-many-arguments _LOGGER.warning( "hass.track_time_change is deprecated. " "Please use homeassistant.helpers.event.track_time_change" ) import homeassistant.helpers.event as helper helper.track_time_change(self, action, year, month, day, hour, minute, second)
def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the LIFX platform.""" server_addr = config.get(CONF_SERVER) broadcast_addr = config.get(CONF_BROADCAST) lifx_library = LIFX(add_devices, server_addr, broadcast_addr) # Register our poll service track_time_change(hass, lifx_library.poll, second=[10, 40]) lifx_library.probe()
def track_time_change(self, action, year=None, month=None, day=None, hour=None, minute=None, second=None, utc=False): """Deprecated method as of 8/4/2015 to track time change.""" # pylint: disable=too-many-arguments _LOGGER.warning( 'hass.track_time_change is deprecated. ' 'Please use homeassistant.helpers.event.track_time_change') import homeassistant.helpers.event as helper helper.track_time_change(self, action, year, month, day, hour, minute, second)
def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Set up platform. """ server_addr = config.get(CONF_SERVER, None) broadcast_addr = config.get(CONF_BROADCAST, None) lifx_library = LIFX(add_devices_callback, server_addr, broadcast_addr) # register our poll service track_time_change(hass, lifx_library.poll, second=10) lifx_library.probe()
def __init__( self, hass, min_colortemp, max_colortemp, sunrise_offset, sunset_offset, sunrise_time, sunset_time, latitude, longitude, elevation, interval, transition, ): self.hass = hass self.data = {} self.data["min_colortemp"] = min_colortemp self.data["max_colortemp"] = max_colortemp self.data["sunrise_offset"] = sunrise_offset self.data["sunset_offset"] = sunset_offset self.data["sunrise_time"] = sunrise_time self.data["sunset_time"] = sunset_time self.data["latitude"] = latitude self.data["longitude"] = longitude self.data["elevation"] = elevation self.data["interval"] = interval self.data["transition"] = transition self.data["timezone"] = self.get_timezone() self.data["percent"] = self.calc_percent() self.data["colortemp"] = self.calc_colortemp() self.data["rgb_color"] = self.calc_rgb() self.data["xy_color"] = self.calc_xy() self.data["hs_color"] = self.calc_hs() self.update = Throttle(timedelta(seconds=interval))(self._update) for which in ["sunrise", "sunrise"]: time = self.data[f"{which}_time"] if time is not None: track_time_change( self.hass, self._update, hour=int(time.strftime("%H")), minute=int(time.strftime("%M")), second=int(time.strftime("%S")), ) elif which == "sunrise": track_sunrise(self.hass, self._update, self.data["sunrise_offset"]) elif which == "sunset": track_sunset(self.hass, self._update, self.data["sunset_offset"])
def register(hass, config, action): """ Listen for state changes based on `config`. """ hours = convert(config.get(CONF_HOURS), int) minutes = convert(config.get(CONF_MINUTES), int) seconds = convert(config.get(CONF_SECONDS), int) def time_automation_listener(now): """ Listens for time changes and calls action. """ action() track_time_change(hass, time_automation_listener, hour=hours, minute=minutes, second=seconds) return True
def setup(hass, config): """ Setup the updater component. """ def check_newest_version(_=None): """ Check if a new version is available and report if one is. """ newest = get_newest_version() if newest != CURRENT_VERSION and newest is not None: hass.states.set(ENTITY_ID, newest, {ATTR_FRIENDLY_NAME: "Update Available"}) event.track_time_change(hass, check_newest_version, hour=[0, 12], minute=0, second=0) check_newest_version() return True
def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the LIFX platform.""" _LOGGER.warning( "The LIFX Legacy platform is deprecated and will be removed in " "Home Assistant Core 2021.6.0. Use the LIFX integration instead.") server_addr = config.get(CONF_SERVER) broadcast_addr = config.get(CONF_BROADCAST) lifx_library = LIFX(add_entities, server_addr, broadcast_addr) # Register our poll service track_time_change(hass, lifx_library.poll, second=[10, 40]) lifx_library.probe()
def __init__(self, hass, name, rate, timeout): """Initialize the sensor object.""" self.hass = hass self._name = name self.entity_id = async_generate_entity_id(ENTITY_ID_FORMAT, self._name, hass=self.hass) self.rate = rate self._timeout = timeout self._attributes = {ATTR_RATE: self.rate.upper()} self._state = None self._today_prices = None self._tomorrow_prices = None track_time_change(self.hass, self.update, second=[0], minute=[0]) _LOGGER.debug("Setup of %s (%s) ok", self.name, self.entity_id)
def setup(hass, config): """Setup the updater component.""" def check_newest_version(_=None): """Check if a new version is available and report if one is.""" newest = get_newest_version() if newest != CURRENT_VERSION and newest is not None: hass.states.set( ENTITY_ID, newest, {ATTR_FRIENDLY_NAME: 'Update Available'}) event.track_time_change(hass, check_newest_version, hour=[0, 12], minute=0, second=0) check_newest_version() return True
def __init__(self, hass, firstname, lastname): """ :param firstname: :param lastname: """ self._hass = hass self._firstname = firstname self._lastname = lastname self._relationships = [] self._device_trackers = [] self._gender = None # Run update every 5 seconds. track_time_change(hass, lambda now: self.update(), second=range(0, 60, 5))
def test_periodic_task_leaving_dst(self): """Test periodic task behavior when leaving dst.""" tz = dt_util.get_time_zone('Europe/Vienna') dt_util.set_default_time_zone(tz) specific_runs = [] unsub = track_time_change(self.hass, lambda x: specific_runs.append(1), hour=2, minute=30, second=0) self._send_time_changed( tz.localize(datetime(2018, 10, 28, 2, 5, 0), is_dst=False)) self.hass.block_till_done() self.assertEqual(0, len(specific_runs)) self._send_time_changed( tz.localize(datetime(2018, 10, 28, 2, 55, 0), is_dst=False)) self.hass.block_till_done() self.assertEqual(1, len(specific_runs)) self._send_time_changed( tz.localize(datetime(2018, 10, 28, 2, 5, 0), is_dst=True)) self.hass.block_till_done() self.assertEqual(1, len(specific_runs)) self._send_time_changed( tz.localize(datetime(2018, 10, 28, 2, 55, 0), is_dst=True)) self.hass.block_till_done() self.assertEqual(2, len(specific_runs)) unsub()
def test_track_time_change(self): """Test tracking time change.""" wildcard_runs = [] specific_runs = [] unsub = track_time_change(self.hass, lambda x: wildcard_runs.append(1)) unsub_utc = track_utc_time_change( self.hass, lambda x: specific_runs.append(1), second=[0, 30]) self._send_time_changed(datetime(2014, 5, 24, 12, 0, 0)) self.hass.block_till_done() self.assertEqual(1, len(specific_runs)) self.assertEqual(1, len(wildcard_runs)) self._send_time_changed(datetime(2014, 5, 24, 12, 0, 15)) self.hass.block_till_done() self.assertEqual(1, len(specific_runs)) self.assertEqual(2, len(wildcard_runs)) self._send_time_changed(datetime(2014, 5, 24, 12, 0, 30)) self.hass.block_till_done() self.assertEqual(2, len(specific_runs)) self.assertEqual(3, len(wildcard_runs)) unsub() unsub_utc() self._send_time_changed(datetime(2014, 5, 24, 12, 0, 30)) self.hass.block_till_done() self.assertEqual(2, len(specific_runs)) self.assertEqual(3, len(wildcard_runs))
def test_periodic_task_entering_dst(self): """Test periodic task behavior when entering dst.""" tz = dt_util.get_time_zone('Europe/Vienna') dt_util.set_default_time_zone(tz) specific_runs = [] unsub = track_time_change( self.hass, lambda x: specific_runs.append(1), hour=2, minute=30, second=0) self._send_time_changed( tz.localize(datetime(2018, 3, 25, 1, 50, 0))) self.hass.block_till_done() assert 0 == len(specific_runs) self._send_time_changed( tz.localize(datetime(2018, 3, 25, 3, 50, 0))) self.hass.block_till_done() assert 0 == len(specific_runs) self._send_time_changed( tz.localize(datetime(2018, 3, 26, 1, 50, 0))) self.hass.block_till_done() assert 0 == len(specific_runs) self._send_time_changed( tz.localize(datetime(2018, 3, 26, 2, 50, 0))) self.hass.block_till_done() assert 1 == len(specific_runs) unsub()
def test_periodic_task_leaving_dst(self): """Test periodic task behavior when leaving dst.""" tz = dt_util.get_time_zone('Europe/Vienna') dt_util.set_default_time_zone(tz) specific_runs = [] unsub = track_time_change( self.hass, lambda x: specific_runs.append(1), hour=2, minute=30, second=0) self._send_time_changed( tz.localize(datetime(2018, 10, 28, 2, 5, 0), is_dst=False)) self.hass.block_till_done() assert 0 == len(specific_runs) self._send_time_changed( tz.localize(datetime(2018, 10, 28, 2, 55, 0), is_dst=False)) self.hass.block_till_done() assert 1 == len(specific_runs) self._send_time_changed( tz.localize(datetime(2018, 10, 28, 2, 5, 0), is_dst=True)) self.hass.block_till_done() assert 1 == len(specific_runs) self._send_time_changed( tz.localize(datetime(2018, 10, 28, 2, 55, 0), is_dst=True)) self.hass.block_till_done() assert 2 == len(specific_runs) unsub()
def setup(hass, config): """Set up the updater component.""" if 'dev' in CURRENT_VERSION: # This component only makes sense in release versions _LOGGER.warning("Running on 'dev', only analytics will be submitted") config = config.get(DOMAIN, {}) huuid = _load_uuid(hass) if config.get(CONF_REPORTING) else None # Update daily, start 1 hour after startup _dt = datetime.now() + timedelta(hours=1) event.track_time_change( hass, lambda _: check_newest_version(hass, huuid), hour=_dt.hour, minute=_dt.minute, second=_dt.second) return True
def setup(hass, config): """ Set up our service call interface, a refresher task that stops itself and hook into the zwave events """ global LOCKSI LOCKSI = LocksInterface(hass) LOCKSI.schedule_update_ha_state() hass.services.register( DOMAIN, "setusercode", LOCKSI.set_user_code, { 'description': "Sets a user code on all locks", 'fields': { 'newname': { 'description': 'A name for reference' }, 'code': { 'description': 'The code to use as an ascii string of [0-9]' } } }) hass.services.register( DOMAIN, "clearusercode", LOCKSI.clear_user_code, { 'description': "Clear a user code on all locks using name", 'fields': { 'oldname': { 'description': 'The name of the code' } } }) hass.services.register( DOMAIN, "renameusercode", LOCKSI.rename_user_code, { 'description': "Rename a user code on all locks", 'fields': { 'oldname': { 'description': 'The present name for the code' }, 'newname': { 'description': 'The new name for the code' } } }) dispatcher.connect(LOCKSI.value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED) #, weak=False) dispatcher.connect(LOCKSI.value_changed, ZWaveNetwork.SIGNAL_VALUE_CHANGED) #, weak=False) track_time_change(hass, LOCKSI.refresh_unknown, second='/5') return True
def do_authentication(hass, config): """Notify user of actions and authenticate. Notify user of user_code and verification_url then poll until we have an access token. """ from oauth2client import client as oauth2client from oauth2client import file as oauth2file oauth = oauth2client.OAuth2WebServerFlow( client_id=config[CONF_CLIENT_ID], client_secret=config[CONF_CLIENT_SECRET], scope=SCOPES, redirect_uri='Home-Assistant.io', ) try: dev_flow = oauth.step1_get_device_and_user_codes() except oauth2client.OAuth2DeviceCodeError as err: hass.components.persistent_notification.create( 'Error: {}<br />You will need to restart hass after fixing.' ''.format(err), title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID) return False hass.components.persistent_notification.create( 'In order to authorize Home-Assistant to view your Google Fit data ' 'you must visit: <a href="{}" target="_blank">{}</a> and enter ' 'code: {}'.format(dev_flow.verification_url, dev_flow.verification_url, dev_flow.user_code), title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID) def step2_exchange(now): """Keep trying to validate the user_code until it expires.""" if now >= util.dt.as_local(dev_flow.user_code_expiry): hass.components.persistent_notification.create( 'Authentication code expired, please restart ' 'Home-Assistant and try again', title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID) listener() try: credentials = oauth.step2_exchange(device_flow_info=dev_flow) except oauth2client.FlowExchangeError: # not ready yet, call again return name = config.get(const.CONF_NAME) TOKEN_FILE = '.{}_{}.token'.format(name, SENSOR) storage = oauth2file.Storage(hass.config.path(TOKEN_FILE)) storage.put(credentials) listener() listener = track_time_change(hass, step2_exchange, second=range(0, 60, dev_flow.interval)) return True
def __init__(self, hass, min_colortemp, max_colortemp, transition_colortemp, sunrise_offset, sunset_offset, sunrise_time, sunset_time, latitude, longitude, elevation, interval, transition): self.hass = hass self.data = {} self.data['min_colortemp'] = min_colortemp self.data['max_colortemp'] = max_colortemp self.data[ 'transition_colortemp'] = transition_colortemp if transition_colortemp else min_colortemp self.data['sunrise_offset'] = sunrise_offset self.data['sunset_offset'] = sunset_offset self.data['sunrise_time'] = sunrise_time self.data['sunset_time'] = sunset_time self.data['latitude'] = latitude self.data['longitude'] = longitude self.data['elevation'] = elevation self.data['interval'] = interval self.data['transition'] = transition self.data['timezone'] = self.get_timezone() self.data['percent'] = self.calc_percent() self.data['colortemp'] = self.calc_colortemp() self.data['rgb_color'] = self.calc_rgb() self.data['xy_color'] = self.calc_xy() self.data['hs_color'] = self.calc_hs() self.update = Throttle(timedelta(seconds=interval))(self._update) if self.data['sunrise_time'] is not None: track_time_change( self.hass, self._update, hour=int(self.data['sunrise_time'].strftime("%H")), minute=int(self.data['sunrise_time'].strftime("%M")), second=int(self.data['sunrise_time'].strftime("%S"))) else: track_sunrise(self.hass, self._update, self.data['sunrise_offset']) if self.data['sunset_time'] is not None: track_time_change( self.hass, self._update, hour=int(self.data['sunset_time'].strftime("%H")), minute=int(self.data['sunset_time'].strftime("%M")), second=int(self.data['sunset_time'].strftime("%S"))) else: track_sunset(self.hass, self._update, self.data['sunset_offset'])
def turn_on(self, **kwargs): """Turn on flux.""" if not self._state: # make initial update self.flux_update() self._state = True self.unsub_tracker = track_time_change(self.hass, self.flux_update, second=[0, 30]) self.schedule_update_ha_state()
def setup(hass, config): """Setup example component.""" target_entity = config[DOMAIN].get('target') name = config[DOMAIN].get('name', DOMAIN + ' ' + target_entity) object_id_enable = DOMAIN + '_' + target_entity + '_enable' object_id_hour = DOMAIN + '_' + target_entity + '_hour' object_id_temp = DOMAIN + '_' + target_entity + '_temp' def activate(now): if hass.states.get('input_boolean.' + object_id_enable).state == 'off': return if not str(now.hour) == str(int(float(hass.states.get('input_slider.' + object_id_hour).state))): return climate.set_temperature(hass, hass.states.get('input_slider.' + object_id_temp).state, entity_id='climate.'+target_entity) hass.states.set('input_boolean.' + object_id_enable, 'off') _config = config['input_boolean'] _config[object_id_enable] = {'name': 'Enable', 'initial': False} config['input_boolean'] = _config input_boolean.setup(hass, config) _config = config['input_slider'] _config[object_id_hour] = {'name': 'Hour', 'initial': 15, 'min': 7, 'max': 23, 'step': 1} _config[object_id_temp] = {'name': 'Temp', 'initial': 20, 'min': 17, 'max': 22, 'step': 0.5} config['input_slider'] = _config input_slider.setup(hass, config) #_config = {'platform': 'template', 'sensors': { object_id_hour: {'value_template': '{{ states("input_slider.' + object_id_hour + '") | round(0) }}'}}} #config['sensor'] = _config #sensor.setup(hass, config) group.Group(hass,name, ['input_boolean.' + object_id_enable, 'input_slider.' + object_id_hour, 'input_slider.' + object_id_temp]) track_time_change(hass, activate, minute=0, second=2) def enable(entity_id, old_state, new_state): hass.states.set('input_boolean.' + object_id_enable, 'on') track_state_change(hass, ['input_slider.' + object_id_hour, 'input_slider.' + object_id_temp], enable) return True
def setup(hass, config): """Setup the updater component.""" if 'dev' in CURRENT_VERSION: _LOGGER.warning("Updater not supported in development version") return False def check_newest_version(_=None): """Check if a new version is available and report if one is.""" newest = get_newest_version() if newest != CURRENT_VERSION and newest is not None: hass.states.set( ENTITY_ID, newest, {ATTR_FRIENDLY_NAME: 'Update available'}) event.track_time_change( hass, check_newest_version, hour=[0, 12], minute=0, second=0) check_newest_version() return True
def turn_on(self, **kwargs): """Turn on flux.""" if self.is_on: return # Make initial update self.flux_update() self.unsub_tracker = track_time_change( self.hass, self.flux_update, second=[0, self._interval]) self.schedule_update_ha_state()
def __init__(self, hass, config): self.hass = hass self.attr = { CONF_FRIENDLY_NAME: config.get(CONF_NAME), ATTR_DATETIME_INPUT: config.get(CONF_DATETIME_INPUT), } self._status = STATE_OFF self._name = config.get(CONF_NAME) if not config.get(CONF_NAME): self._name = (config.get(CONF_DATETIME_INPUT).replace(".", "_") + DEFAULT_SENSOR_NAME_SUFFIX) # http://dev-docs.home-assistant.io/en/master/api/helpers.html#homeassistant.helpers.event.track_state_change eventHelper.track_state_change(self.hass, self.attr[ATTR_DATETIME_INPUT], self.state_changed) # http://dev-docs.home-assistant.io/en/master/api/helpers.html#homeassistant.helpers.event.track_time_change eventHelper.track_time_change(self.hass, self.time_changed) self.hass_state_update()
def setup(hass, config): """Setup the updater component.""" if 'dev' in CURRENT_VERSION: _LOGGER.warning("Updater not supported in development version") return False def check_newest_version(_=None): """Check if a new version is available and report if one is.""" newest = get_newest_version() if newest != CURRENT_VERSION and newest is not None: hass.states.set(ENTITY_ID, newest, {ATTR_FRIENDLY_NAME: 'Update available'}) event.track_time_change(hass, check_newest_version, hour=[0, 12], minute=0, second=0) check_newest_version() return True
def trigger(hass, config, action): """Listen for state changes based on configuration.""" if CONF_AFTER in config: after = config.get(CONF_AFTER) hours, minutes, seconds = after.hour, after.minute, after.second else: hours = config.get(CONF_HOURS) minutes = config.get(CONF_MINUTES) seconds = config.get(CONF_SECONDS) def time_automation_listener(now): """Listen for time changes and calls action.""" action({ 'trigger': { 'platform': 'time', 'now': now, }, }) track_time_change(hass, time_automation_listener, hour=hours, minute=minutes, second=seconds) return True
def __init__(self, hass, hour, minute, entity_id): self.hass = hass self.hour = hour self.minute = minute self.entity_id = entity_id _LOGGER.info('Setting up an alarm for %02d:%02d - %s' % (self.hour, self.minute, self.entity_id)) self.unsubscribe = track_time_change(self.hass, lambda now: self._update(), hour=self.hour, minute=self.minute, second=0)
def __init__(self, sensor_type, client, hass): """Initialize the sensor.""" self._sensor_type = sensor_type self._client = client self._state = None self._channel_name = None self._web_adress = None def _update(now=None): stations = client.get_stations() shuffle(stations) for station in stations: print(station) if self._sensor_type in station["canonical_name"]: station_id = station["station_id"] print(client.get_station(station_id=station_id)) while client.get_station(station_id=station_id)['playable'] == 0: sub_stations = client.get_stations_by_id(parent_id=station_id) shuffle(sub_stations) station_id = sub_stations[0]['station_id'] for sub_station in sub_stations: print(station) if '8hours' in station["canonical_name"]: station_id = sub_station['station_id'] break try: token_data = client.get_token(station_id=station_id) self._web_adress = "https://stream.brain.fm/?tkn=" + token_data["session_token"] mp3file = urlopen(self._web_adress) with open('/home/dahoiv/.homeassistant/www/sleep.mp3','wb') as output: output.write(mp3file.read()) self._state = token_data["name"] print(token_data) break except: continue track_time_change(hass, _update, hour=9, minute=14, second=36)
def __init__(self, hass, config): self.hass = hass authtoken_path = get_default_config_dir() + "gmusic_authtoken" if os.path.isfile(authtoken_path): with open(authtoken_path, 'rb') as handle: authtoken = pickle.load(handle) else: authtoken = None self._api = GMusic() logged_in = self._api.login(config.get('user'), config.get('password'), config.get('device_id'), authtoken) if not logged_in: _LOGGER.error( "Failed to log in, check http://unofficial-google-music-api.readthedocs.io/en/latest/reference/mobileclient.html#gmusicapi.clients.Mobileclient.login" ) return False with open(authtoken_path, 'wb') as f: pickle.dump(self._api.session._authtoken, f) self._playlist = "input_select." + config.get("playlist", "") self._media_player = "input_select." + config.get("media_player", "") self._entity_ids = [] self._playing = False self._playlists = [] self._tracks = [] self._next_track_no = 0 self._playlist_to_index = {} self._unsub_tracker = None self._name = "Google music" track_time_change(hass, self._update_playlist, hour=[15, 6], minute=46, second=46) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, self._update_playlist)
def turn_on(self): """Turn on flux.""" # Make initial update self.flux_force_update() if self.is_on: return self.unsub_tracker = track_time_change( self.hass, self.flux_update, second=[0, self._interval]) if self._init_on_turn_on: self.unsub_turn_on_trigger = async_track_state_change(self.hass, self._lights, self.flux_force_update_cb, 'off', 'on') else: self.unsub_turn_on_trigger = None self.schedule_update_ha_state()
def trigger(hass, config, action): """Listen for state changes based on configuration.""" if CONF_AFTER in config: after = config.get(CONF_AFTER) hours, minutes, seconds = after.hour, after.minute, after.second else: hours = config.get(CONF_HOURS) minutes = config.get(CONF_MINUTES) seconds = config.get(CONF_SECONDS) def time_automation_listener(now): """Listen for time changes and calls action.""" action({ 'trigger': { 'platform': 'time', 'now': now, }, }) return track_time_change(hass, time_automation_listener, hour=hours, minute=minutes, second=seconds)
def setup(hass, config): """Set up Z-Wave. Will automatically load components to support devices found on the network. """ from pydispatch import dispatcher # pylint: disable=import-error from openzwave.option import ZWaveOption from openzwave.network import ZWaveNetwork from openzwave.group import ZWaveGroup # Load configuration use_debug = config[DOMAIN].get(CONF_DEBUG) autoheal = config[DOMAIN].get(CONF_AUTOHEAL) device_config = EntityValues( config[DOMAIN][CONF_DEVICE_CONFIG], config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN], config[DOMAIN][CONF_DEVICE_CONFIG_GLOB]) new_entity_ids = config[DOMAIN][CONF_NEW_ENTITY_IDS] if not new_entity_ids: _LOGGER.warning( "ZWave entity_ids will soon be changing. To opt in to new " "entity_ids now, set `new_entity_ids: true` under zwave in your " "configuration.yaml. See the following blog post for details: " "https://home-assistant.io/blog/2017/06/15/zwave-entity-ids/") # Setup options options = ZWaveOption( config[DOMAIN].get(CONF_USB_STICK_PATH), user_path=hass.config.config_dir, config_path=config[DOMAIN].get(CONF_CONFIG_PATH)) options.set_console_output(use_debug) if CONF_NETWORK_KEY in config[DOMAIN]: options.addOption("NetworkKey", config[DOMAIN][CONF_NETWORK_KEY]) options.lock() network = hass.data[DATA_NETWORK] = ZWaveNetwork(options, autostart=False) hass.data[DATA_DEVICES] = {} hass.data[DATA_ENTITY_VALUES] = [] if use_debug: # pragma: no cover def log_all(signal, value=None): """Log all the signals.""" print("") print("SIGNAL *****", signal) if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED, ZWaveNetwork.SIGNAL_VALUE_ADDED, ZWaveNetwork.SIGNAL_SCENE_EVENT, ZWaveNetwork.SIGNAL_NODE_EVENT, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED): pprint(_obj_to_dict(value)) print("") dispatcher.connect(log_all, weak=False) def value_added(node, value): """Handle new added value to a node on the network.""" # Check if this value should be tracked by an existing entity for values in hass.data[DATA_ENTITY_VALUES]: values.check_value(value) for schema in DISCOVERY_SCHEMAS: if not check_node_schema(node, schema): continue if not check_value_schema( value, schema[const.DISC_VALUES][const.DISC_PRIMARY]): continue values = ZWaveDeviceEntityValues( hass, schema, value, config, device_config) # We create a new list and update the reference here so that # the list can be safely iterated over in the main thread new_values = hass.data[DATA_ENTITY_VALUES] + [values] hass.data[DATA_ENTITY_VALUES] = new_values component = EntityComponent(_LOGGER, DOMAIN, hass) def node_added(node): """Handle a new node on the network.""" entity = ZWaveNodeEntity(node, network, new_entity_ids) name = node_name(node) if new_entity_ids: generated_id = generate_entity_id(DOMAIN + '.{}', name, []) else: generated_id = entity.entity_id node_config = device_config.get(generated_id) if node_config.get(CONF_IGNORED): _LOGGER.info( "Ignoring node entity %s due to device settings", generated_id) return component.add_entities([entity]) def network_ready(): """Handle the query of all awake nodes.""" _LOGGER.info("Zwave network is ready for use. All awake nodes " "have been queried. Sleeping nodes will be " "queried when they awake.") hass.bus.fire(const.EVENT_NETWORK_READY) def network_complete(): """Handle the querying of all nodes on network.""" _LOGGER.info("Z-Wave network is complete. All nodes on the network " "have been queried") hass.bus.fire(const.EVENT_NETWORK_COMPLETE) dispatcher.connect( value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False) dispatcher.connect( node_added, ZWaveNetwork.SIGNAL_NODE_ADDED, weak=False) dispatcher.connect( network_ready, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, weak=False) dispatcher.connect( network_complete, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED, weak=False) def add_node(service): """Switch into inclusion mode.""" _LOGGER.info("Z-Wave add_node have been initialized") network.controller.add_node() def add_node_secure(service): """Switch into secure inclusion mode.""" _LOGGER.info("Z-Wave add_node_secure have been initialized") network.controller.add_node(True) def remove_node(service): """Switch into exclusion mode.""" _LOGGER.info("Z-Wwave remove_node have been initialized") network.controller.remove_node() def cancel_command(service): """Cancel a running controller command.""" _LOGGER.info("Cancel running Z-Wave command") network.controller.cancel_command() def heal_network(service): """Heal the network.""" _LOGGER.info("Z-Wave heal running") network.heal() def soft_reset(service): """Soft reset the controller.""" _LOGGER.info("Z-Wave soft_reset have been initialized") network.controller.soft_reset() def test_network(service): """Test the network by sending commands to all the nodes.""" _LOGGER.info("Z-Wave test_network have been initialized") network.test() def stop_network(_service_or_event): """Stop Z-Wave network.""" _LOGGER.info("Stopping Z-Wave network") network.stop() if hass.state == CoreState.running: hass.bus.fire(const.EVENT_NETWORK_STOP) def rename_node(service): """Rename a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] name = service.data.get(const.ATTR_NAME) node.name = name _LOGGER.info( "Renamed Z-Wave node %d to %s", node_id, name) def rename_value(service): """Rename a node value.""" node_id = service.data.get(const.ATTR_NODE_ID) value_id = service.data.get(const.ATTR_VALUE_ID) node = network.nodes[node_id] value = node.values[value_id] name = service.data.get(const.ATTR_NAME) value.label = name _LOGGER.info( "Renamed Z-Wave value (Node %d Value %d) to %s", node_id, value_id, name) def set_poll_intensity(service): """Set the polling intensity of a node value.""" node_id = service.data.get(const.ATTR_NODE_ID) value_id = service.data.get(const.ATTR_VALUE_ID) node = network.nodes[node_id] value = node.values[value_id] intensity = service.data.get(const.ATTR_POLL_INTENSITY) if intensity == 0: if value.disable_poll(): _LOGGER.info("Polling disabled (Node %d Value %d)", node_id, value_id) return _LOGGER.info("Polling disabled failed (Node %d Value %d)", node_id, value_id) else: if value.enable_poll(intensity): _LOGGER.info( "Set polling intensity (Node %d Value %d) to %s", node_id, value_id, intensity) return _LOGGER.info("Set polling intensity failed (Node %d Value %d)", node_id, value_id) def remove_failed_node(service): """Remove failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info("Trying to remove zwave node %d", node_id) network.controller.remove_failed_node(node_id) def replace_failed_node(service): """Replace failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info("Trying to replace zwave node %d", node_id) network.controller.replace_failed_node(node_id) def set_config_parameter(service): """Set a config parameter to a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) selection = service.data.get(const.ATTR_CONFIG_VALUE) size = service.data.get(const.ATTR_CONFIG_SIZE) for value in ( node.get_values(class_id=const.COMMAND_CLASS_CONFIGURATION) .values()): if value.index != param: continue if value.type in [const.TYPE_LIST, const.TYPE_BOOL]: value.data = selection _LOGGER.info("Setting config list parameter %s on Node %s " "with selection %s", param, node_id, selection) return value.data = int(selection) _LOGGER.info("Setting config parameter %s on Node %s " "with selection %s", param, node_id, selection) return node.set_config_param(param, selection, size) _LOGGER.info("Setting unknown config parameter %s on Node %s " "with selection %s", param, node_id, selection) def print_config_parameter(service): """Print a config parameter from a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) _LOGGER.info("Config parameter %s on Node %s: %s", param, node_id, get_config_value(node, param)) def print_node(service): """Print all information about z-wave node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] nice_print_node(node) def set_wakeup(service): """Set wake-up interval of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] value = service.data.get(const.ATTR_CONFIG_VALUE) if node.can_wake_up(): for value_id in node.get_values( class_id=const.COMMAND_CLASS_WAKE_UP): node.values[value_id].data = value _LOGGER.info("Node %s wake-up set to %d", node_id, value) else: _LOGGER.info("Node %s is not wakeable", node_id) def change_association(service): """Change an association in the zwave network.""" association_type = service.data.get(const.ATTR_ASSOCIATION) node_id = service.data.get(const.ATTR_NODE_ID) target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID) group = service.data.get(const.ATTR_GROUP) instance = service.data.get(const.ATTR_INSTANCE) node = ZWaveGroup(group, network, node_id) if association_type == 'add': node.add_association(target_node_id, instance) _LOGGER.info("Adding association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) if association_type == 'remove': node.remove_association(target_node_id, instance) _LOGGER.info("Removing association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) @asyncio.coroutine def async_refresh_entity(service): """Refresh values that specific entity depends on.""" entity_id = service.data.get(ATTR_ENTITY_ID) async_dispatcher_send( hass, SIGNAL_REFRESH_ENTITY_FORMAT.format(entity_id)) def refresh_node(service): """Refresh all node info.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] node.refresh_info() def reset_node_meters(service): """Reset meter counters of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) instance = service.data.get(const.ATTR_INSTANCE) node = network.nodes[node_id] for value in ( node.get_values(class_id=const.COMMAND_CLASS_METER) .values()): if value.index != const.INDEX_METER_RESET: continue if value.instance != instance: continue network.manager.pressButton(value.value_id) network.manager.releaseButton(value.value_id) _LOGGER.info("Resetting meters on node %s instance %s....", node_id, instance) return _LOGGER.info("Node %s on instance %s does not have resettable " "meters.", node_id, instance) def heal_node(service): """Heal a node on the network.""" node_id = service.data.get(const.ATTR_NODE_ID) update_return_routes = service.data.get(const.ATTR_RETURN_ROUTES) node = network.nodes[node_id] _LOGGER.info("Z-Wave node heal running for node %s", node_id) node.heal(update_return_routes) def test_node(service): """Send test messages to a node on the network.""" node_id = service.data.get(const.ATTR_NODE_ID) messages = service.data.get(const.ATTR_MESSAGES) node = network.nodes[node_id] _LOGGER.info("Sending %s test-messages to node %s.", messages, node_id) node.test(messages) def start_zwave(_service_or_event): """Startup Z-Wave network.""" _LOGGER.info("Starting Z-Wave network...") network.start() hass.bus.fire(const.EVENT_NETWORK_START) @asyncio.coroutine def _check_awaked(): """Wait for Z-wave awaked state (or timeout) and finalize start.""" _LOGGER.debug( "network state: %d %s", network.state, network.state_str) start_time = dt_util.utcnow() while True: waited = int((dt_util.utcnow()-start_time).total_seconds()) if network.state >= network.STATE_AWAKED: # Need to be in STATE_AWAKED before talking to nodes. _LOGGER.info("Z-Wave ready after %d seconds", waited) break elif waited >= const.NETWORK_READY_WAIT_SECS: # Wait up to NETWORK_READY_WAIT_SECS seconds for the Z-Wave # network to be ready. _LOGGER.warning( "Z-Wave not ready after %d seconds, continuing anyway", waited) _LOGGER.info( "final network state: %d %s", network.state, network.state_str) break else: yield from asyncio.sleep(1, loop=hass.loop) hass.async_add_job(_finalize_start) hass.add_job(_check_awaked) def _finalize_start(): """Perform final initializations after Z-Wave network is awaked.""" polling_interval = convert( config[DOMAIN].get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: network.set_poll_interval(polling_interval, False) poll_interval = network.get_poll_interval() _LOGGER.info("Z-Wave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network) # Register node services for Z-Wave network hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node) hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE, add_node_secure) hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node) hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND, cancel_command) hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK, heal_network) hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset) hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK, test_network) hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_network) hass.services.register(DOMAIN, const.SERVICE_START_NETWORK, start_zwave) hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node, schema=RENAME_NODE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_RENAME_VALUE, rename_value, schema=RENAME_VALUE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER, set_config_parameter, schema=SET_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_CONFIG_PARAMETER, print_config_parameter, schema=PRINT_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REMOVE_FAILED_NODE, remove_failed_node, schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REPLACE_FAILED_NODE, replace_failed_node, schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_CHANGE_ASSOCIATION, change_association, schema=CHANGE_ASSOCIATION_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_WAKEUP, set_wakeup, schema=SET_WAKEUP_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_NODE, print_node, schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_ENTITY, async_refresh_entity, schema=REFRESH_ENTITY_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_NODE, refresh_node, schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_RESET_NODE_METERS, reset_node_meters, schema=RESET_NODE_METERS_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_POLL_INTENSITY, set_poll_intensity, schema=SET_POLL_INTENSITY_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_HEAL_NODE, heal_node, schema=HEAL_NODE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_TEST_NODE, test_node, schema=TEST_NODE_SCHEMA) # Setup autoheal if autoheal: _LOGGER.info("Z-Wave network autoheal is enabled") track_time_change(hass, heal_network, hour=0, minute=0, second=0) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave) return True
def setup(hass, config): """Set up Z-Wave. Will automatically load components to support devices found on the network. """ descriptions = conf_util.load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) from pydispatch import dispatcher # pylint: disable=import-error from openzwave.option import ZWaveOption from openzwave.network import ZWaveNetwork from openzwave.group import ZWaveGroup # Load configuration use_debug = config[DOMAIN].get(CONF_DEBUG) autoheal = config[DOMAIN].get(CONF_AUTOHEAL) device_config = EntityValues(config[DOMAIN][CONF_DEVICE_CONFIG], config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN], config[DOMAIN][CONF_DEVICE_CONFIG_GLOB]) new_entity_ids = config[DOMAIN][CONF_NEW_ENTITY_IDS] if not new_entity_ids: _LOGGER.warning( "ZWave entity_ids will soon be changing. To opt in to new " "entity_ids now, set `new_entity_ids: true` under zwave in your " "configuration.yaml. See the following blog post for details: " "https://home-assistant.io/blog/2017/06/15/zwave-entity-ids/") # Setup options options = ZWaveOption(config[DOMAIN].get(CONF_USB_STICK_PATH), user_path=hass.config.config_dir, config_path=config[DOMAIN].get(CONF_CONFIG_PATH)) options.set_console_output(use_debug) if CONF_NETWORK_KEY in config[DOMAIN]: options.addOption("NetworkKey", config[DOMAIN][CONF_NETWORK_KEY]) options.lock() network = hass.data[DATA_NETWORK] = ZWaveNetwork(options, autostart=False) hass.data[DATA_DEVICES] = {} hass.data[DATA_ENTITY_VALUES] = [] if use_debug: # pragma: no cover def log_all(signal, value=None): """Log all the signals.""" print("") print("SIGNAL *****", signal) if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED, ZWaveNetwork.SIGNAL_VALUE_ADDED, ZWaveNetwork.SIGNAL_SCENE_EVENT, ZWaveNetwork.SIGNAL_NODE_EVENT, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED): pprint(_obj_to_dict(value)) print("") dispatcher.connect(log_all, weak=False) def value_added(node, value): """Handle new added value to a node on the network.""" # Check if this value should be tracked by an existing entity for values in hass.data[DATA_ENTITY_VALUES]: values.check_value(value) for schema in DISCOVERY_SCHEMAS: if not check_node_schema(node, schema): continue if not check_value_schema( value, schema[const.DISC_VALUES][const.DISC_PRIMARY]): continue values = ZWaveDeviceEntityValues(hass, schema, value, config, device_config) # We create a new list and update the reference here so that # the list can be safely iterated over in the main thread new_values = hass.data[DATA_ENTITY_VALUES] + [values] hass.data[DATA_ENTITY_VALUES] = new_values component = EntityComponent(_LOGGER, DOMAIN, hass) def node_added(node): """Handle a new node on the network.""" entity = ZWaveNodeEntity(node, network, new_entity_ids) name = node_name(node) if new_entity_ids: generated_id = generate_entity_id(DOMAIN + '.{}', name, []) else: generated_id = entity.entity_id node_config = device_config.get(generated_id) if node_config.get(CONF_IGNORED): _LOGGER.info("Ignoring node entity %s due to device settings", generated_id) return component.add_entities([entity]) def network_ready(): """Handle the query of all awake nodes.""" _LOGGER.info("Zwave network is ready for use. All awake nodes " "have been queried. Sleeping nodes will be " "queried when they awake.") hass.bus.fire(const.EVENT_NETWORK_READY) def network_complete(): """Handle the querying of all nodes on network.""" _LOGGER.info("Z-Wave network is complete. All nodes on the network " "have been queried") hass.bus.fire(const.EVENT_NETWORK_COMPLETE) dispatcher.connect(value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False) dispatcher.connect(node_added, ZWaveNetwork.SIGNAL_NODE_ADDED, weak=False) dispatcher.connect(network_ready, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, weak=False) dispatcher.connect(network_complete, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED, weak=False) def add_node(service): """Switch into inclusion mode.""" _LOGGER.info("Z-Wave add_node have been initialized") network.controller.add_node() def add_node_secure(service): """Switch into secure inclusion mode.""" _LOGGER.info("Z-Wave add_node_secure have been initialized") network.controller.add_node(True) def remove_node(service): """Switch into exclusion mode.""" _LOGGER.info("Z-Wwave remove_node have been initialized") network.controller.remove_node() def cancel_command(service): """Cancel a running controller command.""" _LOGGER.info("Cancel running Z-Wave command") network.controller.cancel_command() def heal_network(service): """Heal the network.""" _LOGGER.info("Z-Wave heal running") network.heal() def soft_reset(service): """Soft reset the controller.""" _LOGGER.info("Z-Wave soft_reset have been initialized") network.controller.soft_reset() def test_network(service): """Test the network by sending commands to all the nodes.""" _LOGGER.info("Z-Wave test_network have been initialized") network.test() def stop_network(_service_or_event): """Stop Z-Wave network.""" _LOGGER.info("Stopping Z-Wave network") network.stop() if hass.state == CoreState.running: hass.bus.fire(const.EVENT_NETWORK_STOP) def rename_node(service): """Rename a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] name = service.data.get(const.ATTR_NAME) node.name = name _LOGGER.info("Renamed Z-Wave node %d to %s", node_id, name) def rename_value(service): """Rename a node value.""" node_id = service.data.get(const.ATTR_NODE_ID) value_id = service.data.get(const.ATTR_VALUE_ID) node = network.nodes[node_id] value = node.values[value_id] name = service.data.get(const.ATTR_NAME) value.label = name _LOGGER.info("Renamed Z-Wave value (Node %d Value %d) to %s", node_id, value_id, name) def set_poll_intensity(service): """Set the polling intensity of a node value.""" node_id = service.data.get(const.ATTR_NODE_ID) value_id = service.data.get(const.ATTR_VALUE_ID) node = network.nodes[node_id] value = node.values[value_id] intensity = service.data.get(const.ATTR_POLL_INTENSITY) if intensity == 0: if value.disable_poll(): _LOGGER.info("Polling disabled (Node %d Value %d)", node_id, value_id) return _LOGGER.info("Polling disabled failed (Node %d Value %d)", node_id, value_id) else: if value.enable_poll(intensity): _LOGGER.info("Set polling intensity (Node %d Value %d) to %s", node_id, value_id, intensity) return _LOGGER.info("Set polling intensity failed (Node %d Value %d)", node_id, value_id) def remove_failed_node(service): """Remove failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info("Trying to remove zwave node %d", node_id) network.controller.remove_failed_node(node_id) def replace_failed_node(service): """Replace failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info("Trying to replace zwave node %d", node_id) network.controller.replace_failed_node(node_id) def set_config_parameter(service): """Set a config parameter to a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) selection = service.data.get(const.ATTR_CONFIG_VALUE) size = service.data.get(const.ATTR_CONFIG_SIZE) for value in (node.get_values( class_id=const.COMMAND_CLASS_CONFIGURATION).values()): if value.index != param: continue if value.type in [const.TYPE_LIST, const.TYPE_BOOL]: value.data = selection _LOGGER.info( "Setting config list parameter %s on Node %s " "with selection %s", param, node_id, selection) return value.data = int(selection) _LOGGER.info( "Setting config parameter %s on Node %s " "with selection %s", param, node_id, selection) return node.set_config_param(param, selection, size) _LOGGER.info( "Setting unknown config parameter %s on Node %s " "with selection %s", param, node_id, selection) def print_config_parameter(service): """Print a config parameter from a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) _LOGGER.info("Config parameter %s on Node %s: %s", param, node_id, get_config_value(node, param)) def print_node(service): """Print all information about z-wave node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] nice_print_node(node) def set_wakeup(service): """Set wake-up interval of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] value = service.data.get(const.ATTR_CONFIG_VALUE) if node.can_wake_up(): for value_id in node.get_values( class_id=const.COMMAND_CLASS_WAKE_UP): node.values[value_id].data = value _LOGGER.info("Node %s wake-up set to %d", node_id, value) else: _LOGGER.info("Node %s is not wakeable", node_id) def change_association(service): """Change an association in the zwave network.""" association_type = service.data.get(const.ATTR_ASSOCIATION) node_id = service.data.get(const.ATTR_NODE_ID) target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID) group = service.data.get(const.ATTR_GROUP) instance = service.data.get(const.ATTR_INSTANCE) node = ZWaveGroup(group, network, node_id) if association_type == 'add': node.add_association(target_node_id, instance) _LOGGER.info( "Adding association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) if association_type == 'remove': node.remove_association(target_node_id, instance) _LOGGER.info( "Removing association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) @asyncio.coroutine def async_refresh_entity(service): """Refresh values that specific entity depends on.""" entity_id = service.data.get(ATTR_ENTITY_ID) async_dispatcher_send(hass, SIGNAL_REFRESH_ENTITY_FORMAT.format(entity_id)) def refresh_node(service): """Refresh all node info.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] node.refresh_info() def reset_node_meters(service): """Reset meter counters of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) instance = service.data.get(const.ATTR_INSTANCE) node = network.nodes[node_id] for value in (node.get_values( class_id=const.COMMAND_CLASS_METER).values()): if value.index != const.INDEX_METER_RESET: continue if value.instance != instance: continue network.manager.pressButton(value.value_id) network.manager.releaseButton(value.value_id) _LOGGER.info("Resetting meters on node %s instance %s....", node_id, instance) return _LOGGER.info( "Node %s on instance %s does not have resettable " "meters.", node_id, instance) def start_zwave(_service_or_event): """Startup Z-Wave network.""" _LOGGER.info("Starting Z-Wave network...") network.start() hass.bus.fire(const.EVENT_NETWORK_START) # Need to be in STATE_AWAKED before talking to nodes. # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network # to be ready. for i in range(const.NETWORK_READY_WAIT_SECS): _LOGGER.debug("network state: %d %s", network.state, network.state_str) if network.state >= network.STATE_AWAKED: _LOGGER.info("Z-Wave ready after %d seconds", i) break time.sleep(1) else: _LOGGER.warning( "zwave not ready after %d seconds, continuing anyway", const.NETWORK_READY_WAIT_SECS) _LOGGER.info("final network state: %d %s", network.state, network.state_str) polling_interval = convert(config[DOMAIN].get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: network.set_poll_interval(polling_interval, False) poll_interval = network.get_poll_interval() _LOGGER.info("Z-Wave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network) # Register node services for Z-Wave network hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node, descriptions[const.SERVICE_ADD_NODE]) hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE, add_node_secure, descriptions[const.SERVICE_ADD_NODE_SECURE]) hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node, descriptions[const.SERVICE_REMOVE_NODE]) hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND, cancel_command, descriptions[const.SERVICE_CANCEL_COMMAND]) hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK, heal_network, descriptions[const.SERVICE_HEAL_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset, descriptions[const.SERVICE_SOFT_RESET]) hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK, test_network, descriptions[const.SERVICE_TEST_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_network, descriptions[const.SERVICE_STOP_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_START_NETWORK, start_zwave, descriptions[const.SERVICE_START_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node, descriptions[const.SERVICE_RENAME_NODE], schema=RENAME_NODE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_RENAME_VALUE, rename_value, descriptions[const.SERVICE_RENAME_VALUE], schema=RENAME_VALUE_SCHEMA) hass.services.register( DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER, set_config_parameter, descriptions[const.SERVICE_SET_CONFIG_PARAMETER], schema=SET_CONFIG_PARAMETER_SCHEMA) hass.services.register( DOMAIN, const.SERVICE_PRINT_CONFIG_PARAMETER, print_config_parameter, descriptions[const.SERVICE_PRINT_CONFIG_PARAMETER], schema=PRINT_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REMOVE_FAILED_NODE, remove_failed_node, descriptions[const.SERVICE_REMOVE_FAILED_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REPLACE_FAILED_NODE, replace_failed_node, descriptions[const.SERVICE_REPLACE_FAILED_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_CHANGE_ASSOCIATION, change_association, descriptions[const.SERVICE_CHANGE_ASSOCIATION], schema=CHANGE_ASSOCIATION_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_WAKEUP, set_wakeup, descriptions[const.SERVICE_SET_WAKEUP], schema=SET_WAKEUP_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_NODE, print_node, descriptions[const.SERVICE_PRINT_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_ENTITY, async_refresh_entity, descriptions[const.SERVICE_REFRESH_ENTITY], schema=REFRESH_ENTITY_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_NODE, refresh_node, descriptions[const.SERVICE_REFRESH_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_RESET_NODE_METERS, reset_node_meters, descriptions[const.SERVICE_RESET_NODE_METERS], schema=RESET_NODE_METERS_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_POLL_INTENSITY, set_poll_intensity, descriptions[const.SERVICE_SET_POLL_INTENSITY], schema=SET_POLL_INTENSITY_SCHEMA) # Setup autoheal if autoheal: _LOGGER.info("Z-Wave network autoheal is enabled") track_time_change(hass, heal_network, hour=0, minute=0, second=0) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave) return True
def setup(hass, config): """ Set up the iCloud Scanner. """ if config.get(DOMAIN) is None: return False for account, account_config in config[DOMAIN].items(): if not isinstance(account_config, dict): _LOGGER.error("Missing configuration data for account %s", account) continue if CONF_USERNAME not in account_config: _LOGGER.error("Missing username for account %s", account) continue if CONF_PASSWORD not in account_config: _LOGGER.error("Missing password for account %s", account) continue # Get the username and password from the configuration username = account_config.get(CONF_USERNAME) password = account_config.get(CONF_PASSWORD) ignored_devices = [] if 'ignored_devices' in account_config: ignored_dev = account_config.get('ignored_devices') for each_dev in ignored_dev: ignored_devices.append(each_dev) getevents = account_config.get(CONF_EVENTS, DEFAULT_EVENTS) icloudaccount = Icloud(hass, username, password, account, ignored_devices, getevents) icloudaccount.update_ha_state() ICLOUDTRACKERS[account] = icloudaccount if ICLOUDTRACKERS[account].api is not None: for device in ICLOUDTRACKERS[account].devices: iclouddevice = ICLOUDTRACKERS[account].devices[device] devicename = iclouddevice.devicename.lower() track_state_change(hass, 'device_tracker.' + devicename, iclouddevice.devicechanged) if 'manual_update' in account_config: def update_now(now): ICLOUDTRACKERS[account].update_icloud(see) manual_update = account_config.get('manual_update') for each_time in manual_update: each_time = dt_util.parse_time(each_time) track_time_change(hass, update_now, hour=each_time.hour, minute=each_time.minute, second=each_time.second) if not ICLOUDTRACKERS: _LOGGER.error("No ICLOUDTRACKERS added") return False randomseconds = random.randint(10, 59) def lost_iphone(call): """ Calls the lost iphone function if the device is found """ accountname = call.data.get('accountname') devicename = call.data.get('devicename') if accountname in ICLOUDTRACKERS: ICLOUDTRACKERS[accountname].lost_iphone(devicename) hass.services.register(DOMAIN, 'lost_iphone', lost_iphone) def update_icloud(call): """ Calls the update function of an icloud account """ accountname = call.data.get('accountname') devicename = call.data.get('devicename') if accountname in ICLOUDTRACKERS: ICLOUDTRACKERS[accountname].update_icloud(see, devicename) hass.services.register(DOMAIN, 'update_icloud', update_icloud) def keep_alive(now): """ Keeps the api logged in of all account """ for accountname in ICLOUDTRACKERS: try: ICLOUDTRACKERS[accountname].keep_alive() except ValueError: _LOGGER.info("something went wrong for this account, " + "retrying in a minute") track_utc_time_change( hass, keep_alive, second=randomseconds ) def setinterval(call): """ Calls the update function of an icloud account """ accountname = call.data.get('accountname') interval = call.data.get('interval') if accountname in ICLOUDTRACKERS: ICLOUDTRACKERS[accountname].setinterval(interval) hass.services.register(DOMAIN, 'setinterval', setinterval) # Tells the bootstrapper that the component was successfully initialized return True
def setup(hass, config): """Setup Z-Wave. Will automatically load components to support devices found on the network. """ descriptions = conf_util.load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) try: import libopenzwave except ImportError: _LOGGER.error("You are missing required dependency Python Open " "Z-Wave. Please follow instructions at: " "https://home-assistant.io/components/zwave/") return False from pydispatch import dispatcher # pylint: disable=import-error from openzwave.option import ZWaveOption from openzwave.network import ZWaveNetwork from openzwave.group import ZWaveGroup default_zwave_config_path = os.path.join(os.path.dirname( libopenzwave.__file__), 'config') # Load configuration use_debug = config[DOMAIN].get(CONF_DEBUG) autoheal = config[DOMAIN].get(CONF_AUTOHEAL) device_config = EntityValues( config[DOMAIN][CONF_DEVICE_CONFIG], config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN], config[DOMAIN][CONF_DEVICE_CONFIG_GLOB]) # Setup options options = ZWaveOption( config[DOMAIN].get(CONF_USB_STICK_PATH), user_path=hass.config.config_dir, config_path=config[DOMAIN].get( CONF_CONFIG_PATH, default_zwave_config_path)) options.set_console_output(use_debug) options.lock() network = hass.data[ZWAVE_NETWORK] = ZWaveNetwork(options, autostart=False) hass.data[DATA_ZWAVE_DICT] = {} if use_debug: # pragma: no cover def log_all(signal, value=None): """Log all the signals.""" print("") print("SIGNAL *****", signal) if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED, ZWaveNetwork.SIGNAL_VALUE_ADDED, ZWaveNetwork.SIGNAL_SCENE_EVENT, ZWaveNetwork.SIGNAL_NODE_EVENT, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED): pprint(_obj_to_dict(value)) print("") dispatcher.connect(log_all, weak=False) discovered_values = [] def value_added(node, value): """Called when a value is added to a node on the network.""" # Check if this value should be tracked by an existing entity for values in discovered_values: values.check_value(value) for schema in DISCOVERY_SCHEMAS: if not check_node_schema(node, schema): continue if not check_value_schema( value, schema[const.DISC_VALUES][const.DISC_PRIMARY]): continue values = ZWaveDeviceEntityValues( hass, schema, value, config, device_config) discovered_values.append(values) component = EntityComponent(_LOGGER, DOMAIN, hass) def node_added(node): """Called when a node is added on the network.""" entity = ZWaveNodeEntity(node, network) node_config = device_config.get(entity.entity_id) if node_config.get(CONF_IGNORED): _LOGGER.info( "Ignoring node entity %s due to device settings.", entity.entity_id) return component.add_entities([entity]) def scene_activated(node, scene_id): """Called when a scene is activated on any node in the network.""" hass.bus.fire(const.EVENT_SCENE_ACTIVATED, { ATTR_ENTITY_ID: _node_object_id(node), const.ATTR_OBJECT_ID: _node_object_id(node), const.ATTR_SCENE_ID: scene_id }) def node_event_activated(node, value): """Called when a nodeevent is activated on any node in the network.""" hass.bus.fire(const.EVENT_NODE_EVENT, { const.ATTR_OBJECT_ID: _node_object_id(node), const.ATTR_BASIC_LEVEL: value }) def network_ready(): """Called when all awake nodes have been queried.""" _LOGGER.info("Zwave network is ready for use. All awake nodes" " have been queried. Sleeping nodes will be" " queried when they awake.") hass.bus.fire(const.EVENT_NETWORK_READY) def network_complete(): """Called when all nodes on network have been queried.""" _LOGGER.info("Zwave network is complete. All nodes on the network" " have been queried") hass.bus.fire(const.EVENT_NETWORK_COMPLETE) dispatcher.connect( value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False) dispatcher.connect( node_added, ZWaveNetwork.SIGNAL_NODE_ADDED, weak=False) dispatcher.connect( scene_activated, ZWaveNetwork.SIGNAL_SCENE_EVENT, weak=False) dispatcher.connect( node_event_activated, ZWaveNetwork.SIGNAL_NODE_EVENT, weak=False) dispatcher.connect( network_ready, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, weak=False) dispatcher.connect( network_complete, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED, weak=False) def add_node(service): """Switch into inclusion mode.""" _LOGGER.info("Zwave add_node have been initialized.") network.controller.add_node() def add_node_secure(service): """Switch into secure inclusion mode.""" _LOGGER.info("Zwave add_node_secure have been initialized.") network.controller.add_node(True) def remove_node(service): """Switch into exclusion mode.""" _LOGGER.info("Zwave remove_node have been initialized.") network.controller.remove_node() def cancel_command(service): """Cancel a running controller command.""" _LOGGER.info("Cancel running ZWave command.") network.controller.cancel_command() def heal_network(service): """Heal the network.""" _LOGGER.info("ZWave heal running.") network.heal() def soft_reset(service): """Soft reset the controller.""" _LOGGER.info("Zwave soft_reset have been initialized.") network.controller.soft_reset() def test_network(service): """Test the network by sending commands to all the nodes.""" _LOGGER.info("Zwave test_network have been initialized.") network.test() def stop_network(_service_or_event): """Stop Z-Wave network.""" _LOGGER.info("Stopping ZWave network.") network.stop() if hass.state == CoreState.running: hass.bus.fire(const.EVENT_NETWORK_STOP) def rename_node(service): """Rename a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = hass.data[ZWAVE_NETWORK].nodes[node_id] name = service.data.get(const.ATTR_NAME) node.name = name _LOGGER.info( "Renamed ZWave node %d to %s", node_id, name) def remove_failed_node(service): """Remove failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info('Trying to remove zwave node %d', node_id) network.controller.remove_failed_node(node_id) def replace_failed_node(service): """Replace failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info('Trying to replace zwave node %d', node_id) network.controller.replace_failed_node(node_id) def set_config_parameter(service): """Set a config parameter to a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) selection = service.data.get(const.ATTR_CONFIG_VALUE) size = service.data.get(const.ATTR_CONFIG_SIZE, 2) i = 0 for value in ( node.get_values(class_id=const.COMMAND_CLASS_CONFIGURATION) .values()): if value.index == param and value.type == const.TYPE_LIST: _LOGGER.debug('Values for parameter %s: %s', param, value.data_items) i = len(value.data_items) - 1 if i == 0: node.set_config_param(param, selection, size) else: if selection > i: _LOGGER.info('Config parameter selection does not exist!' ' Please check zwcfg_[home_id].xml in' ' your homeassistant config directory. ' ' Available selections are 0 to %s', i) return node.set_config_param(param, selection, size) _LOGGER.info('Setting config parameter %s on Node %s ' 'with selection %s and size=%s', param, node_id, selection, size) def print_config_parameter(service): """Print a config parameter from a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) _LOGGER.info("Config parameter %s on Node %s : %s", param, node_id, get_config_value(node, param)) def print_node(service): """Print all information about z-wave node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] nice_print_node(node) def set_wakeup(service): """Set wake-up interval of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] value = service.data.get(const.ATTR_CONFIG_VALUE) if node.can_wake_up(): for value_id in node.get_values( class_id=const.COMMAND_CLASS_WAKE_UP): node.values[value_id].data = value _LOGGER.info("Node %s wake-up set to %d", node_id, value) else: _LOGGER.info("Node %s is not wakeable", node_id) def change_association(service): """Change an association in the zwave network.""" association_type = service.data.get(const.ATTR_ASSOCIATION) node_id = service.data.get(const.ATTR_NODE_ID) target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID) group = service.data.get(const.ATTR_GROUP) instance = service.data.get(const.ATTR_INSTANCE) node = ZWaveGroup(group, network, node_id) if association_type == 'add': node.add_association(target_node_id, instance) _LOGGER.info("Adding association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) if association_type == 'remove': node.remove_association(target_node_id, instance) _LOGGER.info("Removing association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) @asyncio.coroutine def async_refresh_entity(service): """Refresh values that specific entity depends on.""" entity_id = service.data.get(ATTR_ENTITY_ID) async_dispatcher_send( hass, SIGNAL_REFRESH_ENTITY_FORMAT.format(entity_id)) def refresh_node(service): """Refresh all node info.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] node.refresh_info() def start_zwave(_service_or_event): """Startup Z-Wave network.""" _LOGGER.info("Starting ZWave network.") network.start() hass.bus.fire(const.EVENT_NETWORK_START) # Need to be in STATE_AWAKED before talking to nodes. # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network # to be ready. for i in range(const.NETWORK_READY_WAIT_SECS): _LOGGER.debug( "network state: %d %s", hass.data[ZWAVE_NETWORK].state, network.state_str) if network.state >= network.STATE_AWAKED: _LOGGER.info("zwave ready after %d seconds", i) break time.sleep(1) else: _LOGGER.warning( "zwave not ready after %d seconds, continuing anyway", const.NETWORK_READY_WAIT_SECS) _LOGGER.info( "final network state: %d %s", network.state, network.state_str) polling_interval = convert( config[DOMAIN].get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: network.set_poll_interval(polling_interval, False) poll_interval = network.get_poll_interval() _LOGGER.info("zwave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network) # Register node services for Z-Wave network hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node, descriptions[const.SERVICE_ADD_NODE]) hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE, add_node_secure, descriptions[const.SERVICE_ADD_NODE_SECURE]) hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node, descriptions[const.SERVICE_REMOVE_NODE]) hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND, cancel_command, descriptions[const.SERVICE_CANCEL_COMMAND]) hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK, heal_network, descriptions[const.SERVICE_HEAL_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset, descriptions[const.SERVICE_SOFT_RESET]) hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK, test_network, descriptions[const.SERVICE_TEST_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_network, descriptions[const.SERVICE_STOP_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_START_NETWORK, start_zwave, descriptions[const.SERVICE_START_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node, descriptions[const.SERVICE_RENAME_NODE], schema=RENAME_NODE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER, set_config_parameter, descriptions[ const.SERVICE_SET_CONFIG_PARAMETER], schema=SET_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_CONFIG_PARAMETER, print_config_parameter, descriptions[ const.SERVICE_PRINT_CONFIG_PARAMETER], schema=PRINT_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REMOVE_FAILED_NODE, remove_failed_node, descriptions[const.SERVICE_REMOVE_FAILED_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REPLACE_FAILED_NODE, replace_failed_node, descriptions[const.SERVICE_REPLACE_FAILED_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_CHANGE_ASSOCIATION, change_association, descriptions[ const.SERVICE_CHANGE_ASSOCIATION], schema=CHANGE_ASSOCIATION_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_WAKEUP, set_wakeup, descriptions[ const.SERVICE_SET_WAKEUP], schema=SET_WAKEUP_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_NODE, print_node, descriptions[ const.SERVICE_PRINT_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_ENTITY, async_refresh_entity, descriptions[ const.SERVICE_REFRESH_ENTITY], schema=REFRESH_ENTITY_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_NODE, refresh_node, descriptions[ const.SERVICE_REFRESH_NODE], schema=NODE_SERVICE_SCHEMA) # Setup autoheal if autoheal: _LOGGER.info("ZWave network autoheal is enabled.") track_time_change(hass, heal_network, hour=0, minute=0, second=0) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave) if 'frontend' in hass.config.components: register_built_in_panel(hass, 'zwave', 'Z-Wave', 'mdi:nfc') return True
def setup(hass, config): """Setup Z-Wave. Will automatically load components to support devices found on the network. """ # pylint: disable=global-statement, import-error global NETWORK try: import libopenzwave except ImportError: _LOGGER.error("You are missing required dependency Python Open " "Z-Wave. Please follow instructions at: " "https://home-assistant.io/components/zwave/") return False from pydispatch import dispatcher from openzwave.option import ZWaveOption from openzwave.network import ZWaveNetwork default_zwave_config_path = os.path.join(os.path.dirname( libopenzwave.__file__), 'config') # Load configuration use_debug = str(config[DOMAIN].get(CONF_DEBUG)) == '1' customize = config[DOMAIN].get(CONF_CUSTOMIZE, {}) autoheal = config[DOMAIN].get(CONF_AUTOHEAL, DEFAULT_CONF_AUTOHEAL) # Setup options options = ZWaveOption( config[DOMAIN].get(CONF_USB_STICK_PATH, DEFAULT_CONF_USB_STICK_PATH), user_path=hass.config.config_dir, config_path=config[DOMAIN].get('config_path', default_zwave_config_path),) options.set_console_output(use_debug) options.lock() NETWORK = ZWaveNetwork(options, autostart=False) if use_debug: def log_all(signal, value=None): """Log all the signals.""" print("") print("SIGNAL *****", signal) if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED, ZWaveNetwork.SIGNAL_VALUE_ADDED): pprint(_obj_to_dict(value)) print("") dispatcher.connect(log_all, weak=False) def value_added(node, value): """Called when a value is added to a node on the network.""" for (component, generic_device_class, specific_device_class, command_class, value_type, value_genre) in DISCOVERY_COMPONENTS: _LOGGER.debug("Component=%s Node_id=%s query start", component, node.node_id) if node.generic not in generic_device_class and \ None not in generic_device_class: _LOGGER.debug("node.generic %s not None and in \ generic_device_class %s", node.generic, generic_device_class) continue if node.specific not in specific_device_class and \ None not in specific_device_class: _LOGGER.debug("node.specific %s is not None and in \ specific_device_class %s", node.specific, specific_device_class) continue if value.command_class not in command_class and \ None not in command_class: _LOGGER.debug("value.command_class %s is not None \ and in command_class %s", value.command_class, command_class) continue if value_type != value.type and value_type is not None: _LOGGER.debug("value.type %s != value_type %s", value.type, value_type) continue if value_genre != value.genre and value_genre is not None: _LOGGER.debug("value.genre %s != value_genre %s", value.genre, value_genre) continue # Configure node _LOGGER.debug("Adding Node_id=%s Generic_command_class=%s, \ Specific_command_class=%s, \ Command_class=%s, Value type=%s, \ Genre=%s", node.node_id, node.generic, node.specific, value.command_class, value.type, value.genre) name = "{}.{}".format(component, _object_id(value)) node_config = customize.get(name, {}) polling_intensity = convert( node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: value.enable_poll(polling_intensity) else: value.disable_poll() discovery.load_platform(hass, component, DOMAIN, { ATTR_NODE_ID: node.node_id, ATTR_VALUE_ID: value.value_id, }, config) def scene_activated(node, scene_id): """Called when a scene is activated on any node in the network.""" name = _node_name(node) object_id = "{}_{}".format(slugify(name), node.node_id) hass.bus.fire(EVENT_SCENE_ACTIVATED, { ATTR_ENTITY_ID: object_id, ATTR_SCENE_ID: scene_id }) dispatcher.connect( value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False) dispatcher.connect( scene_activated, ZWaveNetwork.SIGNAL_SCENE_EVENT, weak=False) def add_node(service): """Switch into inclusion mode.""" NETWORK.controller.add_node() def remove_node(service): """Switch into exclusion mode.""" NETWORK.controller.remove_node() def heal_network(service): """Heal the network.""" _LOGGER.info("ZWave heal running.") NETWORK.heal() def soft_reset(service): """Soft reset the controller.""" NETWORK.controller.soft_reset() def test_network(service): """Test the network by sending commands to all the nodes.""" NETWORK.test() def stop_zwave(event): """Stop Z-Wave.""" NETWORK.stop() def start_zwave(event): """Startup Z-Wave.""" NETWORK.start() # Need to be in STATE_AWAKED before talking to nodes. # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network # to be ready. for i in range(NETWORK_READY_WAIT_SECS): _LOGGER.debug( "network state: %d %s", NETWORK.state, NETWORK.state_str) if NETWORK.state >= NETWORK.STATE_AWAKED: _LOGGER.info("zwave ready after %d seconds", i) break time.sleep(1) else: _LOGGER.warning( "zwave not ready after %d seconds, continuing anyway", NETWORK_READY_WAIT_SECS) _LOGGER.info( "final network state: %d %s", NETWORK.state, NETWORK.state_str) polling_interval = convert( config[DOMAIN].get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: NETWORK.set_poll_interval(polling_interval, False) poll_interval = NETWORK.get_poll_interval() _LOGGER.info("zwave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zwave) # Register add / remove node services for Z-Wave sticks without # hardware inclusion button hass.services.register(DOMAIN, SERVICE_ADD_NODE, add_node) hass.services.register(DOMAIN, SERVICE_REMOVE_NODE, remove_node) hass.services.register(DOMAIN, SERVICE_HEAL_NETWORK, heal_network) hass.services.register(DOMAIN, SERVICE_SOFT_RESET, soft_reset) hass.services.register(DOMAIN, SERVICE_TEST_NETWORK, test_network) # Setup autoheal if autoheal: _LOGGER.info("ZWave network autoheal is enabled.") track_time_change(hass, heal_network, hour=0, minute=0, second=0) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave) return True
def setup(hass, config): # pylint: disable=too-many-locals,too-many-return-statements, # pylint: disable=too-many-statements,too-many-branches """ get the zones and offsets from configuration.yaml""" thermostat_controls = [] # no config found if config.get(DOMAIN) is None: return False for control_location, control_config in config[DOMAIN].items(): # ============== Thermostat checking ============== thermostat_entity = "not set" # HA does not have a thermostat if len(hass.states.entity_ids('thermostat')) == 0: _LOGGER.error('HA does not have any thermostats') continue # a single thermostat has been found so default to it if len(hass.states.entity_ids('thermostat')) == 1: thermostat_entity = hass.states.entity_ids('thermostat')[0] _LOGGER.error('defaulting to thermostat: %s', thermostat_entity) # get the thermostat if it's in the config if 'thermostat' in control_config: thermostat_entity = ('thermostat.' + control_config['thermostat']) # check thermostat exists if thermostat_entity not in hass.states.entity_ids('thermostat'): _LOGGER.error('thermostat_entity not found') continue # skip processing if we don't have a thermostat if thermostat_entity == "not set": continue _LOGGER.error('thermostat_entity confirmed: %s', thermostat_entity) # ============== Schedule checking ============== # Config does not include schedule if 'schedule' not in control_config: _LOGGER.error('no schedule in config') continue # get maximum set temperature max_temp = control_config.get('max_temp', DEFAULT_MAX_TEMP) _LOGGER.error('max_temp set to: %s', max_temp) # get minimum set temperature min_temp = control_config.get('min_temp', DEFAULT_MIN_TEMP) _LOGGER.error('min_temp set to: %s', min_temp) # check the timers schedule_error = 0 control_schedule = {} for each_time in control_config.get('schedule'): each_temp = control_config['schedule'][each_time] # incorrectly formatted schedule time, mark as an error test_time = dt_util.parse_time(each_time) if test_time is None: schedule_error = 1 _LOGGER.error('schedule error: incorrectly formatted time: %s', each_time) continue # schedule temp exceeds max temp, mark as an error if each_temp > max_temp: schedule_error = 1 _LOGGER.error('schedule error: temp exceeds max_temp: %s', each_temp) continue # schedule temp is lower than min temp, mark as an error if each_temp < min_temp: schedule_error = 1 _LOGGER.error('schedule error: temp is lower than min_temp:' '%s', each_temp) continue control_schedule[each_time] = each_temp _LOGGER.error('time: %s temp: %s', each_time, each_temp) # skip processing if config does not have a properly formatted time if schedule_error == 1: continue _LOGGER.error('schedule read successfully') # ============== Proximity checking ============== proximity_zone = "not set" dist_offset = DEFAULT_OFFSET away_distance = DEFAULT_AWAY # do we need to add proximity control if 'proximity' in control_config: # HA does not have a proximity_zone if len(hass.states.entity_ids('proximity')) == 0: _LOGGER.error('Error in setup: No proximity_zone entities ' + 'exist') continue # Single Prozimity Zone found if len(hass.states.entity_ids('proximity')) == 1: proximity_zone = hass.states.entity_ids('proximity')[0] _LOGGER.error('defaulting to proximity zone: %s', proximity_zone) # get the proximity zone if it's in the config if 'zone' in control_config['proximity']: proximity_zone = ('proximity.' + control_config['proximity']['zone']) _LOGGER.error('proximity_zone in config: %s', proximity_zone) # if proximity_zone is "not set" there is a problem in the config if proximity_zone == "not set": _LOGGER.error('Error in Config: No Proximity zone found') continue # check proximity zone we are going to use exists if proximity_zone not in hass.states.entity_ids('proximity'): _LOGGER.error('Error in Config: Specified proximity zone ' + 'does not exist') continue _LOGGER.error('proximity_zone entity confirmed: %s', proximity_zone) # get the distance offset if 'distance_offset' in control_config['proximity']: dist_offset = control_config['proximity']['distance_offset'] _LOGGER.error('dist_offset: %s', dist_offset) # get the away distance if 'away_distance' in control_config['proximity']: away_distance = control_config['proximity']['away_distance'] _LOGGER.error('away_distance: %s', away_distance) # config contains neither distance offset nor away distance # proximity control is useless if dist_offset == DEFAULT_OFFSET and away_distance == DEFAULT_AWAY: proximity_zone = "not set" # ============== Create the thermostat control entities ============== # set the entity ID entity_id = DOMAIN + '.' + control_location _LOGGER.error('entity_id: %s', entity_id) # set the friendly name for the created entity friendly_name = control_location # we have all the information required, now create the entity thermostat_control = Thermostatcontrol(hass, thermostat_entity, dist_offset, away_distance, control_schedule, friendly_name, proximity_zone, max_temp, min_temp) thermostat_control.entity_id = entity_id thermostat_control.update_ha_state() thermostat_controls.append(thermostat_control) thermostat_control.check_initial_state() # setup the schedule triggers for each_time in control_schedule: each_time = dt_util.parse_time(each_time) track_time_change(hass, thermostat_control.check_time_change, hour=each_time.hour, minute=each_time.minute, second=each_time.second) _LOGGER.error('added time triggers: %s triggers', len(control_schedule)) # setup the thermostat trigger track_state_change(hass, thermostat_control.thermostat_entity, thermostat_control.check_thermostat_change) _LOGGER.error('added thermostat trigger: %s', thermostat_entity) # setup the proximity trigger if required if not proximity_zone == "not set": track_state_change(hass, thermostat_control.proximity_zone, thermostat_control.check_proximity_change) _LOGGER.error('added proximity trigger: %s', proximity_zone) if not thermostat_controls: _LOGGER.error('No controls defined') return False # Tell the bootstrapper that the component was successfully initialized return True
def setup(hass, config): """Set up Z-Wave. Will automatically load components to support devices found on the network. """ descriptions = conf_util.load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) from pydispatch import dispatcher # pylint: disable=import-error from openzwave.option import ZWaveOption from openzwave.network import ZWaveNetwork from openzwave.group import ZWaveGroup # Load configuration use_debug = config[DOMAIN].get(CONF_DEBUG) autoheal = config[DOMAIN].get(CONF_AUTOHEAL) device_config = EntityValues( config[DOMAIN][CONF_DEVICE_CONFIG], config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN], config[DOMAIN][CONF_DEVICE_CONFIG_GLOB]) # Setup options options = ZWaveOption( config[DOMAIN].get(CONF_USB_STICK_PATH), user_path=hass.config.config_dir, config_path=config[DOMAIN].get(CONF_CONFIG_PATH)) options.set_console_output(use_debug) if CONF_NETWORK_KEY in config[DOMAIN]: options.addOption("NetworkKey", config[DOMAIN][CONF_NETWORK_KEY]) options.lock() network = hass.data[DATA_NETWORK] = ZWaveNetwork(options, autostart=False) hass.data[DATA_DEVICES] = {} hass.data[DATA_ENTITY_VALUES] = [] if use_debug: # pragma: no cover def log_all(signal, value=None): """Log all the signals.""" print("") print("SIGNAL *****", signal) if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED, ZWaveNetwork.SIGNAL_VALUE_ADDED, ZWaveNetwork.SIGNAL_SCENE_EVENT, ZWaveNetwork.SIGNAL_NODE_EVENT, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED): pprint(_obj_to_dict(value)) print("") dispatcher.connect(log_all, weak=False) def value_added(node, value): """Handle new added value to a node on the network.""" # Check if this value should be tracked by an existing entity for values in hass.data[DATA_ENTITY_VALUES]: values.check_value(value) for schema in DISCOVERY_SCHEMAS: if not check_node_schema(node, schema): continue if not check_value_schema( value, schema[const.DISC_VALUES][const.DISC_PRIMARY]): continue values = ZWaveDeviceEntityValues( hass, schema, value, config, device_config) # We create a new list and update the reference here so that # the list can be safely iterated over in the main thread new_values = hass.data[DATA_ENTITY_VALUES] + [values] hass.data[DATA_ENTITY_VALUES] = new_values component = EntityComponent(_LOGGER, DOMAIN, hass) def node_added(node): """Handle a new node on the network.""" entity = ZWaveNodeEntity(node, network) node_config = device_config.get(entity.entity_id) if node_config.get(CONF_IGNORED): _LOGGER.info( "Ignoring node entity %s due to device settings", entity.entity_id) return component.add_entities([entity]) def scene_activated(node, scene_id): """Handle an activated scene on any node in the network.""" hass.bus.fire(const.EVENT_SCENE_ACTIVATED, { ATTR_ENTITY_ID: _node_object_id(node), const.ATTR_OBJECT_ID: _node_object_id(node), const.ATTR_SCENE_ID: scene_id }) def node_event_activated(node, value): """Handle a nodeevent on any node in the network.""" hass.bus.fire(const.EVENT_NODE_EVENT, { const.ATTR_OBJECT_ID: _node_object_id(node), const.ATTR_BASIC_LEVEL: value }) def network_ready(): """Handle the query of all awake nodes.""" _LOGGER.info("Zwave network is ready for use. All awake nodes " "have been queried. Sleeping nodes will be " "queried when they awake.") hass.bus.fire(const.EVENT_NETWORK_READY) def network_complete(): """Handle the querying of all nodes on network.""" _LOGGER.info("Z-Wave network is complete. All nodes on the network " "have been queried") hass.bus.fire(const.EVENT_NETWORK_COMPLETE) dispatcher.connect( value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False) dispatcher.connect( node_added, ZWaveNetwork.SIGNAL_NODE_ADDED, weak=False) dispatcher.connect( scene_activated, ZWaveNetwork.SIGNAL_SCENE_EVENT, weak=False) dispatcher.connect( node_event_activated, ZWaveNetwork.SIGNAL_NODE_EVENT, weak=False) dispatcher.connect( network_ready, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, weak=False) dispatcher.connect( network_complete, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED, weak=False) def add_node(service): """Switch into inclusion mode.""" _LOGGER.info("Z-Wave add_node have been initialized") network.controller.add_node() def add_node_secure(service): """Switch into secure inclusion mode.""" _LOGGER.info("Z-Wave add_node_secure have been initialized") network.controller.add_node(True) def remove_node(service): """Switch into exclusion mode.""" _LOGGER.info("Z-Wwave remove_node have been initialized") network.controller.remove_node() def cancel_command(service): """Cancel a running controller command.""" _LOGGER.info("Cancel running Z-Wave command") network.controller.cancel_command() def heal_network(service): """Heal the network.""" _LOGGER.info("Z-Wave heal running") network.heal() def soft_reset(service): """Soft reset the controller.""" _LOGGER.info("Z-Wave soft_reset have been initialized") network.controller.soft_reset() def test_network(service): """Test the network by sending commands to all the nodes.""" _LOGGER.info("Z-Wave test_network have been initialized") network.test() def stop_network(_service_or_event): """Stop Z-Wave network.""" _LOGGER.info("Stopping Z-Wave network") network.stop() if hass.state == CoreState.running: hass.bus.fire(const.EVENT_NETWORK_STOP) def rename_node(service): """Rename a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] name = service.data.get(const.ATTR_NAME) node.name = name _LOGGER.info( "Renamed Z-Wave node %d to %s", node_id, name) def rename_value(service): """Rename a node value.""" node_id = service.data.get(const.ATTR_NODE_ID) value_id = service.data.get(const.ATTR_VALUE_ID) node = network.nodes[node_id] value = node.values[value_id] name = service.data.get(const.ATTR_NAME) value.label = name _LOGGER.info( "Renamed Z-Wave value (Node %d Value %d) to %s", node_id, value_id, name) def remove_failed_node(service): """Remove failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info("Trying to remove zwave node %d", node_id) network.controller.remove_failed_node(node_id) def replace_failed_node(service): """Replace failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info("Trying to replace zwave node %d", node_id) network.controller.replace_failed_node(node_id) def set_config_parameter(service): """Set a config parameter to a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) selection = service.data.get(const.ATTR_CONFIG_VALUE) size = service.data.get(const.ATTR_CONFIG_SIZE) for value in ( node.get_values(class_id=const.COMMAND_CLASS_CONFIGURATION) .values()): if value.index != param: continue if value.type in [const.TYPE_LIST, const.TYPE_BOOL]: value.data = selection _LOGGER.info("Setting config list parameter %s on Node %s " "with selection %s", param, node_id, selection) return else: value.data = int(selection) _LOGGER.info("Setting config parameter %s on Node %s " "with selection %s", param, node_id, selection) return node.set_config_param(param, selection, size) _LOGGER.info("Setting unknown config parameter %s on Node %s " "with selection %s", param, node_id, selection) def print_config_parameter(service): """Print a config parameter from a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) _LOGGER.info("Config parameter %s on Node %s: %s", param, node_id, get_config_value(node, param)) def print_node(service): """Print all information about z-wave node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] nice_print_node(node) def set_wakeup(service): """Set wake-up interval of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] value = service.data.get(const.ATTR_CONFIG_VALUE) if node.can_wake_up(): for value_id in node.get_values( class_id=const.COMMAND_CLASS_WAKE_UP): node.values[value_id].data = value _LOGGER.info("Node %s wake-up set to %d", node_id, value) else: _LOGGER.info("Node %s is not wakeable", node_id) def change_association(service): """Change an association in the zwave network.""" association_type = service.data.get(const.ATTR_ASSOCIATION) node_id = service.data.get(const.ATTR_NODE_ID) target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID) group = service.data.get(const.ATTR_GROUP) instance = service.data.get(const.ATTR_INSTANCE) node = ZWaveGroup(group, network, node_id) if association_type == 'add': node.add_association(target_node_id, instance) _LOGGER.info("Adding association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) if association_type == 'remove': node.remove_association(target_node_id, instance) _LOGGER.info("Removing association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) @asyncio.coroutine def async_refresh_entity(service): """Refresh values that specific entity depends on.""" entity_id = service.data.get(ATTR_ENTITY_ID) async_dispatcher_send( hass, SIGNAL_REFRESH_ENTITY_FORMAT.format(entity_id)) def refresh_node(service): """Refresh all node info.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] node.refresh_info() def reset_node_meters(service): """Reset meter counters of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) instance = service.data.get(const.ATTR_INSTANCE) node = network.nodes[node_id] for value in ( node.get_values(class_id=const.COMMAND_CLASS_METER) .values()): if value.index != const.METER_RESET_INDEX: continue if value.instance != instance: continue network.manager.pressButton(value.value_id) network.manager.releaseButton(value.value_id) _LOGGER.info("Resetting meters on node %s instance %s....", node_id, instance) return _LOGGER.info("Node %s on instance %s does not have resettable " "meters.", node_id, instance) def start_zwave(_service_or_event): """Startup Z-Wave network.""" _LOGGER.info("Starting Z-Wave network...") network.start() hass.bus.fire(const.EVENT_NETWORK_START) # Need to be in STATE_AWAKED before talking to nodes. # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network # to be ready. for i in range(const.NETWORK_READY_WAIT_SECS): _LOGGER.debug( "network state: %d %s", network.state, network.state_str) if network.state >= network.STATE_AWAKED: _LOGGER.info("Z-Wave ready after %d seconds", i) break time.sleep(1) else: _LOGGER.warning( "zwave not ready after %d seconds, continuing anyway", const.NETWORK_READY_WAIT_SECS) _LOGGER.info( "final network state: %d %s", network.state, network.state_str) polling_interval = convert( config[DOMAIN].get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: network.set_poll_interval(polling_interval, False) poll_interval = network.get_poll_interval() _LOGGER.info("Z-Wave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network) # Register node services for Z-Wave network hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node, descriptions[const.SERVICE_ADD_NODE]) hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE, add_node_secure, descriptions[const.SERVICE_ADD_NODE_SECURE]) hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node, descriptions[const.SERVICE_REMOVE_NODE]) hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND, cancel_command, descriptions[const.SERVICE_CANCEL_COMMAND]) hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK, heal_network, descriptions[const.SERVICE_HEAL_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset, descriptions[const.SERVICE_SOFT_RESET]) hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK, test_network, descriptions[const.SERVICE_TEST_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_network, descriptions[const.SERVICE_STOP_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_START_NETWORK, start_zwave, descriptions[const.SERVICE_START_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node, descriptions[const.SERVICE_RENAME_NODE], schema=RENAME_NODE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_RENAME_VALUE, rename_value, descriptions[const.SERVICE_RENAME_VALUE], schema=RENAME_VALUE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER, set_config_parameter, descriptions[ const.SERVICE_SET_CONFIG_PARAMETER], schema=SET_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_CONFIG_PARAMETER, print_config_parameter, descriptions[ const.SERVICE_PRINT_CONFIG_PARAMETER], schema=PRINT_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REMOVE_FAILED_NODE, remove_failed_node, descriptions[const.SERVICE_REMOVE_FAILED_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REPLACE_FAILED_NODE, replace_failed_node, descriptions[const.SERVICE_REPLACE_FAILED_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_CHANGE_ASSOCIATION, change_association, descriptions[ const.SERVICE_CHANGE_ASSOCIATION], schema=CHANGE_ASSOCIATION_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_WAKEUP, set_wakeup, descriptions[ const.SERVICE_SET_WAKEUP], schema=SET_WAKEUP_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_NODE, print_node, descriptions[ const.SERVICE_PRINT_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_ENTITY, async_refresh_entity, descriptions[ const.SERVICE_REFRESH_ENTITY], schema=REFRESH_ENTITY_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_NODE, refresh_node, descriptions[ const.SERVICE_REFRESH_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_RESET_NODE_METERS, reset_node_meters, descriptions[ const.SERVICE_RESET_NODE_METERS], schema=RESET_NODE_METERS_SCHEMA) # Setup autoheal if autoheal: _LOGGER.info("Z-Wave network autoheal is enabled") track_time_change(hass, heal_network, hour=0, minute=0, second=0) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave) if 'frontend' in hass.config.components: register_built_in_panel(hass, 'zwave', 'Z-Wave', 'mdi:nfc') hass.http.register_view(api.ZWaveNodeValueView) hass.http.register_view(api.ZWaveNodeGroupView) hass.http.register_view(api.ZWaveNodeConfigView) hass.http.register_view(api.ZWaveUserCodeView) hass.http.register_static_path( URL_API_OZW_LOG, hass.config.path(OZW_LOG_FILENAME), False) return True
def do_authentication(hass, config): """Notify user of actions and authenticate. Notify user of user_code and verification_url then poll until we have an access token. """ from oauth2client.client import ( OAuth2WebServerFlow, OAuth2DeviceCodeError, FlowExchangeError ) from oauth2client.file import Storage oauth = OAuth2WebServerFlow( config[CONF_CLIENT_ID], config[CONF_CLIENT_SECRET], 'https://www.googleapis.com/auth/calendar.readonly', 'Home-Assistant.io', ) persistent_notification = loader.get_component('persistent_notification') try: dev_flow = oauth.step1_get_device_and_user_codes() except OAuth2DeviceCodeError as err: persistent_notification.create( hass, 'Error: {}<br />You will need to restart hass after fixing.' ''.format(err), title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID) return False persistent_notification.create( hass, 'In order to authorize Home-Assistant to view your calendars ' 'you must visit: <a href="{}" target="_blank">{}</a> and enter ' 'code: {}'.format(dev_flow.verification_url, dev_flow.verification_url, dev_flow.user_code), title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID ) def step2_exchange(now): """Keep trying to validate the user_code until it expires.""" if now >= dt.as_local(dev_flow.user_code_expiry): persistent_notification.create( hass, 'Authenication code expired, please restart ' 'Home-Assistant and try again', title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID) listener() try: credentials = oauth.step2_exchange(device_flow_info=dev_flow) except FlowExchangeError: # not ready yet, call again return storage = Storage(hass.config.path(TOKEN_FILE)) storage.put(credentials) do_setup(hass, config) listener() persistent_notification.create( hass, 'We are all setup now. Check {} for calendars that have ' 'been found'.format(YAML_DEVICES), title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID) listener = track_time_change(hass, step2_exchange, second=range(0, 60, dev_flow.interval)) return True
def setup(hass, config): """Setup Z-Wave. Will automatically load components to support devices found on the network. """ # pylint: disable=global-statement, import-error global NETWORK descriptions = conf_util.load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) try: import libopenzwave except ImportError: _LOGGER.error("You are missing required dependency Python Open " "Z-Wave. Please follow instructions at: " "https://home-assistant.io/components/zwave/") return False from pydispatch import dispatcher from openzwave.option import ZWaveOption from openzwave.network import ZWaveNetwork from openzwave.group import ZWaveGroup default_zwave_config_path = os.path.join(os.path.dirname( libopenzwave.__file__), 'config') # Load configuration use_debug = config[DOMAIN].get(CONF_DEBUG) autoheal = config[DOMAIN].get(CONF_AUTOHEAL) hass.data[DATA_DEVICE_CONFIG] = EntityValues( config[DOMAIN][CONF_DEVICE_CONFIG], config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN], config[DOMAIN][CONF_DEVICE_CONFIG_GLOB]) # Setup options options = ZWaveOption( config[DOMAIN].get(CONF_USB_STICK_PATH), user_path=hass.config.config_dir, config_path=config[DOMAIN].get( CONF_CONFIG_PATH, default_zwave_config_path)) options.set_console_output(use_debug) options.lock() NETWORK = ZWaveNetwork(options, autostart=False) if use_debug: def log_all(signal, value=None): """Log all the signals.""" print("") print("SIGNAL *****", signal) if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED, ZWaveNetwork.SIGNAL_VALUE_ADDED, ZWaveNetwork.SIGNAL_SCENE_EVENT, ZWaveNetwork.SIGNAL_NODE_EVENT, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED): pprint(_obj_to_dict(value)) print("") dispatcher.connect(log_all, weak=False) def value_added(node, value): """Called when a value is added to a node on the network.""" for (component, generic_device_class, specific_device_class, command_class, value_type, value_genre) in DISCOVERY_COMPONENTS: _LOGGER.debug("Component=%s Node_id=%s query start", component, node.node_id) if node.generic not in generic_device_class and \ None not in generic_device_class: _LOGGER.debug("node.generic %s not None and in " "generic_device_class %s", node.generic, generic_device_class) continue if node.specific not in specific_device_class and \ None not in specific_device_class: _LOGGER.debug("node.specific %s is not None and in " "specific_device_class %s", node.specific, specific_device_class) continue if value.command_class not in command_class and \ None not in command_class: _LOGGER.debug("value.command_class %s is not None " "and in command_class %s", value.command_class, command_class) continue if value_type != value.type and value_type is not None: _LOGGER.debug("value.type %s != value_type %s", value.type, value_type) continue if value_genre != value.genre and value_genre is not None: _LOGGER.debug("value.genre %s != value_genre %s", value.genre, value_genre) continue # Configure node _LOGGER.debug("Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " "Genre=%s as %s", node.node_id, node.generic, node.specific, value.command_class, value.type, value.genre, component) workaround_component = workaround.get_device_component_mapping( value) if workaround_component and workaround_component != component: if workaround_component == workaround.WORKAROUND_IGNORE: _LOGGER.info("Ignoring device %s due to workaround.", "{}.{}".format(component, object_id(value))) continue _LOGGER.debug("Using %s instead of %s", workaround_component, component) component = workaround_component name = "{}.{}".format(component, object_id(value)) node_config = hass.data[DATA_DEVICE_CONFIG].get(name) if node_config.get(CONF_IGNORED): _LOGGER.info( "Ignoring device %s due to device settings.", name) return polling_intensity = convert( node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: value.enable_poll(polling_intensity) else: value.disable_poll() discovery.load_platform(hass, component, DOMAIN, { const.ATTR_NODE_ID: node.node_id, const.ATTR_VALUE_ID: value.value_id, }, config) def scene_activated(node, scene_id): """Called when a scene is activated on any node in the network.""" hass.bus.fire(const.EVENT_SCENE_ACTIVATED, { ATTR_ENTITY_ID: _node_object_id(node), const.ATTR_OBJECT_ID: _node_object_id(node), const.ATTR_SCENE_ID: scene_id }) def node_event_activated(node, value): """Called when a nodeevent is activated on any node in the network.""" hass.bus.fire(const.EVENT_NODE_EVENT, { const.ATTR_OBJECT_ID: _node_object_id(node), const.ATTR_BASIC_LEVEL: value }) def network_ready(): """Called when all awake nodes have been queried.""" _LOGGER.info("Zwave network is ready for use. All awake nodes" " have been queried. Sleeping nodes will be" " queried when they awake.") hass.bus.fire(const.EVENT_NETWORK_READY) def network_complete(): """Called when all nodes on network have been queried.""" _LOGGER.info("Zwave network is complete. All nodes on the network" " have been queried") hass.bus.fire(const.EVENT_NETWORK_COMPLETE) dispatcher.connect( value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False) dispatcher.connect( scene_activated, ZWaveNetwork.SIGNAL_SCENE_EVENT, weak=False) dispatcher.connect( node_event_activated, ZWaveNetwork.SIGNAL_NODE_EVENT, weak=False) dispatcher.connect( network_ready, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, weak=False) dispatcher.connect( network_complete, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED, weak=False) def add_node(service): """Switch into inclusion mode.""" _LOGGER.info("Zwave add_node have been initialized.") NETWORK.controller.add_node() def add_node_secure(service): """Switch into secure inclusion mode.""" _LOGGER.info("Zwave add_node_secure have been initialized.") NETWORK.controller.add_node(True) def remove_node(service): """Switch into exclusion mode.""" _LOGGER.info("Zwave remove_node have been initialized.") NETWORK.controller.remove_node() def cancel_command(service): """Cancel a running controller command.""" _LOGGER.info("Cancel running ZWave command.") NETWORK.controller.cancel_command() def heal_network(service): """Heal the network.""" _LOGGER.info("ZWave heal running.") NETWORK.heal() def soft_reset(service): """Soft reset the controller.""" _LOGGER.info("Zwave soft_reset have been initialized.") NETWORK.controller.soft_reset() def test_network(service): """Test the network by sending commands to all the nodes.""" _LOGGER.info("Zwave test_network have been initialized.") NETWORK.test() def stop_zwave(_service_or_event): """Stop Z-Wave network.""" _LOGGER.info("Stopping ZWave network.") NETWORK.stop() if hass.state == 'RUNNING': hass.bus.fire(const.EVENT_NETWORK_STOP) def rename_node(service): """Rename a node.""" state = hass.states.get(service.data.get(ATTR_ENTITY_ID)) node_id = state.attributes.get(const.ATTR_NODE_ID) node = NETWORK.nodes[node_id] name = service.data.get(const.ATTR_NAME) node.name = name _LOGGER.info( "Renamed ZWave node %d to %s", node_id, name) def set_config_parameter(service): """Set a config parameter to a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = NETWORK.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) selection = service.data.get(const.ATTR_CONFIG_VALUE) size = service.data.get(const.ATTR_CONFIG_SIZE, 2) i = 0 for value in ( node.get_values(class_id=const.COMMAND_CLASS_CONFIGURATION) .values()): if value.index == param and value.type == const.TYPE_LIST: _LOGGER.debug('Values for parameter %s: %s', param, value.data_items) i = len(value.data_items) - 1 if i == 0: node.set_config_param(param, selection, size) else: if selection > i: _LOGGER.info('Config parameter selection does not exist!' ' Please check zwcfg_[home_id].xml in' ' your homeassistant config directory. ' ' Available selections are 0 to %s', i) return node.set_config_param(param, selection, size) _LOGGER.info('Setting config parameter %s on Node %s ' 'with selection %s and size=%s', param, node_id, selection, size) def print_config_parameter(service): """Print a config parameter from a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = NETWORK.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) _LOGGER.info("Config parameter %s on Node %s : %s", param, node_id, get_config_value(node, param)) def print_node(service): """Print all information about z-wave node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = NETWORK.nodes[node_id] nice_print_node(node) def set_wakeup(service): """Set wake-up interval of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = NETWORK.nodes[node_id] value = service.data.get(const.ATTR_CONFIG_VALUE) if node.can_wake_up(): for value_id in node.get_values( class_id=const.COMMAND_CLASS_WAKE_UP): node.values[value_id].data = value _LOGGER.info("Node %s wake-up set to %d", node_id, value) else: _LOGGER.info("Node %s is not wakeable", node_id) def change_association(service): """Change an association in the zwave network.""" association_type = service.data.get(const.ATTR_ASSOCIATION) node_id = service.data.get(const.ATTR_NODE_ID) target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID) group = service.data.get(const.ATTR_GROUP) instance = service.data.get(const.ATTR_INSTANCE) node = ZWaveGroup(group, NETWORK, node_id) if association_type == 'add': node.add_association(target_node_id, instance) _LOGGER.info("Adding association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) if association_type == 'remove': node.remove_association(target_node_id, instance) _LOGGER.info("Removing association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) def start_zwave(_service_or_event): """Startup Z-Wave network.""" _LOGGER.info("Starting ZWave network.") NETWORK.start() hass.bus.fire(const.EVENT_NETWORK_START) # Need to be in STATE_AWAKED before talking to nodes. # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network # to be ready. for i in range(const.NETWORK_READY_WAIT_SECS): _LOGGER.debug( "network state: %d %s", NETWORK.state, NETWORK.state_str) if NETWORK.state >= NETWORK.STATE_AWAKED: _LOGGER.info("zwave ready after %d seconds", i) break time.sleep(1) else: _LOGGER.warning( "zwave not ready after %d seconds, continuing anyway", const.NETWORK_READY_WAIT_SECS) _LOGGER.info( "final network state: %d %s", NETWORK.state, NETWORK.state_str) polling_interval = convert( config[DOMAIN].get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: NETWORK.set_poll_interval(polling_interval, False) poll_interval = NETWORK.get_poll_interval() _LOGGER.info("zwave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zwave) # Register node services for Z-Wave network hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node, descriptions[const.SERVICE_ADD_NODE]) hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE, add_node_secure, descriptions[const.SERVICE_ADD_NODE_SECURE]) hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node, descriptions[const.SERVICE_REMOVE_NODE]) hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND, cancel_command, descriptions[const.SERVICE_CANCEL_COMMAND]) hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK, heal_network, descriptions[const.SERVICE_HEAL_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset, descriptions[const.SERVICE_SOFT_RESET]) hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK, test_network, descriptions[const.SERVICE_TEST_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_zwave, descriptions[const.SERVICE_STOP_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_START_NETWORK, start_zwave, descriptions[const.SERVICE_START_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node, descriptions[const.SERVICE_RENAME_NODE], schema=RENAME_NODE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER, set_config_parameter, descriptions[ const.SERVICE_SET_CONFIG_PARAMETER], schema=SET_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_CONFIG_PARAMETER, print_config_parameter, descriptions[ const.SERVICE_PRINT_CONFIG_PARAMETER], schema=PRINT_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_CHANGE_ASSOCIATION, change_association, descriptions[ const.SERVICE_CHANGE_ASSOCIATION], schema=CHANGE_ASSOCIATION_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_WAKEUP, set_wakeup, descriptions[ const.SERVICE_SET_WAKEUP], schema=SET_WAKEUP_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_NODE, print_node, descriptions[ const.SERVICE_PRINT_NODE], schema=PRINT_NODE_SCHEMA) # Setup autoheal if autoheal: _LOGGER.info("ZWave network autoheal is enabled.") track_time_change(hass, heal_network, hour=0, minute=0, second=0) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave) return True
def setup(hass, config): """Setup Z-Wave. Will automatically load components to support devices found on the network. """ # pylint: disable=global-statement, import-error global NETWORK descriptions = conf_util.load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) try: import libopenzwave except ImportError: _LOGGER.error("You are missing required dependency Python Open " "Z-Wave. Please follow instructions at: " "https://home-assistant.io/components/zwave/") return False from pydispatch import dispatcher from openzwave.option import ZWaveOption from openzwave.network import ZWaveNetwork from openzwave.group import ZWaveGroup default_zwave_config_path = os.path.join( os.path.dirname(libopenzwave.__file__), 'config') # Load configuration use_debug = config[DOMAIN].get(CONF_DEBUG) autoheal = config[DOMAIN].get(CONF_AUTOHEAL) hass.data[DATA_DEVICE_CONFIG] = EntityValues( config[DOMAIN][CONF_DEVICE_CONFIG], config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN], config[DOMAIN][CONF_DEVICE_CONFIG_GLOB]) # Setup options options = ZWaveOption(config[DOMAIN].get(CONF_USB_STICK_PATH), user_path=hass.config.config_dir, config_path=config[DOMAIN].get( CONF_CONFIG_PATH, default_zwave_config_path)) options.set_console_output(use_debug) options.lock() NETWORK = ZWaveNetwork(options, autostart=False) if use_debug: def log_all(signal, value=None): """Log all the signals.""" print("") print("SIGNAL *****", signal) if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED, ZWaveNetwork.SIGNAL_VALUE_ADDED, ZWaveNetwork.SIGNAL_SCENE_EVENT, ZWaveNetwork.SIGNAL_NODE_EVENT, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED): pprint(_obj_to_dict(value)) print("") dispatcher.connect(log_all, weak=False) def value_added(node, value): """Called when a value is added to a node on the network.""" for (component, generic_device_class, specific_device_class, command_class, value_type, value_genre) in DISCOVERY_COMPONENTS: _LOGGER.debug("Component=%s Node_id=%s query start", component, node.node_id) if node.generic not in generic_device_class and \ None not in generic_device_class: _LOGGER.debug( "node.generic %s not None and in " "generic_device_class %s", node.generic, generic_device_class) continue if node.specific not in specific_device_class and \ None not in specific_device_class: _LOGGER.debug( "node.specific %s is not None and in " "specific_device_class %s", node.specific, specific_device_class) continue if value.command_class not in command_class and \ None not in command_class: _LOGGER.debug( "value.command_class %s is not None " "and in command_class %s", value.command_class, command_class) continue if value_type != value.type and value_type is not None: _LOGGER.debug("value.type %s != value_type %s", value.type, value_type) continue if value_genre != value.genre and value_genre is not None: _LOGGER.debug("value.genre %s != value_genre %s", value.genre, value_genre) continue # Configure node _LOGGER.debug( "Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " "Genre=%s as %s", node.node_id, node.generic, node.specific, value.command_class, value.type, value.genre, component) workaround_component = workaround.get_device_component_mapping( value) if workaround_component and workaround_component != component: if workaround_component == workaround.WORKAROUND_IGNORE: _LOGGER.info("Ignoring device %s due to workaround.", "{}.{}".format(component, object_id(value))) continue _LOGGER.debug("Using %s instead of %s", workaround_component, component) component = workaround_component name = "{}.{}".format(component, object_id(value)) node_config = hass.data[DATA_DEVICE_CONFIG].get(name) if node_config.get(CONF_IGNORED): _LOGGER.info("Ignoring device %s due to device settings.", name) return polling_intensity = convert( node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: value.enable_poll(polling_intensity) else: value.disable_poll() discovery.load_platform( hass, component, DOMAIN, { const.ATTR_NODE_ID: node.node_id, const.ATTR_VALUE_ID: value.value_id, }, config) def scene_activated(node, scene_id): """Called when a scene is activated on any node in the network.""" hass.bus.fire( const.EVENT_SCENE_ACTIVATED, { ATTR_ENTITY_ID: _node_object_id(node), const.ATTR_OBJECT_ID: _node_object_id(node), const.ATTR_SCENE_ID: scene_id }) def node_event_activated(node, value): """Called when a nodeevent is activated on any node in the network.""" hass.bus.fire( const.EVENT_NODE_EVENT, { const.ATTR_OBJECT_ID: _node_object_id(node), const.ATTR_BASIC_LEVEL: value }) def network_ready(): """Called when all awake nodes have been queried.""" _LOGGER.info("Zwave network is ready for use. All awake nodes" " have been queried. Sleeping nodes will be" " queried when they awake.") hass.bus.fire(const.EVENT_NETWORK_READY) def network_complete(): """Called when all nodes on network have been queried.""" _LOGGER.info("Zwave network is complete. All nodes on the network" " have been queried") hass.bus.fire(const.EVENT_NETWORK_COMPLETE) dispatcher.connect(value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False) dispatcher.connect(scene_activated, ZWaveNetwork.SIGNAL_SCENE_EVENT, weak=False) dispatcher.connect(node_event_activated, ZWaveNetwork.SIGNAL_NODE_EVENT, weak=False) dispatcher.connect(network_ready, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, weak=False) dispatcher.connect(network_complete, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED, weak=False) def add_node(service): """Switch into inclusion mode.""" _LOGGER.info("Zwave add_node have been initialized.") NETWORK.controller.add_node() def add_node_secure(service): """Switch into secure inclusion mode.""" _LOGGER.info("Zwave add_node_secure have been initialized.") NETWORK.controller.add_node(True) def remove_node(service): """Switch into exclusion mode.""" _LOGGER.info("Zwave remove_node have been initialized.") NETWORK.controller.remove_node() def cancel_command(service): """Cancel a running controller command.""" _LOGGER.info("Cancel running ZWave command.") NETWORK.controller.cancel_command() def heal_network(service): """Heal the network.""" _LOGGER.info("ZWave heal running.") NETWORK.heal() def soft_reset(service): """Soft reset the controller.""" _LOGGER.info("Zwave soft_reset have been initialized.") NETWORK.controller.soft_reset() def test_network(service): """Test the network by sending commands to all the nodes.""" _LOGGER.info("Zwave test_network have been initialized.") NETWORK.test() def stop_zwave(_service_or_event): """Stop Z-Wave network.""" _LOGGER.info("Stopping ZWave network.") NETWORK.stop() if hass.state == 'RUNNING': hass.bus.fire(const.EVENT_NETWORK_STOP) def rename_node(service): """Rename a node.""" state = hass.states.get(service.data.get(ATTR_ENTITY_ID)) node_id = state.attributes.get(const.ATTR_NODE_ID) node = NETWORK.nodes[node_id] name = service.data.get(const.ATTR_NAME) node.name = name _LOGGER.info("Renamed ZWave node %d to %s", node_id, name) def set_config_parameter(service): """Set a config parameter to a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = NETWORK.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) selection = service.data.get(const.ATTR_CONFIG_VALUE) size = service.data.get(const.ATTR_CONFIG_SIZE, 2) i = 0 for value in (node.get_values( class_id=const.COMMAND_CLASS_CONFIGURATION).values()): if value.index == param and value.type == const.TYPE_LIST: _LOGGER.debug('Values for parameter %s: %s', param, value.data_items) i = len(value.data_items) - 1 if i == 0: node.set_config_param(param, selection, size) else: if selection > i: _LOGGER.info( 'Config parameter selection does not exist!' ' Please check zwcfg_[home_id].xml in' ' your homeassistant config directory. ' ' Available selections are 0 to %s', i) return node.set_config_param(param, selection, size) _LOGGER.info( 'Setting config parameter %s on Node %s ' 'with selection %s and size=%s', param, node_id, selection, size) def print_config_parameter(service): """Print a config parameter from a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = NETWORK.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) _LOGGER.info("Config parameter %s on Node %s : %s", param, node_id, get_config_value(node, param)) def print_node(service): """Print all information about z-wave node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = NETWORK.nodes[node_id] nice_print_node(node) def set_wakeup(service): """Set wake-up interval of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = NETWORK.nodes[node_id] value = service.data.get(const.ATTR_CONFIG_VALUE) if node.can_wake_up(): for value_id in node.get_values( class_id=const.COMMAND_CLASS_WAKE_UP): node.values[value_id].data = value _LOGGER.info("Node %s wake-up set to %d", node_id, value) else: _LOGGER.info("Node %s is not wakeable", node_id) def change_association(service): """Change an association in the zwave network.""" association_type = service.data.get(const.ATTR_ASSOCIATION) node_id = service.data.get(const.ATTR_NODE_ID) target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID) group = service.data.get(const.ATTR_GROUP) instance = service.data.get(const.ATTR_INSTANCE) node = ZWaveGroup(group, NETWORK, node_id) if association_type == 'add': node.add_association(target_node_id, instance) _LOGGER.info( "Adding association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) if association_type == 'remove': node.remove_association(target_node_id, instance) _LOGGER.info( "Removing association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) def start_zwave(_service_or_event): """Startup Z-Wave network.""" _LOGGER.info("Starting ZWave network.") NETWORK.start() hass.bus.fire(const.EVENT_NETWORK_START) # Need to be in STATE_AWAKED before talking to nodes. # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network # to be ready. for i in range(const.NETWORK_READY_WAIT_SECS): _LOGGER.debug("network state: %d %s", NETWORK.state, NETWORK.state_str) if NETWORK.state >= NETWORK.STATE_AWAKED: _LOGGER.info("zwave ready after %d seconds", i) break time.sleep(1) else: _LOGGER.warning( "zwave not ready after %d seconds, continuing anyway", const.NETWORK_READY_WAIT_SECS) _LOGGER.info("final network state: %d %s", NETWORK.state, NETWORK.state_str) polling_interval = convert(config[DOMAIN].get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: NETWORK.set_poll_interval(polling_interval, False) poll_interval = NETWORK.get_poll_interval() _LOGGER.info("zwave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zwave) # Register node services for Z-Wave network hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node, descriptions[const.SERVICE_ADD_NODE]) hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE, add_node_secure, descriptions[const.SERVICE_ADD_NODE_SECURE]) hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node, descriptions[const.SERVICE_REMOVE_NODE]) hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND, cancel_command, descriptions[const.SERVICE_CANCEL_COMMAND]) hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK, heal_network, descriptions[const.SERVICE_HEAL_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset, descriptions[const.SERVICE_SOFT_RESET]) hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK, test_network, descriptions[const.SERVICE_TEST_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_zwave, descriptions[const.SERVICE_STOP_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_START_NETWORK, start_zwave, descriptions[const.SERVICE_START_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node, descriptions[const.SERVICE_RENAME_NODE], schema=RENAME_NODE_SCHEMA) hass.services.register( DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER, set_config_parameter, descriptions[const.SERVICE_SET_CONFIG_PARAMETER], schema=SET_CONFIG_PARAMETER_SCHEMA) hass.services.register( DOMAIN, const.SERVICE_PRINT_CONFIG_PARAMETER, print_config_parameter, descriptions[const.SERVICE_PRINT_CONFIG_PARAMETER], schema=PRINT_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_CHANGE_ASSOCIATION, change_association, descriptions[const.SERVICE_CHANGE_ASSOCIATION], schema=CHANGE_ASSOCIATION_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_WAKEUP, set_wakeup, descriptions[const.SERVICE_SET_WAKEUP], schema=SET_WAKEUP_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_NODE, print_node, descriptions[const.SERVICE_PRINT_NODE], schema=PRINT_NODE_SCHEMA) # Setup autoheal if autoheal: _LOGGER.info("ZWave network autoheal is enabled.") track_time_change(hass, heal_network, hour=0, minute=0, second=0) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave) return True
def setup(hass, config): """Setup Z-Wave. Will automatically load components to support devices found on the network. """ descriptions = conf_util.load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) try: import libopenzwave except ImportError: _LOGGER.error("You are missing required dependency Python Open " "Z-Wave. Please follow instructions at: " "https://home-assistant.io/components/zwave/") return False from pydispatch import dispatcher # pylint: disable=import-error from openzwave.option import ZWaveOption from openzwave.network import ZWaveNetwork from openzwave.group import ZWaveGroup default_zwave_config_path = os.path.join( os.path.dirname(libopenzwave.__file__), 'config') # Load configuration use_debug = config[DOMAIN].get(CONF_DEBUG) autoheal = config[DOMAIN].get(CONF_AUTOHEAL) device_config = EntityValues(config[DOMAIN][CONF_DEVICE_CONFIG], config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN], config[DOMAIN][CONF_DEVICE_CONFIG_GLOB]) # Setup options options = ZWaveOption(config[DOMAIN].get(CONF_USB_STICK_PATH), user_path=hass.config.config_dir, config_path=config[DOMAIN].get( CONF_CONFIG_PATH, default_zwave_config_path)) options.set_console_output(use_debug) options.lock() network = hass.data[ZWAVE_NETWORK] = ZWaveNetwork(options, autostart=False) hass.data[DATA_ZWAVE_DICT] = {} if use_debug: # pragma: no cover def log_all(signal, value=None): """Log all the signals.""" print("") print("SIGNAL *****", signal) if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED, ZWaveNetwork.SIGNAL_VALUE_ADDED, ZWaveNetwork.SIGNAL_SCENE_EVENT, ZWaveNetwork.SIGNAL_NODE_EVENT, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED): pprint(_obj_to_dict(value)) print("") dispatcher.connect(log_all, weak=False) discovered_values = [] def value_added(node, value): """Called when a value is added to a node on the network.""" # Check if this value should be tracked by an existing entity for values in discovered_values: values.check_value(value) for schema in DISCOVERY_SCHEMAS: if not check_node_schema(node, schema): continue if not check_value_schema( value, schema[const.DISC_VALUES][const.DISC_PRIMARY]): continue values = ZWaveDeviceEntityValues(hass, schema, value, config, device_config) discovered_values.append(values) component = EntityComponent(_LOGGER, DOMAIN, hass) def node_added(node): """Called when a node is added on the network.""" entity = ZWaveNodeEntity(node, network) node_config = device_config.get(entity.entity_id) if node_config.get(CONF_IGNORED): _LOGGER.info("Ignoring node entity %s due to device settings.", entity.entity_id) return component.add_entities([entity]) def scene_activated(node, scene_id): """Called when a scene is activated on any node in the network.""" hass.bus.fire( const.EVENT_SCENE_ACTIVATED, { ATTR_ENTITY_ID: _node_object_id(node), const.ATTR_OBJECT_ID: _node_object_id(node), const.ATTR_SCENE_ID: scene_id }) def node_event_activated(node, value): """Called when a nodeevent is activated on any node in the network.""" hass.bus.fire( const.EVENT_NODE_EVENT, { const.ATTR_OBJECT_ID: _node_object_id(node), const.ATTR_BASIC_LEVEL: value }) def network_ready(): """Called when all awake nodes have been queried.""" _LOGGER.info("Zwave network is ready for use. All awake nodes" " have been queried. Sleeping nodes will be" " queried when they awake.") hass.bus.fire(const.EVENT_NETWORK_READY) def network_complete(): """Called when all nodes on network have been queried.""" _LOGGER.info("Zwave network is complete. All nodes on the network" " have been queried") hass.bus.fire(const.EVENT_NETWORK_COMPLETE) dispatcher.connect(value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False) dispatcher.connect(node_added, ZWaveNetwork.SIGNAL_NODE_ADDED, weak=False) dispatcher.connect(scene_activated, ZWaveNetwork.SIGNAL_SCENE_EVENT, weak=False) dispatcher.connect(node_event_activated, ZWaveNetwork.SIGNAL_NODE_EVENT, weak=False) dispatcher.connect(network_ready, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, weak=False) dispatcher.connect(network_complete, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED, weak=False) def add_node(service): """Switch into inclusion mode.""" _LOGGER.info("Zwave add_node have been initialized.") network.controller.add_node() def add_node_secure(service): """Switch into secure inclusion mode.""" _LOGGER.info("Zwave add_node_secure have been initialized.") network.controller.add_node(True) def remove_node(service): """Switch into exclusion mode.""" _LOGGER.info("Zwave remove_node have been initialized.") network.controller.remove_node() def cancel_command(service): """Cancel a running controller command.""" _LOGGER.info("Cancel running ZWave command.") network.controller.cancel_command() def heal_network(service): """Heal the network.""" _LOGGER.info("ZWave heal running.") network.heal() def soft_reset(service): """Soft reset the controller.""" _LOGGER.info("Zwave soft_reset have been initialized.") network.controller.soft_reset() def test_network(service): """Test the network by sending commands to all the nodes.""" _LOGGER.info("Zwave test_network have been initialized.") network.test() def stop_network(_service_or_event): """Stop Z-Wave network.""" _LOGGER.info("Stopping ZWave network.") network.stop() if hass.state == CoreState.running: hass.bus.fire(const.EVENT_NETWORK_STOP) def rename_node(service): """Rename a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = hass.data[ZWAVE_NETWORK].nodes[node_id] name = service.data.get(const.ATTR_NAME) node.name = name _LOGGER.info("Renamed ZWave node %d to %s", node_id, name) def remove_failed_node(service): """Remove failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info('Trying to remove zwave node %d', node_id) network.controller.remove_failed_node(node_id) def replace_failed_node(service): """Replace failed node.""" node_id = service.data.get(const.ATTR_NODE_ID) _LOGGER.info('Trying to replace zwave node %d', node_id) network.controller.replace_failed_node(node_id) def set_config_parameter(service): """Set a config parameter to a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) selection = service.data.get(const.ATTR_CONFIG_VALUE) size = service.data.get(const.ATTR_CONFIG_SIZE, 2) i = 0 for value in (node.get_values( class_id=const.COMMAND_CLASS_CONFIGURATION).values()): if value.index == param and value.type == const.TYPE_LIST: _LOGGER.debug('Values for parameter %s: %s', param, value.data_items) i = len(value.data_items) - 1 if i == 0: node.set_config_param(param, selection, size) else: if selection > i: _LOGGER.info( 'Config parameter selection does not exist!' ' Please check zwcfg_[home_id].xml in' ' your homeassistant config directory. ' ' Available selections are 0 to %s', i) return node.set_config_param(param, selection, size) _LOGGER.info( 'Setting config parameter %s on Node %s ' 'with selection %s and size=%s', param, node_id, selection, size) def print_config_parameter(service): """Print a config parameter from a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) _LOGGER.info("Config parameter %s on Node %s : %s", param, node_id, get_config_value(node, param)) def print_node(service): """Print all information about z-wave node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] nice_print_node(node) def set_wakeup(service): """Set wake-up interval of a node.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] value = service.data.get(const.ATTR_CONFIG_VALUE) if node.can_wake_up(): for value_id in node.get_values( class_id=const.COMMAND_CLASS_WAKE_UP): node.values[value_id].data = value _LOGGER.info("Node %s wake-up set to %d", node_id, value) else: _LOGGER.info("Node %s is not wakeable", node_id) def change_association(service): """Change an association in the zwave network.""" association_type = service.data.get(const.ATTR_ASSOCIATION) node_id = service.data.get(const.ATTR_NODE_ID) target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID) group = service.data.get(const.ATTR_GROUP) instance = service.data.get(const.ATTR_INSTANCE) node = ZWaveGroup(group, network, node_id) if association_type == 'add': node.add_association(target_node_id, instance) _LOGGER.info( "Adding association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) if association_type == 'remove': node.remove_association(target_node_id, instance) _LOGGER.info( "Removing association for node:%s in group:%s " "target node:%s, instance=%s", node_id, group, target_node_id, instance) @asyncio.coroutine def async_refresh_entity(service): """Refresh values that specific entity depends on.""" entity_id = service.data.get(ATTR_ENTITY_ID) async_dispatcher_send(hass, SIGNAL_REFRESH_ENTITY_FORMAT.format(entity_id)) def refresh_node(service): """Refresh all node info.""" node_id = service.data.get(const.ATTR_NODE_ID) node = network.nodes[node_id] node.refresh_info() def start_zwave(_service_or_event): """Startup Z-Wave network.""" _LOGGER.info("Starting ZWave network.") network.start() hass.bus.fire(const.EVENT_NETWORK_START) # Need to be in STATE_AWAKED before talking to nodes. # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network # to be ready. for i in range(const.NETWORK_READY_WAIT_SECS): _LOGGER.debug("network state: %d %s", hass.data[ZWAVE_NETWORK].state, network.state_str) if network.state >= network.STATE_AWAKED: _LOGGER.info("zwave ready after %d seconds", i) break time.sleep(1) else: _LOGGER.warning( "zwave not ready after %d seconds, continuing anyway", const.NETWORK_READY_WAIT_SECS) _LOGGER.info("final network state: %d %s", network.state, network.state_str) polling_interval = convert(config[DOMAIN].get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: network.set_poll_interval(polling_interval, False) poll_interval = network.get_poll_interval() _LOGGER.info("zwave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network) # Register node services for Z-Wave network hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node, descriptions[const.SERVICE_ADD_NODE]) hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE, add_node_secure, descriptions[const.SERVICE_ADD_NODE_SECURE]) hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node, descriptions[const.SERVICE_REMOVE_NODE]) hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND, cancel_command, descriptions[const.SERVICE_CANCEL_COMMAND]) hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK, heal_network, descriptions[const.SERVICE_HEAL_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset, descriptions[const.SERVICE_SOFT_RESET]) hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK, test_network, descriptions[const.SERVICE_TEST_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_network, descriptions[const.SERVICE_STOP_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_START_NETWORK, start_zwave, descriptions[const.SERVICE_START_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node, descriptions[const.SERVICE_RENAME_NODE], schema=RENAME_NODE_SCHEMA) hass.services.register( DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER, set_config_parameter, descriptions[const.SERVICE_SET_CONFIG_PARAMETER], schema=SET_CONFIG_PARAMETER_SCHEMA) hass.services.register( DOMAIN, const.SERVICE_PRINT_CONFIG_PARAMETER, print_config_parameter, descriptions[const.SERVICE_PRINT_CONFIG_PARAMETER], schema=PRINT_CONFIG_PARAMETER_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REMOVE_FAILED_NODE, remove_failed_node, descriptions[const.SERVICE_REMOVE_FAILED_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REPLACE_FAILED_NODE, replace_failed_node, descriptions[const.SERVICE_REPLACE_FAILED_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_CHANGE_ASSOCIATION, change_association, descriptions[const.SERVICE_CHANGE_ASSOCIATION], schema=CHANGE_ASSOCIATION_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_WAKEUP, set_wakeup, descriptions[const.SERVICE_SET_WAKEUP], schema=SET_WAKEUP_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_PRINT_NODE, print_node, descriptions[const.SERVICE_PRINT_NODE], schema=NODE_SERVICE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_ENTITY, async_refresh_entity, descriptions[const.SERVICE_REFRESH_ENTITY], schema=REFRESH_ENTITY_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_REFRESH_NODE, refresh_node, descriptions[const.SERVICE_REFRESH_NODE], schema=NODE_SERVICE_SCHEMA) # Setup autoheal if autoheal: _LOGGER.info("ZWave network autoheal is enabled.") track_time_change(hass, heal_network, hour=0, minute=0, second=0) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave) if 'frontend' in hass.config.components: register_built_in_panel(hass, 'zwave', 'Z-Wave', 'mdi:nfc') return True
def setup(hass, config): """Setup Z-Wave. Will automatically load components to support devices found on the network. """ # pylint: disable=global-statement, import-error global NETWORK descriptions = conf_util.load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) try: import libopenzwave except ImportError: _LOGGER.error("You are missing required dependency Python Open " "Z-Wave. Please follow instructions at: " "https://home-assistant.io/components/zwave/") return False from pydispatch import dispatcher from openzwave.option import ZWaveOption from openzwave.network import ZWaveNetwork default_zwave_config_path = os.path.join(os.path.dirname( libopenzwave.__file__), 'config') # Load configuration use_debug = config[DOMAIN].get(CONF_DEBUG) customize = config[DOMAIN].get(CONF_CUSTOMIZE) autoheal = config[DOMAIN].get(CONF_AUTOHEAL) # Setup options options = ZWaveOption( config[DOMAIN].get(CONF_USB_STICK_PATH), user_path=hass.config.config_dir, config_path=config[DOMAIN].get( CONF_CONFIG_PATH, default_zwave_config_path)) options.set_console_output(use_debug) options.lock() NETWORK = ZWaveNetwork(options, autostart=False) if use_debug: def log_all(signal, value=None): """Log all the signals.""" print("") print("SIGNAL *****", signal) if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED, ZWaveNetwork.SIGNAL_VALUE_ADDED, ZWaveNetwork.SIGNAL_SCENE_EVENT, ZWaveNetwork.SIGNAL_NODE_EVENT, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED): pprint(_obj_to_dict(value)) print("") dispatcher.connect(log_all, weak=False) def value_added(node, value): """Called when a value is added to a node on the network.""" for (component, generic_device_class, specific_device_class, command_class, value_type, value_genre) in DISCOVERY_COMPONENTS: _LOGGER.debug("Component=%s Node_id=%s query start", component, node.node_id) if node.generic not in generic_device_class and \ None not in generic_device_class: _LOGGER.debug("node.generic %s not None and in " "generic_device_class %s", node.generic, generic_device_class) continue if node.specific not in specific_device_class and \ None not in specific_device_class: _LOGGER.debug("node.specific %s is not None and in " "specific_device_class %s", node.specific, specific_device_class) continue if value.command_class not in command_class and \ None not in command_class: _LOGGER.debug("value.command_class %s is not None " "and in command_class %s", value.command_class, command_class) continue if value_type != value.type and value_type is not None: _LOGGER.debug("value.type %s != value_type %s", value.type, value_type) continue if value_genre != value.genre and value_genre is not None: _LOGGER.debug("value.genre %s != value_genre %s", value.genre, value_genre) continue # Configure node _LOGGER.debug("Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " "Genre=%s", node.node_id, node.generic, node.specific, value.command_class, value.type, value.genre) name = "{}.{}".format(component, _object_id(value)) node_config = customize.get(name, {}) polling_intensity = convert( node_config.get(CONF_POLLING_INTENSITY), int) if polling_intensity: value.enable_poll(polling_intensity) else: value.disable_poll() discovery.load_platform(hass, component, DOMAIN, { const.ATTR_NODE_ID: node.node_id, const.ATTR_VALUE_ID: value.value_id, }, config) def scene_activated(node, scene_id): """Called when a scene is activated on any node in the network.""" hass.bus.fire(const.EVENT_SCENE_ACTIVATED, { ATTR_ENTITY_ID: _node_object_id(node), const.ATTR_OBJECT_ID: _node_object_id(node), const.ATTR_SCENE_ID: scene_id }) def node_event_activated(node, value): """Called when a nodeevent is activated on any node in the network.""" hass.bus.fire(const.EVENT_NODE_EVENT, { const.ATTR_OBJECT_ID: _node_object_id(node), const.ATTR_BASIC_LEVEL: value }) def network_ready(): """Called when all awake nodes have been queried.""" _LOGGER.info("Zwave network is ready for use. All awake nodes" " have been queried. Sleeping nodes will be" " queried when they awake.") hass.bus.fire(const.EVENT_NETWORK_READY) def network_complete(): """Called when all nodes on network have been queried.""" _LOGGER.info("Zwave network is complete. All nodes on the network" " have been queried") hass.bus.fire(const.EVENT_NETWORK_COMPLETE) dispatcher.connect( value_added, ZWaveNetwork.SIGNAL_VALUE_ADDED, weak=False) dispatcher.connect( scene_activated, ZWaveNetwork.SIGNAL_SCENE_EVENT, weak=False) dispatcher.connect( node_event_activated, ZWaveNetwork.SIGNAL_NODE_EVENT, weak=False) dispatcher.connect( network_ready, ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED, weak=False) dispatcher.connect( network_complete, ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED, weak=False) def add_node(service): """Switch into inclusion mode.""" _LOGGER.info("Zwave add_node have been initialized.") NETWORK.controller.add_node() def add_node_secure(service): """Switch into secure inclusion mode.""" _LOGGER.info("Zwave add_node_secure have been initialized.") NETWORK.controller.add_node(True) def remove_node(service): """Switch into exclusion mode.""" _LOGGER.info("Zwave remove_node have been initialized.") NETWORK.controller.remove_node() def cancel_command(service): """Cancel a running controller command.""" _LOGGER.info("Cancel running ZWave command.") NETWORK.controller.cancel_command() def heal_network(service): """Heal the network.""" _LOGGER.info("ZWave heal running.") NETWORK.heal() def soft_reset(service): """Soft reset the controller.""" _LOGGER.info("Zwave soft_reset have been initialized.") NETWORK.controller.soft_reset() def test_network(service): """Test the network by sending commands to all the nodes.""" _LOGGER.info("Zwave test_network have been initialized.") NETWORK.test() def stop_zwave(_service_or_event): """Stop Z-Wave network.""" _LOGGER.info("Stopping ZWave network.") NETWORK.stop() hass.bus.fire(const.EVENT_NETWORK_STOP) def rename_node(service): """Rename a node.""" state = hass.states.get(service.data.get(ATTR_ENTITY_ID)) node_id = state.attributes.get(const.ATTR_NODE_ID) node = NETWORK.nodes[node_id] name = service.data.get(const.ATTR_NAME) node.name = name _LOGGER.info( "Renamed ZWave node %d to %s", node_id, name) def set_config_parameter(service): """Set a config parameter to a node.""" state = hass.states.get(service.data.get(ATTR_ENTITY_ID)) node_id = state.attributes.get(const.ATTR_NODE_ID) node = NETWORK.nodes[node_id] param = service.data.get(const.ATTR_CONFIG_PARAMETER) value = service.data.get(const.ATTR_CONFIG_VALUE) size = service.data.get(const.ATTR_CONFIG_SIZE, 2) node.set_config_param(param, value, size) _LOGGER.info("Setting config parameter %s on Node %s " "with value %s and size=%s", param, node_id, value, size) def start_zwave(_service_or_event): """Startup Z-Wave network.""" _LOGGER.info("Starting ZWave network.") NETWORK.start() hass.bus.fire(const.EVENT_NETWORK_START) # Need to be in STATE_AWAKED before talking to nodes. # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network # to be ready. for i in range(const.NETWORK_READY_WAIT_SECS): _LOGGER.debug( "network state: %d %s", NETWORK.state, NETWORK.state_str) if NETWORK.state >= NETWORK.STATE_AWAKED: _LOGGER.info("zwave ready after %d seconds", i) break time.sleep(1) else: _LOGGER.warning( "zwave not ready after %d seconds, continuing anyway", const.NETWORK_READY_WAIT_SECS) _LOGGER.info( "final network state: %d %s", NETWORK.state, NETWORK.state_str) polling_interval = convert( config[DOMAIN].get(CONF_POLLING_INTERVAL), int) if polling_interval is not None: NETWORK.set_poll_interval(polling_interval, False) poll_interval = NETWORK.get_poll_interval() _LOGGER.info("zwave polling interval set to %d ms", poll_interval) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_zwave) # Register node services for Z-Wave network hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node, descriptions[const.SERVICE_ADD_NODE]) hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE, add_node_secure, descriptions[const.SERVICE_ADD_NODE_SECURE]) hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node, descriptions[const.SERVICE_REMOVE_NODE]) hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND, cancel_command, descriptions[const.SERVICE_CANCEL_COMMAND]) hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK, heal_network, descriptions[const.SERVICE_HEAL_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset, descriptions[const.SERVICE_SOFT_RESET]) hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK, test_network, descriptions[const.SERVICE_TEST_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK, stop_zwave, descriptions[const.SERVICE_STOP_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_START_NETWORK, start_zwave, descriptions[const.SERVICE_START_NETWORK]) hass.services.register(DOMAIN, const.SERVICE_RENAME_NODE, rename_node, descriptions[const.SERVICE_RENAME_NODE], schema=RENAME_NODE_SCHEMA) hass.services.register(DOMAIN, const.SERVICE_SET_CONFIG_PARAMETER, set_config_parameter, descriptions[ const.SERVICE_SET_CONFIG_PARAMETER], schema=SET_CONFIG_PARAMETER_SCHEMA) # Setup autoheal if autoheal: _LOGGER.info("ZWave network autoheal is enabled.") track_time_change(hass, heal_network, hour=0, minute=0, second=0) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave) return True
def track_time_change_decorator(action): """Decorator to track time changes.""" event.track_time_change(HASS, functools.partial(action, HASS), year, month, day, hour, minute, second) return action