Example #1
0
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
Example #2
0
 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))
Example #3
0
 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))
Example #4
0
 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))
Example #5
0
 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))
Example #6
0
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
Example #7
0
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
Example #8
0
 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))
Example #9
0
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()
Example #10
0
    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)
Example #11
0
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()
Example #12
0
 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)
Example #13
0
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()
Example #14
0
    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"])
Example #15
0
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
Example #16
0
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
Example #17
0
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)
Example #19
0
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
Example #20
0
    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))
Example #21
0
    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()
Example #22
0
    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))
Example #23
0
    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_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))
Example #25
0
    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()
Example #26
0
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
Example #27
0
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
Example #28
0
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
Example #29
0
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 __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'])
Example #31
0
 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()
Example #32
0
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
Example #33
0
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
Example #34
0
    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()
Example #35
0
    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
Example #38
0
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
Example #39
0
    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)
Example #41
0
    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)
Example #42
0
    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()
Example #43
0
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)
Example #44
0
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
Example #45
0
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
Example #46
0
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
Example #47
0
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
Example #48
0
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
Example #50
0
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
Example #51
0
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
Example #52
0
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
Example #53
0
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
Example #54
0
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
Example #55
0
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