示例#1
0
def setup(hass, config):
    """ Track states and offer events for switches. """
    component = EntityComponent(
        _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS,
        GROUP_NAME_ALL_SWITCHES)
    component.setup(config)

    def handle_switch_service(service):
        """ Handles calls to the switch services. """
        target_switches = component.extract_from_service(service)

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

            if switch.should_poll:
                switch.update_ha_state(True)

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

    return True
示例#2
0
def setup(hass, config):
    """Set up the Remember the milk component."""
    component = EntityComponent(_LOGGER,
                                DOMAIN,
                                hass,
                                group_name=GROUP_NAME_RTM)

    stored_rtm_config = RememberTheMilkConfiguration(hass)
    for rtm_config in config[DOMAIN]:
        account_name = rtm_config[CONF_NAME]
        _LOGGER.info("Adding Remember the milk account %s", account_name)
        api_key = rtm_config[CONF_API_KEY]
        shared_secret = rtm_config[CONF_SHARED_SECRET]
        token = stored_rtm_config.get_token(account_name)
        if token:
            _LOGGER.debug("found token for account %s", account_name)
            _create_instance(hass, account_name, api_key, shared_secret, token,
                             stored_rtm_config, component)
        else:
            _register_new_account(hass, account_name, api_key, shared_secret,
                                  stored_rtm_config, component)

    _LOGGER.debug("Finished adding all Remember the milk accounts")
    return True
示例#3
0
async def test_set_entity_namespace_via_config(hass):
    """Test setting an entity namespace."""
    def platform_setup(hass, config, add_entities, discovery_info=None):
        """Test the platform setup."""
        add_entities([MockEntity(name="beer"), MockEntity(name=None)])

    platform = MockPlatform(platform_setup)

    mock_entity_platform(hass, "test_domain.platform", platform)

    component = EntityComponent(_LOGGER, DOMAIN, hass)

    component.setup(
        {DOMAIN: {
            "platform": "platform",
            "entity_namespace": "yummy"
        }})

    await hass.async_block_till_done()

    assert sorted(hass.states.async_entity_ids()) == [
        "test_domain.yummy_beer",
        "test_domain.yummy_unnamed_device",
    ]
示例#4
0
def async_setup(hass, config):
    """Set up the camera component."""
    component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL)

    hass.http.register_view(CameraImageView(component.entities))
    hass.http.register_view(CameraMjpegStream(component.entities))

    yield from component.async_setup(config)

    @callback
    def update_tokens(time):
        """Update tokens of the entities."""
        for entity in component.entities.values():
            entity.async_update_token()
            hass.async_add_job(entity.async_update_ha_state())

    async_track_time_interval(hass, update_tokens, TOKEN_CHANGE_INTERVAL)

    @asyncio.coroutine
    def async_handle_camera_service(service):
        """Handle calls to the camera services."""
        target_cameras = component.async_extract_from_service(service)

        for camera in target_cameras:
            try:
                if service.service == SERVICE_ARM:
                    yield from camera.async_arm()
                elif service.service == SERVICE_DISARM:
                    yield from camera.async_disarm()
            except AttributeError:
                pass

        update_tasks = []
        for camera in target_cameras:
            if not camera.should_poll:
                continue

            update_coro = hass.async_add_job(
                camera.async_update_ha_state(True))
            if hasattr(camera, 'async_update'):
                update_tasks.append(update_coro)
            else:
                yield from update_coro

        if update_tasks:
            yield from asyncio.wait(update_tasks, loop=hass.loop)

    descriptions = yield from hass.async_add_job(
        load_yaml_config_file,
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    hass.services.async_register(DOMAIN,
                                 SERVICE_ARM,
                                 async_handle_camera_service,
                                 descriptions.get(SERVICE_ARM),
                                 schema=CAMERA_SERVICE_SCHEMA)
    hass.services.async_register(DOMAIN,
                                 SERVICE_DISARM,
                                 async_handle_camera_service,
                                 descriptions.get(SERVICE_DISARM),
                                 schema=CAMERA_SERVICE_SCHEMA)

    return True
示例#5
0
def _async_get_component(hass: HomeAssistant) -> EntityComponent:
    if (component := hass.data.get(DOMAIN)) is None:
        component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass)
示例#6
0
def async_setup(hass, config):
    """Setup the automation."""
    component = EntityComponent(_LOGGER,
                                DOMAIN,
                                hass,
                                group_name=GROUP_NAME_ALL_AUTOMATIONS)

    success = yield from _async_process_config(hass, config, component)

    if not success:
        return False

    descriptions = yield from hass.loop.run_in_executor(
        None, conf_util.load_yaml_config_file,
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    @asyncio.coroutine
    def trigger_service_handler(service_call):
        """Handle automation triggers."""
        tasks = []
        for entity in component.async_extract_from_service(service_call):
            tasks.append(
                entity.async_trigger(service_call.data.get(ATTR_VARIABLES),
                                     True))

        if tasks:
            yield from asyncio.wait(tasks, loop=hass.loop)

    @asyncio.coroutine
    def turn_onoff_service_handler(service_call):
        """Handle automation turn on/off service calls."""
        tasks = []
        method = 'async_{}'.format(service_call.service)
        for entity in component.async_extract_from_service(service_call):
            tasks.append(getattr(entity, method)())

        if tasks:
            yield from asyncio.wait(tasks, loop=hass.loop)

    @asyncio.coroutine
    def toggle_service_handler(service_call):
        """Handle automation toggle service calls."""
        tasks = []
        for entity in component.async_extract_from_service(service_call):
            if entity.is_on:
                tasks.append(entity.async_turn_off())
            else:
                tasks.append(entity.async_turn_on())

        if tasks:
            yield from asyncio.wait(tasks, loop=hass.loop)

    @asyncio.coroutine
    def reload_service_handler(service_call):
        """Remove all automations and load new ones from config."""
        conf = yield from component.async_prepare_reload()
        if conf is None:
            return
        yield from _async_process_config(hass, conf, component)

    hass.services.async_register(DOMAIN,
                                 SERVICE_TRIGGER,
                                 trigger_service_handler,
                                 descriptions.get(SERVICE_TRIGGER),
                                 schema=TRIGGER_SERVICE_SCHEMA)

    hass.services.async_register(DOMAIN,
                                 SERVICE_RELOAD,
                                 reload_service_handler,
                                 descriptions.get(SERVICE_RELOAD),
                                 schema=RELOAD_SERVICE_SCHEMA)

    hass.services.async_register(DOMAIN,
                                 SERVICE_TOGGLE,
                                 toggle_service_handler,
                                 descriptions.get(SERVICE_TOGGLE),
                                 schema=SERVICE_SCHEMA)

    for service in (SERVICE_TURN_ON, SERVICE_TURN_OFF):
        hass.services.async_register(DOMAIN,
                                     service,
                                     turn_onoff_service_handler,
                                     descriptions.get(service),
                                     schema=SERVICE_SCHEMA)

    return True
示例#7
0
def setup(hass, config):
    """Track states and offer events for media_players."""
    component = EntityComponent(
        logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL)

    component.setup(config)

    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    def media_player_service_handler(service):
        """Map services to methods on MediaPlayerDevice."""
        method = SERVICE_TO_METHOD[service.service]

        for player in component.extract_from_service(service):
            getattr(player, method)()

            if player.should_poll:
                player.update_ha_state(True)

    for service in SERVICE_TO_METHOD:
        hass.services.register(DOMAIN, service, media_player_service_handler,
                               descriptions.get(service),
                               schema=MEDIA_PLAYER_SCHEMA)

    def volume_set_service(service):
        """Set specified volume on the media player."""
        volume = service.data.get(ATTR_MEDIA_VOLUME_LEVEL)

        for player in component.extract_from_service(service):
            player.set_volume_level(volume)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_VOLUME_SET, volume_set_service,
                           descriptions.get(SERVICE_VOLUME_SET),
                           schema=MEDIA_PLAYER_SET_VOLUME_SCHEMA)

    def volume_mute_service(service):
        """Mute (true) or unmute (false) the media player."""
        mute = service.data.get(ATTR_MEDIA_VOLUME_MUTED)

        for player in component.extract_from_service(service):
            player.mute_volume(mute)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_VOLUME_MUTE, volume_mute_service,
                           descriptions.get(SERVICE_VOLUME_MUTE),
                           schema=MEDIA_PLAYER_MUTE_VOLUME_SCHEMA)

    def media_seek_service(service):
        """Seek to a position."""
        position = service.data.get(ATTR_MEDIA_SEEK_POSITION)

        for player in component.extract_from_service(service):
            player.media_seek(position)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_MEDIA_SEEK, media_seek_service,
                           descriptions.get(SERVICE_MEDIA_SEEK),
                           schema=MEDIA_PLAYER_MEDIA_SEEK_SCHEMA)

    def select_source_service(service):
        """Change input to selected source."""
        input_source = service.data.get(ATTR_INPUT_SOURCE)

        for player in component.extract_from_service(service):
            player.select_source(input_source)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_SELECT_SOURCE,
                           select_source_service,
                           descriptions.get(SERVICE_SELECT_SOURCE),
                           schema=MEDIA_PLAYER_SELECT_SOURCE_SCHEMA)

    def play_media_service(service):
        """Play specified media_id on the media player."""
        media_type = service.data.get(ATTR_MEDIA_CONTENT_TYPE)
        media_id = service.data.get(ATTR_MEDIA_CONTENT_ID)
        enqueue = service.data.get(ATTR_MEDIA_ENQUEUE)

        kwargs = {
            ATTR_MEDIA_ENQUEUE: enqueue,
        }

        for player in component.extract_from_service(service):
            player.play_media(media_type, media_id, **kwargs)

            if player.should_poll:
                player.update_ha_state(True)

    hass.services.register(DOMAIN, SERVICE_PLAY_MEDIA, play_media_service,
                           descriptions.get(SERVICE_PLAY_MEDIA),
                           schema=MEDIA_PLAYER_PLAY_MEDIA_SCHEMA)

    return True
示例#8
0
async def async_setup(hass, config):
    """Track states and offer events for media_players."""
    component = hass.data[DOMAIN] = EntityComponent(
        logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL)

    hass.components.websocket_api.async_register_command(
        WS_TYPE_MEDIA_PLAYER_THUMBNAIL, websocket_handle_thumbnail,
        SCHEMA_WEBSOCKET_GET_THUMBNAIL)
    hass.http.register_view(MediaPlayerImageView(component))

    await component.async_setup(config)

    component.async_register_entity_service(SERVICE_TURN_ON,
                                            MEDIA_PLAYER_SCHEMA,
                                            'async_turn_on')
    component.async_register_entity_service(SERVICE_TURN_OFF,
                                            MEDIA_PLAYER_SCHEMA,
                                            'async_turn_off')
    component.async_register_entity_service(SERVICE_TOGGLE,
                                            MEDIA_PLAYER_SCHEMA,
                                            'async_toggle')
    component.async_register_entity_service(SERVICE_VOLUME_UP,
                                            MEDIA_PLAYER_SCHEMA,
                                            'async_volume_up')
    component.async_register_entity_service(SERVICE_VOLUME_DOWN,
                                            MEDIA_PLAYER_SCHEMA,
                                            'async_volume_down')
    component.async_register_entity_service(SERVICE_MEDIA_PLAY_PAUSE,
                                            MEDIA_PLAYER_SCHEMA,
                                            'async_media_play_pause')
    component.async_register_entity_service(SERVICE_MEDIA_PLAY,
                                            MEDIA_PLAYER_SCHEMA,
                                            'async_media_play')
    component.async_register_entity_service(SERVICE_MEDIA_PAUSE,
                                            MEDIA_PLAYER_SCHEMA,
                                            'async_media_pause')
    component.async_register_entity_service(SERVICE_MEDIA_STOP,
                                            MEDIA_PLAYER_SCHEMA,
                                            'async_media_stop')
    component.async_register_entity_service(SERVICE_MEDIA_NEXT_TRACK,
                                            MEDIA_PLAYER_SCHEMA,
                                            'async_media_next_track')
    component.async_register_entity_service(SERVICE_MEDIA_PREVIOUS_TRACK,
                                            MEDIA_PLAYER_SCHEMA,
                                            'async_media_previous_track')
    component.async_register_entity_service(SERVICE_CLEAR_PLAYLIST,
                                            MEDIA_PLAYER_SCHEMA,
                                            'async_clear_playlist')
    component.async_register_entity_service(
        SERVICE_VOLUME_SET, MEDIA_PLAYER_SET_VOLUME_SCHEMA,
        lambda entity, call: entity.async_set_volume_level(volume=call.data[
            ATTR_MEDIA_VOLUME_LEVEL]))
    component.async_register_entity_service(
        SERVICE_VOLUME_MUTE, MEDIA_PLAYER_MUTE_VOLUME_SCHEMA,
        lambda entity, call: entity.async_mute_volume(mute=call.data[
            ATTR_MEDIA_VOLUME_MUTED]))
    component.async_register_entity_service(
        SERVICE_MEDIA_SEEK, MEDIA_PLAYER_MEDIA_SEEK_SCHEMA,
        lambda entity, call: entity.async_media_seek(position=call.data[
            ATTR_MEDIA_SEEK_POSITION]))
    component.async_register_entity_service(SERVICE_SELECT_SOURCE,
                                            MEDIA_PLAYER_SELECT_SOURCE_SCHEMA,
                                            'async_select_source')
    component.async_register_entity_service(
        SERVICE_SELECT_SOUND_MODE, MEDIA_PLAYER_SELECT_SOUND_MODE_SCHEMA,
        'async_select_sound_mode')
    component.async_register_entity_service(
        SERVICE_PLAY_MEDIA, MEDIA_PLAYER_PLAY_MEDIA_SCHEMA,
        lambda entity, call: entity.async_play_media(
            media_type=call.data[ATTR_MEDIA_CONTENT_TYPE],
            media_id=call.data[ATTR_MEDIA_CONTENT_ID],
            enqueue=call.data.get(ATTR_MEDIA_ENQUEUE)))
    component.async_register_entity_service(SERVICE_SHUFFLE_SET,
                                            MEDIA_PLAYER_SET_SHUFFLE_SCHEMA,
                                            'async_set_shuffle')

    return True
示例#9
0
def async_setup(hass, config):
    """Expose light control via statemachine and services."""
    component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL,
                                GROUP_NAME_ALL_LIGHTS)
    yield from component.async_setup(config)

    # load profiles from files
    profiles = yield from hass.loop.run_in_executor(None, _load_profile_data,
                                                    hass)

    if profiles is None:
        return False

    @asyncio.coroutine
    def async_handle_light_service(service):
        """Hande a turn light on or off service call."""
        # Get the validated data
        params = service.data.copy()

        # Convert the entity ids to valid light ids
        target_lights = component.async_extract_from_service(service)
        params.pop(ATTR_ENTITY_ID, None)

        # Processing extra data for turn light on request.
        profile = profiles.get(params.pop(ATTR_PROFILE, None))

        if profile:
            params.setdefault(ATTR_XY_COLOR, profile[:2])
            params.setdefault(ATTR_BRIGHTNESS, profile[2])

        color_name = params.pop(ATTR_COLOR_NAME, None)

        if color_name is not None:
            params[ATTR_RGB_COLOR] = color_util.color_name_to_rgb(color_name)

        for light in target_lights:
            if service.service == SERVICE_TURN_ON:
                yield from light.async_turn_on(**params)
            elif service.service == SERVICE_TURN_OFF:
                yield from light.async_turn_off(**params)
            else:
                yield from light.async_toggle(**params)

        update_tasks = []

        for light in target_lights:
            if not light.should_poll:
                continue

            update_coro = hass.loop.create_task(
                light.async_update_ha_state(True))
            if hasattr(light, 'async_update'):
                update_tasks.append(update_coro)
            else:
                yield from update_coro

        if update_tasks:
            yield from asyncio.wait(update_tasks, loop=hass.loop)

    # Listen for light on and light off service calls.
    descriptions = yield from hass.loop.run_in_executor(
        None, load_yaml_config_file,
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    hass.services.async_register(DOMAIN,
                                 SERVICE_TURN_ON,
                                 async_handle_light_service,
                                 descriptions.get(SERVICE_TURN_ON),
                                 schema=LIGHT_TURN_ON_SCHEMA)

    hass.services.async_register(DOMAIN,
                                 SERVICE_TURN_OFF,
                                 async_handle_light_service,
                                 descriptions.get(SERVICE_TURN_OFF),
                                 schema=LIGHT_TURN_OFF_SCHEMA)

    hass.services.async_register(DOMAIN,
                                 SERVICE_TOGGLE,
                                 async_handle_light_service,
                                 descriptions.get(SERVICE_TOGGLE),
                                 schema=LIGHT_TOGGLE_SCHEMA)

    return True
示例#10
0
async def async_setup(hass, config):
    """Expose light control via state machine and services."""
    component = hass.data[DOMAIN] = EntityComponent(
        _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_LIGHTS)
    await component.async_setup(config)

    # load profiles from files
    profiles_valid = await Profiles.load_profiles(hass)
    if not profiles_valid:
        return False

    async def async_handle_light_on_service(service):
        """Handle a turn light on service call."""
        # Get the validated data
        params = service.data.copy()

        # Convert the entity ids to valid light ids
        target_lights = await component.async_extract_from_service(service)
        params.pop(ATTR_ENTITY_ID, None)

        if service.context.user_id:
            user = await hass.auth.async_get_user(service.context.user_id)
            if user is None:
                raise UnknownUser(context=service.context)

            entity_perms = user.permissions.check_entity

            for light in target_lights:
                if not entity_perms(light, POLICY_CONTROL):
                    raise Unauthorized(
                        context=service.context,
                        entity_id=light,
                        permission=POLICY_CONTROL
                    )

        preprocess_turn_on_alternatives(params)
        turn_lights_off, off_params = preprocess_turn_off(params)

        update_tasks = []
        for light in target_lights:
            light.async_set_context(service.context)

            pars = params
            off_pars = off_params
            turn_light_off = turn_lights_off
            if not pars:
                pars = params.copy()
                pars[ATTR_PROFILE] = Profiles.get_default(light.entity_id)
                preprocess_turn_on_alternatives(pars)
                turn_light_off, off_pars = preprocess_turn_off(pars)
            if turn_light_off:
                await light.async_turn_off(**off_pars)
            else:
                await light.async_turn_on(**pars)

            if not light.should_poll:
                continue

            update_tasks.append(
                light.async_update_ha_state(True))

        if update_tasks:
            await asyncio.wait(update_tasks)

    # Listen for light on and light off service calls.
    hass.services.async_register(
        DOMAIN, SERVICE_TURN_ON, async_handle_light_on_service,
        schema=LIGHT_TURN_ON_SCHEMA)

    component.async_register_entity_service(
        SERVICE_TURN_OFF, LIGHT_TURN_OFF_SCHEMA,
        'async_turn_off'
    )

    component.async_register_entity_service(
        SERVICE_TOGGLE, LIGHT_TOGGLE_SCHEMA,
        'async_toggle'
    )

    hass.helpers.intent.async_register(SetIntentHandler())

    return True
示例#11
0
async def test_setup_entry_platform_not_exist(hass):
    """Test setup entry fails if platform doesnt exist."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    entry = MockConfigEntry(domain='non_existing')

    assert (await component.async_setup_entry(entry)) is False
示例#12
0
async def async_setup(hass, config):
    """Track states and offer events for media_players."""
    component = hass.data[DOMAIN] = EntityComponent(
        logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL)

    hass.components.websocket_api.async_register_command(
        websocket_handle_thumbnail)
    hass.components.websocket_api.async_register_command(
        websocket_browse_media)
    hass.http.register_view(MediaPlayerImageView(component))

    await component.async_setup(config)

    component.async_register_entity_service(SERVICE_TURN_ON, {},
                                            "async_turn_on", [SUPPORT_TURN_ON])
    component.async_register_entity_service(SERVICE_TURN_OFF, {},
                                            "async_turn_off",
                                            [SUPPORT_TURN_OFF])
    component.async_register_entity_service(
        SERVICE_TOGGLE, {}, "async_toggle",
        [SUPPORT_TURN_OFF | SUPPORT_TURN_ON])
    component.async_register_entity_service(
        SERVICE_VOLUME_UP,
        {},
        "async_volume_up",
        [SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP],
    )
    component.async_register_entity_service(
        SERVICE_VOLUME_DOWN,
        {},
        "async_volume_down",
        [SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP],
    )
    component.async_register_entity_service(
        SERVICE_MEDIA_PLAY_PAUSE,
        {},
        "async_media_play_pause",
        [SUPPORT_PLAY | SUPPORT_PAUSE],
    )
    component.async_register_entity_service(SERVICE_MEDIA_PLAY, {},
                                            "async_media_play", [SUPPORT_PLAY])
    component.async_register_entity_service(SERVICE_MEDIA_PAUSE, {},
                                            "async_media_pause",
                                            [SUPPORT_PAUSE])
    component.async_register_entity_service(SERVICE_MEDIA_STOP, {},
                                            "async_media_stop", [SUPPORT_STOP])
    component.async_register_entity_service(SERVICE_MEDIA_NEXT_TRACK, {},
                                            "async_media_next_track",
                                            [SUPPORT_NEXT_TRACK])
    component.async_register_entity_service(
        SERVICE_MEDIA_PREVIOUS_TRACK,
        {},
        "async_media_previous_track",
        [SUPPORT_PREVIOUS_TRACK],
    )
    component.async_register_entity_service(SERVICE_CLEAR_PLAYLIST, {},
                                            "async_clear_playlist",
                                            [SUPPORT_CLEAR_PLAYLIST])
    component.async_register_entity_service(
        SERVICE_VOLUME_SET,
        vol.All(
            cv.make_entity_service_schema(
                {vol.Required(ATTR_MEDIA_VOLUME_LEVEL): cv.small_float}),
            _rename_keys(volume=ATTR_MEDIA_VOLUME_LEVEL),
        ),
        "async_set_volume_level",
        [SUPPORT_VOLUME_SET],
    )
    component.async_register_entity_service(
        SERVICE_VOLUME_MUTE,
        vol.All(
            cv.make_entity_service_schema(
                {vol.Required(ATTR_MEDIA_VOLUME_MUTED): cv.boolean}),
            _rename_keys(mute=ATTR_MEDIA_VOLUME_MUTED),
        ),
        "async_mute_volume",
        [SUPPORT_VOLUME_MUTE],
    )
    component.async_register_entity_service(
        SERVICE_MEDIA_SEEK,
        vol.All(
            cv.make_entity_service_schema(
                {vol.Required(ATTR_MEDIA_SEEK_POSITION): cv.positive_float}),
            _rename_keys(position=ATTR_MEDIA_SEEK_POSITION),
        ),
        "async_media_seek",
        [SUPPORT_SEEK],
    )
    component.async_register_entity_service(
        SERVICE_SELECT_SOURCE,
        {vol.Required(ATTR_INPUT_SOURCE): cv.string},
        "async_select_source",
        [SUPPORT_SELECT_SOURCE],
    )
    component.async_register_entity_service(
        SERVICE_SELECT_SOUND_MODE,
        {vol.Required(ATTR_SOUND_MODE): cv.string},
        "async_select_sound_mode",
        [SUPPORT_SELECT_SOUND_MODE],
    )
    component.async_register_entity_service(
        SERVICE_PLAY_MEDIA,
        vol.All(
            cv.make_entity_service_schema(MEDIA_PLAYER_PLAY_MEDIA_SCHEMA),
            _rename_keys(
                media_type=ATTR_MEDIA_CONTENT_TYPE,
                media_id=ATTR_MEDIA_CONTENT_ID,
                enqueue=ATTR_MEDIA_ENQUEUE,
            ),
        ),
        "async_play_media",
        [SUPPORT_PLAY_MEDIA],
    )
    component.async_register_entity_service(
        SERVICE_SHUFFLE_SET,
        {vol.Required(ATTR_MEDIA_SHUFFLE): cv.boolean},
        "async_set_shuffle",
        [SUPPORT_SHUFFLE_SET],
    )

    component.async_register_entity_service(
        SERVICE_REPEAT_SET,
        {vol.Required(ATTR_MEDIA_REPEAT): vol.In(REPEAT_MODES)},
        "async_set_repeat",
        [SUPPORT_REPEAT_SET],
    )

    return True
示例#13
0
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
    """Set up an input datetime."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    id_manager = collection.IDManager()

    yaml_collection = collection.YamlCollection(
        logging.getLogger(f"{__name__}.yaml_collection"), id_manager)
    collection.sync_entity_lifecycle(hass, DOMAIN, DOMAIN, component,
                                     yaml_collection, InputDatetime.from_yaml)

    storage_collection = DateTimeStorageCollection(
        Store(hass, STORAGE_VERSION, STORAGE_KEY),
        logging.getLogger(f"{__name__}.storage_collection"),
        id_manager,
    )
    collection.sync_entity_lifecycle(hass, DOMAIN, DOMAIN, component,
                                     storage_collection, InputDatetime)

    await yaml_collection.async_load([{
        CONF_ID: id_,
        **cfg
    } for id_, cfg in config.get(DOMAIN, {}).items()])
    await storage_collection.async_load()

    collection.StorageCollectionWebsocket(storage_collection, DOMAIN, DOMAIN,
                                          CREATE_FIELDS,
                                          UPDATE_FIELDS).async_setup(hass)

    async def reload_service_handler(service_call: ServiceCallType) -> None:
        """Reload yaml entities."""
        conf = await component.async_prepare_reload(skip_reset=True)
        if conf is None:
            conf = {DOMAIN: {}}
        await yaml_collection.async_load([{
            CONF_ID: id_,
            **cfg
        } for id_, cfg in conf.get(DOMAIN, {}).items()])

    homeassistant.helpers.service.async_register_admin_service(
        hass,
        DOMAIN,
        SERVICE_RELOAD,
        reload_service_handler,
        schema=RELOAD_SERVICE_SCHEMA,
    )

    component.async_register_entity_service(
        "set_datetime",
        vol.All(
            vol.Schema(
                {
                    vol.Optional(ATTR_DATE): cv.date,
                    vol.Optional(ATTR_TIME): cv.time,
                    vol.Optional(ATTR_DATETIME): cv.datetime,
                    vol.Optional(ATTR_TIMESTAMP): vol.Coerce(float),
                },
                extra=vol.ALLOW_EXTRA,
            ),
            cv.has_at_least_one_key(ATTR_DATE, ATTR_TIME, ATTR_DATETIME,
                                    ATTR_TIMESTAMP),
            validate_set_datetime_attrs,
        ),
        "async_set_datetime",
    )

    return True
示例#14
0
def setup(hass, config):
    """Setup thermostats."""
    component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL)
    component.setup(config)

    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    def away_mode_set_service(service):
        """Set away mode on target thermostats."""
        target_thermostats = component.extract_from_service(service)

        away_mode = service.data[ATTR_AWAY_MODE]

        for thermostat in target_thermostats:
            if away_mode:
                thermostat.turn_away_mode_on()
            else:
                thermostat.turn_away_mode_off()

            thermostat.update_ha_state(True)

    hass.services.register(DOMAIN,
                           SERVICE_SET_AWAY_MODE,
                           away_mode_set_service,
                           descriptions.get(SERVICE_SET_AWAY_MODE),
                           schema=SET_AWAY_MODE_SCHEMA)

    def temperature_set_service(service):
        """Set temperature on the target thermostats."""
        target_thermostats = component.extract_from_service(service)

        temperature = service.data[ATTR_TEMPERATURE]

        for thermostat in target_thermostats:
            thermostat.set_temperature(
                convert(temperature, hass.config.temperature_unit,
                        thermostat.unit_of_measurement))

            thermostat.update_ha_state(True)

    hass.services.register(DOMAIN,
                           SERVICE_SET_TEMPERATURE,
                           temperature_set_service,
                           descriptions.get(SERVICE_SET_TEMPERATURE),
                           schema=SET_TEMPERATURE_SCHEMA)

    def fan_mode_set_service(service):
        """Set fan mode on target thermostats."""
        target_thermostats = component.extract_from_service(service)

        fan_mode = service.data[ATTR_FAN]

        for thermostat in target_thermostats:
            if fan_mode:
                thermostat.turn_fan_on()
            else:
                thermostat.turn_fan_off()

            thermostat.update_ha_state(True)

    hass.services.register(DOMAIN,
                           SERVICE_SET_FAN_MODE,
                           fan_mode_set_service,
                           descriptions.get(SERVICE_SET_FAN_MODE),
                           schema=SET_FAN_MODE_SCHEMA)

    def hvac_mode_set_service(service):
        """Set hvac mode on target thermostats."""
        target_thermostats = component.extract_from_service(service)

        hvac_mode = service.data[ATTR_HVAC_MODE]

        for thermostat in target_thermostats:
            thermostat.set_hvac_mode(hvac_mode)

            thermostat.update_ha_state(True)

    hass.services.register(DOMAIN,
                           SERVICE_SET_HVAC_MODE,
                           hvac_mode_set_service,
                           descriptions.get(SERVICE_SET_HVAC_MODE),
                           schema=SET_HVAC_MODE_SCHEMA)

    return True
示例#15
0
def setup(hass, config):
    """Set up variables."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    items = config.get(DOMAIN)
    if items is not None:

        for variable_id, variable_config in items.items():
            if not variable_config:
                variable_config = {}

            name = variable_config.get(CONF_NAME)
            default_temp = variable_config.get(ATTR_DEFAULT_TEMP)

            entities.append(TemperatureControl(variable_id, name,
                                               default_temp))

    def get_temperature_service(call):
        """Handle calls to the set_variable service."""
        entity_id = ENTITY_ID_FORMAT.format(call.data.get(ATTR_CONTROLLER))
        entity = component.get_entity(entity_id)

        if entity:
            return entity.get_temperature(call.data.get(CONF_TIME_STEP))
        else:
            _LOGGER.warning("Failed to set unknown variable: %s", entity_id)

    def set_period_service(call):
        """Handle calls to the set_variable service."""

        entity_id = ENTITY_ID_FORMAT.format(call.data.get(CONF_NAME))
        entity = component.get_entity(entity_id)
        _LOGGER.warning(
            f'Start updating (set_period_service) period on {entity_id}')

        if entity:
            entity.set_period(
                call.data.get(CONF_PERIOD_ID),
                call.data.get(CONF_TIME_START),
                call.data.get(CONF_TIME_STOP),
                call.data.get(CONF_PERIOD_TEMP),
                call.data.get(CONF_DAYS),
            )
        else:
            _LOGGER.warning("Failed to set unknown variable: %s", entity_id)

    hass.services.register(
        DOMAIN,
        SERVICE_GET_TEMPERATURE,
        get_temperature_service,
        schema=SERVICE_GET_TEMPERATURE_SCHEMA,
    )

    hass.services.register(
        DOMAIN,
        SERVICE_SET_PERIOD,
        set_period_service,
        schema=SERVICE_SET_PERIOD_SCHEMA,
    )

    component.add_entities(entities)
    return True
示例#16
0
def setup(hass, config):
    """Set up the Wink component."""

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

    if config.get(DOMAIN) is not None:
        client_id = config[DOMAIN].get(CONF_CLIENT_ID)
        client_secret = config[DOMAIN].get(CONF_CLIENT_SECRET)
        email = config[DOMAIN].get(CONF_EMAIL)
        password = config[DOMAIN].get(CONF_PASSWORD)
        local_control = config[DOMAIN].get(CONF_LOCAL_CONTROL)
    else:
        client_id = None
        client_secret = None
        email = None
        password = None
        local_control = None
        hass.data[DOMAIN]["configurator"] = True
    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"][CONF_CLIENT_ID] = client_id
        hass.data[DOMAIN]["oauth"][CONF_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)
    else:
        _LOGGER.info("Using 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 = load_json(config_path)
            if config_file == DEFAULT_CONFIG:
                _request_app_setup(hass, config)
                return True
            # else move on because the user modified the file
        else:
            save_json(config_path, DEFAULT_CONFIG)
            _request_app_setup(hass, config)
            return True

        if DOMAIN in hass.data[DOMAIN]["configuring"]:
            _configurator = hass.data[DOMAIN]["configuring"]
            hass.components.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(CONF_CLIENT_ID),
                config_file.get(CONF_CLIENT_SECRET),
                access_token=access_token,
                refresh_token=refresh_token,
            )
        # This is called to create the redirect so the user can Authorize
        # Home .
        else:

            redirect_uri = f"{get_url(hass)}{WINK_AUTH_CALLBACK_PATH}"

            wink_auth_start_url = pywink.get_authorization_url(
                config_file.get(CONF_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)
    sub_details = pywink.get_subscription_details()
    hass.data[DOMAIN]["pubnub"] = PubNubSubscriptionHandler(
        sub_details[0], origin=sub_details[1])

    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("%s", _temp_response)
        _temp_response = pywink.post_session()
        _LOGGER.debug("%s", _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.data[DOMAIN]["pubnub"] = None

    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()
            save_json(config_path, _config)

    hass.bus.listen(EVENT_HOMEASSISTANT_STOP, save_credentials)

    # Save the users potentially updated oauth credentials at a regular
    # interval to prevent them from being expired after a HA reboot.
    track_time_interval(hass, save_credentials, timedelta(minutes=60))

    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)

    def set_pairing_mode(call):
        """Put the hub in provided pairing mode."""
        hub_name = call.data.get("hub_name")
        pairing_mode = call.data.get("pairing_mode")
        kidde_code = call.data.get("kidde_radio_code")
        for hub in WINK_HUBS:
            if hub.name() == hub_name:
                hub.pair_new_device(pairing_mode, kidde_radio_code=kidde_code)

    def rename_device(call):
        """Set specified device's name."""
        # This should only be called on one device at a time.
        found_device = None
        entity_id = call.data.get("entity_id")[0]
        all_devices = []
        for list_of_devices in hass.data[DOMAIN]["entities"].values():
            all_devices += list_of_devices
        for device in all_devices:
            if device.entity_id == entity_id:
                found_device = device
        if found_device is not None:
            name = call.data.get("name")
            found_device.wink.set_name(name)

    hass.services.register(DOMAIN,
                           SERVICE_RENAME_DEVICE,
                           rename_device,
                           schema=RENAME_DEVICE_SCHEMA)

    def delete_device(call):
        """Delete specified device."""
        # This should only be called on one device at a time.
        found_device = None
        entity_id = call.data.get("entity_id")[0]
        all_devices = []
        for list_of_devices in hass.data[DOMAIN]["entities"].values():
            all_devices += list_of_devices
        for device in all_devices:
            if device.entity_id == entity_id:
                found_device = device
        if found_device is not None:
            found_device.wink.remove_device()

    hass.services.register(DOMAIN,
                           SERVICE_DELETE_DEVICE,
                           delete_device,
                           schema=DELETE_DEVICE_SCHEMA)

    hubs = pywink.get_hubs()
    for hub in hubs:
        if hub.device_manufacturer() == "wink":
            WINK_HUBS.append(hub)

    if WINK_HUBS:
        hass.services.register(
            DOMAIN,
            SERVICE_SET_PAIRING_MODE,
            set_pairing_mode,
            schema=SET_PAIRING_MODE_SCHEMA,
        )

    def nimbus_service_handle(service):
        """Handle nimbus services."""
        entity_id = service.data.get("entity_id")[0]
        _all_dials = []
        for sensor in hass.data[DOMAIN]["entities"]["sensor"]:
            if isinstance(sensor, WinkNimbusDialDevice):
                _all_dials.append(sensor)
        for _dial in _all_dials:
            if _dial.entity_id == entity_id:
                if service.service == SERVICE_SET_DIAL_CONFIG:
                    _dial.set_configuration(**service.data)
                if service.service == SERVICE_SET_DIAL_STATE:
                    _dial.wink.set_state(service.data.get("value"),
                                         service.data.get("labels"))

    def siren_service_handle(service):
        """Handle siren services."""
        entity_ids = service.data.get("entity_id")
        all_sirens = []
        for switch in hass.data[DOMAIN]["entities"]["switch"]:
            if isinstance(switch, WinkSirenDevice):
                all_sirens.append(switch)
        sirens_to_set = []
        if entity_ids is None:
            sirens_to_set = all_sirens
        else:
            for siren in all_sirens:
                if siren.entity_id in entity_ids:
                    sirens_to_set.append(siren)

        for siren in sirens_to_set:
            _man = siren.wink.device_manufacturer()
            if (service.service != SERVICE_SET_AUTO_SHUTOFF
                    and service.service != SERVICE_ENABLE_SIREN
                    and _man not in ("dome", "wink")):
                _LOGGER.error("Service only valid for Dome or Wink sirens")
                return

            if service.service == SERVICE_ENABLE_SIREN:
                siren.wink.set_state(service.data.get(ATTR_ENABLED))
            elif service.service == SERVICE_SET_AUTO_SHUTOFF:
                siren.wink.set_auto_shutoff(
                    service.data.get(ATTR_AUTO_SHUTOFF))
            elif service.service == SERVICE_SET_CHIME_VOLUME:
                siren.wink.set_chime_volume(service.data.get(ATTR_VOLUME))
            elif service.service == SERVICE_SET_SIREN_VOLUME:
                siren.wink.set_siren_volume(service.data.get(ATTR_VOLUME))
            elif service.service == SERVICE_SET_SIREN_TONE:
                siren.wink.set_siren_sound(service.data.get(ATTR_TONE))
            elif service.service == SERVICE_ENABLE_CHIME:
                siren.wink.set_chime(service.data.get(ATTR_TONE))
            elif service.service == SERVICE_SIREN_STROBE_ENABLED:
                siren.wink.set_siren_strobe_enabled(
                    service.data.get(ATTR_ENABLED))
            elif service.service == SERVICE_CHIME_STROBE_ENABLED:
                siren.wink.set_chime_strobe_enabled(
                    service.data.get(ATTR_ENABLED))

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

    component = EntityComponent(_LOGGER, DOMAIN, hass)

    sirens = []
    has_dome_or_wink_siren = False
    for siren in pywink.get_sirens():
        _man = siren.device_manufacturer()
        if _man in ("dome", "wink"):
            has_dome_or_wink_siren = True
        _id = siren.object_id() + siren.name()
        if _id not in hass.data[DOMAIN]["unique_ids"]:
            sirens.append(WinkSirenDevice(siren, hass))

    if sirens:

        hass.services.register(
            DOMAIN,
            SERVICE_SET_AUTO_SHUTOFF,
            siren_service_handle,
            schema=SET_AUTO_SHUTOFF_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_ENABLE_SIREN,
            siren_service_handle,
            schema=ENABLED_SIREN_SCHEMA,
        )

    if has_dome_or_wink_siren:

        hass.services.register(
            DOMAIN,
            SERVICE_SET_SIREN_TONE,
            siren_service_handle,
            schema=SET_SIREN_TONE_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_ENABLE_CHIME,
            siren_service_handle,
            schema=SET_CHIME_MODE_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_SET_SIREN_VOLUME,
            siren_service_handle,
            schema=SET_VOLUME_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_SET_CHIME_VOLUME,
            siren_service_handle,
            schema=SET_VOLUME_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_SIREN_STROBE_ENABLED,
            siren_service_handle,
            schema=SET_STROBE_ENABLED_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_CHIME_STROBE_ENABLED,
            siren_service_handle,
            schema=SET_STROBE_ENABLED_SCHEMA,
        )

    component.add_entities(sirens)

    nimbi = []
    dials = {}
    all_nimbi = pywink.get_cloud_clocks()
    all_dials = []
    for nimbus in all_nimbi:
        if nimbus.object_type() == "cloud_clock":
            nimbi.append(nimbus)
            dials[nimbus.object_id()] = []
    for nimbus in all_nimbi:
        if nimbus.object_type() == "dial":
            dials[nimbus.parent_id()].append(nimbus)

    for nimbus in nimbi:
        for dial in dials[nimbus.object_id()]:
            all_dials.append(WinkNimbusDialDevice(nimbus, dial, hass))

    if nimbi:
        hass.services.register(
            DOMAIN,
            SERVICE_SET_DIAL_CONFIG,
            nimbus_service_handle,
            schema=DIAL_CONFIG_SCHEMA,
        )

        hass.services.register(
            DOMAIN,
            SERVICE_SET_DIAL_STATE,
            nimbus_service_handle,
            schema=DIAL_STATE_SCHEMA,
        )

    component.add_entities(all_dials)

    return True
示例#17
0
def setup(hass, config):
    """Set up Z-Wave.

    Will automatically load components to support devices found on the network.
    """
    descriptions = conf_util.load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    from pydispatch import dispatcher
    # pylint: disable=import-error
    from openzwave.option import ZWaveOption
    from openzwave.network import ZWaveNetwork
    from openzwave.group import ZWaveGroup

    # Load configuration
    use_debug = config[DOMAIN].get(CONF_DEBUG)
    autoheal = config[DOMAIN].get(CONF_AUTOHEAL)
    device_config = EntityValues(config[DOMAIN][CONF_DEVICE_CONFIG],
                                 config[DOMAIN][CONF_DEVICE_CONFIG_DOMAIN],
                                 config[DOMAIN][CONF_DEVICE_CONFIG_GLOB])
    new_entity_ids = config[DOMAIN][CONF_NEW_ENTITY_IDS]
    if not new_entity_ids:
        _LOGGER.warning(
            "ZWave entity_ids will soon be changing. To opt in to new "
            "entity_ids now, set `new_entity_ids: true` under zwave in your "
            "configuration.yaml. See the following blog post for details: "
            "https://home-assistant.io/blog/2017/06/15/zwave-entity-ids/")

    # Setup options
    options = ZWaveOption(config[DOMAIN].get(CONF_USB_STICK_PATH),
                          user_path=hass.config.config_dir,
                          config_path=config[DOMAIN].get(CONF_CONFIG_PATH))

    options.set_console_output(use_debug)

    if CONF_NETWORK_KEY in config[DOMAIN]:
        options.addOption("NetworkKey", config[DOMAIN][CONF_NETWORK_KEY])

    options.lock()

    network = hass.data[DATA_NETWORK] = ZWaveNetwork(options, autostart=False)
    hass.data[DATA_DEVICES] = {}
    hass.data[DATA_ENTITY_VALUES] = []

    if use_debug:  # pragma: no cover

        def log_all(signal, value=None):
            """Log all the signals."""
            print("")
            print("SIGNAL *****", signal)
            if value and signal in (ZWaveNetwork.SIGNAL_VALUE_CHANGED,
                                    ZWaveNetwork.SIGNAL_VALUE_ADDED,
                                    ZWaveNetwork.SIGNAL_SCENE_EVENT,
                                    ZWaveNetwork.SIGNAL_NODE_EVENT,
                                    ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED,
                                    ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED):
                pprint(_obj_to_dict(value))

            print("")

        dispatcher.connect(log_all, weak=False)

    def value_added(node, value):
        """Handle new added value to a node on the network."""
        # Check if this value should be tracked by an existing entity
        for values in hass.data[DATA_ENTITY_VALUES]:
            values.check_value(value)

        for schema in DISCOVERY_SCHEMAS:
            if not check_node_schema(node, schema):
                continue
            if not check_value_schema(
                    value, schema[const.DISC_VALUES][const.DISC_PRIMARY]):
                continue

            values = ZWaveDeviceEntityValues(hass, schema, value, config,
                                             device_config)

            # We create a new list and update the reference here so that
            # the list can be safely iterated over in the main thread
            new_values = hass.data[DATA_ENTITY_VALUES] + [values]
            hass.data[DATA_ENTITY_VALUES] = new_values

    component = EntityComponent(_LOGGER, DOMAIN, hass)

    def node_added(node):
        """Handle a new node on the network."""
        entity = ZWaveNodeEntity(node, network, new_entity_ids)
        name = node_name(node)
        if new_entity_ids:
            generated_id = generate_entity_id(DOMAIN + '.{}', name, [])
        else:
            generated_id = entity.entity_id
        node_config = device_config.get(generated_id)
        if node_config.get(CONF_IGNORED):
            _LOGGER.info("Ignoring node entity %s due to device settings",
                         generated_id)
            return
        component.add_entities([entity])

    def network_ready():
        """Handle the query of all awake nodes."""
        _LOGGER.info("Zwave network is ready for use. All awake nodes "
                     "have been queried. Sleeping nodes will be "
                     "queried when they awake.")
        hass.bus.fire(const.EVENT_NETWORK_READY)

    def network_complete():
        """Handle the querying of all nodes on network."""
        _LOGGER.info("Z-Wave network is complete. All nodes on the network "
                     "have been queried")
        hass.bus.fire(const.EVENT_NETWORK_COMPLETE)

    dispatcher.connect(value_added,
                       ZWaveNetwork.SIGNAL_VALUE_ADDED,
                       weak=False)
    dispatcher.connect(node_added, ZWaveNetwork.SIGNAL_NODE_ADDED, weak=False)
    dispatcher.connect(network_ready,
                       ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED,
                       weak=False)
    dispatcher.connect(network_complete,
                       ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED,
                       weak=False)

    def add_node(service):
        """Switch into inclusion mode."""
        _LOGGER.info("Z-Wave add_node have been initialized")
        network.controller.add_node()

    def add_node_secure(service):
        """Switch into secure inclusion mode."""
        _LOGGER.info("Z-Wave add_node_secure have been initialized")
        network.controller.add_node(True)

    def remove_node(service):
        """Switch into exclusion mode."""
        _LOGGER.info("Z-Wwave remove_node have been initialized")
        network.controller.remove_node()

    def cancel_command(service):
        """Cancel a running controller command."""
        _LOGGER.info("Cancel running Z-Wave command")
        network.controller.cancel_command()

    def heal_network(service):
        """Heal the network."""
        _LOGGER.info("Z-Wave heal running")
        network.heal()

    def soft_reset(service):
        """Soft reset the controller."""
        _LOGGER.info("Z-Wave soft_reset have been initialized")
        network.controller.soft_reset()

    def test_network(service):
        """Test the network by sending commands to all the nodes."""
        _LOGGER.info("Z-Wave test_network have been initialized")
        network.test()

    def stop_network(_service_or_event):
        """Stop Z-Wave network."""
        _LOGGER.info("Stopping Z-Wave network")
        network.stop()
        if hass.state == CoreState.running:
            hass.bus.fire(const.EVENT_NETWORK_STOP)

    def rename_node(service):
        """Rename a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        name = service.data.get(const.ATTR_NAME)
        node.name = name
        _LOGGER.info("Renamed Z-Wave node %d to %s", node_id, name)

    def rename_value(service):
        """Rename a node value."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        value_id = service.data.get(const.ATTR_VALUE_ID)
        node = network.nodes[node_id]
        value = node.values[value_id]
        name = service.data.get(const.ATTR_NAME)
        value.label = name
        _LOGGER.info("Renamed Z-Wave value (Node %d Value %d) to %s", node_id,
                     value_id, name)

    def set_poll_intensity(service):
        """Set the polling intensity of a node value."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        value_id = service.data.get(const.ATTR_VALUE_ID)
        node = network.nodes[node_id]
        value = node.values[value_id]
        intensity = service.data.get(const.ATTR_POLL_INTENSITY)
        if intensity == 0:
            if value.disable_poll():
                _LOGGER.info("Polling disabled (Node %d Value %d)", node_id,
                             value_id)
                return
            _LOGGER.info("Polling disabled failed (Node %d Value %d)", node_id,
                         value_id)
        else:
            if value.enable_poll(intensity):
                _LOGGER.info("Set polling intensity (Node %d Value %d) to %s",
                             node_id, value_id, intensity)
                return
            _LOGGER.info("Set polling intensity failed (Node %d Value %d)",
                         node_id, value_id)

    def remove_failed_node(service):
        """Remove failed node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        _LOGGER.info("Trying to remove zwave node %d", node_id)
        network.controller.remove_failed_node(node_id)

    def replace_failed_node(service):
        """Replace failed node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        _LOGGER.info("Trying to replace zwave node %d", node_id)
        network.controller.replace_failed_node(node_id)

    def set_config_parameter(service):
        """Set a config parameter to a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        param = service.data.get(const.ATTR_CONFIG_PARAMETER)
        selection = service.data.get(const.ATTR_CONFIG_VALUE)
        size = service.data.get(const.ATTR_CONFIG_SIZE)
        for value in (node.get_values(
                class_id=const.COMMAND_CLASS_CONFIGURATION).values()):
            if value.index != param:
                continue
            if value.type in [const.TYPE_LIST, const.TYPE_BOOL]:
                value.data = selection
                _LOGGER.info(
                    "Setting config list parameter %s on Node %s "
                    "with selection %s", param, node_id, selection)
                return
            value.data = int(selection)
            _LOGGER.info(
                "Setting config parameter %s on Node %s "
                "with selection %s", param, node_id, selection)
            return
        node.set_config_param(param, selection, size)
        _LOGGER.info(
            "Setting unknown config parameter %s on Node %s "
            "with selection %s", param, node_id, selection)

    def print_config_parameter(service):
        """Print a config parameter from a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        param = service.data.get(const.ATTR_CONFIG_PARAMETER)
        _LOGGER.info("Config parameter %s on Node %s: %s", param, node_id,
                     get_config_value(node, param))

    def print_node(service):
        """Print all information about z-wave node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        nice_print_node(node)

    def set_wakeup(service):
        """Set wake-up interval of a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        value = service.data.get(const.ATTR_CONFIG_VALUE)
        if node.can_wake_up():
            for value_id in node.get_values(
                    class_id=const.COMMAND_CLASS_WAKE_UP):
                node.values[value_id].data = value
                _LOGGER.info("Node %s wake-up set to %d", node_id, value)
        else:
            _LOGGER.info("Node %s is not wakeable", node_id)

    def change_association(service):
        """Change an association in the zwave network."""
        association_type = service.data.get(const.ATTR_ASSOCIATION)
        node_id = service.data.get(const.ATTR_NODE_ID)
        target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID)
        group = service.data.get(const.ATTR_GROUP)
        instance = service.data.get(const.ATTR_INSTANCE)

        node = ZWaveGroup(group, network, node_id)
        if association_type == 'add':
            node.add_association(target_node_id, instance)
            _LOGGER.info(
                "Adding association for node:%s in group:%s "
                "target node:%s, instance=%s", node_id, group, target_node_id,
                instance)
        if association_type == 'remove':
            node.remove_association(target_node_id, instance)
            _LOGGER.info(
                "Removing association for node:%s in group:%s "
                "target node:%s, instance=%s", node_id, group, target_node_id,
                instance)

    @asyncio.coroutine
    def async_refresh_entity(service):
        """Refresh values that specific entity depends on."""
        entity_id = service.data.get(ATTR_ENTITY_ID)
        async_dispatcher_send(hass,
                              SIGNAL_REFRESH_ENTITY_FORMAT.format(entity_id))

    def refresh_node(service):
        """Refresh all node info."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        node.refresh_info()

    def reset_node_meters(service):
        """Reset meter counters of a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        instance = service.data.get(const.ATTR_INSTANCE)
        node = network.nodes[node_id]
        for value in (node.get_values(
                class_id=const.COMMAND_CLASS_METER).values()):
            if value.index != const.INDEX_METER_RESET:
                continue
            if value.instance != instance:
                continue
            network.manager.pressButton(value.value_id)
            network.manager.releaseButton(value.value_id)
            _LOGGER.info("Resetting meters on node %s instance %s....",
                         node_id, instance)
            return
        _LOGGER.info(
            "Node %s on instance %s does not have resettable "
            "meters.", node_id, instance)

    def start_zwave(_service_or_event):
        """Startup Z-Wave network."""
        _LOGGER.info("Starting Z-Wave network...")
        network.start()
        hass.bus.fire(const.EVENT_NETWORK_START)

        # Need to be in STATE_AWAKED before talking to nodes.
        # Wait up to NETWORK_READY_WAIT_SECS seconds for the zwave network
        # to be ready.
        for i in range(const.NETWORK_READY_WAIT_SECS):
            _LOGGER.debug("network state: %d %s", network.state,
                          network.state_str)
            if network.state >= network.STATE_AWAKED:
                _LOGGER.info("Z-Wave ready after %d seconds", i)
                break
            time.sleep(1)
        else:
            _LOGGER.warning(
                "zwave not ready after %d seconds, continuing anyway",
                const.NETWORK_READY_WAIT_SECS)
            _LOGGER.info("final network state: %d %s", network.state,
                         network.state_str)

        polling_interval = convert(config[DOMAIN].get(CONF_POLLING_INTERVAL),
                                   int)
        if polling_interval is not None:
            network.set_poll_interval(polling_interval, False)

        poll_interval = network.get_poll_interval()
        _LOGGER.info("Z-Wave polling interval set to %d ms", poll_interval)

        hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network)

        # Register node services for Z-Wave network
        hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node,
                               descriptions[const.SERVICE_ADD_NODE])
        hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE,
                               add_node_secure,
                               descriptions[const.SERVICE_ADD_NODE_SECURE])
        hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node,
                               descriptions[const.SERVICE_REMOVE_NODE])
        hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND,
                               cancel_command,
                               descriptions[const.SERVICE_CANCEL_COMMAND])
        hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK,
                               heal_network,
                               descriptions[const.SERVICE_HEAL_NETWORK])
        hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset,
                               descriptions[const.SERVICE_SOFT_RESET])
        hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK,
                               test_network,
                               descriptions[const.SERVICE_TEST_NETWORK])
        hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK,
                               stop_network,
                               descriptions[const.SERVICE_STOP_NETWORK])
        hass.services.register(DOMAIN, const.SERVICE_START_NETWORK,
                               start_zwave,
                               descriptions[const.SERVICE_START_NETWORK])
        hass.services.register(DOMAIN,
                               const.SERVICE_RENAME_NODE,
                               rename_node,
                               descriptions[const.SERVICE_RENAME_NODE],
                               schema=RENAME_NODE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_RENAME_VALUE,
                               rename_value,
                               descriptions[const.SERVICE_RENAME_VALUE],
                               schema=RENAME_VALUE_SCHEMA)
        hass.services.register(
            DOMAIN,
            const.SERVICE_SET_CONFIG_PARAMETER,
            set_config_parameter,
            descriptions[const.SERVICE_SET_CONFIG_PARAMETER],
            schema=SET_CONFIG_PARAMETER_SCHEMA)
        hass.services.register(
            DOMAIN,
            const.SERVICE_PRINT_CONFIG_PARAMETER,
            print_config_parameter,
            descriptions[const.SERVICE_PRINT_CONFIG_PARAMETER],
            schema=PRINT_CONFIG_PARAMETER_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REMOVE_FAILED_NODE,
                               remove_failed_node,
                               descriptions[const.SERVICE_REMOVE_FAILED_NODE],
                               schema=NODE_SERVICE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REPLACE_FAILED_NODE,
                               replace_failed_node,
                               descriptions[const.SERVICE_REPLACE_FAILED_NODE],
                               schema=NODE_SERVICE_SCHEMA)

        hass.services.register(DOMAIN,
                               const.SERVICE_CHANGE_ASSOCIATION,
                               change_association,
                               descriptions[const.SERVICE_CHANGE_ASSOCIATION],
                               schema=CHANGE_ASSOCIATION_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_SET_WAKEUP,
                               set_wakeup,
                               descriptions[const.SERVICE_SET_WAKEUP],
                               schema=SET_WAKEUP_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_PRINT_NODE,
                               print_node,
                               descriptions[const.SERVICE_PRINT_NODE],
                               schema=NODE_SERVICE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REFRESH_ENTITY,
                               async_refresh_entity,
                               descriptions[const.SERVICE_REFRESH_ENTITY],
                               schema=REFRESH_ENTITY_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REFRESH_NODE,
                               refresh_node,
                               descriptions[const.SERVICE_REFRESH_NODE],
                               schema=NODE_SERVICE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_RESET_NODE_METERS,
                               reset_node_meters,
                               descriptions[const.SERVICE_RESET_NODE_METERS],
                               schema=RESET_NODE_METERS_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_SET_POLL_INTENSITY,
                               set_poll_intensity,
                               descriptions[const.SERVICE_SET_POLL_INTENSITY],
                               schema=SET_POLL_INTENSITY_SCHEMA)

    # Setup autoheal
    if autoheal:
        _LOGGER.info("Z-Wave network autoheal is enabled")
        track_time_change(hass, heal_network, hour=0, minute=0, second=0)

    hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_zwave)

    return True
示例#18
0
async def async_setup_entry(hass, config_entry):
    """Set up Z-Wave from a config entry.

    Will automatically load components to support devices found on the network.
    """
    from pydispatch import dispatcher
    # pylint: disable=import-error
    from openzwave.option import ZWaveOption
    from openzwave.network import ZWaveNetwork
    from openzwave.group import ZWaveGroup

    config = {}
    if DATA_ZWAVE_CONFIG in hass.data:
        config = hass.data[DATA_ZWAVE_CONFIG]

    # Load configuration
    use_debug = config.get(CONF_DEBUG, DEFAULT_DEBUG)
    autoheal = config.get(CONF_AUTOHEAL, DEFAULT_CONF_AUTOHEAL)
    device_config = EntityValues(config.get(CONF_DEVICE_CONFIG),
                                 config.get(CONF_DEVICE_CONFIG_DOMAIN),
                                 config.get(CONF_DEVICE_CONFIG_GLOB))

    # Setup options
    options = ZWaveOption(config_entry.data[CONF_USB_STICK_PATH],
                          user_path=hass.config.config_dir,
                          config_path=config.get(CONF_CONFIG_PATH))

    options.set_console_output(use_debug)

    if config_entry.data.get(CONF_NETWORK_KEY):
        options.addOption("NetworkKey", config_entry.data[CONF_NETWORK_KEY])

    await hass.async_add_executor_job(options.lock)
    network = hass.data[DATA_NETWORK] = ZWaveNetwork(options, autostart=False)
    hass.data[DATA_DEVICES] = {}
    hass.data[DATA_ENTITY_VALUES] = []

    if use_debug:  # pragma: no cover

        def log_all(signal, value=None):
            """Log all the signals."""
            print("")
            print("SIGNAL *****", signal)
            if value and signal in (
                    ZWaveNetwork.SIGNAL_VALUE_CHANGED,
                    ZWaveNetwork.SIGNAL_VALUE_ADDED,
                    ZWaveNetwork.SIGNAL_SCENE_EVENT,
                    ZWaveNetwork.SIGNAL_NODE_EVENT,
                    ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED,
                    ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED,
                    ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED_SOME_DEAD):
                pprint(_obj_to_dict(value))

            print("")

        dispatcher.connect(log_all, weak=False)

    def value_added(node, value):
        """Handle new added value to a node on the network."""
        # Check if this value should be tracked by an existing entity
        for values in hass.data[DATA_ENTITY_VALUES]:
            values.check_value(value)

        for schema in DISCOVERY_SCHEMAS:
            if not check_node_schema(node, schema):
                continue
            if not check_value_schema(
                    value, schema[const.DISC_VALUES][const.DISC_PRIMARY]):
                continue

            values = ZWaveDeviceEntityValues(hass, schema, value, config,
                                             device_config, registry)

            # We create a new list and update the reference here so that
            # the list can be safely iterated over in the main thread
            new_values = hass.data[DATA_ENTITY_VALUES] + [values]
            hass.data[DATA_ENTITY_VALUES] = new_values

    component = EntityComponent(_LOGGER, DOMAIN, hass)
    registry = await async_get_registry(hass)

    def node_added(node):
        """Handle a new node on the network."""
        entity = ZWaveNodeEntity(node, network)

        def _add_node_to_component():
            if hass.data[DATA_DEVICES].get(entity.unique_id):
                return

            name = node_name(node)
            generated_id = generate_entity_id(DOMAIN + '.{}', name, [])
            node_config = device_config.get(generated_id)
            if node_config.get(CONF_IGNORED):
                _LOGGER.info("Ignoring node entity %s due to device settings",
                             generated_id)
                return

            hass.data[DATA_DEVICES][entity.unique_id] = entity
            component.add_entities([entity])

        if entity.unique_id:
            _add_node_to_component()
            return

        @callback
        def _on_ready(sec):
            _LOGGER.info("Z-Wave node %d ready after %d seconds",
                         entity.node_id, sec)
            hass.async_add_job(_add_node_to_component)

        @callback
        def _on_timeout(sec):
            _LOGGER.warning(
                "Z-Wave node %d not ready after %d seconds, "
                "continuing anyway", entity.node_id, sec)
            hass.async_add_job(_add_node_to_component)

        hass.add_job(check_has_unique_id, entity, _on_ready, _on_timeout,
                     hass.loop)

    def network_ready():
        """Handle the query of all awake nodes."""
        _LOGGER.info("Zwave network is ready for use. All awake nodes "
                     "have been queried. Sleeping nodes will be "
                     "queried when they awake.")
        hass.bus.fire(const.EVENT_NETWORK_READY)

    def network_complete():
        """Handle the querying of all nodes on network."""
        _LOGGER.info("Z-Wave network is complete. All nodes on the network "
                     "have been queried")
        hass.bus.fire(const.EVENT_NETWORK_COMPLETE)

    def network_complete_some_dead():
        """Handle the querying of all nodes on network."""
        _LOGGER.info("Z-Wave network is complete. All nodes on the network "
                     "have been queried, but some nodes are marked dead")
        hass.bus.fire(const.EVENT_NETWORK_COMPLETE_SOME_DEAD)

    dispatcher.connect(value_added,
                       ZWaveNetwork.SIGNAL_VALUE_ADDED,
                       weak=False)
    dispatcher.connect(node_added, ZWaveNetwork.SIGNAL_NODE_ADDED, weak=False)
    dispatcher.connect(network_ready,
                       ZWaveNetwork.SIGNAL_AWAKE_NODES_QUERIED,
                       weak=False)
    dispatcher.connect(network_complete,
                       ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED,
                       weak=False)
    dispatcher.connect(network_complete_some_dead,
                       ZWaveNetwork.SIGNAL_ALL_NODES_QUERIED_SOME_DEAD,
                       weak=False)

    def add_node(service):
        """Switch into inclusion mode."""
        _LOGGER.info("Z-Wave add_node have been initialized")
        network.controller.add_node()

    def add_node_secure(service):
        """Switch into secure inclusion mode."""
        _LOGGER.info("Z-Wave add_node_secure have been initialized")
        network.controller.add_node(True)

    def remove_node(service):
        """Switch into exclusion mode."""
        _LOGGER.info("Z-Wave remove_node have been initialized")
        network.controller.remove_node()

    def cancel_command(service):
        """Cancel a running controller command."""
        _LOGGER.info("Cancel running Z-Wave command")
        network.controller.cancel_command()

    def heal_network(service):
        """Heal the network."""
        _LOGGER.info("Z-Wave heal running")
        network.heal()

    def soft_reset(service):
        """Soft reset the controller."""
        _LOGGER.info("Z-Wave soft_reset have been initialized")
        network.controller.soft_reset()

    def update_config(service):
        """Update the config from git."""
        _LOGGER.info("Configuration update has been initialized")
        network.controller.update_ozw_config()

    def test_network(service):
        """Test the network by sending commands to all the nodes."""
        _LOGGER.info("Z-Wave test_network have been initialized")
        network.test()

    def stop_network(_service_or_event):
        """Stop Z-Wave network."""
        _LOGGER.info("Stopping Z-Wave network")
        network.stop()
        if hass.state == CoreState.running:
            hass.bus.fire(const.EVENT_NETWORK_STOP)

    def rename_node(service):
        """Rename a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        name = service.data.get(const.ATTR_NAME)
        node.name = name
        _LOGGER.info("Renamed Z-Wave node %d to %s", node_id, name)

    def rename_value(service):
        """Rename a node value."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        value_id = service.data.get(const.ATTR_VALUE_ID)
        node = network.nodes[node_id]
        value = node.values[value_id]
        name = service.data.get(const.ATTR_NAME)
        value.label = name
        _LOGGER.info("Renamed Z-Wave value (Node %d Value %d) to %s", node_id,
                     value_id, name)

    def set_poll_intensity(service):
        """Set the polling intensity of a node value."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        value_id = service.data.get(const.ATTR_VALUE_ID)
        node = network.nodes[node_id]
        value = node.values[value_id]
        intensity = service.data.get(const.ATTR_POLL_INTENSITY)
        if intensity == 0:
            if value.disable_poll():
                _LOGGER.info("Polling disabled (Node %d Value %d)", node_id,
                             value_id)
                return
            _LOGGER.info("Polling disabled failed (Node %d Value %d)", node_id,
                         value_id)
        else:
            if value.enable_poll(intensity):
                _LOGGER.info("Set polling intensity (Node %d Value %d) to %s",
                             node_id, value_id, intensity)
                return
            _LOGGER.info("Set polling intensity failed (Node %d Value %d)",
                         node_id, value_id)

    def remove_failed_node(service):
        """Remove failed node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        _LOGGER.info("Trying to remove zwave node %d", node_id)
        network.controller.remove_failed_node(node_id)

    def replace_failed_node(service):
        """Replace failed node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        _LOGGER.info("Trying to replace zwave node %d", node_id)
        network.controller.replace_failed_node(node_id)

    def set_config_parameter(service):
        """Set a config parameter to a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        param = service.data.get(const.ATTR_CONFIG_PARAMETER)
        selection = service.data.get(const.ATTR_CONFIG_VALUE)
        size = service.data.get(const.ATTR_CONFIG_SIZE)
        for value in (node.get_values(
                class_id=const.COMMAND_CLASS_CONFIGURATION).values()):
            if value.index != param:
                continue
            if value.type in [const.TYPE_LIST, const.TYPE_BOOL]:
                value.data = str(selection)
                _LOGGER.info(
                    "Setting config parameter %s on Node %s "
                    "with list/bool selection %s", param, node_id,
                    str(selection))
                return
            if value.type == const.TYPE_BUTTON:
                network.manager.pressButton(value.value_id)
                network.manager.releaseButton(value.value_id)
                _LOGGER.info(
                    "Setting config parameter %s on Node %s "
                    "with button selection %s", param, node_id, selection)
                return
            value.data = int(selection)
            _LOGGER.info(
                "Setting config parameter %s on Node %s "
                "with selection %s", param, node_id, selection)
            return
        node.set_config_param(param, selection, size)
        _LOGGER.info(
            "Setting unknown config parameter %s on Node %s "
            "with selection %s", param, node_id, selection)

    def refresh_node_value(service):
        """Refresh the specified value from a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        value_id = service.data.get(const.ATTR_VALUE_ID)
        node = network.nodes[node_id]
        node.values[value_id].refresh()
        _LOGGER.info("Node %s value %s refreshed", node_id, value_id)

    def set_node_value(service):
        """Set the specified value on a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        value_id = service.data.get(const.ATTR_VALUE_ID)
        value = service.data.get(const.ATTR_CONFIG_VALUE)
        node = network.nodes[node_id]
        node.values[value_id].data = value
        _LOGGER.info("Node %s value %s set to %s", node_id, value_id, value)

    def print_config_parameter(service):
        """Print a config parameter from a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        param = service.data.get(const.ATTR_CONFIG_PARAMETER)
        _LOGGER.info("Config parameter %s on Node %s: %s", param, node_id,
                     get_config_value(node, param))

    def print_node(service):
        """Print all information about z-wave node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        nice_print_node(node)

    def set_wakeup(service):
        """Set wake-up interval of a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        value = service.data.get(const.ATTR_CONFIG_VALUE)
        if node.can_wake_up():
            for value_id in node.get_values(
                    class_id=const.COMMAND_CLASS_WAKE_UP):
                node.values[value_id].data = value
                _LOGGER.info("Node %s wake-up set to %d", node_id, value)
        else:
            _LOGGER.info("Node %s is not wakeable", node_id)

    def change_association(service):
        """Change an association in the zwave network."""
        association_type = service.data.get(const.ATTR_ASSOCIATION)
        node_id = service.data.get(const.ATTR_NODE_ID)
        target_node_id = service.data.get(const.ATTR_TARGET_NODE_ID)
        group = service.data.get(const.ATTR_GROUP)
        instance = service.data.get(const.ATTR_INSTANCE)

        node = ZWaveGroup(group, network, node_id)
        if association_type == 'add':
            node.add_association(target_node_id, instance)
            _LOGGER.info(
                "Adding association for node:%s in group:%s "
                "target node:%s, instance=%s", node_id, group, target_node_id,
                instance)
        if association_type == 'remove':
            node.remove_association(target_node_id, instance)
            _LOGGER.info(
                "Removing association for node:%s in group:%s "
                "target node:%s, instance=%s", node_id, group, target_node_id,
                instance)

    async def async_refresh_entity(service):
        """Refresh values that specific entity depends on."""
        entity_id = service.data.get(ATTR_ENTITY_ID)
        async_dispatcher_send(hass,
                              SIGNAL_REFRESH_ENTITY_FORMAT.format(entity_id))

    def refresh_node(service):
        """Refresh all node info."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        node = network.nodes[node_id]
        node.refresh_info()

    def reset_node_meters(service):
        """Reset meter counters of a node."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        instance = service.data.get(const.ATTR_INSTANCE)
        node = network.nodes[node_id]
        for value in (node.get_values(
                class_id=const.COMMAND_CLASS_METER).values()):
            if value.index != const.INDEX_METER_RESET:
                continue
            if value.instance != instance:
                continue
            network.manager.pressButton(value.value_id)
            network.manager.releaseButton(value.value_id)
            _LOGGER.info("Resetting meters on node %s instance %s....",
                         node_id, instance)
            return
        _LOGGER.info(
            "Node %s on instance %s does not have resettable "
            "meters.", node_id, instance)

    def heal_node(service):
        """Heal a node on the network."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        update_return_routes = service.data.get(const.ATTR_RETURN_ROUTES)
        node = network.nodes[node_id]
        _LOGGER.info("Z-Wave node heal running for node %s", node_id)
        node.heal(update_return_routes)

    def test_node(service):
        """Send test messages to a node on the network."""
        node_id = service.data.get(const.ATTR_NODE_ID)
        messages = service.data.get(const.ATTR_MESSAGES)
        node = network.nodes[node_id]
        _LOGGER.info("Sending %s test-messages to node %s.", messages, node_id)
        node.test(messages)

    def start_zwave(_service_or_event):
        """Startup Z-Wave network."""
        _LOGGER.info("Starting Z-Wave network...")
        network.start()
        hass.bus.fire(const.EVENT_NETWORK_START)

        async def _check_awaked():
            """Wait for Z-wave awaked state (or timeout) and finalize start."""
            _LOGGER.debug("network state: %d %s", network.state,
                          network.state_str)

            start_time = dt_util.utcnow()
            while True:
                waited = int((dt_util.utcnow() - start_time).total_seconds())

                if network.state >= network.STATE_AWAKED:
                    # Need to be in STATE_AWAKED before talking to nodes.
                    _LOGGER.info("Z-Wave ready after %d seconds", waited)
                    break
                elif waited >= const.NETWORK_READY_WAIT_SECS:
                    # Wait up to NETWORK_READY_WAIT_SECS seconds for the Z-Wave
                    # network to be ready.
                    _LOGGER.warning(
                        "Z-Wave not ready after %d seconds, continuing anyway",
                        waited)
                    _LOGGER.info("final network state: %d %s", network.state,
                                 network.state_str)
                    break
                else:
                    await asyncio.sleep(1, loop=hass.loop)

            hass.async_add_job(_finalize_start)

        hass.add_job(_check_awaked)

    def _finalize_start():
        """Perform final initializations after Z-Wave network is awaked."""
        polling_interval = convert(config.get(CONF_POLLING_INTERVAL), int)
        if polling_interval is not None:
            network.set_poll_interval(polling_interval, False)

        poll_interval = network.get_poll_interval()
        _LOGGER.info("Z-Wave polling interval set to %d ms", poll_interval)

        hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_network)

        # Register node services for Z-Wave network
        hass.services.register(DOMAIN, const.SERVICE_ADD_NODE, add_node)
        hass.services.register(DOMAIN, const.SERVICE_ADD_NODE_SECURE,
                               add_node_secure)
        hass.services.register(DOMAIN, const.SERVICE_REMOVE_NODE, remove_node)
        hass.services.register(DOMAIN, const.SERVICE_CANCEL_COMMAND,
                               cancel_command)
        hass.services.register(DOMAIN, const.SERVICE_HEAL_NETWORK,
                               heal_network)
        hass.services.register(DOMAIN, const.SERVICE_SOFT_RESET, soft_reset)
        hass.services.register(DOMAIN, const.SERVICE_UPDATE_CONFIG,
                               update_config)
        hass.services.register(DOMAIN, const.SERVICE_TEST_NETWORK,
                               test_network)
        hass.services.register(DOMAIN, const.SERVICE_STOP_NETWORK,
                               stop_network)
        hass.services.register(DOMAIN,
                               const.SERVICE_RENAME_NODE,
                               rename_node,
                               schema=RENAME_NODE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_RENAME_VALUE,
                               rename_value,
                               schema=RENAME_VALUE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_SET_CONFIG_PARAMETER,
                               set_config_parameter,
                               schema=SET_CONFIG_PARAMETER_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_SET_NODE_VALUE,
                               set_node_value,
                               schema=SET_NODE_VALUE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REFRESH_NODE_VALUE,
                               refresh_node_value,
                               schema=REFRESH_NODE_VALUE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_PRINT_CONFIG_PARAMETER,
                               print_config_parameter,
                               schema=PRINT_CONFIG_PARAMETER_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REMOVE_FAILED_NODE,
                               remove_failed_node,
                               schema=NODE_SERVICE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REPLACE_FAILED_NODE,
                               replace_failed_node,
                               schema=NODE_SERVICE_SCHEMA)

        hass.services.register(DOMAIN,
                               const.SERVICE_CHANGE_ASSOCIATION,
                               change_association,
                               schema=CHANGE_ASSOCIATION_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_SET_WAKEUP,
                               set_wakeup,
                               schema=SET_WAKEUP_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_PRINT_NODE,
                               print_node,
                               schema=NODE_SERVICE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REFRESH_ENTITY,
                               async_refresh_entity,
                               schema=REFRESH_ENTITY_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_REFRESH_NODE,
                               refresh_node,
                               schema=NODE_SERVICE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_RESET_NODE_METERS,
                               reset_node_meters,
                               schema=RESET_NODE_METERS_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_SET_POLL_INTENSITY,
                               set_poll_intensity,
                               schema=SET_POLL_INTENSITY_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_HEAL_NODE,
                               heal_node,
                               schema=HEAL_NODE_SCHEMA)
        hass.services.register(DOMAIN,
                               const.SERVICE_TEST_NODE,
                               test_node,
                               schema=TEST_NODE_SCHEMA)

    # Setup autoheal
    if autoheal:
        _LOGGER.info("Z-Wave network autoheal is enabled")
        async_track_time_change(hass, heal_network, hour=0, minute=0, second=0)

    hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, start_zwave)

    hass.services.async_register(DOMAIN, const.SERVICE_START_NETWORK,
                                 start_zwave)

    for entry_component in SUPPORTED_PLATFORMS:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(
                config_entry, entry_component))

    return True
示例#19
0
async def async_setup(hass, config):
    """Set up all groups found defined in the configuration."""
    component = hass.data.get(DOMAIN)

    if component is None:
        component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass)

    hass.data[REG_KEY] = GroupIntegrationRegistry()

    await async_process_integration_platforms(hass, DOMAIN, _process_group_platform)

    await _async_process_config(hass, config, component)

    async def reload_service_handler(service):
        """Remove all user-defined groups and load new ones from config."""
        auto = list(filter(lambda e: not e.user_defined, component.entities))

        conf = await component.async_prepare_reload()
        if conf is None:
            return
        await _async_process_config(hass, conf, component)

        await component.async_add_entities(auto)

        await async_reload_integration_platforms(hass, DOMAIN, PLATFORMS)

    hass.services.async_register(
        DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=vol.Schema({})
    )

    service_lock = asyncio.Lock()

    async def locked_service_handler(service):
        """Handle a service with an async lock."""
        async with service_lock:
            await groups_service_handler(service)

    async def groups_service_handler(service):
        """Handle dynamic group service functions."""
        object_id = service.data[ATTR_OBJECT_ID]
        entity_id = f"{DOMAIN}.{object_id}"
        group = component.get_entity(entity_id)

        # new group
        if service.service == SERVICE_SET and group is None:
            entity_ids = (
                service.data.get(ATTR_ENTITIES)
                or service.data.get(ATTR_ADD_ENTITIES)
                or None
            )

            extra_arg = {
                attr: service.data[attr]
                for attr in (ATTR_ICON,)
                if service.data.get(attr) is not None
            }

            await Group.async_create_group(
                hass,
                service.data.get(ATTR_NAME, object_id),
                object_id=object_id,
                entity_ids=entity_ids,
                user_defined=False,
                mode=service.data.get(ATTR_ALL),
                **extra_arg,
            )
            return

        if group is None:
            _LOGGER.warning("%s:Group '%s' doesn't exist!", service.service, object_id)
            return

        # update group
        if service.service == SERVICE_SET:
            need_update = False

            if ATTR_ADD_ENTITIES in service.data:
                delta = service.data[ATTR_ADD_ENTITIES]
                entity_ids = set(group.tracking) | set(delta)
                await group.async_update_tracked_entity_ids(entity_ids)

            if ATTR_ENTITIES in service.data:
                entity_ids = service.data[ATTR_ENTITIES]
                await group.async_update_tracked_entity_ids(entity_ids)

            if ATTR_NAME in service.data:
                group.name = service.data[ATTR_NAME]
                need_update = True

            if ATTR_ICON in service.data:
                group.icon = service.data[ATTR_ICON]
                need_update = True

            if ATTR_ALL in service.data:
                group.mode = all if service.data[ATTR_ALL] else any
                need_update = True

            if need_update:
                group.async_write_ha_state()

            return

        # remove group
        if service.service == SERVICE_REMOVE:
            await component.async_remove_entity(entity_id)

    hass.services.async_register(
        DOMAIN,
        SERVICE_SET,
        locked_service_handler,
        schema=vol.All(
            vol.Schema(
                {
                    vol.Required(ATTR_OBJECT_ID): cv.slug,
                    vol.Optional(ATTR_NAME): cv.string,
                    vol.Optional(ATTR_ICON): cv.string,
                    vol.Optional(ATTR_ALL): cv.boolean,
                    vol.Exclusive(ATTR_ENTITIES, "entities"): cv.entity_ids,
                    vol.Exclusive(ATTR_ADD_ENTITIES, "entities"): cv.entity_ids,
                }
            )
        ),
    )

    hass.services.async_register(
        DOMAIN,
        SERVICE_REMOVE,
        groups_service_handler,
        schema=vol.Schema({vol.Required(ATTR_OBJECT_ID): cv.slug}),
    )

    return True
示例#20
0
文件: __init__.py 项目: jbouwh/core
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
    """Set up an input slider."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    # Process integration platforms right away since
    # we will create entities before firing EVENT_COMPONENT_LOADED
    await async_process_integration_platform_for_component(hass, DOMAIN)

    id_manager = collection.IDManager()

    yaml_collection = collection.YamlCollection(
        logging.getLogger(f"{__name__}.yaml_collection"), id_manager
    )
    collection.sync_entity_lifecycle(
        hass, DOMAIN, DOMAIN, component, yaml_collection, InputNumber.from_yaml
    )

    storage_collection = NumberStorageCollection(
        Store(hass, STORAGE_VERSION, STORAGE_KEY),
        logging.getLogger(f"{__name__}.storage_collection"),
        id_manager,
    )
    collection.sync_entity_lifecycle(
        hass, DOMAIN, DOMAIN, component, storage_collection, InputNumber
    )

    await yaml_collection.async_load(
        [{CONF_ID: id_, **(conf or {})} for id_, conf in config.get(DOMAIN, {}).items()]
    )
    await storage_collection.async_load()

    collection.StorageCollectionWebsocket(
        storage_collection, DOMAIN, DOMAIN, CREATE_FIELDS, UPDATE_FIELDS
    ).async_setup(hass)

    async def reload_service_handler(service_call: ServiceCall) -> None:
        """Reload yaml entities."""
        conf = await component.async_prepare_reload(skip_reset=True)
        if conf is None:
            conf = {DOMAIN: {}}
        await yaml_collection.async_load(
            [{CONF_ID: id_, **conf} for id_, conf in conf.get(DOMAIN, {}).items()]
        )

    homeassistant.helpers.service.async_register_admin_service(
        hass,
        DOMAIN,
        SERVICE_RELOAD,
        reload_service_handler,
        schema=RELOAD_SERVICE_SCHEMA,
    )

    component.async_register_entity_service(
        SERVICE_SET_VALUE,
        {vol.Required(ATTR_VALUE): vol.Coerce(float)},
        "async_set_value",
    )

    component.async_register_entity_service(SERVICE_INCREMENT, {}, "async_increment")

    component.async_register_entity_service(SERVICE_DECREMENT, {}, "async_decrement")

    return True
示例#21
0
async def test_using_prescribed_entity_id(hass):
    """Test for using predefined entity ID."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    await component.async_add_entities(
        [MockEntity(name="bla", entity_id="hello.world")])
    assert "hello.world" in hass.states.async_entity_ids()
示例#22
0
async def async_setup(hass, config):
    """Set up the weather component."""
    component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass,
                                                    SCAN_INTERVAL)
    await component.async_setup(config)
    return True
示例#23
0
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
    """Set up the camera component."""
    component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass,
                                                    SCAN_INTERVAL)

    prefs = CameraPreferences(hass)
    await prefs.async_initialize()
    hass.data[DATA_CAMERA_PREFS] = prefs

    hass.http.register_view(CameraImageView(component))
    hass.http.register_view(CameraMjpegStream(component))
    hass.components.websocket_api.async_register_command(
        WS_TYPE_CAMERA_THUMBNAIL, websocket_camera_thumbnail,
        SCHEMA_WS_CAMERA_THUMBNAIL)
    hass.components.websocket_api.async_register_command(ws_camera_stream)
    hass.components.websocket_api.async_register_command(
        ws_camera_web_rtc_offer)
    hass.components.websocket_api.async_register_command(websocket_get_prefs)
    hass.components.websocket_api.async_register_command(
        websocket_update_prefs)

    await component.async_setup(config)

    async def preload_stream(_event: Event) -> None:
        for camera in component.entities:
            camera = cast(Camera, camera)
            camera_prefs = prefs.get(camera.entity_id)
            if not camera_prefs.preload_stream:
                continue
            stream = await camera.async_create_stream()
            if not stream:
                continue
            stream.keepalive = True
            stream.add_provider("hls")
            stream.start()

    hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, preload_stream)

    @callback
    def update_tokens(time: datetime) -> None:
        """Update tokens of the entities."""
        for entity in component.entities:
            entity = cast(Camera, entity)
            entity.async_update_token()
            entity.async_write_ha_state()

    hass.helpers.event.async_track_time_interval(update_tokens,
                                                 TOKEN_CHANGE_INTERVAL)

    component.async_register_entity_service(SERVICE_ENABLE_MOTION, {},
                                            "async_enable_motion_detection")
    component.async_register_entity_service(SERVICE_DISABLE_MOTION, {},
                                            "async_disable_motion_detection")
    component.async_register_entity_service(SERVICE_TURN_OFF, {},
                                            "async_turn_off")
    component.async_register_entity_service(SERVICE_TURN_ON, {},
                                            "async_turn_on")
    component.async_register_entity_service(SERVICE_SNAPSHOT,
                                            CAMERA_SERVICE_SNAPSHOT,
                                            async_handle_snapshot_service)
    component.async_register_entity_service(
        SERVICE_PLAY_STREAM,
        CAMERA_SERVICE_PLAY_STREAM,
        async_handle_play_stream_service,
    )
    component.async_register_entity_service(SERVICE_RECORD,
                                            CAMERA_SERVICE_RECORD,
                                            async_handle_record_service)

    return True
示例#24
0
async def async_setup(hass: HomeAssistant,
                      config: ConfigType) -> bool:  # noqa: C901
    """Expose light control via state machine and services."""
    component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass,
                                                    SCAN_INTERVAL)
    await component.async_setup(config)

    profiles = hass.data[DATA_PROFILES] = Profiles(hass)
    await profiles.async_initialize()

    def preprocess_data(data):
        """Preprocess the service data."""
        base = {
            entity_field: data.pop(entity_field)
            for entity_field in cv.ENTITY_SERVICE_FIELDS
            if entity_field in data
        }

        preprocess_turn_on_alternatives(hass, data)
        base["params"] = data
        return base

    async def async_handle_light_on_service(light, call):
        """Handle turning a light on.

        If brightness is set to 0, this service will turn the light off.
        """
        params = dict(call.data["params"])

        # Only process params once we processed brightness step
        if params and (ATTR_BRIGHTNESS_STEP in params
                       or ATTR_BRIGHTNESS_STEP_PCT in params):
            brightness = light.brightness if light.is_on else 0

            if ATTR_BRIGHTNESS_STEP in params:
                brightness += params.pop(ATTR_BRIGHTNESS_STEP)

            else:
                brightness += round(
                    params.pop(ATTR_BRIGHTNESS_STEP_PCT) / 100 * 255)

            params[ATTR_BRIGHTNESS] = max(0, min(255, brightness))

            preprocess_turn_on_alternatives(hass, params)

        if (not params or
                not light.is_on) or (params and ATTR_TRANSITION not in params):
            profiles.apply_default(light.entity_id, light.is_on, params)

        legacy_supported_color_modes = (
            light._light_internal_supported_color_modes  # pylint: disable=protected-access
        )
        supported_color_modes = light.supported_color_modes
        # Backwards compatibility: if an RGBWW color is specified, convert to RGB + W
        # for legacy lights
        if ATTR_RGBW_COLOR in params:
            if (ColorMode.RGBW in legacy_supported_color_modes
                    and not supported_color_modes):
                rgbw_color = params.pop(ATTR_RGBW_COLOR)
                params[ATTR_RGB_COLOR] = rgbw_color[0:3]
                params[ATTR_WHITE_VALUE] = rgbw_color[3]

        # If a color temperature is specified, emulate it if not supported by the light
        if ATTR_COLOR_TEMP in params:
            if (supported_color_modes
                    and ColorMode.COLOR_TEMP not in supported_color_modes
                    and ColorMode.RGBWW in supported_color_modes):
                color_temp = params.pop(ATTR_COLOR_TEMP)
                brightness = params.get(ATTR_BRIGHTNESS, light.brightness)
                params[
                    ATTR_RGBWW_COLOR] = color_util.color_temperature_to_rgbww(
                        color_temp, brightness, light.min_mireds,
                        light.max_mireds)
            elif ColorMode.COLOR_TEMP not in legacy_supported_color_modes:
                color_temp = params.pop(ATTR_COLOR_TEMP)
                if color_supported(legacy_supported_color_modes):
                    temp_k = color_util.color_temperature_mired_to_kelvin(
                        color_temp)
                    params[ATTR_HS_COLOR] = color_util.color_temperature_to_hs(
                        temp_k)

        # If a color is specified, convert to the color space supported by the light
        # Backwards compatibility: Fall back to hs color if light.supported_color_modes
        # is not implemented
        if not supported_color_modes:
            if (rgb_color := params.pop(ATTR_RGB_COLOR, None)) is not None:
                params[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color)
            elif (xy_color := params.pop(ATTR_XY_COLOR, None)) is not None:
                params[ATTR_HS_COLOR] = color_util.color_xy_to_hs(*xy_color)
            elif (rgbw_color := params.pop(ATTR_RGBW_COLOR, None)) is not None:
                rgb_color = color_util.color_rgbw_to_rgb(*rgbw_color)
                params[ATTR_HS_COLOR] = color_util.color_RGB_to_hs(*rgb_color)
示例#25
0
async def async_setup(hass, config):
    """Set up the automation."""
    component = EntityComponent(_LOGGER,
                                DOMAIN,
                                hass,
                                group_name=GROUP_NAME_ALL_AUTOMATIONS)

    await _async_process_config(hass, config, component)

    async def trigger_service_handler(service_call):
        """Handle automation triggers."""
        tasks = []
        for entity in await component.async_extract_from_service(service_call):
            tasks.append(
                entity.async_trigger(
                    service_call.data.get(ATTR_VARIABLES),
                    skip_condition=True,
                    context=service_call.context,
                ))

        if tasks:
            await asyncio.wait(tasks)

    async def turn_onoff_service_handler(service_call):
        """Handle automation turn on/off service calls."""
        tasks = []
        method = f"async_{service_call.service}"
        for entity in await component.async_extract_from_service(service_call):
            tasks.append(getattr(entity, method)())

        if tasks:
            await asyncio.wait(tasks)

    async def toggle_service_handler(service_call):
        """Handle automation toggle service calls."""
        tasks = []
        for entity in await component.async_extract_from_service(service_call):
            if entity.is_on:
                tasks.append(entity.async_turn_off())
            else:
                tasks.append(entity.async_turn_on())

        if tasks:
            await asyncio.wait(tasks)

    async def reload_service_handler(service_call):
        """Remove all automations and load new ones from config."""
        conf = await component.async_prepare_reload()
        if conf is None:
            return
        await _async_process_config(hass, conf, component)

    hass.services.async_register(DOMAIN,
                                 SERVICE_TRIGGER,
                                 trigger_service_handler,
                                 schema=TRIGGER_SERVICE_SCHEMA)

    hass.services.async_register(DOMAIN,
                                 SERVICE_RELOAD,
                                 reload_service_handler,
                                 schema=RELOAD_SERVICE_SCHEMA)

    hass.services.async_register(DOMAIN,
                                 SERVICE_TOGGLE,
                                 toggle_service_handler,
                                 schema=ENTITY_SERVICE_SCHEMA)

    for service in (SERVICE_TURN_ON, SERVICE_TURN_OFF):
        hass.services.async_register(DOMAIN,
                                     service,
                                     turn_onoff_service_handler,
                                     schema=ENTITY_SERVICE_SCHEMA)

    return True
示例#26
0
def async_setup(hass, config):
    """Set up a input_label."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    entities = []

    for object_id, cfg in config[DOMAIN].items():
        if not cfg:
            cfg = {}

        name = cfg.get(CONF_NAME)
        value = cfg.get(ATTR_VALUE)
        icon = cfg.get(CONF_ICON)
        readonly = cfg.get(ATTR_READONLY)

        entities.append(GlobalLabelData(object_id, name, value, icon,
                                        readonly))

    if not entities:
        return False

    @asyncio.coroutine
    def async_handler_service(service):
        """Handle a call to the input_label services."""
        target_global_labels = component.async_extract_from_service(service)

        if service.service == SERVICE_SETVALUE:
            attr = 'async_set_value'
        elif service.service == SERVICE_SETNAME:
            attr = 'async_set_name'
        else:
            attr = "async_set_icon"

        tasks = [
            getattr(global_label, attr)(service.data[ATTR_VALUE])
            for global_label in target_global_labels
        ]
        if tasks:
            yield from asyncio.wait(tasks, loop=hass.loop)

    descriptions = yield from hass.async_add_job(
        load_yaml_config_file,
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    hass.services.async_register(DOMAIN, SERVICE_SETVALUE,
                                 async_handler_service,
                                 descriptions[DOMAIN][SERVICE_SETVALUE],
                                 SERVICE_SCHEMA)

    hass.services.async_register(DOMAIN, SERVICE_SETICON,
                                 async_handler_service,
                                 descriptions[DOMAIN][SERVICE_SETICON],
                                 SERVICE_SCHEMA)

    hass.services.async_register(DOMAIN, SERVICE_SETNAME,
                                 async_handler_service,
                                 descriptions[DOMAIN][SERVICE_SETNAME],
                                 SERVICE_SCHEMA)

    yield from component.async_add_entities(entities)
    return True
示例#27
0
async def async_setup(hass, config):
    """Set up all groups found defined in the configuration."""
    component = hass.data.get(DOMAIN)

    if component is None:
        component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass)

    await _async_process_config(hass, config, component)

    async def reload_service_handler(service):
        """Remove all user-defined groups and load new ones from config."""
        #auto = list(filter(lambda e: not e.user_defined, component.entities))
        # fix for ais-dom groups defined in packages
        auto = list(component.entities)

        conf = await component.async_prepare_reload()
        if conf is None:
            return
        await _async_process_config(hass, conf, component)

        await component.async_add_entities(auto)

    hass.services.async_register(DOMAIN,
                                 SERVICE_RELOAD,
                                 reload_service_handler,
                                 schema=RELOAD_SERVICE_SCHEMA)

    service_lock = asyncio.Lock()

    async def locked_service_handler(service):
        """Handle a service with an async lock."""
        async with service_lock:
            await groups_service_handler(service)

    async def groups_service_handler(service):
        """Handle dynamic group service functions."""
        object_id = service.data[ATTR_OBJECT_ID]
        entity_id = ENTITY_ID_FORMAT.format(object_id)
        group = component.get_entity(entity_id)

        # new group
        if service.service == SERVICE_SET and group is None:
            entity_ids = service.data.get(ATTR_ENTITIES) or \
                service.data.get(ATTR_ADD_ENTITIES) or None

            extra_arg = {
                attr: service.data[attr]
                for attr in (ATTR_VISIBLE, ATTR_ICON, ATTR_VIEW, ATTR_CONTROL)
                if service.data.get(attr) is not None
            }

            await Group.async_create_group(hass,
                                           service.data.get(
                                               ATTR_NAME, object_id),
                                           object_id=object_id,
                                           entity_ids=entity_ids,
                                           user_defined=False,
                                           mode=service.data.get(ATTR_ALL),
                                           **extra_arg)
            return

        if group is None:
            _LOGGER.warning("%s:Group '%s' doesn't exist!", service.service,
                            object_id)
            return

        # update group
        if service.service == SERVICE_SET:
            need_update = False

            if ATTR_ADD_ENTITIES in service.data:
                delta = service.data[ATTR_ADD_ENTITIES]
                entity_ids = set(group.tracking) | set(delta)
                await group.async_update_tracked_entity_ids(entity_ids)

            if ATTR_ENTITIES in service.data:
                entity_ids = service.data[ATTR_ENTITIES]
                await group.async_update_tracked_entity_ids(entity_ids)

            if ATTR_NAME in service.data:
                group.name = service.data[ATTR_NAME]
                need_update = True

            if ATTR_VISIBLE in service.data:
                group.visible = service.data[ATTR_VISIBLE]
                need_update = True

            if ATTR_ICON in service.data:
                group.icon = service.data[ATTR_ICON]
                need_update = True

            if ATTR_CONTROL in service.data:
                group.control = service.data[ATTR_CONTROL]
                need_update = True

            if ATTR_VIEW in service.data:
                group.view = service.data[ATTR_VIEW]
                need_update = True

            if ATTR_ALL in service.data:
                group.mode = all if service.data[ATTR_ALL] else any
                need_update = True

            if need_update:
                await group.async_update_ha_state()

            return

        # remove group
        if service.service == SERVICE_REMOVE:
            await component.async_remove_entity(entity_id)

    hass.services.async_register(DOMAIN,
                                 SERVICE_SET,
                                 locked_service_handler,
                                 schema=SET_SERVICE_SCHEMA)

    hass.services.async_register(DOMAIN,
                                 SERVICE_REMOVE,
                                 groups_service_handler,
                                 schema=REMOVE_SERVICE_SCHEMA)

    async def visibility_service_handler(service):
        """Change visibility of a group."""
        visible = service.data.get(ATTR_VISIBLE)

        tasks = []
        for group in await component.async_extract_from_service(
                service, expand_group=False):
            group.visible = visible
            tasks.append(group.async_update_ha_state())

        if tasks:
            await asyncio.wait(tasks, loop=hass.loop)

    hass.services.async_register(DOMAIN,
                                 SERVICE_SET_VISIBILITY,
                                 visibility_service_handler,
                                 schema=SET_VISIBILITY_SERVICE_SCHEMA)

    return True
示例#28
0
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
    """Track states and offer events for media_players."""
    component = hass.data[DOMAIN] = EntityComponent(
        logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL)

    websocket_api.async_register_command(hass, websocket_browse_media)
    hass.http.register_view(MediaPlayerImageView(component))

    await component.async_setup(config)

    component.async_register_entity_service(SERVICE_TURN_ON, {},
                                            "async_turn_on",
                                            [MediaPlayerEntityFeature.TURN_ON])
    component.async_register_entity_service(
        SERVICE_TURN_OFF, {}, "async_turn_off",
        [MediaPlayerEntityFeature.TURN_OFF])
    component.async_register_entity_service(
        SERVICE_TOGGLE,
        {},
        "async_toggle",
        [MediaPlayerEntityFeature.TURN_OFF | MediaPlayerEntityFeature.TURN_ON],
    )
    component.async_register_entity_service(
        SERVICE_VOLUME_UP,
        {},
        "async_volume_up",
        [
            MediaPlayerEntityFeature.VOLUME_SET,
            MediaPlayerEntityFeature.VOLUME_STEP
        ],
    )
    component.async_register_entity_service(
        SERVICE_VOLUME_DOWN,
        {},
        "async_volume_down",
        [
            MediaPlayerEntityFeature.VOLUME_SET,
            MediaPlayerEntityFeature.VOLUME_STEP
        ],
    )
    component.async_register_entity_service(
        SERVICE_MEDIA_PLAY_PAUSE,
        {},
        "async_media_play_pause",
        [MediaPlayerEntityFeature.PLAY | MediaPlayerEntityFeature.PAUSE],
    )
    component.async_register_entity_service(SERVICE_MEDIA_PLAY, {},
                                            "async_media_play",
                                            [MediaPlayerEntityFeature.PLAY])
    component.async_register_entity_service(SERVICE_MEDIA_PAUSE, {},
                                            "async_media_pause",
                                            [MediaPlayerEntityFeature.PAUSE])
    component.async_register_entity_service(SERVICE_MEDIA_STOP, {},
                                            "async_media_stop",
                                            [MediaPlayerEntityFeature.STOP])
    component.async_register_entity_service(
        SERVICE_MEDIA_NEXT_TRACK,
        {},
        "async_media_next_track",
        [MediaPlayerEntityFeature.NEXT_TRACK],
    )
    component.async_register_entity_service(
        SERVICE_MEDIA_PREVIOUS_TRACK,
        {},
        "async_media_previous_track",
        [MediaPlayerEntityFeature.PREVIOUS_TRACK],
    )
    component.async_register_entity_service(
        SERVICE_CLEAR_PLAYLIST,
        {},
        "async_clear_playlist",
        [MediaPlayerEntityFeature.CLEAR_PLAYLIST],
    )
    component.async_register_entity_service(
        SERVICE_VOLUME_SET,
        vol.All(
            cv.make_entity_service_schema(
                {vol.Required(ATTR_MEDIA_VOLUME_LEVEL): cv.small_float}),
            _rename_keys(volume=ATTR_MEDIA_VOLUME_LEVEL),
        ),
        "async_set_volume_level",
        [MediaPlayerEntityFeature.VOLUME_SET],
    )
    component.async_register_entity_service(
        SERVICE_VOLUME_MUTE,
        vol.All(
            cv.make_entity_service_schema(
                {vol.Required(ATTR_MEDIA_VOLUME_MUTED): cv.boolean}),
            _rename_keys(mute=ATTR_MEDIA_VOLUME_MUTED),
        ),
        "async_mute_volume",
        [MediaPlayerEntityFeature.VOLUME_MUTE],
    )
    component.async_register_entity_service(
        SERVICE_MEDIA_SEEK,
        vol.All(
            cv.make_entity_service_schema(
                {vol.Required(ATTR_MEDIA_SEEK_POSITION): cv.positive_float}),
            _rename_keys(position=ATTR_MEDIA_SEEK_POSITION),
        ),
        "async_media_seek",
        [MediaPlayerEntityFeature.SEEK],
    )
    component.async_register_entity_service(
        SERVICE_JOIN,
        {
            vol.Required(ATTR_GROUP_MEMBERS):
            vol.All(cv.ensure_list, [cv.entity_id])
        },
        "async_join_players",
        [MediaPlayerEntityFeature.GROUPING],
    )
    component.async_register_entity_service(
        SERVICE_SELECT_SOURCE,
        {vol.Required(ATTR_INPUT_SOURCE): cv.string},
        "async_select_source",
        [MediaPlayerEntityFeature.SELECT_SOURCE],
    )
    component.async_register_entity_service(
        SERVICE_SELECT_SOUND_MODE,
        {vol.Required(ATTR_SOUND_MODE): cv.string},
        "async_select_sound_mode",
        [MediaPlayerEntityFeature.SELECT_SOUND_MODE],
    )

    # Remove in Home Assistant 2022.9
    def _rewrite_enqueue(value):
        """Rewrite the enqueue value."""
        if ATTR_MEDIA_ENQUEUE not in value:
            pass
        elif value[ATTR_MEDIA_ENQUEUE] is True:
            value[ATTR_MEDIA_ENQUEUE] = MediaPlayerEnqueue.ADD
            _LOGGER.warning(
                "Playing media with enqueue set to True is deprecated. Use 'add' instead"
            )
        elif value[ATTR_MEDIA_ENQUEUE] is False:
            value[ATTR_MEDIA_ENQUEUE] = MediaPlayerEnqueue.PLAY
            _LOGGER.warning(
                "Playing media with enqueue set to False is deprecated. Use 'play' instead"
            )

        return value

    component.async_register_entity_service(
        SERVICE_PLAY_MEDIA,
        vol.All(
            cv.make_entity_service_schema(MEDIA_PLAYER_PLAY_MEDIA_SCHEMA),
            _rewrite_enqueue,
            _rename_keys(
                media_type=ATTR_MEDIA_CONTENT_TYPE,
                media_id=ATTR_MEDIA_CONTENT_ID,
                enqueue=ATTR_MEDIA_ENQUEUE,
            ),
        ),
        "async_play_media",
        [MediaPlayerEntityFeature.PLAY_MEDIA],
    )
    component.async_register_entity_service(
        SERVICE_SHUFFLE_SET,
        {vol.Required(ATTR_MEDIA_SHUFFLE): cv.boolean},
        "async_set_shuffle",
        [MediaPlayerEntityFeature.SHUFFLE_SET],
    )
    component.async_register_entity_service(
        SERVICE_UNJOIN, {}, "async_unjoin_player",
        [MediaPlayerEntityFeature.GROUPING])

    component.async_register_entity_service(
        SERVICE_REPEAT_SET,
        {vol.Required(ATTR_MEDIA_REPEAT): vol.In(REPEAT_MODES)},
        "async_set_repeat",
        [MediaPlayerEntityFeature.REPEAT_SET],
    )

    return True
示例#29
0
def async_setup(hass, config):
    """Set up the weather component."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)

    yield from component.async_setup(config)
    return True
示例#30
0
def test_using_prescribed_entity_id(hass):
    """Test for using predefined entity ID."""
    component = EntityComponent(_LOGGER, DOMAIN, hass)
    yield from component.async_add_entities(
        [MockEntity(name='bla', entity_id='hello.world')])
    assert 'hello.world' in hass.states.async_entity_ids()