Пример #1
0
UNAVAILABLE_GRACE = 90

FIX_MAC_FW = AwesomeVersion("3.70")
SWITCH_PRODUCT_IDS = [70, 71, 89]

SERVICE_LIFX_SET_STATE = "set_state"

ATTR_INFRARED = "infrared"
ATTR_ZONES = "zones"
ATTR_POWER = "power"

LIFX_SET_STATE_SCHEMA = cv.make_entity_service_schema({
    **LIGHT_TURN_ON_SCHEMA,
    ATTR_INFRARED:
    vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255)),
    ATTR_ZONES:
    vol.All(cv.ensure_list, [cv.positive_int]),
    ATTR_POWER:
    cv.boolean,
})

SERVICE_EFFECT_PULSE = "effect_pulse"
SERVICE_EFFECT_COLORLOOP = "effect_colorloop"
SERVICE_EFFECT_STOP = "effect_stop"

ATTR_POWER_ON = "power_on"
ATTR_PERIOD = "period"
ATTR_CYCLES = "cycles"
ATTR_SPREAD = "spread"
ATTR_CHANGE = "change"
Пример #2
0
# mypy: allow-untyped-defs, no-check-untyped-defs

ATTR_CHANGED_BY = "changed_by"

DOMAIN = "lock"
SCAN_INTERVAL = timedelta(seconds=30)

ENTITY_ID_ALL_LOCKS = group.ENTITY_ID_FORMAT.format("all_locks")
ENTITY_ID_FORMAT = DOMAIN + ".{}"

GROUP_NAME_ALL_LOCKS = "all locks"

MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)

LOCK_SERVICE_SCHEMA = make_entity_service_schema(
    {vol.Optional(ATTR_CODE): cv.string})

# Bitfield of features supported by the lock entity
SUPPORT_OPEN = 1

_LOGGER = logging.getLogger(__name__)

PROP_TO_ATTR = {"changed_by": ATTR_CHANGED_BY, "code_format": ATTR_CODE_FORMAT}


@bind_hass
def is_locked(hass, entity_id=None):
    """Return if the lock is locked based on the statemachine."""
    entity_id = entity_id or ENTITY_ID_ALL_LOCKS
    return hass.states.is_state(entity_id, STATE_LOCKED)
Пример #3
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
Пример #4
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)
    await component.async_setup(config)

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

    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
        }

        base["params"] = preprocess_turn_on_alternatives(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 = call.data["params"]

        if not params:
            default_profile = Profiles.get_default(light.entity_id)

            if default_profile is not None:
                params = {ATTR_PROFILE: default_profile}
                preprocess_turn_on_alternatives(params)

        elif ATTR_BRIGHTNESS_STEP in params or ATTR_BRIGHTNESS_STEP_PCT in params:
            brightness = light.brightness if light.is_on else 0

            params = params.copy()

            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))

        turn_light_off, off_params = preprocess_turn_off(params)
        if turn_light_off:
            await light.async_turn_off(**off_params)
        else:
            await light.async_turn_on(**params)

    async def async_handle_toggle_service(light, call):
        """Handle toggling a light.

        If brightness is set to 0, this service will turn the light off.
        """
        if light.is_on:
            off_params = filter_turn_off_params(call.data["params"])
            await light.async_turn_off(**off_params)
        else:
            await async_handle_light_on_service(light, call)

    # Listen for light on and light off service calls.

    component.async_register_entity_service(
        SERVICE_TURN_ON,
        vol.All(cv.make_entity_service_schema(LIGHT_TURN_ON_SCHEMA),
                preprocess_data),
        async_handle_light_on_service,
    )

    component.async_register_entity_service(
        SERVICE_TURN_OFF,
        {
            ATTR_TRANSITION: VALID_TRANSITION,
            ATTR_FLASH: VALID_FLASH
        },
        "async_turn_off",
    )

    component.async_register_entity_service(
        SERVICE_TOGGLE,
        vol.All(cv.make_entity_service_schema(LIGHT_TURN_ON_SCHEMA),
                preprocess_data),
        async_handle_toggle_service,
    )

    return True
Пример #5
0
async def async_setup_entry(hass, config_entry, async_add_entities):
    """Set up Sonos from a config entry."""
    if DATA_SONOS not in hass.data:
        hass.data[DATA_SONOS] = SonosData()

    config = hass.data[SONOS_DOMAIN].get("media_player", {})
    _LOGGER.debug("Reached async_setup_entry, config=%s", config)

    advertise_addr = config.get(CONF_ADVERTISE_ADDR)
    if advertise_addr:
        pysonos.config.EVENT_ADVERTISE_IP = advertise_addr

    def _stop_discovery(event):
        data = hass.data[DATA_SONOS]
        if data.discovery_thread:
            data.discovery_thread.stop()
            data.discovery_thread = None
        if data.hosts_heartbeat:
            data.hosts_heartbeat()
            data.hosts_heartbeat = None

    def _discovery(now=None):
        """Discover players from network or configuration."""
        hosts = config.get(CONF_HOSTS)

        def _discovered_player(soco):
            """Handle a (re)discovered player."""
            try:
                _LOGGER.debug("Reached _discovered_player, soco=%s", soco)

                if soco.uid not in hass.data[DATA_SONOS].discovered:
                    _LOGGER.debug("Adding new entity")
                    hass.data[DATA_SONOS].discovered.append(soco.uid)
                    hass.add_job(async_add_entities, [SonosEntity(soco)])
                else:
                    entity = _get_entity_from_soco_uid(hass, soco.uid)
                    if entity and (entity.soco == soco
                                   or not entity.available):
                        _LOGGER.debug("Seen %s", entity)
                        hass.add_job(entity.async_seen(soco))

            except SoCoException as ex:
                _LOGGER.debug("SoCoException, ex=%s", ex)

        if hosts:
            for host in hosts:
                try:
                    _LOGGER.debug("Testing %s", host)
                    player = pysonos.SoCo(socket.gethostbyname(host))
                    if player.is_visible:
                        # Make sure that the player is available
                        _ = player.volume

                        _discovered_player(player)
                except (OSError, SoCoException) as ex:
                    _LOGGER.debug("Exception %s", ex)
                    if now is None:
                        _LOGGER.warning("Failed to initialize '%s'", host)

            _LOGGER.debug("Tested all hosts")
            hass.data[
                DATA_SONOS].hosts_heartbeat = hass.helpers.event.call_later(
                    DISCOVERY_INTERVAL, _discovery)
        else:
            _LOGGER.debug("Starting discovery thread")
            hass.data[DATA_SONOS].discovery_thread = pysonos.discover_thread(
                _discovered_player,
                interval=DISCOVERY_INTERVAL,
                interface_addr=config.get(CONF_INTERFACE_ADDR),
            )

    _LOGGER.debug("Adding discovery job")
    hass.async_add_executor_job(_discovery)
    hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _stop_discovery)

    platform = entity_platform.current_platform.get()

    @service.verify_domain_control(hass, SONOS_DOMAIN)
    async def async_service_handle(service_call: ServiceCall):
        """Handle dispatched services."""
        entities = await platform.async_extract_from_service(service_call)

        if not entities:
            return

        if service_call.service == SERVICE_JOIN:
            master = platform.entities.get(service_call.data[ATTR_MASTER])
            if master:
                await SonosEntity.join_multi(hass, master, entities)
            else:
                _LOGGER.error(
                    "Invalid master specified for join service: %s",
                    service_call.data[ATTR_MASTER],
                )
        elif service_call.service == SERVICE_UNJOIN:
            await SonosEntity.unjoin_multi(hass, entities)
        elif service_call.service == SERVICE_SNAPSHOT:
            await SonosEntity.snapshot_multi(
                hass, entities, service_call.data[ATTR_WITH_GROUP])
        elif service_call.service == SERVICE_RESTORE:
            await SonosEntity.restore_multi(hass, entities,
                                            service_call.data[ATTR_WITH_GROUP])

    hass.services.async_register(
        SONOS_DOMAIN,
        SERVICE_JOIN,
        async_service_handle,
        cv.make_entity_service_schema(
            {vol.Required(ATTR_MASTER): cv.entity_id}),
    )

    hass.services.async_register(
        SONOS_DOMAIN,
        SERVICE_UNJOIN,
        async_service_handle,
        cv.make_entity_service_schema({}),
    )

    join_unjoin_schema = cv.make_entity_service_schema(
        {vol.Optional(ATTR_WITH_GROUP, default=True): cv.boolean})

    hass.services.async_register(SONOS_DOMAIN, SERVICE_SNAPSHOT,
                                 async_service_handle, join_unjoin_schema)

    hass.services.async_register(SONOS_DOMAIN, SERVICE_RESTORE,
                                 async_service_handle, join_unjoin_schema)

    platform.async_register_entity_service(
        SERVICE_SET_TIMER,
        {
            vol.Required(ATTR_SLEEP_TIME):
            vol.All(vol.Coerce(int), vol.Range(min=0, max=86399))
        },
        "set_sleep_timer",
    )

    platform.async_register_entity_service(SERVICE_CLEAR_TIMER, {},
                                           "clear_sleep_timer")

    platform.async_register_entity_service(
        SERVICE_UPDATE_ALARM,
        {
            vol.Required(ATTR_ALARM_ID): cv.positive_int,
            vol.Optional(ATTR_TIME): cv.time,
            vol.Optional(ATTR_VOLUME): cv.small_float,
            vol.Optional(ATTR_ENABLED): cv.boolean,
            vol.Optional(ATTR_INCLUDE_LINKED_ZONES): cv.boolean,
        },
        "set_alarm",
    )

    platform.async_register_entity_service(
        SERVICE_SET_OPTION,
        {
            vol.Optional(ATTR_NIGHT_SOUND): cv.boolean,
            vol.Optional(ATTR_SPEECH_ENHANCE): cv.boolean,
            vol.Optional(ATTR_STATUS_LIGHT): cv.boolean,
        },
        "set_option",
    )

    platform.async_register_entity_service(
        SERVICE_PLAY_QUEUE,
        {vol.Optional(ATTR_QUEUE_POSITION): cv.positive_int},
        "play_queue",
    )

    platform.async_register_entity_service(
        SERVICE_REMOVE_FROM_QUEUE,
        {vol.Optional(ATTR_QUEUE_POSITION): cv.positive_int},
        "remove_from_queue",
    )
Пример #6
0
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)

SERVICE_SEND_COMMAND = "send_command"
SERVICE_LEARN_COMMAND = "learn_command"
SERVICE_DELETE_COMMAND = "delete_command"
SERVICE_SYNC = "sync"

DEFAULT_NUM_REPEATS = 1
DEFAULT_DELAY_SECS = 0.4
DEFAULT_HOLD_SECS = 0

SUPPORT_LEARN_COMMAND = 1
SUPPORT_DELETE_COMMAND = 2
SUPPORT_ACTIVITY = 4

REMOTE_SERVICE_ACTIVITY_SCHEMA = make_entity_service_schema(
    {vol.Optional(ATTR_ACTIVITY): cv.string})


@bind_hass
def is_on(hass: HomeAssistant, entity_id: str) -> bool:
    """Return if the remote is on based on the statemachine."""
    return hass.states.is_state(entity_id, STATE_ON)


async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
    """Track states and offer events for remotes."""
    component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass,
                                                    SCAN_INTERVAL)
    await component.async_setup(config)

    component.async_register_entity_service(SERVICE_TURN_OFF,
Пример #7
0
def validate_sql_select(value):
    """Validate that value is a SQL SELECT query."""
    if not value.lstrip().lower().startswith('select'):
        raise vol.Invalid('Only SELECT queries allowed')
    return value

SERVICE_SET = "set"
SERVICE_SET_SCHEMA = make_entity_service_schema({
        vol.Optional(ATTR_VALUE): cv.match_all,
        vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
        vol.Optional(CONF_QUERY): vol.All(cv.string, validate_sql_select),
        vol.Optional(CONF_COLUMN): cv.string,
        vol.Optional(ATTR_UNIT_OF_MEASUREMENT): cv.string,
        vol.Optional(CONF_RESTORE): cv.boolean,
        vol.Optional(CONF_FORCE_UPDATE): cv.boolean,
        vol.Optional(ATTR_FRIENDLY_NAME): cv.string,
        vol.Optional(CONF_FRIENDLY_NAME_TEMPLATE): cv.template,
        vol.Optional(CONF_ICON): cv.icon,
        vol.Optional(CONF_ICON_TEMPLATE): cv.template,
        vol.Optional(ATTR_ENTITY_PICTURE): cv.string,
        vol.Optional(CONF_ENTITY_PICTURE_TEMPLATE): cv.template,
        vol.Optional(CONF_TRACKED_ENTITY_ID): cv.entity_ids,
        vol.Optional(CONF_TRACKED_EVENT_TYPE): validate_event_types,
})

SERVICE_UPDATE = "update"
SERVICE_UPDATE_SCHEMA = make_entity_service_schema({})

CONFIG_SCHEMA = vol.Schema({
    DOMAIN: vol.Schema({
        cv.slug: vol.Any({
Пример #8
0
SCAN_INTERVAL = timedelta(seconds=60)

CONVERTIBLE_ATTRIBUTE = [
    ATTR_TEMPERATURE, ATTR_TARGET_TEMP_LOW, ATTR_TARGET_TEMP_HIGH
]

_LOGGER = logging.getLogger(__name__)

SET_TEMPERATURE_SCHEMA = vol.All(
    cv.has_at_least_one_key(ATTR_TEMPERATURE, ATTR_TARGET_TEMP_HIGH,
                            ATTR_TARGET_TEMP_LOW),
    make_entity_service_schema({
        vol.Exclusive(ATTR_TEMPERATURE, "temperature"):
        vol.Coerce(float),
        vol.Inclusive(ATTR_TARGET_TEMP_HIGH, "temperature"):
        vol.Coerce(float),
        vol.Inclusive(ATTR_TARGET_TEMP_LOW, "temperature"):
        vol.Coerce(float),
        vol.Optional(ATTR_HVAC_MODE):
        vol.In(HVAC_MODES),
    }),
)


async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
    """Set up climate entities."""
    component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass,
                                                    SCAN_INTERVAL)
    await component.async_setup(config)

    component.async_register_entity_service(SERVICE_TURN_ON, {},
                                            "async_turn_on")
Пример #9
0
SERVICE_SET_HVAC_RUN_MODE = "set_hvac_run_mode"

SET_AIRCLEANER_SCHEMA = {
    vol.Required(ATTR_AIRCLEANER_MODE): cv.string,
}

SET_HUMIDITY_SCHEMA = {
    vol.Required(ATTR_HUMIDITY):
    vol.All(vol.Coerce(int), vol.Range(min=35, max=65)),
}

SET_HVAC_RUN_MODE_SCHEMA = vol.All(
    cv.has_at_least_one_key(ATTR_RUN_MODE, ATTR_HVAC_MODE),
    cv.make_entity_service_schema({
        vol.Optional(ATTR_RUN_MODE):
        vol.In([HOLD_PERMANENT, HOLD_RESUME_SCHEDULE]),
        vol.Optional(ATTR_HVAC_MODE):
        vol.In([HVAC_MODE_HEAT, HVAC_MODE_COOL, HVAC_MODE_AUTO]),
    }),
)

#
# Nexia has two bits to determine hvac mode
# There are actually eight states so we map to
# the most significant state
#
# 1. Zone Mode : Auto / Cooling / Heating / Off
# 2. Run Mode  : Hold / Run Schedule
#
#
HA_TO_NEXIA_HVAC_MODE_MAP = {
    HVAC_MODE_HEAT: OPERATION_MODE_HEAT,
Пример #10
0
async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up Sonos from a config entry."""
    platform = entity_platform.async_get_current_platform()

    @callback
    def async_create_entities(speaker: SonosSpeaker) -> None:
        """Handle device discovery and create entities."""
        async_add_entities([SonosMediaPlayerEntity(speaker)])

    @service.verify_domain_control(hass, SONOS_DOMAIN)
    async def async_service_handle(service_call: ServiceCall) -> None:
        """Handle dispatched services."""
        assert platform is not None
        entities = await platform.async_extract_from_service(service_call)

        if not entities:
            return

        speakers = []
        for entity in entities:
            assert isinstance(entity, SonosMediaPlayerEntity)
            speakers.append(entity.speaker)

        if service_call.service == SERVICE_JOIN:
            master = platform.entities.get(service_call.data[ATTR_MASTER])
            if master:
                await SonosSpeaker.join_multi(hass, master.speaker, speakers
                                              )  # type: ignore[arg-type]
            else:
                _LOGGER.error(
                    "Invalid master specified for join service: %s",
                    service_call.data[ATTR_MASTER],
                )
        elif service_call.service == SERVICE_UNJOIN:
            await SonosSpeaker.unjoin_multi(hass,
                                            speakers)  # type: ignore[arg-type]
        elif service_call.service == SERVICE_SNAPSHOT:
            await SonosSpeaker.snapshot_multi(
                hass,
                speakers,
                service_call.data[ATTR_WITH_GROUP]  # type: ignore[arg-type]
            )
        elif service_call.service == SERVICE_RESTORE:
            await SonosSpeaker.restore_multi(
                hass,
                speakers,
                service_call.data[ATTR_WITH_GROUP]  # type: ignore[arg-type]
            )

    config_entry.async_on_unload(
        async_dispatcher_connect(hass, SONOS_CREATE_MEDIA_PLAYER,
                                 async_create_entities))

    hass.services.async_register(
        SONOS_DOMAIN,
        SERVICE_JOIN,
        async_service_handle,
        cv.make_entity_service_schema(
            {vol.Required(ATTR_MASTER): cv.entity_id}),
    )

    hass.services.async_register(
        SONOS_DOMAIN,
        SERVICE_UNJOIN,
        async_service_handle,
        cv.make_entity_service_schema({}),
    )

    join_unjoin_schema = cv.make_entity_service_schema(
        {vol.Optional(ATTR_WITH_GROUP, default=True): cv.boolean})

    hass.services.async_register(SONOS_DOMAIN, SERVICE_SNAPSHOT,
                                 async_service_handle, join_unjoin_schema)

    hass.services.async_register(SONOS_DOMAIN, SERVICE_RESTORE,
                                 async_service_handle, join_unjoin_schema)

    platform.async_register_entity_service(  # type: ignore
        SERVICE_SET_TIMER,
        {
            vol.Required(ATTR_SLEEP_TIME): vol.All(
                vol.Coerce(int), vol.Range(min=0, max=86399)
            )
        },
        "set_sleep_timer",
    )

    platform.async_register_entity_service(SERVICE_CLEAR_TIMER, {},
                                           "clear_sleep_timer")  # type: ignore

    platform.async_register_entity_service(  # type: ignore
        SERVICE_UPDATE_ALARM,
        {
            vol.Required(ATTR_ALARM_ID): cv.positive_int,
            vol.Optional(ATTR_TIME): cv.time,
            vol.Optional(ATTR_VOLUME): cv.small_float,
            vol.Optional(ATTR_ENABLED): cv.boolean,
            vol.Optional(ATTR_INCLUDE_LINKED_ZONES): cv.boolean,
        },
        "set_alarm",
    )

    platform.async_register_entity_service(  # type: ignore
        SERVICE_SET_OPTION,
        {
            vol.Optional(ATTR_BUTTONS_ENABLED): cv.boolean,
            vol.Optional(ATTR_NIGHT_SOUND): cv.boolean,
            vol.Optional(ATTR_SPEECH_ENHANCE): cv.boolean,
            vol.Optional(ATTR_STATUS_LIGHT): cv.boolean,
        },
        "set_option",
    )

    platform.async_register_entity_service(  # type: ignore
        SERVICE_PLAY_QUEUE,
        {vol.Optional(ATTR_QUEUE_POSITION): cv.positive_int},
        "play_queue",
    )

    platform.async_register_entity_service(  # type: ignore
        SERVICE_REMOVE_FROM_QUEUE,
        {vol.Optional(ATTR_QUEUE_POSITION): cv.positive_int},
        "remove_from_queue",
    )
Пример #11
0
DOMAIN = "upb"

ATTR_ADDRESS = "address"
ATTR_BLINK_RATE = "blink_rate"
ATTR_BRIGHTNESS = "brightness"
ATTR_BRIGHTNESS_PCT = "brightness_pct"
ATTR_RATE = "rate"
CONF_NETWORK = "network"
EVENT_UPB_SCENE_CHANGED = "upb.scene_changed"

VALID_BRIGHTNESS = vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255))
VALID_BRIGHTNESS_PCT = vol.All(vol.Coerce(float), vol.Range(min=0, max=100))
VALID_RATE = vol.All(vol.Coerce(float), vol.Clamp(min=-1, max=3600))

UPB_BRIGHTNESS_RATE_SCHEMA = vol.All(
    cv.has_at_least_one_key(ATTR_BRIGHTNESS, ATTR_BRIGHTNESS_PCT),
    cv.make_entity_service_schema({
        vol.Exclusive(ATTR_BRIGHTNESS, ATTR_BRIGHTNESS):
        VALID_BRIGHTNESS,
        vol.Exclusive(ATTR_BRIGHTNESS_PCT, ATTR_BRIGHTNESS):
        VALID_BRIGHTNESS_PCT,
        vol.Optional(ATTR_RATE, default=-1):
        VALID_RATE,
    }),
)

UPB_BLINK_RATE_SCHEMA = {
    vol.Required(ATTR_BLINK_RATE, default=0.5):
    vol.All(vol.Coerce(float), vol.Range(min=0, max=4.25))
}
Пример #12
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)

        poll_lights = []
        change_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:
                task = light.async_request_call(
                    light.async_turn_off(**off_pars))
            else:
                task = light.async_request_call(light.async_turn_on(**pars))

            change_tasks.append(task)

            if light.should_poll:
                poll_lights.append(light)

        if change_tasks:
            await asyncio.wait(change_tasks)

        if poll_lights:
            await asyncio.wait(
                [light.async_update_ha_state(True) for light in poll_lights])

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

    component.async_register_entity_service(
        SERVICE_TURN_OFF,
        {
            ATTR_TRANSITION: VALID_TRANSITION,
            ATTR_FLASH: vol.In([FLASH_SHORT, FLASH_LONG]),
        },
        "async_turn_off",
    )

    component.async_register_entity_service(SERVICE_TOGGLE,
                                            LIGHT_TURN_ON_SCHEMA,
                                            "async_toggle")

    return True