Exemplo n.º 1
0
    def test_disable_component_if_invalid_return(self):
        """Test disabling component if invalid return."""
        loader.set_component(
            'disabled_component',
            MockModule('disabled_component', setup=lambda hass, config: None))

        assert not bootstrap.setup_component(self.hass, 'disabled_component')
        assert loader.get_component('disabled_component') is None
        assert 'disabled_component' not in self.hass.config.components

        loader.set_component(
            'disabled_component',
            MockModule('disabled_component', setup=lambda hass, config: False))

        assert not bootstrap.setup_component(self.hass, 'disabled_component')
        assert loader.get_component('disabled_component') is not None
        assert 'disabled_component' not in self.hass.config.components

        loader.set_component(
            'disabled_component',
            MockModule('disabled_component', setup=lambda hass, config: True))

        assert bootstrap.setup_component(self.hass, 'disabled_component')
        assert loader.get_component('disabled_component') is not None
        assert 'disabled_component' in self.hass.config.components
Exemplo n.º 2
0
def is_on(hass, entity_id=None):
    """Load up the module to call the is_on method.

    If there is no entity id given we will check all.
    """
    if entity_id:
        group = get_component('group')

        entity_ids = group.expand_entity_ids(hass, [entity_id])
    else:
        entity_ids = hass.states.entity_ids()

    for entity_id in entity_ids:
        domain = split_entity_id(entity_id)[0]

        module = get_component(domain)

        try:
            if module.is_on(hass, entity_id):
                return True

        except AttributeError:
            # module is None or method is_on does not exist
            _LOGGER.exception("Failed to call %s.is_on for %s",
                              module, entity_id)

    return False
Exemplo n.º 3
0
    def __init__(self, hass, state_topic, command_topic, qos, retain,
                 payload_on, payload_off, optimistic, value_template):
        """

        @return:
        """
        self.hass = hass
        self._mqtt = loader.get_component('mqtt')
        self._switch = loader.get_component("switch")
        self._hass = hass
        self._state_topic = state_topic
        self._command_topic = command_topic
        self._qos = qos
        self._retain = retain
        self._payload_on = payload_on
        self._payload_off = payload_off
        self._optimistic = optimistic

        def command_recevie(topic, payload, qos):
            if payload == payload_on:
                self.turn_on()
            elif payload == payload_off:
                self.turn_off()

        self._mqtt.subscribe(hass, command_topic, command_recevie)
Exemplo n.º 4
0
async def test_log_warning_custom_component(hass, caplog):
    """Test that we log a warning when loading a custom component."""
    loader.get_component(hass, 'test_standalone')
    assert \
        'You are using a custom component for test_standalone' in caplog.text

    loader.get_component(hass, 'light.test')
    assert 'You are using a custom component for light.test' in caplog.text
Exemplo n.º 5
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the Fitbit sensor."""
    config_path = hass.config.path(FITBIT_CONFIG_FILE)
    if os.path.isfile(config_path):
        config_file = config_from_file(config_path)
        if config_file == DEFAULT_CONFIG:
            request_app_setup(hass, config, add_devices, config_path,
                              discovery_info=None)
            return False
    else:
        config_file = config_from_file(config_path, DEFAULT_CONFIG)
        request_app_setup(hass, config, add_devices, config_path,
                          discovery_info=None)
        return False

    if "fitbit" in _CONFIGURING:
        get_component("configurator").request_done(_CONFIGURING.pop("fitbit"))

    import fitbit

    access_token = config_file.get("access_token")
    refresh_token = config_file.get("refresh_token")
    if None not in (access_token, refresh_token):
        authd_client = fitbit.Fitbit(config_file.get("client_id"),
                                     config_file.get("client_secret"),
                                     access_token=access_token,
                                     refresh_token=refresh_token)

        if int(time.time()) - config_file.get("last_saved_at", 0) > 3600:
            authd_client.client.refresh_token()

        authd_client.system = authd_client.user_profile_get()["user"]["locale"]

        dev = []
        for resource in config.get("monitored_resources",
                                   FITBIT_DEFAULT_RESOURCE_LIST):
            dev.append(FitbitSensor(authd_client, config_path, resource,
                                    hass.config.temperature_unit ==
                                    TEMP_CELSIUS))
        add_devices(dev)

    else:
        oauth = fitbit.api.FitbitOauth2Client(config_file.get("client_id"),
                                              config_file.get("client_secret"))

        redirect_uri = "{}{}".format(hass.config.api.base_url,
                                     FITBIT_AUTH_CALLBACK_PATH)

        fitbit_auth_start_url, _ = oauth.authorize_token_url(
            redirect_uri=redirect_uri,
            scope=["activity", "heartrate", "nutrition", "profile",
                   "settings", "sleep", "weight"])

        hass.wsgi.register_redirect(FITBIT_AUTH_START, fitbit_auth_start_url)
        hass.wsgi.register_view(FitbitAuthCallbackView(hass, config,
                                                       add_devices, oauth))

        request_oauth_completion(hass)
Exemplo n.º 6
0
    def setUp(self):  # pylint: disable=invalid-name
        """ Init needed objects. """
        self.hass = get_test_home_assistant()

        self.hass.states.set('light.Bowl', STATE_ON)
        self.hass.states.set('light.Ceiling', STATE_OFF)
        self.hass.states.set('light.Kitchen', STATE_OFF)

        loader.get_component('group').setup_group(
            self.hass, 'test', ['light.Ceiling', 'light.Kitchen'])
Exemplo n.º 7
0
def setup_ecobee(hass, network, config):
    """Setup Ecobee thermostat."""
    # If ecobee has a PIN then it needs to be configured.
    if network.pin is not None:
        request_configuration(network, hass, config)
        return

    if 'ecobee' in _CONFIGURING:
        configurator = get_component('configurator')
        configurator.request_done(_CONFIGURING.pop('ecobee'))

    # Ensure component is loaded
    bootstrap.setup_component(hass, 'thermostat', config)
    bootstrap.setup_component(hass, 'sensor', config)

    hold_temp = config[DOMAIN].get(HOLD_TEMP, False)

    # Fire thermostat discovery event
    hass.bus.fire(EVENT_PLATFORM_DISCOVERED, {
        ATTR_SERVICE: DISCOVER_THERMOSTAT,
        ATTR_DISCOVERED: {'hold_temp': hold_temp}
    })

    # Fire sensor discovery event
    hass.bus.fire(EVENT_PLATFORM_DISCOVERED, {
        ATTR_SERVICE: DISCOVER_SENSORS,
        ATTR_DISCOVERED: {}
    })
Exemplo n.º 8
0
def setup(hass, config):
    """ Sets up the device tracker. """

    if not util.validate_config(config, {DOMAIN: [ha.CONF_TYPE]}, _LOGGER):
        return False

    tracker_type = config[DOMAIN][ha.CONF_TYPE]

    tracker_implementation = get_component(
        'device_tracker.{}'.format(tracker_type))

    if tracker_implementation is None:
        _LOGGER.error("Unknown device_tracker type specified.")

        return False

    device_scanner = tracker_implementation.get_scanner(hass, config)

    if device_scanner is None:
        _LOGGER.error("Failed to initialize device scanner for %s",
                      tracker_type)

        return False

    DeviceTracker(hass, device_scanner)

    return True
Exemplo n.º 9
0
def request_configuration(nest, hass, config):
    """Request configuration steps from the user."""
    configurator = get_component('configurator')
    if 'nest' in _CONFIGURING:
        _LOGGER.debug("configurator failed")
        configurator.notify_errors(
            _CONFIGURING['nest'], "Failed to configure, please try again.")
        return

    def nest_configuration_callback(data):
        """The actions to do when our configuration callback is called."""
        _LOGGER.debug("configurator callback")
        pin = data.get('pin')
        setup_nest(hass, nest, config, pin=pin)

    _CONFIGURING['nest'] = configurator.request_config(
        hass, "Nest", nest_configuration_callback,
        description=('To configure Nest, click Request Authorization below, '
                     'log into your Nest account, '
                     'and then enter the resulting PIN'),
        link_name='Request Authorization',
        link_url=nest.authorize_url,
        submit_caption="Confirm",
        fields=[{'id': 'pin', 'name': 'Enter the PIN', 'type': ''}]
    )
Exemplo n.º 10
0
    def test_light_profiles(self):
        """ Test light profiles. """
        platform = loader.get_component('light.test')
        platform.init()

        user_light_file = self.hass.get_config_path(light.LIGHT_PROFILES_FILE)

        with open(user_light_file, 'w') as user_file:
            user_file.write('id,x,y,brightness\n')
            user_file.write('test,.4,.6,100\n')

        self.assertTrue(light.setup(
            self.hass, {light.DOMAIN: {CONF_PLATFORM: 'test'}}
        ))

        dev1, dev2, dev3 = platform.DEVICES

        light.turn_on(self.hass, dev1.entity_id, profile='test')

        self.hass.pool.block_till_done()

        method, data = dev1.last_call('turn_on')

        self.assertEqual(
            {light.ATTR_XY_COLOR: [.4, .6], light.ATTR_BRIGHTNESS: 100},
            data)
Exemplo n.º 11
0
def request_configuration(device_id, insteonhub, model, hass,
                          add_devices_callback):
    """Request configuration steps from the user."""
    configurator = get_component('configurator')

    # We got an error if this method is called while we are configuring
    if device_id in _CONFIGURING:
        configurator.notify_errors(
            _CONFIGURING[device_id], 'Failed to register, please try again.')

        return

    def insteon_fan_config_callback(data):
        """The actions to do when our configuration callback is called."""
        setup_fan(device_id, data.get('name'), insteonhub, hass,
                  add_devices_callback)

    _CONFIGURING[device_id] = configurator.request_config(
        hass, 'Insteon  ' + model + ' addr: ' + device_id,
        insteon_fan_config_callback,
        description=('Enter a name for ' + model + ' Fan addr: ' + device_id),
        entity_picture='/static/images/config_insteon.png',
        submit_caption='Confirm',
        fields=[{'id': 'name', 'name': 'Name', 'type': ''}]
    )
Exemplo n.º 12
0
    def test_update_stale(self):
        """Test stalled update."""
        scanner = get_component('device_tracker.test').SCANNER
        scanner.reset()
        scanner.come_home('DEV1')

        register_time = datetime(2015, 9, 15, 23, tzinfo=dt_util.UTC)
        scan_time = datetime(2015, 9, 15, 23, 1, tzinfo=dt_util.UTC)

        with patch('homeassistant.components.device_tracker.dt_util.utcnow',
                   return_value=register_time):
            self.assertTrue(device_tracker.setup(self.hass, {
                'device_tracker': {
                    'platform': 'test',
                    'consider_home': 59,
                }}))

        self.assertEqual(STATE_HOME,
                         self.hass.states.get('device_tracker.dev1').state)

        scanner.leave_home('DEV1')

        with patch('homeassistant.components.device_tracker.dt_util.utcnow',
                   return_value=scan_time):
            fire_time_changed(self.hass, scan_time)
            self.hass.pool.block_till_done()

        self.assertEqual(STATE_NOT_HOME,
                         self.hass.states.get('device_tracker.dev1').state)
Exemplo n.º 13
0
    def test_update_stale(self):
        """Test stalled update."""
        scanner = get_component(self.hass, 'device_tracker.test').SCANNER
        scanner.reset()
        scanner.come_home('DEV1')

        register_time = datetime(2015, 9, 15, 23, tzinfo=dt_util.UTC)
        scan_time = datetime(2015, 9, 15, 23, 1, tzinfo=dt_util.UTC)

        with patch('homeassistant.components.device_tracker.dt_util.utcnow',
                   return_value=register_time):
            with assert_setup_component(1, device_tracker.DOMAIN):
                assert setup_component(self.hass, device_tracker.DOMAIN, {
                    device_tracker.DOMAIN: {
                        CONF_PLATFORM: 'test',
                        device_tracker.CONF_CONSIDER_HOME: 59,
                    }})
                self.hass.block_till_done()

        assert STATE_HOME == \
            self.hass.states.get('device_tracker.dev1').state

        scanner.leave_home('DEV1')

        with patch('homeassistant.components.device_tracker.dt_util.utcnow',
                   return_value=scan_time):
            fire_time_changed(self.hass, scan_time)
            self.hass.block_till_done()

        assert STATE_NOT_HOME == \
            self.hass.states.get('device_tracker.dev1').state
Exemplo n.º 14
0
def setup(hass, config):
    """ Sets up the device tracker. """

    if not validate_config(config, {DOMAIN: [CONF_PLATFORM]}, _LOGGER):
        return False

    tracker_type = config[DOMAIN].get(CONF_PLATFORM)

    tracker_implementation = get_component(
        'device_tracker.{}'.format(tracker_type))

    if tracker_implementation is None:
        _LOGGER.error("Unknown device_tracker type specified.")

        return False

    device_scanner = tracker_implementation.get_scanner(hass, config)

    if device_scanner is None:
        _LOGGER.error("Failed to initialize device scanner for %s",
                      tracker_type)

        return False

    seconds = util.convert(config[DOMAIN].get(CONF_SECONDS), int,
                           DEFAULT_CONF_SECONDS)

    track_new_devices = config[DOMAIN].get(TRACK_NEW_DEVICES) or False
    _LOGGER.info("Tracking new devices: %s", track_new_devices)

    tracker = DeviceTracker(hass, device_scanner, seconds, track_new_devices)

    # We only succeeded if we got to parse the known devices file
    return not tracker.invalid_known_devices_file
Exemplo n.º 15
0
def _setup_component(hass, domain, config):
    """ Setup a component for Home Assistant. """
    component = loader.get_component(domain)

    missing_deps = [dep for dep in component.DEPENDENCIES if dep not in hass.config.components]

    if missing_deps:
        _LOGGER.error("Not initializing %s because not all dependencies loaded: %s", domain, ", ".join(missing_deps))

        return False

    try:
        if component.setup(hass, config):
            hass.config.components.append(component.DOMAIN)

            # Assumption: if a component does not depend on groups
            # it communicates with devices
            if group.DOMAIN not in component.DEPENDENCIES:
                hass.pool.add_worker()

            hass.bus.fire(EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: component.DOMAIN})

            return True

        else:
            _LOGGER.error("component %s failed to initialize", domain)

    except Exception:  # pylint: disable=broad-except
        _LOGGER.exception("Error during setup of component %s", domain)

    return False
    def test_heater_switch(self):
        """Test heater switching test switch."""
        platform = loader.get_component(self.hass, 'switch.test')
        platform.init()
        self.switch_1 = platform.DEVICES[1]
        assert setup_component(self.hass, switch.DOMAIN, {'switch': {
            'platform': 'test'}})
        heater_switch = self.switch_1.entity_id

        assert setup_component(self.hass, climate.DOMAIN, {'climate': {
            'platform': 'generic_thermostat',
            'name': 'test',
            'heater': heater_switch,
            'target_sensor': ENT_SENSOR
        }})

        self.assertEqual(STATE_OFF,
                         self.hass.states.get(heater_switch).state)

        self._setup_sensor(18)
        self.hass.block_till_done()
        climate.set_temperature(self.hass, 23)
        self.hass.block_till_done()

        self.assertEqual(STATE_ON,
                         self.hass.states.get(heater_switch).state)
Exemplo n.º 17
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup the mysensors platform for sensors."""
    # Only act if loaded via mysensors by discovery event.
    # Otherwise gateway is not setup.
    if discovery_info is None:
        return

    mysensors = get_component('mysensors')

    for gateway in mysensors.GATEWAYS.values():
        # Define the S_TYPES and V_TYPES that the platform should handle as
        # states. Map them in a dict of lists.
        pres = gateway.const.Presentation
        set_req = gateway.const.SetReq
        map_sv_types = {
            pres.S_DIMMER: [set_req.V_DIMMER],
        }
        device_class_map = {
            pres.S_DIMMER: MySensorsLightDimmer,
        }
        if float(gateway.version) >= 1.5:
            # Add V_RGBW when rgb_white is implemented in the frontend
            map_sv_types.update({
                pres.S_RGB_LIGHT: [set_req.V_RGB],
            })
            map_sv_types[pres.S_DIMMER].append(set_req.V_PERCENTAGE)
            device_class_map.update({
                pres.S_RGB_LIGHT: MySensorsLightRGB,
            })
        devices = {}
        gateway.platform_callbacks.append(mysensors.pf_callback_factory(
            map_sv_types, devices, add_devices, device_class_map))
Exemplo n.º 18
0
def prepare_setup_platform(hass, config, domain, platform_name):
    """ Loads a platform and makes sure dependencies are setup. """
    _ensure_loader_prepared(hass)

    platform_path = PLATFORM_FORMAT.format(domain, platform_name)

    platform = loader.get_component(platform_path)

    # Not found
    if platform is None:
        return None

    # Already loaded or no dependencies
    elif platform_path in hass.config.components or not hasattr(platform, "DEPENDENCIES"):
        return platform

    # Load dependencies
    for component in platform.DEPENDENCIES:
        if not setup_component(hass, component, config):
            _LOGGER.error(
                "Unable to prepare setup for platform %s because dependency " "%s could not be initialized",
                platform_path,
                component,
            )
            return None

    return platform
Exemplo n.º 19
0
def prepare_setup_platform(hass, config, domain, platform_name):
    """ Loads a platform and makes sure dependencies are setup. """
    _ensure_loader_prepared(hass)

    platform_path = PLATFORM_FORMAT.format(domain, platform_name)

    platform = loader.get_component(platform_path)

    # Not found
    if platform is None:
        return None

    # Already loaded
    elif platform_path in hass.config.components:
        return platform

    # Load dependencies
    if hasattr(platform, 'DEPENDENCIES'):
        for component in platform.DEPENDENCIES:
            if not setup_component(hass, component, config):
                _LOGGER.error(
                    'Unable to prepare setup for platform %s because '
                    'dependency %s could not be initialized', platform_path,
                    component)
                return None

    if not _handle_requirements(platform, platform_path):
        return None

    return platform
Exemplo n.º 20
0
def setup(hass, config):
    """ Sets up the Wink component. """
    logger = logging.getLogger(__name__)

    if not validate_config(config, {DOMAIN: [CONF_ACCESS_TOKEN]}, logger):
        return False

    import pywink
    pywink.set_bearer_token(config[DOMAIN][CONF_ACCESS_TOKEN])

    # Load components for the devices in the Wink that we support
    for component_name, func_exists, discovery_type in (
            ('light', pywink.get_bulbs, DISCOVER_LIGHTS),
            ('switch', pywink.get_switches, DISCOVER_SWITCHES),
            ('sensor', pywink.get_sensors, DISCOVER_SENSORS)):

        if func_exists():
            component = get_component(component_name)

            # Ensure component is loaded
            bootstrap.setup_component(hass, component.DOMAIN, config)

            # Fire discovery event
            hass.bus.fire(EVENT_PLATFORM_DISCOVERED, {
                ATTR_SERVICE: discovery_type,
                ATTR_DISCOVERED: {}
            })

    return True
Exemplo n.º 21
0
def extract_entity_ids(hass, service_call, expand_group=True):
    """Helper method to extract a list of entity ids from a service call.

    Will convert group entity ids to the entity ids it represents.

    Async friendly.
    """
    if not (service_call.data and ATTR_ENTITY_ID in service_call.data):
        return []

    group = get_component('group')

    # Entity ID attr can be a list or a string
    service_ent_id = service_call.data[ATTR_ENTITY_ID]

    if expand_group:

        if isinstance(service_ent_id, str):
            return group.expand_entity_ids(hass, [service_ent_id])

        return [ent_id for ent_id in
                group.expand_entity_ids(hass, service_ent_id)]

    else:

        if isinstance(service_ent_id, str):
            return [service_ent_id]

        return service_ent_id
Exemplo n.º 22
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the available Netatmo weather sensors."""
    netatmo = get_component('netatmo')
    data = NetAtmoData(netatmo.NETATMO_AUTH, config.get(CONF_STATION, None))

    dev = []
    import lnetatmo
    try:
        if CONF_MODULES in config:
            # Iterate each module
            for module_name, monitored_conditions in\
                    config[CONF_MODULES].items():
                # Test if module exist """
                if module_name not in data.get_module_names():
                    _LOGGER.error('Module name: "%s" not found', module_name)
                    continue
                # Only create sensor for monitored """
                for variable in monitored_conditions:
                    dev.append(NetAtmoSensor(data, module_name, variable))
        else:
            for module_name in data.get_module_names():
                for variable in\
                        data.station_data.monitoredConditions(module_name):
                    if variable in SENSOR_TYPES.keys():
                        dev.append(NetAtmoSensor(data, module_name, variable))
                    else:
                        _LOGGER.warning("Ignoring unknown var %s for mod %s",
                                        variable, module_name)
    except lnetatmo.NoDevice:
        return None

    add_devices(dev, True)
Exemplo n.º 23
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup access to Netatmo binary sensor."""
    netatmo = get_component('netatmo')
    home = config.get(CONF_HOME, None)
    timeout = config.get(CONF_TIMEOUT, 15)

    module_name = None

    import lnetatmo
    try:
        data = WelcomeData(netatmo.NETATMO_AUTH, home)
        if data.get_camera_names() == []:
            return None
    except lnetatmo.NoDevice:
        return None

    sensors = config.get(CONF_MONITORED_CONDITIONS, SENSOR_TYPES)

    for camera_name in data.get_camera_names():
        if CONF_CAMERAS in config:
            if config[CONF_CAMERAS] != [] and \
               camera_name not in config[CONF_CAMERAS]:
                continue
        for variable in sensors:
            if variable in ('Tag Vibration', 'Tag Open'):
                continue
            add_devices([WelcomeBinarySensor(data, camera_name, module_name,
                                             home, timeout, variable)])

        for module_name in data.get_module_names(camera_name):
            for variable in sensors:
                if variable in ('Tag Vibration', 'Tag Open'):
                    add_devices([WelcomeBinarySensor(data, camera_name,
                                                     module_name, home,
                                                     timeout, variable)])
Exemplo n.º 24
0
def request_configuration(host, hass, add_devices, filename,
                          allow_unreachable, allow_in_emulated_hue,
                          allow_hue_groups):
    """Request configuration steps from the user."""
    configurator = get_component('configurator')

    # We got an error if this method is called while we are configuring
    if host in _CONFIGURING:
        configurator.notify_errors(
            _CONFIGURING[host], "Failed to register, please try again.")

        return

    # pylint: disable=unused-argument
    def hue_configuration_callback(data):
        """The actions to do when our configuration callback is called."""
        setup_bridge(host, hass, add_devices, filename, allow_unreachable,
                     allow_in_emulated_hue, allow_hue_groups)

    _CONFIGURING[host] = configurator.request_config(
        hass, "Philips Hue", hue_configuration_callback,
        description=("Press the button on the bridge to register Philips Hue "
                     "with Home Assistant."),
        entity_picture="/static/images/logo_philips_hue.png",
        description_image="/static/images/config_philips_hue.jpg",
        submit_caption="I have pressed the button"
    )
Exemplo n.º 25
0
def request_configuration(host, hass, config, add_devices_callback):
    """Request configuration steps from the user."""
    configurator = get_component('configurator')
    # We got an error if this method is called while we are configuring
    if host in _CONFIGURING:
        configurator.notify_errors(_CONFIGURING[host],
                                   'Failed to register, please try again.')

        return

    def plex_configuration_callback(data):
        """The actions to do when our configuration callback is called."""
        setup_plexserver(host,
                         data.get('token'), hass, config,
                         add_devices_callback)

    _CONFIGURING[host] = configurator.request_config(
        hass,
        'Plex Media Server',
        plex_configuration_callback,
        description=('Enter the X-Plex-Token'),
        entity_picture='/static/images/logo_plex_mediaserver.png',
        submit_caption='Confirm',
        fields=[{
            'id': 'token',
            'name': 'X-Plex-Token',
            'type': ''
        }])
Exemplo n.º 26
0
def get_scanner(hass, config):
    """Setup Unifi device_tracker."""
    from pyunifi.controller import Controller

    host = config[DOMAIN].get(CONF_HOST)
    username = config[DOMAIN].get(CONF_USERNAME)
    password = config[DOMAIN].get(CONF_PASSWORD)
    site_id = config[DOMAIN].get(CONF_SITE_ID)
    port = config[DOMAIN].get(CONF_PORT)

    persistent_notification = loader.get_component('persistent_notification')
    try:
        ctrl = Controller(host, username, password, port, 'v4', site_id)
    except urllib.error.HTTPError as ex:
        _LOGGER.error('Failed to connect to Unifi: %s', ex)
        persistent_notification.create(
            hass, 'Failed to connect to Unifi. '
            'Error: {}<br />'
            'You will need to restart hass after fixing.'
            ''.format(ex),
            title=NOTIFICATION_TITLE,
            notification_id=NOTIFICATION_ID)
        return False

    return UnifiScanner(ctrl)
Exemplo n.º 27
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup the available OctoPrint sensors."""
    octoprint = get_component('octoprint')
    name = config.get(CONF_NAME)
    monitored_conditions = config.get(CONF_MONITORED_CONDITIONS)

    devices = []
    types = ["actual", "target"]
    for octo_type in monitored_conditions:
        if octo_type == "Temperatures":
            for tool in octoprint.OCTOPRINT.get_tools():
                for temp_type in types:
                    new_sensor = OctoPrintSensor(octoprint.OCTOPRINT,
                                                 temp_type,
                                                 temp_type,
                                                 name,
                                                 SENSOR_TYPES[octo_type][3],
                                                 SENSOR_TYPES[octo_type][0],
                                                 SENSOR_TYPES[octo_type][1],
                                                 tool)
                    devices.append(new_sensor)
        else:
            new_sensor = OctoPrintSensor(octoprint.OCTOPRINT,
                                         octo_type,
                                         SENSOR_TYPES[octo_type][2],
                                         name,
                                         SENSOR_TYPES[octo_type][3],
                                         SENSOR_TYPES[octo_type][0],
                                         SENSOR_TYPES[octo_type][1])
            devices.append(new_sensor)
    add_devices(devices)
Exemplo n.º 28
0
def setup_nest(hass, nest, config, pin=None):
    """Setup Nest Devices."""
    if pin is not None:
        _LOGGER.debug("pin acquired, requesting access token")
        nest.request_token(pin)

    if nest.access_token is None:
        _LOGGER.debug("no access_token, requesting configuration")
        request_configuration(nest, hass, config)
        return

    if 'nest' in _CONFIGURING:
        _LOGGER.debug("configuration done")
        configurator = get_component('configurator')
        configurator.request_done(_CONFIGURING.pop('nest'))

    _LOGGER.debug("proceeding with setup")
    conf = config[DOMAIN]
    hass.data[DATA_NEST] = NestDevice(hass, conf, nest)

    _LOGGER.debug("proceeding with discovery")
    discovery.load_platform(hass, 'climate', DOMAIN, {}, config)
    discovery.load_platform(hass, 'sensor', DOMAIN, {}, config)
    discovery.load_platform(hass, 'binary_sensor', DOMAIN, {}, config)
    discovery.load_platform(hass, 'camera', DOMAIN, {}, config)
    _LOGGER.debug("setup done")

    return True
Exemplo n.º 29
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the SimpliSafe platform."""
    from simplipy.api import SimpliSafeApiInterface, get_systems
    name = config.get(CONF_NAME)
    code = config.get(CONF_CODE)
    username = config.get(CONF_USERNAME)
    password = config.get(CONF_PASSWORD)

    persistent_notification = loader.get_component('persistent_notification')
    simplisafe = SimpliSafeApiInterface()
    status = simplisafe.set_credentials(username, password)
    if status:
        hass.data[DOMAIN] = simplisafe
        locations = get_systems(simplisafe)
        for location in locations:
            add_devices([SimpliSafeAlarm(location, name, code)])
    else:
        message = 'Failed to log into SimpliSafe. Check credentials.'
        _LOGGER.error(message)
        persistent_notification.create(
            hass, message,
            title=NOTIFICATION_TITLE,
            notification_id=NOTIFICATION_ID)
        return False

    def logout(event):
        """Logout of the SimpliSafe API."""
        hass.data[DOMAIN].logout()

    hass.bus.listen(EVENT_HOMEASSISTANT_STOP, logout)
Exemplo n.º 30
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the MyQ component."""
    from pymyq import MyQAPI as pymyq

    username = config.get(CONF_USERNAME)
    password = config.get(CONF_PASSWORD)
    brand = config.get(CONF_TYPE)
    persistent_notification = loader.get_component('persistent_notification')
    myq = pymyq(username, password, brand)

    try:
        if not myq.is_supported_brand():
            raise ValueError("Unsupported type. See documentation")

        if not myq.is_login_valid():
            raise ValueError("Username or Password is incorrect")

        add_devices(MyQDevice(myq, door) for door in myq.get_garage_doors())
        return True

    except (TypeError, KeyError, NameError, ValueError) as ex:
        _LOGGER.error("%s", ex)
        persistent_notification.create(
            hass, 'Error: {}<br />'
            'You will need to restart hass after fixing.'
            ''.format(ex),
            title=NOTIFICATION_TITLE,
            notification_id=NOTIFICATION_ID)
        return False
Exemplo n.º 31
0
def _async_setup_component(hass: core.HomeAssistant, domain: str,
                           config) -> bool:
    """Setup a component for Home Assistant.

    This method is a coroutine.
    """
    # pylint: disable=too-many-return-statements
    if domain in hass.config.components:
        return True

    setup_lock = hass.data.get('setup_lock')
    if setup_lock is None:
        setup_lock = hass.data['setup_lock'] = asyncio.Lock(loop=hass.loop)

    setup_progress = hass.data.get('setup_progress')
    if setup_progress is None:
        setup_progress = hass.data['setup_progress'] = []

    if domain in setup_progress:
        _LOGGER.error('Attempt made to setup %s during setup of %s', domain,
                      domain)
        _async_persistent_notification(hass, domain, True)
        return False

    try:
        # Used to indicate to discovery that a setup is ongoing and allow it
        # to wait till it is done.
        did_lock = False
        if not setup_lock.locked():
            yield from setup_lock.acquire()
            did_lock = True

        setup_progress.append(domain)
        config = yield from async_prepare_setup_component(hass, config, domain)

        if config is None:
            return False

        component = loader.get_component(domain)
        if component is None:
            _async_persistent_notification(hass, domain)
            return False

        async_comp = hasattr(component, 'async_setup')

        try:
            _LOGGER.info("Setting up %s", domain)
            if async_comp:
                result = yield from component.async_setup(hass, config)
            else:
                result = yield from hass.loop.run_in_executor(
                    None, component.setup, hass, config)
        except Exception:  # pylint: disable=broad-except
            _LOGGER.exception('Error during setup of component %s', domain)
            _async_persistent_notification(hass, domain, True)
            return False

        if result is False:
            _LOGGER.error('component %s failed to initialize', domain)
            _async_persistent_notification(hass, domain, True)
            return False
        elif result is not True:
            _LOGGER.error(
                'component %s did not return boolean if setup '
                'was successful. Disabling component.', domain)
            _async_persistent_notification(hass, domain, True)
            loader.set_component(domain, None)
            return False

        hass.config.components.append(component.DOMAIN)

        hass.bus.async_fire(EVENT_COMPONENT_LOADED,
                            {ATTR_COMPONENT: component.DOMAIN})

        return True
    finally:
        setup_progress.remove(domain)
        if did_lock:
            setup_lock.release()
Exemplo n.º 32
0
def setup(hass, config):
    """ Track states and offer events for switches. """
    logger = logging.getLogger(__name__)

    if not util.validate_config(config, {DOMAIN: [ha.CONF_TYPE]}, logger):
        return False

    switch_type = config[DOMAIN][ha.CONF_TYPE]

    switch_init = get_component('switch.{}'.format(switch_type))

    if switch_init is None:
        logger.error("Error loading switch component %s", switch_type)

        return False

    switches = switch_init.get_switches(hass, config[DOMAIN])

    if len(switches) == 0:
        logger.error("No switches found")
        return False

    # Setup a dict mapping entity IDs to devices
    ent_to_switch = {}

    no_name_count = 1

    for switch in switches:
        name = switch.get_name()

        if name is None:
            name = "Switch #{}".format(no_name_count)
            no_name_count += 1

        entity_id = util.ensure_unique_string(
            ENTITY_ID_FORMAT.format(util.slugify(name)),
            list(ent_to_switch.keys()))

        switch.entity_id = entity_id
        ent_to_switch[entity_id] = switch

    # pylint: disable=unused-argument
    def update_states(time, force_reload=False):
        """ Update states of all switches. """

        # First time this method gets called, force_reload should be True
        if force_reload or \
           datetime.now() - update_states.last_updated > \
           MIN_TIME_BETWEEN_SCANS:

            logger.info("Updating switch states")
            update_states.last_updated = datetime.now()

            for switch in switches:
                switch.update_ha_state(hass)

    update_states(None, True)

    def handle_switch_service(service):
        """ Handles calls to the switch services. """
        devices = [
            ent_to_switch[entity_id]
            for entity_id in extract_entity_ids(hass, service)
            if entity_id in ent_to_switch
        ]

        if not devices:
            devices = switches

        for switch in devices:
            if service.service == SERVICE_TURN_ON:
                switch.turn_on()
            else:
                switch.turn_off()

            switch.update_ha_state(hass)

    # Track all switches in a group
    group.setup_group(hass, GROUP_NAME_ALL_SWITCHES, ent_to_switch.keys(),
                      False)

    # Update state every 30 seconds
    hass.track_time_change(update_states, second=[0, 30])

    hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_switch_service)

    hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_switch_service)

    return True
Exemplo n.º 33
0
    def test_see_passive_zone_state(self):
        """Test that the device tracker sets gps for passive trackers."""
        register_time = datetime(2015, 9, 15, 23, tzinfo=dt_util.UTC)
        scan_time = datetime(2015, 9, 15, 23, 1, tzinfo=dt_util.UTC)

        with assert_setup_component(1, zone.DOMAIN):
            zone_info = {
                'name': 'Home',
                'latitude': 1,
                'longitude': 2,
                'radius': 250,
                'passive': False
            }

            setup_component(self.hass, zone.DOMAIN, {
                'zone': zone_info
            })

        scanner = get_component('device_tracker.test').SCANNER
        scanner.reset()
        scanner.come_home('dev1')

        with patch('homeassistant.components.device_tracker.dt_util.utcnow',
                   return_value=register_time):
            with assert_setup_component(1, device_tracker.DOMAIN):
                assert setup_component(self.hass, device_tracker.DOMAIN, {
                    device_tracker.DOMAIN: {
                        CONF_PLATFORM: 'test',
                        device_tracker.CONF_CONSIDER_HOME: 59,
                    }})

        state = self.hass.states.get('device_tracker.dev1')
        attrs = state.attributes
        self.assertEqual(STATE_HOME, state.state)
        self.assertEqual(state.object_id, 'dev1')
        self.assertEqual(state.name, 'dev1')
        self.assertEqual(attrs.get('friendly_name'), 'dev1')
        self.assertEqual(attrs.get('latitude'), 1)
        self.assertEqual(attrs.get('longitude'), 2)
        self.assertEqual(attrs.get('gps_accuracy'), 0)
        self.assertEqual(attrs.get('source_type'),
                         device_tracker.SOURCE_TYPE_ROUTER)

        scanner.leave_home('dev1')

        with patch('homeassistant.components.device_tracker.dt_util.utcnow',
                   return_value=scan_time):
            fire_time_changed(self.hass, scan_time)
            self.hass.block_till_done()

        state = self.hass.states.get('device_tracker.dev1')
        attrs = state.attributes
        self.assertEqual(STATE_NOT_HOME, state.state)
        self.assertEqual(state.object_id, 'dev1')
        self.assertEqual(state.name, 'dev1')
        self.assertEqual(attrs.get('friendly_name'), 'dev1')
        self.assertEqual(attrs.get('latitude'), None)
        self.assertEqual(attrs.get('longitude'), None)
        self.assertEqual(attrs.get('gps_accuracy'), None)
        self.assertEqual(attrs.get('source_type'),
                         device_tracker.SOURCE_TYPE_ROUTER)
Exemplo n.º 34
0
def setup_bridge(host, hass, add_devices, filename, allow_unreachable,
                 allow_in_emulated_hue, allow_hue_groups):
    """Setup a phue bridge based on host parameter."""
    import phue

    try:
        bridge = phue.Bridge(host, config_file_path=hass.config.path(filename))
    except ConnectionRefusedError:  # Wrong host was given
        _LOGGER.error("Error connecting to the Hue bridge at %s", host)

        return

    except phue.PhueRegistrationException:
        _LOGGER.warning("Connected to Hue at %s but not registered.", host)

        request_configuration(host, hass, add_devices, filename,
                              allow_unreachable, allow_in_emulated_hue,
                              allow_hue_groups)

        return

    # If we came here and configuring this host, mark as done
    if host in _CONFIGURING:
        request_id = _CONFIGURING.pop(host)

        configurator = get_component('configurator')

        configurator.request_done(request_id)

    lights = {}
    lightgroups = {}
    skip_groups = not allow_hue_groups

    @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
    def update_lights():
        """Update the Hue light objects with latest info from the bridge."""
        nonlocal skip_groups

        try:
            api = bridge.get_api()
        except socket.error:
            # socket.error when we cannot reach Hue
            _LOGGER.exception("Cannot reach the bridge")
            return

        api_lights = api.get('lights')

        if not isinstance(api_lights, dict):
            _LOGGER.error("Got unexpected result from Hue API")
            return

        if skip_groups:
            api_groups = {}
        else:
            api_groups = api.get('groups')

        if not isinstance(api_groups, dict):
            _LOGGER.error("Got unexpected result from Hue API")
            return

        new_lights = []

        api_name = api.get('config').get('name')
        if api_name in ('RaspBee-GW', 'deCONZ-GW'):
            bridge_type = 'deconz'
        else:
            bridge_type = 'hue'

        for light_id, info in api_lights.items():
            if light_id not in lights:
                lights[light_id] = HueLight(int(light_id), info, bridge,
                                            update_lights, bridge_type,
                                            allow_unreachable,
                                            allow_in_emulated_hue)
                new_lights.append(lights[light_id])
            else:
                lights[light_id].info = info
                lights[light_id].schedule_update_ha_state()

        for lightgroup_id, info in api_groups.items():
            if 'state' not in info:
                _LOGGER.warning('Group info does not contain state. '
                                'Please update your hub.')
                skip_groups = True
                break

            if lightgroup_id not in lightgroups:
                lightgroups[lightgroup_id] = HueLight(int(lightgroup_id), info,
                                                      bridge, update_lights,
                                                      bridge_type,
                                                      allow_unreachable,
                                                      allow_in_emulated_hue,
                                                      True)
                new_lights.append(lightgroups[lightgroup_id])
            else:
                lightgroups[lightgroup_id].info = info
                lightgroups[lightgroup_id].schedule_update_ha_state()

        if new_lights:
            add_devices(new_lights)

    _CONFIGURED_BRIDGES[socket.gethostbyname(host)] = True

    # create a service for calling run_scene directly on the bridge,
    # used to simplify automation rules.
    def hue_activate_scene(call):
        """Service to call directly directly into bridge to set scenes."""
        group_name = call.data[ATTR_GROUP_NAME]
        scene_name = call.data[ATTR_SCENE_NAME]
        bridge.run_scene(group_name, scene_name)

    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))
    hass.services.register(DOMAIN,
                           SERVICE_HUE_SCENE,
                           hue_activate_scene,
                           descriptions.get(SERVICE_HUE_SCENE),
                           schema=SCENE_SCHEMA)

    update_lights()
Exemplo n.º 35
0
def setup(hass, config):
    # pylint: disable=unused-argument,too-many-locals
    """ Listen for chromecast events. """
    logger = logging.getLogger(__name__)
    discovery = get_component('discovery')

    try:
        # pylint: disable=redefined-outer-name
        import pychromecast
    except ImportError:
        logger.exception(("Failed to import pychromecast. "
                          "Did you maybe not install the 'pychromecast' "
                          "dependency?"))

        return False

    casts = {}

    # If discovery component not loaded, scan ourselves
    if discovery.DOMAIN not in hass.components:
        logger.info("Scanning for Chromecasts")
        hosts = pychromecast.discover_chromecasts()

        for host in hosts:
            setup_chromecast(casts, host)

    def chromecast_discovered(service, info):
        """ Called when a Chromecast has been discovered. """
        logger.info("New Chromecast discovered: %s", info[0])
        setup_chromecast(casts, info[0])

    discovery.listen(
        hass, discovery.services.GOOGLE_CAST, chromecast_discovered)

    def update_chromecast_state(entity_id, chromecast):
        """ Retrieve state of Chromecast and update statemachine. """
        chromecast.refresh()

        status = chromecast.app

        state_attr = {ATTR_FRIENDLY_NAME:
                      chromecast.device.friendly_name}

        if status and status.app_id != pychromecast.APP_ID['HOME']:
            state = status.app_id

            ramp = chromecast.get_protocol(pychromecast.PROTOCOL_RAMP)

            if ramp and ramp.state != pychromecast.RAMP_STATE_UNKNOWN:

                if ramp.state == pychromecast.RAMP_STATE_PLAYING:
                    state_attr[ATTR_MEDIA_STATE] = MEDIA_STATE_PLAYING
                else:
                    state_attr[ATTR_MEDIA_STATE] = MEDIA_STATE_STOPPED

                if ramp.content_id:
                    state_attr[ATTR_MEDIA_CONTENT_ID] = ramp.content_id

                if ramp.title:
                    state_attr[ATTR_MEDIA_TITLE] = ramp.title

                if ramp.artist:
                    state_attr[ATTR_MEDIA_ARTIST] = ramp.artist

                if ramp.album:
                    state_attr[ATTR_MEDIA_ALBUM] = ramp.album

                if ramp.image_url:
                    state_attr[ATTR_MEDIA_IMAGE_URL] = ramp.image_url

                if ramp.duration:
                    state_attr[ATTR_MEDIA_DURATION] = ramp.duration

                state_attr[ATTR_MEDIA_VOLUME] = ramp.volume
        else:
            state = STATE_NO_APP

        hass.states.set(entity_id, state, state_attr)

    def update_chromecast_states(time):
        """ Updates all chromecast states. """
        if casts:
            logger.info("Updating Chromecast status")

            for entity_id, cast in casts.items():
                update_chromecast_state(entity_id, cast)

    def _service_to_entities(service):
        """ Helper method to get entities from service. """
        entity_ids = extract_entity_ids(hass, service)

        if entity_ids:
            for entity_id in entity_ids:
                cast = casts.get(entity_id)

                if cast:
                    yield entity_id, cast

        else:
            yield from casts.items()

    def turn_off_service(service):
        """ Service to exit any running app on the specified ChromeCast and
        shows idle screen. Will quit all ChromeCasts if nothing specified.
        """
        for entity_id, cast in _service_to_entities(service):
            cast.quit_app()
            update_chromecast_state(entity_id, cast)

    def volume_up_service(service):
        """ Service to send the chromecast the command for volume up. """
        for _, cast in _service_to_entities(service):
            ramp = cast.get_protocol(pychromecast.PROTOCOL_RAMP)

            if ramp:
                ramp.volume_up()

    def volume_down_service(service):
        """ Service to send the chromecast the command for volume down. """
        for _, cast in _service_to_entities(service):
            ramp = cast.get_protocol(pychromecast.PROTOCOL_RAMP)

            if ramp:
                ramp.volume_down()

    def media_play_pause_service(service):
        """ Service to send the chromecast the command for play/pause. """
        for _, cast in _service_to_entities(service):
            ramp = cast.get_protocol(pychromecast.PROTOCOL_RAMP)

            if ramp:
                ramp.playpause()

    def media_play_service(service):
        """ Service to send the chromecast the command for play/pause. """
        for _, cast in _service_to_entities(service):
            ramp = cast.get_protocol(pychromecast.PROTOCOL_RAMP)

            if ramp and ramp.state == pychromecast.RAMP_STATE_STOPPED:
                ramp.playpause()

    def media_pause_service(service):
        """ Service to send the chromecast the command for play/pause. """
        for _, cast in _service_to_entities(service):
            ramp = cast.get_protocol(pychromecast.PROTOCOL_RAMP)

            if ramp and ramp.state == pychromecast.RAMP_STATE_PLAYING:
                ramp.playpause()

    def media_next_track_service(service):
        """ Service to send the chromecast the command for next track. """
        for entity_id, cast in _service_to_entities(service):
            ramp = cast.get_protocol(pychromecast.PROTOCOL_RAMP)

            if ramp:
                next(ramp)
                update_chromecast_state(entity_id, cast)

    def play_youtube_video_service(service, video_id):
        """ Plays specified video_id on the Chromecast's YouTube channel. """
        if video_id:  # if service.data.get('video') returned None
            for entity_id, cast in _service_to_entities(service):
                pychromecast.play_youtube_video(video_id, cast.host)
                update_chromecast_state(entity_id, cast)

    hass.track_time_change(update_chromecast_states, second=range(0, 60, 15))

    hass.services.register(DOMAIN, SERVICE_TURN_OFF,
                           turn_off_service)

    hass.services.register(DOMAIN, SERVICE_VOLUME_UP,
                           volume_up_service)

    hass.services.register(DOMAIN, SERVICE_VOLUME_DOWN,
                           volume_down_service)

    hass.services.register(DOMAIN, SERVICE_MEDIA_PLAY_PAUSE,
                           media_play_pause_service)

    hass.services.register(DOMAIN, SERVICE_MEDIA_PLAY,
                           media_play_service)

    hass.services.register(DOMAIN, SERVICE_MEDIA_PAUSE,
                           media_pause_service)

    hass.services.register(DOMAIN, SERVICE_MEDIA_NEXT_TRACK,
                           media_next_track_service)

    hass.services.register(DOMAIN, "start_fireplace",
                           lambda service:
                           play_youtube_video_service(service, "eyU3bRy2x44"))

    hass.services.register(DOMAIN, "start_epic_sax",
                           lambda service:
                           play_youtube_video_service(service, "kxopViU98Xo"))

    hass.services.register(DOMAIN, SERVICE_YOUTUBE_VIDEO,
                           lambda service:
                           play_youtube_video_service(service,
                                                      service.data.get(
                                                          'video')))

    update_chromecast_states(None)

    return True
Exemplo n.º 36
0
def setup(hass, config):
    """Setup a demo environment."""
    group = loader.get_component('group')
    configurator = loader.get_component('configurator')

    config.setdefault(ha.DOMAIN, {})
    config.setdefault(DOMAIN, {})

    if config[DOMAIN].get('hide_demo_state') != 1:
        hass.states.set('a.Demo_Mode', 'Enabled')

    # Setup sun
    if not hass.config.latitude:
        hass.config.latitude = 32.87336

    if not hass.config.longitude:
        hass.config.longitude = 117.22743

    bootstrap.setup_component(hass, 'sun')

    # Setup demo platforms
    demo_config = config.copy()
    for component in COMPONENTS_WITH_DEMO_PLATFORM:
        demo_config[component] = {CONF_PLATFORM: 'demo'}
        bootstrap.setup_component(hass, component, demo_config)

    # Setup room groups
    lights = sorted(hass.states.entity_ids('light'))
    switches = sorted(hass.states.entity_ids('switch'))
    media_players = sorted(hass.states.entity_ids('media_player'))
    group.Group(hass, 'living room', [
        lights[1], switches[0], 'input_select.living_room_preset',
        'rollershutter.living_room_window', media_players[1],
        'scene.romantic_lights'])
    group.Group(hass, 'bedroom', [lights[0], switches[1], media_players[0]])
    group.Group(hass, 'kitchen', [
        lights[2], 'rollershutter.kitchen_window', 'lock.kitchen_door'])
    group.Group(hass, 'doors', [
        'lock.front_door', 'lock.kitchen_door',
        'garage_door.right_garage_door', 'garage_door.left_garage_door'])
    group.Group(hass, 'automations', [
        'input_select.who_cooks', 'input_boolean.notify', ])
    group.Group(hass, 'people', [
        'device_tracker.demo_anne_therese', 'device_tracker.demo_home_boy',
        'device_tracker.demo_paulus'])
    group.Group(hass, 'thermostats', [
        'thermostat.nest', 'thermostat.thermostat'])
    group.Group(hass, 'downstairs', [
        'group.living_room', 'group.kitchen',
        'scene.romantic_lights', 'rollershutter.kitchen_window',
        'rollershutter.living_room_window', 'group.doors', 'thermostat.nest',
    ], view=True)
    group.Group(hass, 'Upstairs', [
        'thermostat.thermostat', 'group.bedroom',
    ], view=True)

    # Setup scripts
    bootstrap.setup_component(
        hass, 'script',
        {'script': {
            'demo': {
                'alias': 'Toggle {}'.format(lights[0].split('.')[1]),
                'sequence': [{
                    'service': 'light.turn_off',
                    'data': {ATTR_ENTITY_ID: lights[0]}
                }, {
                    'delay': {'seconds': 5}
                }, {
                    'service': 'light.turn_on',
                    'data': {ATTR_ENTITY_ID: lights[0]}
                }, {
                    'delay': {'seconds': 5}
                }, {
                    'service': 'light.turn_off',
                    'data': {ATTR_ENTITY_ID: lights[0]}
                }]
            }}})

    # Setup scenes
    bootstrap.setup_component(
        hass, 'scene',
        {'scene': [
            {'name': 'Romantic lights',
             'entities': {
                 lights[0]: True,
                 lights[1]: {'state': 'on', 'xy_color': [0.33, 0.66],
                             'brightness': 200},
             }},
            {'name': 'Switch on and off',
             'entities': {
                 switches[0]: True,
                 switches[1]: False,
             }},
            ]})

    # Set up input select
    bootstrap.setup_component(
        hass, 'input_select',
        {'input_select':
         {'living_room_preset': {'options': ['Visitors',
                                             'Visitors with kids',
                                             'Home Alone']},
          'who_cooks': {'icon': 'mdi:panda',
                        'initial': 'Anne Therese',
                        'name': 'Cook today',
                        'options': ['Paulus', 'Anne Therese']}}})
    # Set up input boolean
    bootstrap.setup_component(
        hass, 'input_boolean',
        {'input_boolean': {'notify': {'icon': 'mdi:car',
                                      'initial': False,
                                      'name': 'Notify Anne Therese is home'}}})
    # Set up weblink
    bootstrap.setup_component(
        hass, 'weblink',
        {'weblink': {'entities': [{'name': 'Router',
                                   'url': 'http://192.168.1.1'}]}})
    # Setup configurator
    configurator_ids = []

    def hue_configuration_callback(data):
        """Fake callback, mark config as done."""
        time.sleep(2)

        # First time it is called, pretend it failed.
        if len(configurator_ids) == 1:
            configurator.notify_errors(
                configurator_ids[0],
                "Failed to register, please try again.")

            configurator_ids.append(0)
        else:
            configurator.request_done(configurator_ids[0])

    request_id = configurator.request_config(
        hass, "Philips Hue", hue_configuration_callback,
        description=("Press the button on the bridge to register Philips Hue "
                     "with Home Assistant."),
        description_image="/static/images/config_philips_hue.jpg",
        submit_caption="I have pressed the button"
    )

    configurator_ids.append(request_id)

    return True
Exemplo n.º 37
0
def setup_bridge(host, hass, add_devices_callback, filename,
                 allow_unreachable):
    """Setup a phue bridge based on host parameter."""
    import phue

    try:
        bridge = phue.Bridge(
            host,
            config_file_path=hass.config.path(filename))
    except ConnectionRefusedError:  # Wrong host was given
        _LOGGER.exception("Error connecting to the Hue bridge at %s", host)

        return

    except phue.PhueRegistrationException:
        _LOGGER.warning("Connected to Hue at %s but not registered.", host)

        request_configuration(host, hass, add_devices_callback, filename,
                              allow_unreachable)

        return

    # If we came here and configuring this host, mark as done
    if host in _CONFIGURING:
        request_id = _CONFIGURING.pop(host)

        configurator = get_component('configurator')

        configurator.request_done(request_id)

    lights = {}

    @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
    def update_lights():
        """Update the Hue light objects with latest info from the bridge."""
        try:
            api = bridge.get_api()
        except socket.error:
            # socket.error when we cannot reach Hue
            _LOGGER.exception("Cannot reach the bridge")
            return

        api_states = api.get('lights')

        if not isinstance(api_states, dict):
            _LOGGER.error("Got unexpected result from Hue API")
            return

        new_lights = []

        api_name = api.get('config').get('name')
        if api_name == 'RaspBee-GW':
            bridge_type = 'deconz'
        else:
            bridge_type = 'hue'

        for light_id, info in api_states.items():
            if light_id not in lights:
                lights[light_id] = HueLight(int(light_id), info,
                                            bridge, update_lights,
                                            bridge_type, allow_unreachable)
                new_lights.append(lights[light_id])
            else:
                lights[light_id].info = info

        if new_lights:
            add_devices_callback(new_lights)

    _CONFIGURED_BRIDGES[socket.gethostbyname(host)] = True
    update_lights()
Exemplo n.º 38
0
    def test_flux_with_multiple_lights(self):
        """Test the flux switch with multiple light entities."""
        platform = loader.get_component('light.test')
        platform.init()
        self.assertTrue(
            setup_component(self.hass, light.DOMAIN,
                            {light.DOMAIN: {
                                CONF_PLATFORM: 'test'
                            }}))

        dev1, dev2, dev3 = platform.DEVICES
        light.turn_on(self.hass, entity_id=dev2.entity_id)
        self.hass.block_till_done()
        light.turn_on(self.hass, entity_id=dev3.entity_id)
        self.hass.block_till_done()

        state = self.hass.states.get(dev1.entity_id)
        self.assertEqual(STATE_ON, state.state)
        self.assertIsNone(state.attributes.get('xy_color'))
        self.assertIsNone(state.attributes.get('brightness'))

        state = self.hass.states.get(dev2.entity_id)
        self.assertEqual(STATE_ON, state.state)
        self.assertIsNone(state.attributes.get('xy_color'))
        self.assertIsNone(state.attributes.get('brightness'))

        state = self.hass.states.get(dev3.entity_id)
        self.assertEqual(STATE_ON, state.state)
        self.assertIsNone(state.attributes.get('xy_color'))
        self.assertIsNone(state.attributes.get('brightness'))

        test_time = dt_util.now().replace(hour=12, minute=0, second=0)
        sunset_time = test_time.replace(hour=17, minute=0, second=0)
        sunrise_time = test_time.replace(hour=5, minute=0,
                                         second=0) + timedelta(days=1)

        with patch('homeassistant.util.dt.now', return_value=test_time):
            with patch('homeassistant.components.sun.next_rising',
                       return_value=sunrise_time):
                with patch('homeassistant.components.sun.next_setting',
                           return_value=sunset_time):
                    assert setup_component(
                        self.hass, switch.DOMAIN, {
                            switch.DOMAIN: {
                                'platform':
                                'flux',
                                'name':
                                'flux',
                                'lights': [
                                    dev1.entity_id, dev2.entity_id,
                                    dev3.entity_id
                                ]
                            }
                        })
                    turn_on_calls = mock_service(self.hass, light.DOMAIN,
                                                 SERVICE_TURN_ON)
                    switch.turn_on(self.hass, 'switch.flux')
                    self.hass.block_till_done()
                    fire_time_changed(self.hass, test_time)
                    self.hass.block_till_done()
        call = turn_on_calls[-1]
        self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 171)
        self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.452, 0.386])
        call = turn_on_calls[-2]
        self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 171)
        self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.452, 0.386])
        call = turn_on_calls[-3]
        self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 171)
        self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.452, 0.386])
Exemplo n.º 39
0
def async_process_component_config(hass: HomeAssistant, config: Dict,
                                   domain: str) -> Optional[Dict]:
    """Check component configuration and return processed configuration.

    Returns None on error.

    This method must be run in the event loop.
    """
    component = get_component(hass, domain)

    if hasattr(component, 'CONFIG_SCHEMA'):
        try:
            config = component.CONFIG_SCHEMA(config)  # type: ignore
        except vol.Invalid as ex:
            async_log_exception(ex, domain, config, hass)
            return None

    elif hasattr(component, 'PLATFORM_SCHEMA'):
        platforms = []
        for p_name, p_config in config_per_platform(config, domain):
            # Validate component specific platform schema
            try:
                p_validated = component.PLATFORM_SCHEMA(  # type: ignore
                    p_config)
            except vol.Invalid as ex:
                async_log_exception(ex, domain, config, hass)
                continue

            # Not all platform components follow same pattern for platforms
            # So if p_name is None we are not going to validate platform
            # (the automation component is one of them)
            if p_name is None:
                platforms.append(p_validated)
                continue

            platform = get_platform(hass, domain, p_name)

            if platform is None:
                continue

            # Validate platform specific schema
            if hasattr(platform, 'PLATFORM_SCHEMA'):
                # pylint: disable=no-member
                try:
                    p_validated = platform.PLATFORM_SCHEMA(  # type: ignore
                        p_validated)
                except vol.Invalid as ex:
                    async_log_exception(ex, '{}.{}'.format(domain, p_name),
                                        p_validated, hass)
                    continue

            platforms.append(p_validated)

        # Create a copy of the configuration with all config for current
        # component removed and add validated config back in.
        filter_keys = extract_domain_configs(config, domain)
        config = {
            key: value
            for key, value in config.items() if key not in filter_keys
        }
        config[domain] = platforms

    return config
Exemplo n.º 40
0
def merge_packages_config(hass: HomeAssistant,
                          config: Dict,
                          packages: Dict,
                          _log_pkg_error: Callable = _log_pkg_error) -> Dict:
    """Merge packages into the top-level configuration. Mutate config."""
    # pylint: disable=too-many-nested-blocks
    PACKAGES_CONFIG_SCHEMA(packages)
    for pack_name, pack_conf in packages.items():
        for comp_name, comp_conf in pack_conf.items():
            if comp_name == CONF_CORE:
                continue
            # If component name is given with a trailing description, remove it
            # when looking for component
            domain = comp_name.split(' ')[0]
            component = get_component(hass, domain)

            if component is None:
                _log_pkg_error(pack_name, comp_name, config, "does not exist")
                continue

            if hasattr(component, 'PLATFORM_SCHEMA'):
                if not comp_conf:
                    continue  # Ensure we dont add Falsy items to list
                config[comp_name] = cv.ensure_list(config.get(comp_name))
                config[comp_name].extend(cv.ensure_list(comp_conf))
                continue

            if hasattr(component, 'CONFIG_SCHEMA'):
                merge_type, _ = _identify_config_schema(component)

                if merge_type == 'list':
                    if not comp_conf:
                        continue  # Ensure we dont add Falsy items to list
                    config[comp_name] = cv.ensure_list(config.get(comp_name))
                    config[comp_name].extend(cv.ensure_list(comp_conf))
                    continue

            if comp_conf is None:
                comp_conf = OrderedDict()

            if not isinstance(comp_conf, dict):
                _log_pkg_error(pack_name, comp_name, config,
                               "cannot be merged. Expected a dict.")
                continue

            if comp_name not in config or config[comp_name] is None:
                config[comp_name] = OrderedDict()

            if not isinstance(config[comp_name], dict):
                _log_pkg_error(
                    pack_name, comp_name, config,
                    "cannot be merged. Dict expected in main config.")
                continue
            if not isinstance(comp_conf, dict):
                _log_pkg_error(pack_name, comp_name, config,
                               "cannot be merged. Dict expected in package.")
                continue

            error = _recursive_merge(conf=config[comp_name], package=comp_conf)
            if error:
                _log_pkg_error(pack_name, comp_name, config,
                               "has duplicate key '{}'".format(error))

    return config
Exemplo n.º 41
0
def check_ha_config_file(hass):
    """Check if Home Assistant configuration file is valid."""
    config_dir = hass.config.config_dir
    result = HomeAssistantConfig()

    def _pack_error(package, component, config, message):
        """Handle errors from packages: _log_pkg_error."""
        message = "Package {} setup failed. Component {} {}".format(
            package, component, message)
        domain = 'homeassistant.packages.{}.{}'.format(package, component)
        pack_config = core_config[CONF_PACKAGES].get(package, config)
        result.add_error(message, domain, pack_config)

    def _comp_error(ex, domain, config):
        """Handle errors from components: async_log_exception."""
        result.add_error(_format_config_error(ex, domain, config), domain,
                         config)

    # Load configuration.yaml
    try:
        config_path = find_config_file(config_dir)
        if not config_path:
            return result.add_error("File configuration.yaml not found.")
        config = load_yaml_config_file(config_path)
    except HomeAssistantError as err:
        return result.add_error("Error loading {}: {}".format(
            config_path, err))
    finally:
        yaml.clear_secret_cache()

    # Extract and validate core [homeassistant] config
    try:
        core_config = config.pop(CONF_CORE, {})
        core_config = CORE_CONFIG_SCHEMA(core_config)
        result[CONF_CORE] = core_config
    except vol.Invalid as err:
        result.add_error(err, CONF_CORE, core_config)
        core_config = {}

    # Merge packages
    merge_packages_config(hass, config, core_config.get(CONF_PACKAGES, {}),
                          _pack_error)
    core_config.pop(CONF_PACKAGES, None)

    # Ensure we have no None values after merge
    for key, value in config.items():
        if not value:
            config[key] = {}

    # Filter out repeating config sections
    components = set(key.split(' ')[0] for key in config.keys())

    # Process and validate config
    for domain in components:
        component = loader.get_component(hass, domain)
        if not component:
            result.add_error("Component not found: {}".format(domain))
            continue

        if hasattr(component, 'CONFIG_SCHEMA'):
            try:
                config = component.CONFIG_SCHEMA(config)
                result[domain] = config[domain]
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

        if not hasattr(component, 'PLATFORM_SCHEMA'):
            continue

        platforms = []
        for p_name, p_config in config_per_platform(config, domain):
            # Validate component specific platform schema
            try:
                p_validated = component.PLATFORM_SCHEMA(p_config)
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

            # Not all platform components follow same pattern for platforms
            # So if p_name is None we are not going to validate platform
            # (the automation component is one of them)
            if p_name is None:
                platforms.append(p_validated)
                continue

            platform = loader.get_platform(hass, domain, p_name)

            if platform is None:
                result.add_error("Platform not found: {}.{}".format(
                    domain, p_name))
                continue

            # Validate platform specific schema
            if hasattr(platform, 'PLATFORM_SCHEMA'):
                try:
                    p_validated = platform.PLATFORM_SCHEMA(p_validated)
                except vol.Invalid as ex:
                    _comp_error(ex, '{}.{}'.format(domain, p_name),
                                p_validated)
                    continue

            platforms.append(p_validated)

        # Remove config for current component and add validated config back in.
        for filter_comp in extract_domain_configs(config, domain):
            del config[filter_comp]
        result[domain] = platforms

    return result
Exemplo n.º 42
0
def async_prepare_setup_component(hass: core.HomeAssistant, config: dict,
                                  domain: str):
    """Prepare setup of a component and return processed config.

    This method is a coroutine.
    """
    # pylint: disable=too-many-return-statements
    component = loader.get_component(domain)
    missing_deps = [
        dep for dep in getattr(component, 'DEPENDENCIES', [])
        if dep not in hass.config.components
    ]

    if missing_deps:
        _LOGGER.error(
            'Not initializing %s because not all dependencies loaded: %s',
            domain, ", ".join(missing_deps))
        return None

    if hasattr(component, 'CONFIG_SCHEMA'):
        try:
            config = component.CONFIG_SCHEMA(config)
        except vol.Invalid as ex:
            async_log_exception(ex, domain, config, hass)
            return None

    elif hasattr(component, 'PLATFORM_SCHEMA'):
        platforms = []
        for p_name, p_config in config_per_platform(config, domain):
            # Validate component specific platform schema
            try:
                p_validated = component.PLATFORM_SCHEMA(p_config)
            except vol.Invalid as ex:
                async_log_exception(ex, domain, config, hass)
                continue

            # Not all platform components follow same pattern for platforms
            # So if p_name is None we are not going to validate platform
            # (the automation component is one of them)
            if p_name is None:
                platforms.append(p_validated)
                continue

            platform = yield from async_prepare_setup_platform(
                hass, config, domain, p_name)

            if platform is None:
                continue

            # Validate platform specific schema
            if hasattr(platform, 'PLATFORM_SCHEMA'):
                try:
                    # pylint: disable=no-member
                    p_validated = platform.PLATFORM_SCHEMA(p_validated)
                except vol.Invalid as ex:
                    async_log_exception(ex, '{}.{}'.format(domain, p_name),
                                        p_validated, hass)
                    continue

            platforms.append(p_validated)

        # Create a copy of the configuration with all config for current
        # component removed and add validated config back in.
        filter_keys = extract_domain_configs(config, domain)
        config = {
            key: value
            for key, value in config.items() if key not in filter_keys
        }
        config[domain] = platforms

    res = yield from hass.loop.run_in_executor(None, _handle_requirements,
                                               hass, component, domain)
    if not res:
        return None

    return config
Exemplo n.º 43
0
def setup(hass, config):
    """ Exposes light control via statemachine and services. """

    if not util.validate_config(config, {DOMAIN: [ha.CONF_TYPE]}, _LOGGER):
        return False

    light_type = config[DOMAIN][ha.CONF_TYPE]

    light_init = get_component('light.{}'.format(light_type))

    if light_init is None:
        _LOGGER.error("Unknown light type specified: %s", light_type)

        return False

    lights = light_init.get_lights(hass, config[DOMAIN])

    if len(lights) == 0:
        _LOGGER.error("No lights found")
        return False

    ent_to_light = {}

    no_name_count = 1

    for light in lights:
        name = light.get_name()

        if name is None:
            name = "Light #{}".format(no_name_count)
            no_name_count += 1

        entity_id = util.ensure_unique_string(
            ENTITY_ID_FORMAT.format(util.slugify(name)),
            list(ent_to_light.keys()))

        light.entity_id = entity_id
        ent_to_light[entity_id] = light

    # Load built-in profiles and custom profiles
    profile_paths = [
        os.path.join(os.path.dirname(__file__), LIGHT_PROFILES_FILE),
        hass.get_config_path(LIGHT_PROFILES_FILE)
    ]
    profiles = {}

    for profile_path in profile_paths:

        if os.path.isfile(profile_path):
            with open(profile_path) as inp:
                reader = csv.reader(inp)

                # Skip the header
                next(reader, None)

                try:
                    for profile_id, color_x, color_y, brightness in reader:
                        profiles[profile_id] = (float(color_x), float(color_y),
                                                int(brightness))

                except ValueError:
                    # ValueError if not 4 values per row
                    # ValueError if convert to float/int failed
                    _LOGGER.error("Error parsing light profiles from %s",
                                  profile_path)

                    return False

    # pylint: disable=unused-argument
    def update_lights_state(now):
        """ Update the states of all the lights. """
        for light in lights:
            light.update_ha_state(hass)

    update_lights_state(None)

    # Track all lights in a group
    group.setup_group(hass, GROUP_NAME_ALL_LIGHTS, ent_to_light.keys(), False)

    def handle_light_service(service):
        """ Hande a turn light on or off service call. """
        # Get and validate data
        dat = service.data

        # Convert the entity ids to valid light ids
        lights = [
            ent_to_light[entity_id]
            for entity_id in extract_entity_ids(hass, service)
            if entity_id in ent_to_light
        ]

        if not lights:
            lights = list(ent_to_light.values())

        transition = util.convert(dat.get(ATTR_TRANSITION), int)

        if service.service == SERVICE_TURN_OFF:
            for light in lights:
                light.turn_off(transition=transition)

        else:
            # Processing extra data for turn light on request

            # We process the profile first so that we get the desired
            # behavior that extra service data attributes overwrite
            # profile values
            profile = profiles.get(dat.get(ATTR_PROFILE))

            if profile:
                *color, bright = profile
            else:
                color, bright = None, None

            if ATTR_BRIGHTNESS in dat:
                bright = util.convert(dat.get(ATTR_BRIGHTNESS), int)

            if ATTR_XY_COLOR in dat:
                try:
                    # xy_color should be a list containing 2 floats
                    xy_color = dat.get(ATTR_XY_COLOR)

                    if len(xy_color) == 2:
                        color = [float(val) for val in xy_color]

                except (TypeError, ValueError):
                    # TypeError if xy_color is not iterable
                    # ValueError if value could not be converted to float
                    pass

            if ATTR_RGB_COLOR in dat:
                try:
                    # rgb_color should be a list containing 3 ints
                    rgb_color = dat.get(ATTR_RGB_COLOR)

                    if len(rgb_color) == 3:
                        color = util.color_RGB_to_xy(int(rgb_color[0]),
                                                     int(rgb_color[1]),
                                                     int(rgb_color[2]))

                except (TypeError, ValueError):
                    # TypeError if rgb_color is not iterable
                    # ValueError if not all values can be converted to int
                    pass

            for light in lights:
                light.turn_on(transition=transition,
                              brightness=bright,
                              xy_color=color)

        for light in lights:
            light.update_ha_state(hass, True)

    # Update light state every 30 seconds
    hass.track_time_change(update_lights_state, second=[0, 30])

    # Listen for light on and light off service calls
    hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_light_service)

    hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_light_service)

    return True
Exemplo n.º 44
0
 def device_state_attributes(self):
     """Provide attributes for display on device card."""
     insteon_plm = get_component('insteon_plm')
     return insteon_plm.common_attributes(self)
Exemplo n.º 45
0
 def __init__(self, wink):
     """Initialize the Wink binary sensor."""
     super().__init__(wink)
     wink = get_component('wink')
     self._unit_of_measurement = self.wink.UNIT
     self.capability = self.wink.capability()
Exemplo n.º 46
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the Fitbit sensor."""
    config_path = hass.config.path(FITBIT_CONFIG_FILE)
    if os.path.isfile(config_path):
        config_file = config_from_file(config_path)
        if config_file == DEFAULT_CONFIG:
            request_app_setup(hass, config, add_devices, config_path,
                              discovery_info=None)
            return False
    else:
        config_file = config_from_file(config_path, DEFAULT_CONFIG)
        request_app_setup(hass, config, add_devices, config_path,
                          discovery_info=None)
        return False

    if "fitbit" in _CONFIGURING:
        get_component("configurator").request_done(_CONFIGURING.pop("fitbit"))

    import fitbit

    access_token = config_file.get("access_token")
    refresh_token = config_file.get("refresh_token")
    if None not in (access_token, refresh_token):
        authd_client = fitbit.Fitbit(config_file.get("client_id"),
                                     config_file.get("client_secret"),
                                     access_token=access_token,
                                     refresh_token=refresh_token)

        if int(time.time()) - config_file.get("last_saved_at", 0) > 3600:
            authd_client.client.refresh_token()

        authd_client.system = authd_client.user_profile_get()["user"]["locale"]
        if authd_client.system != 'en_GB':
            if hass.config.units.is_metric:
                authd_client.system = "metric"
            else:
                authd_client.system = "en_US"

        dev = []
        for resource in config.get("monitored_resources",
                                   FITBIT_DEFAULT_RESOURCE_LIST):
            dev.append(FitbitSensor(authd_client, config_path, resource,
                                    hass.config.units.is_metric))
        add_devices(dev)

    else:
        oauth = fitbit.api.FitbitOauth2Client(config_file.get("client_id"),
                                              config_file.get("client_secret"))

        redirect_uri = "{}{}".format(hass.config.api.base_url,
                                     FITBIT_AUTH_CALLBACK_PATH)

        fitbit_auth_start_url, _ = oauth.authorize_token_url(
            redirect_uri=redirect_uri,
            scope=["activity", "heartrate", "nutrition", "profile",
                   "settings", "sleep", "weight"])

        hass.wsgi.register_redirect(FITBIT_AUTH_START, fitbit_auth_start_url)
        hass.wsgi.register_view(FitbitAuthCallbackView(hass, config,
                                                       add_devices, oauth))

        request_oauth_completion(hass)
Exemplo n.º 47
0
def _setup_component(hass: core.HomeAssistant, domain: str, config) -> bool:
    """Setup a component for Home Assistant."""
    # pylint: disable=too-many-return-statements,too-many-branches
    # pylint: disable=too-many-statements
    if domain in hass.config.components:
        return True

    with _SETUP_LOCK:
        # It might have been loaded while waiting for lock
        if domain in hass.config.components:
            return True

        if domain in _CURRENT_SETUP:
            _LOGGER.error('Attempt made to setup %s during setup of %s',
                          domain, domain)
            return False

        component = loader.get_component(domain)
        missing_deps = [dep for dep in getattr(component, 'DEPENDENCIES', [])
                        if dep not in hass.config.components]

        if missing_deps:
            _LOGGER.error(
                'Not initializing %s because not all dependencies loaded: %s',
                domain, ", ".join(missing_deps))
            return False

        if hasattr(component, 'CONFIG_SCHEMA'):
            try:
                config = component.CONFIG_SCHEMA(config)
            except vol.MultipleInvalid as ex:
                _log_exception(ex, domain, config)
                return False

        elif hasattr(component, 'PLATFORM_SCHEMA'):
            platforms = []
            for p_name, p_config in config_per_platform(config, domain):
                # Validate component specific platform schema
                try:
                    p_validated = component.PLATFORM_SCHEMA(p_config)
                except vol.MultipleInvalid as ex:
                    _log_exception(ex, domain, p_config)
                    return False

                # Not all platform components follow same pattern for platforms
                # So if p_name is None we are not going to validate platform
                # (the automation component is one of them)
                if p_name is None:
                    platforms.append(p_validated)
                    continue

                platform = prepare_setup_platform(hass, config, domain,
                                                  p_name)

                if platform is None:
                    return False

                # Validate platform specific schema
                if hasattr(platform, 'PLATFORM_SCHEMA'):
                    try:
                        p_validated = platform.PLATFORM_SCHEMA(p_validated)
                    except vol.MultipleInvalid as ex:
                        _log_exception(ex, '{}.{}'.format(domain, p_name),
                                       p_validated)
                        return False

                platforms.append(p_validated)

            # Create a copy of the configuration with all config for current
            # component removed and add validated config back in.
            filter_keys = extract_domain_configs(config, domain)
            config = {key: value for key, value in config.items()
                      if key not in filter_keys}
            config[domain] = platforms

        if not _handle_requirements(hass, component, domain):
            return False

        _CURRENT_SETUP.append(domain)

        try:
            result = component.setup(hass, config)
            if result is False:
                _LOGGER.error('component %s failed to initialize', domain)
                return False
            elif result is not True:
                _LOGGER.error('component %s did not return boolean if setup '
                              'was successful. Disabling component.', domain)
                loader.set_component(domain, None)
                return False
        except Exception:  # pylint: disable=broad-except
            _LOGGER.exception('Error during setup of component %s', domain)
            return False
        finally:
            _CURRENT_SETUP.remove(domain)

        hass.config.components.append(component.DOMAIN)

        # Assumption: if a component does not depend on groups
        # it communicates with devices
        if group.DOMAIN not in getattr(component, 'DEPENDENCIES', []):
            hass.pool.add_worker()

        hass.bus.fire(
            EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: component.DOMAIN})

        return True
Exemplo n.º 48
0
def get_service(hass, config, discovery_info=None):
  mqtt = loader.get_component('mqtt')
  topic = config.get(CONF_TOPIC, DEFAULT_TOPIC)

  return MqttNotificationService(mqtt, hass, topic)
Exemplo n.º 49
0
def setup_plexserver(host, token, hass, optional_config, add_devices_callback):
    """Setup a plexserver based on host parameter."""
    import plexapi.server
    import plexapi.exceptions

    try:
        plexserver = plexapi.server.PlexServer('http://%s' % host, token)
    except (plexapi.exceptions.BadRequest, plexapi.exceptions.Unauthorized,
            plexapi.exceptions.NotFound) as error:
        _LOGGER.info(error)
        # No token or wrong token
        request_configuration(host, hass, optional_config,
                              add_devices_callback)
        return

    # If we came here and configuring this host, mark as done
    if host in _CONFIGURING:
        request_id = _CONFIGURING.pop(host)
        configurator = get_component('configurator')
        configurator.request_done(request_id)
        _LOGGER.info('Discovery configuration done!')

    # Save config
    if not config_from_file(hass.config.path(PLEX_CONFIG_FILE),
                            {host: {
                                'token': token
                            }}):
        _LOGGER.error('failed to save config file')

    _LOGGER.info('Connected to: http://%s', host)

    plex_clients = {}
    plex_sessions = {}
    track_utc_time_change(hass, lambda now: update_devices(), second=30)

    @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
    def update_devices():
        """Update the devices objects."""
        try:
            devices = plexserver.clients()
        except plexapi.exceptions.BadRequest:
            _LOGGER.exception('Error listing plex devices')
            return
        except OSError:
            _LOGGER.error('Could not connect to plex server at http://%s',
                          host)
            return

        new_plex_clients = []
        for device in devices:
            # For now, let's allow all deviceClass types
            if device.deviceClass in ['badClient']:
                continue

            if device.machineIdentifier not in plex_clients:
                new_client = PlexClient(optional_config, device, None,
                                        plex_sessions, update_devices,
                                        update_sessions)
                plex_clients[device.machineIdentifier] = new_client
                new_plex_clients.append(new_client)
            else:
                plex_clients[device.machineIdentifier].set_device(device)

        # add devices with a session and no client (ex. PlexConnect Apple TV's)
        if optional_config[CONF_INCLUDE_NON_CLIENTS]:
            for machineIdentifier, session in plex_sessions.items():
                if machineIdentifier not in plex_clients:
                    new_client = PlexClient(optional_config, None, session,
                                            plex_sessions, update_devices,
                                            update_sessions)
                    plex_clients[machineIdentifier] = new_client
                    new_plex_clients.append(new_client)
                else:
                    plex_clients[machineIdentifier].set_session(session)

        # force devices to idle that do not have a valid session
        for machineIdentifier, client in plex_clients.items():
            if client.session is None:
                client.set_state(STATE_IDLE)

        # add devices to dynamic groups
        if optional_config[CONF_USE_DYNAMIC_GROUPS]:
            active_entity_id_list = []
            inactive_entity_id_list = []

            for machineIdentifier, client in plex_clients.items():
                if client.entity_id:
                    if client.state in [STATE_IDLE, STATE_OFF]:
                        inactive_entity_id_list.append(client.entity_id)
                    else:
                        active_entity_id_list.append(client.entity_id)

            # set groups with updated memberships
            set_group_members(hass, GROUP_ACTIVE_DEVICES,
                              active_entity_id_list)
            set_group_members(hass, GROUP_INACTIVE_DEVICES,
                              inactive_entity_id_list)

        if new_plex_clients:
            add_devices_callback(new_plex_clients)

    @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
    def update_sessions():
        """Update the sessions objects."""
        try:
            sessions = plexserver.sessions()
        except plexapi.exceptions.BadRequest:
            _LOGGER.exception('Error listing plex sessions')
            return

        plex_sessions.clear()
        for session in sessions:
            plex_sessions[session.player.machineIdentifier] = session

    update_sessions()
    update_devices()
Exemplo n.º 50
0
    def closest(self, *args):
        """Find closest entity.

        Closest to home:
          closest(states)
          closest(states.device_tracker)
          closest('group.children')
          closest(states.group.children)

        Closest to a point:
          closest(23.456, 23.456, 'group.children')
          closest('zone.school', 'group.children')
          closest(states.zone.school, 'group.children')
        """
        if len(args) == 1:
            latitude = self._hass.config.latitude
            longitude = self._hass.config.longitude
            entities = args[0]

        elif len(args) == 2:
            point_state = self._resolve_state(args[0])

            if point_state is None:
                _LOGGER.warning('Closest:Unable to find state %s', args[0])
                return None
            elif not loc_helper.has_location(point_state):
                _LOGGER.warning(
                    'Closest:State does not contain valid location: %s',
                    point_state)
                return None

            latitude = point_state.attributes.get(ATTR_LATITUDE)
            longitude = point_state.attributes.get(ATTR_LONGITUDE)

            entities = args[1]

        else:
            latitude = convert(args[0], float)
            longitude = convert(args[1], float)

            if latitude is None or longitude is None:
                _LOGGER.warning('Closest:Received invalid coordinates: %s, %s',
                                args[0], args[1])
                return None

            entities = args[2]

        if isinstance(entities, (AllStates, DomainStates)):
            states = list(entities)
        else:
            if isinstance(entities, State):
                gr_entity_id = entities.entity_id
            else:
                gr_entity_id = str(entities)

            group = get_component('group')

            states = [
                self._hass.states.get(entity_id)
                for entity_id in group.expand_entity_ids(
                    self._hass, [gr_entity_id])
            ]

        return loc_helper.closest(latitude, longitude, states)
Exemplo n.º 51
0
    def test_flux_with_multiple_lights(self):
        """Test the flux switch with multiple light entities."""
        platform = loader.get_component(self.hass, 'light.test')
        platform.init()
        self.assertTrue(
            setup_component(self.hass, light.DOMAIN,
                            {light.DOMAIN: {
                                CONF_PLATFORM: 'test'
                            }}))

        dev1, dev2, dev3 = platform.DEVICES
        common_light.turn_on(self.hass, entity_id=dev2.entity_id)
        self.hass.block_till_done()
        common_light.turn_on(self.hass, entity_id=dev3.entity_id)
        self.hass.block_till_done()

        state = self.hass.states.get(dev1.entity_id)
        self.assertEqual(STATE_ON, state.state)
        self.assertIsNone(state.attributes.get('xy_color'))
        self.assertIsNone(state.attributes.get('brightness'))

        state = self.hass.states.get(dev2.entity_id)
        self.assertEqual(STATE_ON, state.state)
        self.assertIsNone(state.attributes.get('xy_color'))
        self.assertIsNone(state.attributes.get('brightness'))

        state = self.hass.states.get(dev3.entity_id)
        self.assertEqual(STATE_ON, state.state)
        self.assertIsNone(state.attributes.get('xy_color'))
        self.assertIsNone(state.attributes.get('brightness'))

        test_time = dt_util.now().replace(hour=12, minute=0, second=0)
        sunset_time = test_time.replace(hour=17, minute=0, second=0)
        sunrise_time = test_time.replace(hour=5, minute=0, second=0)

        def event_date(hass, event, now=None):
            if event == 'sunrise':
                print('sunrise {}'.format(sunrise_time))
                return sunrise_time
            print('sunset {}'.format(sunset_time))
            return sunset_time

        with patch('homeassistant.util.dt.now', return_value=test_time):
            with patch('homeassistant.helpers.sun.get_astral_event_date',
                       side_effect=event_date):
                assert setup_component(
                    self.hass, switch.DOMAIN, {
                        switch.DOMAIN: {
                            'platform':
                            'flux',
                            'name':
                            'flux',
                            'lights':
                            [dev1.entity_id, dev2.entity_id, dev3.entity_id]
                        }
                    })
                turn_on_calls = mock_service(self.hass, light.DOMAIN,
                                             SERVICE_TURN_ON)
                common.turn_on(self.hass, 'switch.flux')
                self.hass.block_till_done()
                fire_time_changed(self.hass, test_time)
                self.hass.block_till_done()
        call = turn_on_calls[-1]
        self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 163)
        self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.46, 0.376])
        call = turn_on_calls[-2]
        self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 163)
        self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.46, 0.376])
        call = turn_on_calls[-3]
        self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 163)
        self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.46, 0.376])
Exemplo n.º 52
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the Fitbit sensor."""
    config_path = hass.config.path(FITBIT_CONFIG_FILE)
    if os.path.isfile(config_path):
        config_file = config_from_file(config_path)
        if config_file == DEFAULT_CONFIG:
            request_app_setup(hass, config, add_devices, config_path,
                              discovery_info=None)
            return False
    else:
        config_file = config_from_file(config_path, DEFAULT_CONFIG)
        request_app_setup(hass, config, add_devices, config_path,
                          discovery_info=None)
        return False

    if "fitbit" in _CONFIGURING:
        get_component("configurator").request_done(_CONFIGURING.pop("fitbit"))

    import fitbit

    access_token = config_file.get("access_token")
    refresh_token = config_file.get("refresh_token")
    if None not in (access_token, refresh_token):
        authd_client = fitbit.Fitbit(config_file.get("client_id"),
                                     config_file.get("client_secret"),
                                     access_token=access_token,
                                     refresh_token=refresh_token)

        if int(time.time()) - config_file.get("last_saved_at", 0) > 3600:
            authd_client.client.refresh_token()

        authd_client.system = authd_client.user_profile_get()["user"]["locale"]

        dev = []
        for resource in config.get("monitored_resources",
                                   FITBIT_DEFAULT_RESOURCE_LIST):
            dev.append(FitbitSensor(authd_client, config_path, resource))
        add_devices(dev)

    else:
        oauth = fitbit.api.FitbitOauth2Client(config_file.get("client_id"),
                                              config_file.get("client_secret"))

        redirect_uri = "{}{}".format(hass.config.api.base_url,
                                     FITBIT_AUTH_CALLBACK_PATH)

        def _start_fitbit_auth(handler, path_match, data):
            """Start Fitbit OAuth2 flow."""
            url, _ = oauth.authorize_token_url(redirect_uri=redirect_uri,
                                               scope=["activity", "heartrate",
                                                      "nutrition", "profile",
                                                      "settings", "sleep",
                                                      "weight"])
            handler.send_response(301)
            handler.send_header("Location", url)
            handler.end_headers()

        def _finish_fitbit_auth(handler, path_match, data):
            """Finish Fitbit OAuth2 flow."""
            response_message = """Fitbit has been successfully authorized!
            You can close this window now!"""
            from oauthlib.oauth2.rfc6749.errors import MismatchingStateError
            from oauthlib.oauth2.rfc6749.errors import MissingTokenError
            if data.get("code") is not None:
                try:
                    oauth.fetch_access_token(data.get("code"), redirect_uri)
                except MissingTokenError as error:
                    _LOGGER.error("Missing token: %s", error)
                    response_message = """Something went wrong when
                    attempting authenticating with Fitbit. The error
                    encountered was {}. Please try again!""".format(error)
                except MismatchingStateError as error:
                    _LOGGER.error("Mismatched state, CSRF error: %s", error)
                    response_message = """Something went wrong when
                    attempting authenticating with Fitbit. The error
                    encountered was {}. Please try again!""".format(error)
            else:
                _LOGGER.error("Unknown error when authing")
                response_message = """Something went wrong when
                    attempting authenticating with Fitbit.
                    An unknown error occurred. Please try again!
                    """

            html_response = """<html><head><title>Fitbit Auth</title></head>
            <body><h1>{}</h1></body></html>""".format(response_message)

            html_response = html_response.encode("utf-8")

            handler.send_response(HTTP_OK)
            handler.write_content(html_response, content_type="text/html")

            config_contents = {
                "access_token": oauth.token["access_token"],
                "refresh_token": oauth.token["refresh_token"],
                "client_id": oauth.client_id,
                "client_secret": oauth.client_secret
            }
            if not config_from_file(config_path, config_contents):
                _LOGGER.error("failed to save config file")

            setup_platform(hass, config, add_devices, discovery_info=None)

        hass.http.register_path("GET", FITBIT_AUTH_START, _start_fitbit_auth,
                                require_auth=False)
        hass.http.register_path("GET", FITBIT_AUTH_CALLBACK_PATH,
                                _finish_fitbit_auth, require_auth=False)

        request_oauth_completion(hass)
Exemplo n.º 53
0
def _async_setup_component(hass: core.HomeAssistant,
                           domain: str, config) -> bool:
    """Setup a component for Home Assistant.

    This method is a coroutine.

    hass: Home Assistant instance.
    domain: Domain of component to setup.
    config: The Home Assistant configuration.
    """
    def log_error(msg, link=True):
        """Log helper."""
        _LOGGER.error('Setup failed for %s: %s', domain, msg)
        async_notify_setup_error(hass, domain, link)

    component = loader.get_component(domain)

    if not component:
        log_error('Component not found.', False)
        return False

    # Validate no circular dependencies
    components = loader.load_order_component(domain)

    # OrderedSet is empty if component or dependencies could not be resolved
    if not components:
        log_error('Unable to resolve component or dependencies.')
        return False

    processed_config = \
        conf_util.async_process_component_config(hass, config, domain)

    if processed_config is None:
        log_error('Invalid config.')
        return False

    if not hass.config.skip_pip and hasattr(component, 'REQUIREMENTS'):
        req_success = yield from _async_process_requirements(
            hass, domain, component.REQUIREMENTS)
        if not req_success:
            log_error('Could not install all requirements.')
            return False

    if hasattr(component, 'DEPENDENCIES'):
        dep_success = yield from _async_process_dependencies(
            hass, config, domain, component.DEPENDENCIES)

        if not dep_success:
            log_error('Could not setup all dependencies.')
            return False

    async_comp = hasattr(component, 'async_setup')

    _LOGGER.info("Setting up %s", domain)
    warn_task = hass.loop.call_later(
        SLOW_SETUP_WARNING, _LOGGER.warning,
        'Setup of %s is taking over %s seconds.', domain, SLOW_SETUP_WARNING)

    try:
        if async_comp:
            result = yield from component.async_setup(hass, processed_config)
        else:
            result = yield from hass.loop.run_in_executor(
                None, component.setup, hass, processed_config)
    except Exception:  # pylint: disable=broad-except
        _LOGGER.exception('Error during setup of component %s', domain)
        async_notify_setup_error(hass, domain, True)
        return False
    finally:
        warn_task.cancel()

    if result is False:
        log_error('Component failed to initialize.')
        return False
    elif result is not True:
        log_error('Component did not return boolean if setup was successful. '
                  'Disabling component.')
        loader.set_component(domain, None)
        return False

    hass.config.components.add(component.DOMAIN)

    # cleanup
    if domain in hass.data[DATA_SETUP]:
        hass.data[DATA_SETUP].pop(domain)

    hass.bus.async_fire(
        EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: component.DOMAIN}
    )

    return True
Exemplo n.º 54
0
def setup(hass, config):
    """ Setup a demo environment. """
    group = loader.get_component('group')
    configurator = loader.get_component('configurator')

    config.setdefault(ha.DOMAIN, {})
    config.setdefault(DOMAIN, {})

    if config[DOMAIN].get('hide_demo_state') != '1':
        hass.states.set('a.Demo_Mode', 'Enabled')

    light_colors = [[0.861, 0.3259], [0.6389, 0.3028], [0.1684, 0.0416]]

    def mock_turn_on(service):
        """ Will fake the component has been turned on. """
        if service.data and ATTR_ENTITY_ID in service.data:
            entity_ids = extract_entity_ids(hass, service)
        else:
            entity_ids = hass.states.entity_ids(service.domain)

        for entity_id in entity_ids:
            domain, _ = split_entity_id(entity_id)

            if domain == "light":
                rgb_color = service.data.get(ATTR_RGB_COLOR)

                if rgb_color:
                    color = color_RGB_to_xy(rgb_color[0], rgb_color[1],
                                            rgb_color[2])

                else:
                    cur_state = hass.states.get(entity_id)

                    # Use current color if available
                    if cur_state and cur_state.attributes.get(ATTR_XY_COLOR):
                        color = cur_state.attributes.get(ATTR_XY_COLOR)
                    else:
                        color = random.choice(light_colors)

                data = {
                    ATTR_BRIGHTNESS: service.data.get(ATTR_BRIGHTNESS, 200),
                    ATTR_XY_COLOR: color
                }
            else:
                data = None

            hass.states.set(entity_id, STATE_ON, data)

    def mock_turn_off(service):
        """ Will fake the component has been turned off. """
        if service.data and ATTR_ENTITY_ID in service.data:
            entity_ids = extract_entity_ids(hass, service)
        else:
            entity_ids = hass.states.entity_ids(service.domain)

        for entity_id in entity_ids:
            hass.states.set(entity_id, STATE_OFF)

    # Setup sun
    if CONF_LATITUDE not in config[ha.DOMAIN]:
        config[ha.DOMAIN][CONF_LATITUDE] = '32.87336'

    if CONF_LONGITUDE not in config[ha.DOMAIN]:
        config[ha.DOMAIN][CONF_LONGITUDE] = '-117.22743'

    loader.get_component('sun').setup(hass, config)

    # Setup fake lights
    lights = [
        'light.Bowl', 'light.Ceiling', 'light.TV_Back_light', 'light.Bed_light'
    ]

    hass.services.register('light', SERVICE_TURN_ON, mock_turn_on)
    hass.services.register('light', SERVICE_TURN_OFF, mock_turn_off)

    mock_turn_on(
        ha.ServiceCall('light', SERVICE_TURN_ON, {'entity_id': lights[0:2]}))
    mock_turn_off(
        ha.ServiceCall('light', SERVICE_TURN_OFF, {'entity_id': lights[2:]}))

    group.setup_group(hass, GROUP_NAME_ALL_LIGHTS, lights, False)

    # Setup switch
    switches = ['switch.AC', 'switch.Christmas_Lights']

    hass.services.register('switch', SERVICE_TURN_ON, mock_turn_on)
    hass.services.register('switch', SERVICE_TURN_OFF, mock_turn_off)

    mock_turn_on(
        ha.ServiceCall('switch', SERVICE_TURN_ON,
                       {'entity_id': switches[0:1]}))
    mock_turn_off(
        ha.ServiceCall('switch', SERVICE_TURN_OFF,
                       {'entity_id': switches[1:]}))

    # Setup room groups
    group.setup_group(hass, 'living_room', lights[0:3] + switches[0:1])
    group.setup_group(hass, 'bedroom', [lights[3]] + switches[1:])

    # Setup process
    hass.states.set("process.XBMC", STATE_ON)

    # Setup device tracker
    hass.states.set(
        "device_tracker.Paulus", "home",
        {ATTR_ENTITY_PICTURE: "http://graph.facebook.com/schoutsen/picture"})
    hass.states.set(
        "device_tracker.Anne_Therese", "not_home", {
            ATTR_ENTITY_PICTURE:
            "http://graph.facebook.com/anne.t.frederiksen/picture"
        })

    hass.states.set(
        "group.all_devices", "home", {
            "auto": True,
            "entity_id":
            ["device_tracker.Paulus", "device_tracker.Anne_Therese"]
        })

    # Setup chromecast
    hass.states.set(
        "chromecast.Living_Rm", "Plex", {
            'friendly_name': 'Living Room',
            ATTR_ENTITY_PICTURE:
            'http://graph.facebook.com/KillBillMovie/picture'
        })

    # Setup tellstick sensors
    hass.states.set("tellstick_sensor.Outside_temperature", "15.6", {
        'friendly_name': 'Outside temperature',
        'unit_of_measurement': '°C'
    })
    hass.states.set("tellstick_sensor.Outside_humidity", "54", {
        'friendly_name': 'Outside humidity',
        'unit_of_measurement': '%'
    })

    # Nest demo
    hass.states.set(
        "thermostat.Nest", "23", {
            ATTR_UNIT_OF_MEASUREMENT: TEMP_CELCIUS,
            ATTR_CURRENT_TEMPERATURE: '18',
            ATTR_AWAY_MODE: STATE_OFF
        })

    configurator_ids = []

    def hue_configuration_callback(data):
        """ Fake callback, mark config as done. """
        time.sleep(2)

        # First time it is called, pretend it failed.
        if len(configurator_ids) == 1:
            configurator.notify_errors(
                configurator_ids[0], "Failed to register, please try again.")

            configurator_ids.append(0)
        else:
            configurator.request_done(configurator_ids[0])

    request_id = configurator.request_config(
        hass,
        "Philips Hue",
        hue_configuration_callback,
        description=("Press the button on the bridge to register Philips Hue "
                     "with Home Assistant."),
        description_image="/static/images/config_philips_hue.jpg",
        submit_caption="I have pressed the button")

    configurator_ids.append(request_id)

    return True
Exemplo n.º 55
0
    def test_get_component(self):
        """Test if get_component works."""
        self.assertEqual(http, loader.get_component('http'))

        self.assertIsNotNone(loader.get_component('switch.test'))
Exemplo n.º 56
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the smart mi fan platform."""
    import miio
    host = config.get(CONF_HOST)
    name = config.get(CONF_NAME)
    token = config.get(CONF_TOKEN)
    devices = config.get(CONF_SWITCHES, {})
    persistent_notification = loader.get_component('persistent_notification')

    @asyncio.coroutine
    def _learn_command(call):
        ir_remote = miio.Device(host, token)
        if not ir_remote:
            _LOGGER.error("Failed to connect to device.")
            return

        key = randint(1,1000000)

        ir_remote.send("miIO.ir_learn", {'key': str(key)})

        _LOGGER.info("Press the key you want HASS to learn")
        start_time = utcnow()
        while (utcnow() - start_time) < timedelta(seconds=DEFAULT_TIMEOUT):
            res = ir_remote.send("miIO.ir_read", {'key': str(key)})
            _LOGGER.error(type(res["code"]))
            _LOGGER.error(res["code"])
            if res["code"]:
                log_msg = 'Recieved packet is: %s' % res["code"]
                _LOGGER.info(log_msg)
                persistent_notification.async_create(hass, log_msg,
                                                     title='Chuangmi switch')
                return
            yield from asyncio.sleep(1, loop=hass.loop)
        _LOGGER.error('Did not received any signal.')
        persistent_notification.async_create(hass,
                                             "Did not received any signal",
                                             title='Chuangmi switch')

    @asyncio.coroutine
    def _send_packet(call):
        ir_remote = miio.Device(host, token)
        if not ir_remote:
            _LOGGER.error("Failed to connect to device.")
            return

        packets = call.data.get('packet', [])
        for packet in packets:
            for retry in range(DEFAULT_RETRY):
                try:
                    ir_remote.send("miIO.ir_play", {'freq':38400, 'code': str(packet)})
                    break
                except (socket.timeout, ValueError):
                    _LOGGER.error("Failed to send packet to device.")

    ir_remote = miio.Device(host, token)
    if not ir_remote:
        _LOGGER.error("Failed to connect to device.")

    hass.services.register(DOMAIN, SERVICE_LEARN + '_' +
                            host.replace('.', '_'), _learn_command)
    hass.services.register(DOMAIN, SERVICE_SEND + '_' +
                            host.replace('.', '_'), _send_packet)
    switches = []
    for object_id, device_config in devices.items():
        switches.append(
            ChuangmiIRSwitch(
                ir_remote,
                device_config.get(CONF_NAME, object_id),
                device_config.get(CONF_COMMAND_ON),
                device_config.get(CONF_COMMAND_OFF)
            )
        )

    add_devices(switches)
Exemplo n.º 57
0
def setup(hass, config):
    """Set up the Wink component."""
    import pywink
    from pubnubsubhandler import PubNubSubscriptionHandler

    if hass.data.get(DOMAIN) is None:
        hass.data[DOMAIN] = {
            'unique_ids': [],
            'entities': {},
            'oauth': {},
            'configuring': {},
            'pubnub': None,
            'configurator': False
        }

    def _get_wink_token_from_web():
        _email = hass.data[DOMAIN]["oauth"]["email"]
        _password = hass.data[DOMAIN]["oauth"]["password"]

        payload = {'username': _email, 'password': _password}
        token_response = requests.post(CONF_TOKEN_URL, data=payload)
        try:
            token = token_response.text.split(':')[1].split()[0].rstrip('<br')
        except IndexError:
            _LOGGER.error("Error getting token. Please check email/password.")
            return False
        pywink.set_bearer_token(token)

    client_id = config[DOMAIN].get(ATTR_CLIENT_ID)
    client_secret = config[DOMAIN].get(ATTR_CLIENT_SECRET)
    email = config[DOMAIN].get(CONF_EMAIL)
    password = config[DOMAIN].get(CONF_PASSWORD)
    local_control = config[DOMAIN].get(CONF_LOCAL_CONTROL)
    if None not in [client_id, client_secret]:
        _LOGGER.info("Using legacy oauth authentication")
        if not local_control:
            pywink.disable_local_control()
        hass.data[DOMAIN]["oauth"]["client_id"] = client_id
        hass.data[DOMAIN]["oauth"]["client_secret"] = client_secret
        hass.data[DOMAIN]["oauth"]["email"] = email
        hass.data[DOMAIN]["oauth"]["password"] = password
        pywink.legacy_set_wink_credentials(email, password, client_id,
                                           client_secret)
    elif None not in [email, password]:
        _LOGGER.info("Using web form authentication")
        pywink.disable_local_control()
        hass.data[DOMAIN]["oauth"]["email"] = email
        hass.data[DOMAIN]["oauth"]["password"] = password
        _get_wink_token_from_web()
    else:
        _LOGGER.info("Using new oauth authentication")
        if not local_control:
            pywink.disable_local_control()
        config_path = hass.config.path(WINK_CONFIG_FILE)
        if os.path.isfile(config_path):
            config_file = _read_config_file(config_path)
            if config_file == DEFAULT_CONFIG:
                _request_app_setup(hass, config)
                return True
            # else move on because the user modified the file
        else:
            _write_config_file(config_path, DEFAULT_CONFIG)
            _request_app_setup(hass, config)
            return True

        if DOMAIN in hass.data[DOMAIN]['configuring']:
            _configurator = hass.data[DOMAIN]['configuring']
            get_component('configurator').request_done(
                _configurator.pop(DOMAIN))

        # Using oauth
        access_token = config_file.get(ATTR_ACCESS_TOKEN)
        refresh_token = config_file.get(ATTR_REFRESH_TOKEN)

        # This will be called after authorizing Home-Assistant
        if None not in (access_token, refresh_token):
            pywink.set_wink_credentials(config_file.get(ATTR_CLIENT_ID),
                                        config_file.get(ATTR_CLIENT_SECRET),
                                        access_token=access_token,
                                        refresh_token=refresh_token)
        # This is called to create the redirect so the user can Authorize
        # Home-Assistant
        else:

            redirect_uri = '{}{}'.format(hass.config.api.base_url,
                                         WINK_AUTH_CALLBACK_PATH)

            wink_auth_start_url = pywink.get_authorization_url(
                config_file.get(ATTR_CLIENT_ID), redirect_uri)
            hass.http.register_redirect(WINK_AUTH_START, wink_auth_start_url)
            hass.http.register_view(
                WinkAuthCallbackView(config, config_file,
                                     pywink.request_token))
            _request_oauth_completion(hass, config)
            return True

    pywink.set_user_agent(USER_AGENT)
    hass.data[DOMAIN]['pubnub'] = PubNubSubscriptionHandler(
        pywink.get_subscription_key())

    def _subscribe():
        hass.data[DOMAIN]['pubnub'].subscribe()

    # Call subscribe after the user sets up wink via the configurator
    # All other methods will complete setup before
    # EVENT_HOMEASSISTANT_START is called meaning they
    # will call subscribe via the method below. (start_subscription)
    if hass.data[DOMAIN]['configurator']:
        _subscribe()

    def keep_alive_call(event_time):
        """Call the Wink API endpoints to keep PubNub working."""
        _LOGGER.info("Polling the Wink API to keep PubNub updates flowing.")
        pywink.set_user_agent(str(int(time.time())))
        _temp_response = pywink.get_user()
        _LOGGER.debug(str(json.dumps(_temp_response)))
        time.sleep(1)
        pywink.set_user_agent(USER_AGENT)
        _temp_response = pywink.wink_api_fetch()
        _LOGGER.debug(str(json.dumps(_temp_response)))

    # Call the Wink API every hour to keep PubNub updates flowing
    track_time_interval(hass, keep_alive_call, timedelta(minutes=60))

    def start_subscription(event):
        """Start the pubnub subscription."""
        _subscribe()

    hass.bus.listen(EVENT_HOMEASSISTANT_START, start_subscription)

    def stop_subscription(event):
        """Stop the pubnub subscription."""
        hass.data[DOMAIN]['pubnub'].unsubscribe()

    hass.bus.listen(EVENT_HOMEASSISTANT_STOP, stop_subscription)

    def save_credentials(event):
        """Save currently set oauth credentials."""
        if hass.data[DOMAIN]["oauth"].get("email") is None:
            config_path = hass.config.path(WINK_CONFIG_FILE)
            _config = pywink.get_current_oauth_credentials()
            _write_config_file(config_path, _config)

    hass.bus.listen(EVENT_HOMEASSISTANT_STOP, save_credentials)

    def force_update(call):
        """Force all devices to poll the Wink API."""
        _LOGGER.info("Refreshing Wink states from API")
        for entity_list in hass.data[DOMAIN]['entities'].values():
            # Throttle the calls to Wink API
            for entity in entity_list:
                time.sleep(1)
                entity.schedule_update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_REFRESH_STATES, force_update)

    def pull_new_devices(call):
        """Pull new devices added to users Wink account since startup."""
        _LOGGER.info("Getting new devices from Wink API")
        for _component in WINK_COMPONENTS:
            discovery.load_platform(hass, _component, DOMAIN, {}, config)

    hass.services.register(DOMAIN, SERVICE_ADD_NEW_DEVICES, pull_new_devices)

    # Load components for the devices in Wink that we support
    for component in WINK_COMPONENTS:
        hass.data[DOMAIN]['entities'][component] = []
        discovery.load_platform(hass, component, DOMAIN, {}, config)

    return True
Exemplo n.º 58
0
    def test_services(self):
        """Test the provided services."""
        platform = loader.get_component('light.test')

        platform.init()
        self.assertTrue(
            setup_component(self.hass, light.DOMAIN,
                            {light.DOMAIN: {
                                CONF_PLATFORM: 'test'
                            }}))

        dev1, dev2, dev3 = platform.DEVICES

        # Test init
        self.assertTrue(light.is_on(self.hass, dev1.entity_id))
        self.assertFalse(light.is_on(self.hass, dev2.entity_id))
        self.assertFalse(light.is_on(self.hass, dev3.entity_id))

        # Test basic turn_on, turn_off, toggle services
        light.turn_off(self.hass, entity_id=dev1.entity_id)
        light.turn_on(self.hass, entity_id=dev2.entity_id)

        self.hass.block_till_done()

        self.assertFalse(light.is_on(self.hass, dev1.entity_id))
        self.assertTrue(light.is_on(self.hass, dev2.entity_id))

        # turn on all lights
        light.turn_on(self.hass)

        self.hass.block_till_done()

        self.assertTrue(light.is_on(self.hass, dev1.entity_id))
        self.assertTrue(light.is_on(self.hass, dev2.entity_id))
        self.assertTrue(light.is_on(self.hass, dev3.entity_id))

        # turn off all lights
        light.turn_off(self.hass)

        self.hass.block_till_done()

        self.assertFalse(light.is_on(self.hass, dev1.entity_id))
        self.assertFalse(light.is_on(self.hass, dev2.entity_id))
        self.assertFalse(light.is_on(self.hass, dev3.entity_id))

        # toggle all lights
        light.toggle(self.hass)

        self.hass.block_till_done()

        self.assertTrue(light.is_on(self.hass, dev1.entity_id))
        self.assertTrue(light.is_on(self.hass, dev2.entity_id))
        self.assertTrue(light.is_on(self.hass, dev3.entity_id))

        # toggle all lights
        light.toggle(self.hass)

        self.hass.block_till_done()

        self.assertFalse(light.is_on(self.hass, dev1.entity_id))
        self.assertFalse(light.is_on(self.hass, dev2.entity_id))
        self.assertFalse(light.is_on(self.hass, dev3.entity_id))

        # Ensure all attributes process correctly
        light.turn_on(self.hass,
                      dev1.entity_id,
                      transition=10,
                      brightness=20,
                      color_name='blue')
        light.turn_on(self.hass,
                      dev2.entity_id,
                      rgb_color=(255, 255, 255),
                      white_value=255)
        light.turn_on(self.hass, dev3.entity_id, xy_color=(.4, .6))

        self.hass.block_till_done()

        _, data = dev1.last_call('turn_on')
        self.assertEqual(
            {
                light.ATTR_TRANSITION: 10,
                light.ATTR_BRIGHTNESS: 20,
                light.ATTR_RGB_COLOR: (0, 0, 255)
            }, data)

        _, data = dev2.last_call('turn_on')
        self.assertEqual(
            {
                light.ATTR_RGB_COLOR: (255, 255, 255),
                light.ATTR_WHITE_VALUE: 255
            }, data)

        _, data = dev3.last_call('turn_on')
        self.assertEqual({light.ATTR_XY_COLOR: (.4, .6)}, data)

        # One of the light profiles
        prof_name, prof_x, prof_y, prof_bri = 'relax', 0.5119, 0.4147, 144

        # Test light profiles
        light.turn_on(self.hass, dev1.entity_id, profile=prof_name)
        # Specify a profile and a brightness attribute to overwrite it
        light.turn_on(self.hass,
                      dev2.entity_id,
                      profile=prof_name,
                      brightness=100)

        self.hass.block_till_done()

        _, data = dev1.last_call('turn_on')
        self.assertEqual(
            {
                light.ATTR_BRIGHTNESS: prof_bri,
                light.ATTR_XY_COLOR: (prof_x, prof_y)
            }, data)

        _, data = dev2.last_call('turn_on')
        self.assertEqual(
            {
                light.ATTR_BRIGHTNESS: 100,
                light.ATTR_XY_COLOR: (.5119, .4147)
            }, data)

        # Test bad data
        light.turn_on(self.hass)
        light.turn_on(self.hass, dev1.entity_id, profile="nonexisting")
        light.turn_on(self.hass, dev2.entity_id, xy_color=["bla-di-bla", 5])
        light.turn_on(self.hass, dev3.entity_id, rgb_color=[255, None, 2])

        self.hass.block_till_done()

        _, data = dev1.last_call('turn_on')
        self.assertEqual({}, data)

        _, data = dev2.last_call('turn_on')
        self.assertEqual({}, data)

        _, data = dev3.last_call('turn_on')
        self.assertEqual({}, data)

        # faulty attributes will not trigger a service call
        light.turn_on(self.hass,
                      dev1.entity_id,
                      profile=prof_name,
                      brightness='bright')
        light.turn_on(self.hass, dev1.entity_id, rgb_color='yellowish')
        light.turn_on(self.hass, dev2.entity_id, white_value='high')

        self.hass.block_till_done()

        _, data = dev1.last_call('turn_on')
        self.assertEqual({}, data)

        _, data = dev2.last_call('turn_on')
        self.assertEqual({}, data)
Exemplo n.º 59
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up Broadlink switches."""
    import broadlink
    devices = config.get(CONF_SWITCHES, {})
    ip_addr = config.get(CONF_HOST)
    friendly_name = config.get(CONF_FRIENDLY_NAME)
    mac_addr = binascii.unhexlify(
        config.get(CONF_MAC).encode().replace(b':', b''))
    switch_type = config.get(CONF_TYPE)

    persistent_notification = loader.get_component('persistent_notification')

    @asyncio.coroutine
    def _learn_command(call):
        try:
            auth = yield from hass.async_add_job(broadlink_device.auth)
        except socket.timeout:
            _LOGGER.error("Failed to connect to device, timeout")
            return
        if not auth:
            _LOGGER.error("Failed to connect to device")
            return

        yield from hass.async_add_job(broadlink_device.enter_learning)

        _LOGGER.info("Press the key you want HASS to learn")
        start_time = utcnow()
        while (utcnow() - start_time) < timedelta(seconds=20):
            packet = yield from hass.async_add_job(broadlink_device.check_data)
            if packet:
                log_msg = "Recieved packet is: {}".\
                          format(b64encode(packet).decode('utf8'))
                _LOGGER.info(log_msg)
                persistent_notification.async_create(hass,
                                                     log_msg,
                                                     title='Broadlink switch')
                return
            yield from asyncio.sleep(1, loop=hass.loop)
        _LOGGER.error("Did not received any signal")
        persistent_notification.async_create(hass,
                                             "Did not received any signal",
                                             title='Broadlink switch')

    @asyncio.coroutine
    def _send_packet(call):
        packets = call.data.get('packet', [])
        for packet in packets:
            for retry in range(DEFAULT_RETRY):
                try:
                    payload = b64decode(packet)
                    yield from hass.async_add_job(broadlink_device.send_data,
                                                  payload)
                    break
                except (socket.timeout, ValueError):
                    try:
                        yield from hass.async_add_job(broadlink_device.auth)
                    except socket.timeout:
                        if retry == DEFAULT_RETRY - 1:
                            _LOGGER.error("Failed to send packet to device")

    if switch_type in RM_TYPES:
        broadlink_device = broadlink.rm((ip_addr, 80), mac_addr)
        hass.services.register(DOMAIN,
                               SERVICE_LEARN + '_' + ip_addr.replace('.', '_'),
                               _learn_command)
        hass.services.register(DOMAIN,
                               SERVICE_SEND + '_' + ip_addr.replace('.', '_'),
                               _send_packet)
        switches = []
        for object_id, device_config in devices.items():
            switches.append(
                BroadlinkRMSwitch(
                    device_config.get(CONF_FRIENDLY_NAME, object_id),
                    broadlink_device, device_config.get(CONF_COMMAND_ON),
                    device_config.get(CONF_COMMAND_OFF)))
    elif switch_type in SP1_TYPES:
        broadlink_device = broadlink.sp1((ip_addr, 80), mac_addr)
        switches = [BroadlinkSP1Switch(friendly_name, broadlink_device)]
    elif switch_type in SP2_TYPES:
        broadlink_device = broadlink.sp2((ip_addr, 80), mac_addr)
        switches = [BroadlinkSP2Switch(friendly_name, broadlink_device)]

    broadlink_device.timeout = config.get(CONF_TIMEOUT)
    try:
        broadlink_device.auth()
    except socket.timeout:
        _LOGGER.error("Failed to connect to device")

    add_devices(switches)
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the demo image processing platform."""
    app_id = config.get(CONF_APP_ID)
    api_key = config.get(CONF_API_KEY)
    secret_key = config.get(CONF_SECRET_KEY)
    snapshot_filepath = config.get(CONF_SNAPSHOT_FILEPATH)
    resize = config.get(CONF_RESIZE)
    ha_url = config.get(CONF_HA_URL)
    ha_password = config.get(CONF_HA_PASSWORD)
    detect_top_num = config.get(CONF_DETECT_TOP_NUM)
    entities = []
    for camera in config[CONF_SOURCE]:
        entities.append(
            BaiduFaceIdentifyEntity(hass, camera[CONF_ENTITY_ID],
                                    camera.get(CONF_NAME), app_id, api_key,
                                    secret_key, snapshot_filepath, resize,
                                    ha_url, ha_password, detect_top_num))
    add_devices(entities)
    persistent_notification = loader.get_component('persistent_notification')

    def getAccessToken():
        #请求参数
        client_id = api_key
        client_secret = secret_key
        grant_type = 'client_credentials'
        request_url = 'https://aip.baidubce.com/oauth/2.0/token'
        params = {
            'client_id': client_id,
            'client_secret': client_secret,
            'grant_type': grant_type
        }
        r = requests.get(url=request_url, params=params)
        access_token = json.loads(r.text)['access_token']
        return access_token

    def get_image_base64(image_path):
        with open(image_path, 'rb') as fp:
            return base64.b64encode(fp.read())

    #人脸注册服务
    def registerUserFace(service):
        def register():
            user_info = service.data[ATTR_USERINFO]
            uid = service.data[ATTR_UID]
            image = service.data[ATTR_IMAGE]
            group_id = GROUP_ID
            request_url = "https://aip.baidubce.com/rest/2.0/face/v2/faceset/user/add"

            img = get_image_base64(image)

            params = {'access_token': getAccessToken()}
            data = {
                "group_id": group_id,
                "image": img,
                "uid": uid,
                "user_info": user_info
            }
            r = requests.post(url=request_url, params=params, data=data)
            resultjson = json.loads(r.text)
            if 'error_code' in resultjson:
                persistent_notification.create(hass,
                                               '人脸数据注册失败',
                                               title='百度人脸识别')
            elif 'error_msg' in resultjson:
                if resultjson['error_msg'] == 'image exist':
                    persistent_notification.create(hass,
                                                   '此人脸已经使用过',
                                                   title='百度人脸识别')
            else:
                persistent_notification.create(hass,
                                               '人脸数据注册成功',
                                               title='百度人脸识别')
            return json.loads(r.text)

        threading.Thread(target=register).start()

    hass.services.register(DOMAIN,
                           SERVUCE_REGISTERUSERFACE,
                           registerUserFace,
                           schema=SERVUCE_REGISTERUSERFACE_SCHEMA)

    #人脸数据查询服务
    def getUserInfo(service):
        def userinfo():
            group_id = service.data[ATTR_GROUPID]
            request_url = "https://aip.baidubce.com/rest/2.0/face/v2/faceset/group/getusers"
            params = {'access_token': getAccessToken()}
            data = {"group_id": group_id}
            r = requests.post(url=request_url, params=params, data=data)
            resultjson = json.loads(r.text)
            #outputst = ''
            br_string = ''
            if resultjson['result_num'] == 0:
                persistent_notification.create(hass, '无人脸注册数据', title='百度人脸识别')
            elif 'error_msg' in resultjson:
                if resultjson['error_msg'] == 'image exist':
                    persistent_notification.create(hass,
                                                   '此人脸已经使用过',
                                                   title='百度人脸识别')
            else:
                for i in range(len(resultjson['result'])):
                    br_string = br_string + str(
                        resultjson['result'][i]) + '<br />'

                persistent_notification.create(hass, br_string, title='百度人脸识别')
            return json.loads(r.text)

        threading.Thread(target=userinfo).start()

    hass.services.register(DOMAIN,
                           SERVUCE_GETUSERLIST,
                           getUserInfo,
                           schema=SERVUCE_GETUSERLIST_SCHEMA)

    #人脸数据删除服务
    def delUserInfo(service):
        def deluserinfo():
            uid = service.data[ATTR_UID]
            request_url = "https://aip.baidubce.com/rest/2.0/face/v2/faceset/user/delete"
            params = {'access_token': getAccessToken()}
            data = {'uid': uid}
            r = requests.post(url=request_url, params=params, data=data)
            resultjson = json.loads(r.text)
            if 'error_code' in resultjson:
                persistent_notification.create(hass,
                                               '人脸数据删除失败<br />检查uid是否正确',
                                               title='百度人脸识别')
            elif 'error_msg' in resultjson:
                if resultjson['error_msg'] == 'user not exist':
                    persistent_notification.create(hass,
                                                   '该uid不存在',
                                                   title='百度人脸识别')
            else:
                persistent_notification.create(hass,
                                               '人脸数据删除成功',
                                               title='百度人脸识别')
            return json.loads(r.text)

        threading.Thread(target=deluserinfo).start()

    hass.services.register(DOMAIN,
                           SERVUCE_DELETEUSER,
                           delUserInfo,
                           schema=SERVUCE_DELETEUSER_SCHEMA)

    def details_faceinfo(json):
        resultinfo = ''
        for key, value in json.items():
            if key in face_fields:
                if face_fields[key][1] == "%":
                    resultinfo = resultinfo + face_fields[key][0] + ":" + str(
                        round(json[key] * 100, 2)) + "%<br />"
                elif face_fields[key][1] == "int":
                    resultinfo = resultinfo + face_fields[key][0] + ":" + str(
                        json[key]) + "<br />"
                elif face_fields[key][1] == None:
                    resultinfo = resultinfo + face_fields[key][
                        0] + ":" + face_fields[key][2][str(
                            json[key])] + "<br />"
                else:
                    resultinfo = resultinfo + face_fields[key][0] + ":" + str(
                        json[key]) + face_fields[key][1] + "<br />"
            elif key == 'faceshape':
                for i in range(len(json['faceshape'])):
                    resultinfo = resultinfo + faceshape[
                        json['faceshape'][i]['type']][0] + ":" + str(
                            round(json['faceshape'][i]['probability'] * 100,
                                  2)) + "%<br />"

            elif key == 'qualities':
                resultinfo = resultinfo + human_type['human'][0] + ":" + str(
                    round(json['qualities']['type']['human'] * 100,
                          2)) + "%<br />"
                resultinfo = resultinfo + human_type['cartoon'][0] + ":" + str(
                    round(json['qualities']['type']['cartoon'] * 100,
                          2)) + "%<br />"

        return resultinfo

    #人脸检测服务
    def detectface(service):
        def detect():
            image = service.data[ATTR_IMAGE]
            request_url = "https://aip.baidubce.com/rest/2.0/face/v2/detect"
            img = get_image_base64(image)
            params = {
                'access_token':
                getAccessToken(),
                'face_fields':
                'age,beauty,expression,faceshape,gender,glasses,race,qualities',
            }
            data = {"image": img}
            r = requests.post(url=request_url, params=params, data=data)
            resultjson = json.loads(r.text)
            if resultjson['result_num'] == 0:
                persistent_notification.create(hass,
                                               '没检测到人脸存在!',
                                               title='百度人脸识别')
            elif 'error_msg' in resultjson:
                if resultjson[
                        'error_msg'] == 'Access token invalid or no longer valid':
                    persistent_notification.create(hass,
                                                   '百度Access Token获取失败!',
                                                   title='百度人脸识别')
                elif resultjson[
                        'error_msg'] == 'Open api qps request limit reached':
                    persistent_notification.create(hass,
                                                   'QPS超限额',
                                                   title='百度人脸识别')
                else:
                    persistent_notification.create(hass,
                                                   resultjson['error_msg'],
                                                   title='百度人脸识别')
            else:
                persistent_notification.create(hass,
                                               details_faceinfo(
                                                   resultjson['result'][0]),
                                               title='百度人脸识别')
            return json.loads(r.text)

        threading.Thread(target=detect).start()

    hass.services.register(DOMAIN,
                           SERVUCE_DETECTFACE,
                           detectface,
                           schema=SERVUCE_DETECTFACE_SCHEMA)