Ejemplo n.º 1
0
async def test_get_supported_features_prioritize_state(hass):
    """Test get_supported_features gives priority to state."""
    entity_reg = mock_registry(hass)
    entity_id = entity_reg.async_get_or_create(
        "hello", "world", "5678", supported_features=456).entity_id
    assert entity.get_supported_features(hass, entity_id) == 456

    hass.states.async_set(entity_id, None, {"supported_features": 123})

    assert entity.get_supported_features(hass, entity_id) == 123
Ejemplo n.º 2
0
async def async_get_conditions(hass: HomeAssistant,
                               device_id: str) -> list[dict[str, str]]:
    """List device conditions for Climate devices."""
    registry = await entity_registry.async_get_registry(hass)
    conditions = []

    # Get all the integrations entities for this device
    for entry in entity_registry.async_entries_for_device(registry, device_id):
        if entry.domain != DOMAIN:
            continue

        supported_features = get_supported_features(hass, entry.entity_id)

        base_condition = {
            CONF_CONDITION: "device",
            CONF_DEVICE_ID: device_id,
            CONF_DOMAIN: DOMAIN,
            CONF_ENTITY_ID: entry.entity_id,
        }

        conditions.append({**base_condition, CONF_TYPE: "is_hvac_mode"})

        if supported_features & const.SUPPORT_PRESET_MODE:
            conditions.append({**base_condition, CONF_TYPE: "is_preset_mode"})

    return conditions
Ejemplo n.º 3
0
async def test_get_supported_features_entity_registry(hass):
    """Test get_supported_features falls back to entity registry."""
    entity_reg = mock_registry(hass)
    entity_id = entity_reg.async_get_or_create(
        "hello", "world", "5678", supported_features=456
    ).entity_id
    assert entity.get_supported_features(hass, entity_id) == 456
async def async_get_actions(hass: HomeAssistant,
                            device_id: str) -> list[dict[str, str]]:
    """List device actions."""
    actions = await toggle_entity.async_get_actions(hass, device_id, DOMAIN)

    entity_registry = er.async_get(hass)

    for entry in er.async_entries_for_device(entity_registry, device_id):
        if entry.domain != DOMAIN:
            continue

        supported_color_modes = get_supported_color_modes(
            hass, entry.entity_id)
        supported_features = get_supported_features(hass, entry.entity_id)

        base_action = {
            CONF_DEVICE_ID: device_id,
            CONF_DOMAIN: DOMAIN,
            CONF_ENTITY_ID: entry.entity_id,
        }

        if brightness_supported(supported_color_modes):
            actions.extend((
                {
                    **base_action, CONF_TYPE: TYPE_BRIGHTNESS_INCREASE
                },
                {
                    **base_action, CONF_TYPE: TYPE_BRIGHTNESS_DECREASE
                },
            ))

        if supported_features & LightEntityFeature.FLASH:
            actions.append({**base_action, CONF_TYPE: TYPE_FLASH})

    return actions
async def async_get_action_capabilities(
        hass: HomeAssistant, config: ConfigType) -> dict[str, vol.Schema]:
    """List action capabilities."""
    if config[CONF_TYPE] != toggle_entity.CONF_TURN_ON:
        return {}

    try:
        supported_color_modes = get_supported_color_modes(
            hass, config[ATTR_ENTITY_ID])
    except HomeAssistantError:
        supported_color_modes = None

    try:
        supported_features = get_supported_features(hass,
                                                    config[ATTR_ENTITY_ID])
    except HomeAssistantError:
        supported_features = 0

    extra_fields = {}

    if brightness_supported(supported_color_modes):
        extra_fields[vol.Optional(ATTR_BRIGHTNESS_PCT)] = VALID_BRIGHTNESS_PCT

    if supported_features & LightEntityFeature.FLASH:
        extra_fields[vol.Optional(ATTR_FLASH)] = VALID_FLASH

    return {"extra_fields": vol.Schema(extra_fields)} if extra_fields else {}
Ejemplo n.º 6
0
async def async_get_actions(hass: HomeAssistant,
                            device_id: str) -> list[dict[str, str]]:
    """List device actions for Alarm control panel devices."""
    registry = await entity_registry.async_get_registry(hass)
    actions = []

    # Get all the integrations entities for this device
    for entry in entity_registry.async_entries_for_device(registry, device_id):
        if entry.domain != DOMAIN:
            continue

        supported_features = get_supported_features(hass, entry.entity_id)

        base_action: dict = {
            CONF_DEVICE_ID: device_id,
            CONF_DOMAIN: DOMAIN,
            CONF_ENTITY_ID: entry.entity_id,
        }

        # Add actions for each entity that belongs to this integration
        if supported_features & SUPPORT_ALARM_ARM_AWAY:
            actions.append({**base_action, CONF_TYPE: "arm_away"})
        if supported_features & SUPPORT_ALARM_ARM_HOME:
            actions.append({**base_action, CONF_TYPE: "arm_home"})
        if supported_features & SUPPORT_ALARM_ARM_NIGHT:
            actions.append({**base_action, CONF_TYPE: "arm_night"})
        if supported_features & SUPPORT_ALARM_ARM_VACATION:
            actions.append({**base_action, CONF_TYPE: "arm_vacation"})
        actions.append({**base_action, CONF_TYPE: "disarm"})
        if supported_features & SUPPORT_ALARM_TRIGGER:
            actions.append({**base_action, CONF_TYPE: "trigger"})

    return actions
Ejemplo n.º 7
0
async def async_get_conditions(
    hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
    """List device conditions for Humidifier devices."""
    registry = await entity_registry.async_get_registry(hass)
    conditions = await toggle_entity.async_get_conditions(hass, device_id, DOMAIN)

    # Get all the integrations entities for this device
    for entry in entity_registry.async_entries_for_device(registry, device_id):
        if entry.domain != DOMAIN:
            continue

        supported_features = get_supported_features(hass, entry.entity_id)

        if supported_features & const.SUPPORT_MODES:
            conditions.append(
                {
                    CONF_CONDITION: "device",
                    CONF_DEVICE_ID: device_id,
                    CONF_DOMAIN: DOMAIN,
                    CONF_ENTITY_ID: entry.entity_id,
                    CONF_TYPE: "is_mode",
                }
            )

    return conditions
Ejemplo n.º 8
0
async def async_get_actions(
    hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
    """List device actions for Lock devices."""
    registry = await entity_registry.async_get_registry(hass)
    actions = []

    # Get all the integrations entities for this device
    for entry in entity_registry.async_entries_for_device(registry, device_id):
        if entry.domain != DOMAIN:
            continue

        supported_features = get_supported_features(hass, entry.entity_id)

        # Add actions for each entity that belongs to this integration
        base_action = {
            CONF_DEVICE_ID: device_id,
            CONF_DOMAIN: DOMAIN,
            CONF_ENTITY_ID: entry.entity_id,
        }

        actions.append({**base_action, CONF_TYPE: "lock"})
        actions.append({**base_action, CONF_TYPE: "unlock"})

        if supported_features & (LockEntityFeature.OPEN):
            actions.append({**base_action, CONF_TYPE: "open"})

    return actions
Ejemplo n.º 9
0
async def async_get_conditions(hass: HomeAssistant,
                               device_id: str) -> list[dict[str, str]]:
    """List device conditions for Cover devices."""
    registry = await entity_registry.async_get_registry(hass)
    conditions: list[dict[str, str]] = []

    # Get all the integrations entities for this device
    for entry in entity_registry.async_entries_for_device(registry, device_id):
        if entry.domain != DOMAIN:
            continue

        supported_features = get_supported_features(hass, entry.entity_id)
        supports_open_close = supported_features & (SUPPORT_OPEN
                                                    | SUPPORT_CLOSE)

        # Add conditions for each entity that belongs to this integration
        base_condition = {
            CONF_CONDITION: "device",
            CONF_DEVICE_ID: device_id,
            CONF_DOMAIN: DOMAIN,
            CONF_ENTITY_ID: entry.entity_id,
        }

        if supports_open_close:
            conditions += [{
                **base_condition, CONF_TYPE: cond
            } for cond in STATE_CONDITION_TYPES]
        if supported_features & SUPPORT_SET_POSITION:
            conditions.append({**base_condition, CONF_TYPE: "is_position"})
        if supported_features & SUPPORT_SET_TILT_POSITION:
            conditions.append({
                **base_condition, CONF_TYPE: "is_tilt_position"
            })

    return conditions
async def async_get_conditions(hass: HomeAssistant,
                               device_id: str) -> list[dict[str, str]]:
    """List device conditions for Alarm control panel devices."""
    registry = await entity_registry.async_get_registry(hass)
    conditions = []

    # Get all the integrations entities for this device
    for entry in entity_registry.async_entries_for_device(registry, device_id):
        if entry.domain != DOMAIN:
            continue

        supported_features = get_supported_features(hass, entry.entity_id)

        # Add conditions for each entity that belongs to this integration
        base_condition = {
            CONF_CONDITION: "device",
            CONF_DEVICE_ID: device_id,
            CONF_DOMAIN: DOMAIN,
            CONF_ENTITY_ID: entry.entity_id,
        }

        conditions += [
            {
                **base_condition, CONF_TYPE: CONDITION_DISARMED
            },
            {
                **base_condition, CONF_TYPE: CONDITION_TRIGGERED
            },
        ]
        if supported_features & SUPPORT_ALARM_ARM_HOME:
            conditions.append({
                **base_condition, CONF_TYPE: CONDITION_ARMED_HOME
            })
        if supported_features & SUPPORT_ALARM_ARM_AWAY:
            conditions.append({
                **base_condition, CONF_TYPE: CONDITION_ARMED_AWAY
            })
        if supported_features & SUPPORT_ALARM_ARM_NIGHT:
            conditions.append({
                **base_condition, CONF_TYPE:
                CONDITION_ARMED_NIGHT
            })
        if supported_features & SUPPORT_ALARM_ARM_VACATION:
            conditions.append({
                **base_condition, CONF_TYPE:
                CONDITION_ARMED_VACATION
            })
        if supported_features & SUPPORT_ALARM_ARM_CUSTOM_BYPASS:
            conditions.append({
                **base_condition, CONF_TYPE:
                CONDITION_ARMED_CUSTOM_BYPASS
            })

    return conditions
Ejemplo n.º 11
0
async def async_get_triggers(
    hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
    """List device triggers for Cover devices."""
    registry = entity_registry.async_get(hass)
    triggers = []

    # Get all the integrations entities for this device
    for entry in entity_registry.async_entries_for_device(registry, device_id):
        if entry.domain != DOMAIN:
            continue

        supported_features = get_supported_features(hass, entry.entity_id)
        supports_open_close = supported_features & (SUPPORT_OPEN | SUPPORT_CLOSE)

        # Add triggers for each entity that belongs to this integration
        base_trigger = {
            CONF_PLATFORM: "device",
            CONF_DEVICE_ID: device_id,
            CONF_DOMAIN: DOMAIN,
            CONF_ENTITY_ID: entry.entity_id,
        }

        if supports_open_close:
            triggers += [
                {
                    **base_trigger,
                    CONF_TYPE: trigger,
                }
                for trigger in STATE_TRIGGER_TYPES
            ]
        if supported_features & SUPPORT_SET_POSITION:
            triggers.append(
                {
                    **base_trigger,
                    CONF_TYPE: "position",
                }
            )
        if supported_features & SUPPORT_SET_TILT_POSITION:
            triggers.append(
                {
                    **base_trigger,
                    CONF_TYPE: "tilt_position",
                }
            )

    return triggers
Ejemplo n.º 12
0
async def async_get_triggers(hass: HomeAssistant,
                             device_id: str) -> list[dict[str, Any]]:
    """List device triggers for Alarm control panel devices."""
    registry = entity_registry.async_get(hass)
    triggers: list[dict[str, str]] = []

    # Get all the integrations entities for this device
    for entry in entity_registry.async_entries_for_device(registry, device_id):
        if entry.domain != DOMAIN:
            continue

        supported_features = get_supported_features(hass, entry.entity_id)

        # Add triggers for each entity that belongs to this integration
        base_trigger = {
            CONF_PLATFORM: "device",
            CONF_DEVICE_ID: device_id,
            CONF_DOMAIN: DOMAIN,
            CONF_ENTITY_ID: entry.entity_id,
        }

        triggers += [{
            **base_trigger,
            CONF_TYPE: trigger,
        } for trigger in BASIC_TRIGGER_TYPES]
        if supported_features & SUPPORT_ALARM_ARM_HOME:
            triggers.append({
                **base_trigger,
                CONF_TYPE: "armed_home",
            })
        if supported_features & SUPPORT_ALARM_ARM_AWAY:
            triggers.append({
                **base_trigger,
                CONF_TYPE: "armed_away",
            })
        if supported_features & SUPPORT_ALARM_ARM_NIGHT:
            triggers.append({
                **base_trigger,
                CONF_TYPE: "armed_night",
            })
        if supported_features & SUPPORT_ALARM_ARM_VACATION:
            triggers.append({
                **base_trigger,
                CONF_TYPE: "armed_vacation",
            })

    return triggers
Ejemplo n.º 13
0
async def async_get_actions(hass: HomeAssistant, device_id: str) -> list[dict]:
    """List device actions."""
    actions = await toggle_entity.async_get_actions(hass, device_id, DOMAIN)

    entity_registry = er.async_get(hass)

    for entry in er.async_entries_for_device(entity_registry, device_id):
        if entry.domain != DOMAIN:
            continue

        supported_color_modes = get_supported_color_modes(hass, entry.entity_id)
        supported_features = get_supported_features(hass, entry.entity_id)

        if brightness_supported(supported_color_modes):
            actions.extend(
                (
                    {
                        CONF_TYPE: TYPE_BRIGHTNESS_INCREASE,
                        "device_id": device_id,
                        "entity_id": entry.entity_id,
                        "domain": DOMAIN,
                    },
                    {
                        CONF_TYPE: TYPE_BRIGHTNESS_DECREASE,
                        "device_id": device_id,
                        "entity_id": entry.entity_id,
                        "domain": DOMAIN,
                    },
                )
            )

        if supported_features & SUPPORT_FLASH:
            actions.extend(
                (
                    {
                        CONF_TYPE: TYPE_FLASH,
                        "device_id": device_id,
                        "entity_id": entry.entity_id,
                        "domain": DOMAIN,
                    },
                )
            )

    return actions
async def async_get_action_capabilities(hass: HomeAssistant,
                                        config: dict) -> dict:
    """List action capabilities."""
    if config[CONF_TYPE] != toggle_entity.CONF_TURN_ON:
        return {}

    try:
        supported_features = get_supported_features(hass,
                                                    config[ATTR_ENTITY_ID])
    except HomeAssistantError:
        supported_features = 0

    extra_fields = {}

    if supported_features & SUPPORT_BRIGHTNESS:
        extra_fields[vol.Optional(ATTR_BRIGHTNESS_PCT)] = VALID_BRIGHTNESS_PCT

    if supported_features & SUPPORT_FLASH:
        extra_fields[vol.Optional(ATTR_FLASH)] = VALID_FLASH

    return {"extra_fields": vol.Schema(extra_fields)} if extra_fields else {}
Ejemplo n.º 15
0
async def async_get_actions(
    hass: HomeAssistant, device_id: str
) -> list[dict[str, str]]:
    """List device actions for Cover devices."""
    registry = entity_registry.async_get(hass)
    actions = []

    # Get all the integrations entities for this device
    for entry in entity_registry.async_entries_for_device(registry, device_id):
        if entry.domain != DOMAIN:
            continue

        supported_features = get_supported_features(hass, entry.entity_id)

        # Add actions for each entity that belongs to this integration
        base_action = {
            CONF_DEVICE_ID: device_id,
            CONF_DOMAIN: DOMAIN,
            CONF_ENTITY_ID: entry.entity_id,
        }

        if supported_features & SUPPORT_SET_POSITION:
            actions.append({**base_action, CONF_TYPE: "set_position"})
        else:
            if supported_features & SUPPORT_OPEN:
                actions.append({**base_action, CONF_TYPE: "open"})
            if supported_features & SUPPORT_CLOSE:
                actions.append({**base_action, CONF_TYPE: "close"})
            if supported_features & SUPPORT_STOP:
                actions.append({**base_action, CONF_TYPE: "stop"})

        if supported_features & SUPPORT_SET_TILT_POSITION:
            actions.append({**base_action, CONF_TYPE: "set_tilt_position"})
        else:
            if supported_features & SUPPORT_OPEN_TILT:
                actions.append({**base_action, CONF_TYPE: "open_tilt"})
            if supported_features & SUPPORT_CLOSE_TILT:
                actions.append({**base_action, CONF_TYPE: "close_tilt"})

    return actions
Ejemplo n.º 16
0
async def async_get_actions(hass: HomeAssistant, device_id: str) -> list[dict]:
    """List device actions for Humidifier devices."""
    registry = await entity_registry.async_get_registry(hass)
    actions = await toggle_entity.async_get_actions(hass, device_id, DOMAIN)

    # Get all the integrations entities for this device
    for entry in entity_registry.async_entries_for_device(registry, device_id):
        if entry.domain != DOMAIN:
            continue

        supported_features = get_supported_features(hass, entry.entity_id)

        base_action = {
            CONF_DEVICE_ID: device_id,
            CONF_DOMAIN: DOMAIN,
            CONF_ENTITY_ID: entry.entity_id,
        }
        actions.append({**base_action, CONF_TYPE: "set_humidity"})

        if supported_features & const.SUPPORT_MODES:
            actions.append({**base_action, CONF_TYPE: "set_mode"})

    return actions
Ejemplo n.º 17
0
async def test_get_supported_features_raises_on_unknown(hass):
    """Test get_supported_features raises on unknown entity_id."""
    with pytest.raises(HomeAssistantError):
        entity.get_supported_features(hass, "hello.world")
Ejemplo n.º 18
0
    async def _state_publisher(entity_id, old_state, new_state):
        if new_state is None:
            return

        if not publish_filter(entity_id):
            return

        mybase = f"{base_topic}{entity_id.replace('.', '/')}/"

        if publish_timestamps:
            if new_state.last_updated:
                await mqtt_publish(f"{mybase}last_updated",
                                   new_state.last_updated.isoformat(), 1, True)
            if new_state.last_changed:
                await mqtt_publish(f"{mybase}last_changed",
                                   new_state.last_changed.isoformat(), 1, True)

        if publish_attributes:
            for key, val in new_state.attributes.items():
                encoded_val = json.dumps(val, cls=JSONEncoder)
                await mqtt_publish(mybase + key, encoded_val, 1, True)

        ent_parts = entity_id.split(".")
        ent_domain = ent_parts[0]
        ent_id = ent_parts[1]

        if publish_discovery and not entity_id in hass.data[DOMAIN][
                base_topic]["conf_published"]:
            config = {
                "uniq_id": f"mqtt_{entity_id}",
                "name": ent_id.replace("_", " ").title(),
                "stat_t": f"{mybase}state",
                "json_attr_t": f"{mybase}attributes",
                "avty_t": f"{mybase}availability"
            }
            if ("device_class" in new_state.attributes):
                config["dev_cla"] = new_state.attributes["device_class"]
            if ("unit_of_measurement" in new_state.attributes):
                config["unit_of_meas"] = new_state.attributes[
                    "unit_of_measurement"]
            if ("state_class" in new_state.attributes):
                config["stat_cla"] = new_state.attributes["state_class"]

            publish_config = False
            if ent_domain == "sensor" and (has_includes or "device_class"
                                           in new_state.attributes):
                publish_config = True

            elif ent_domain == "binary_sensor" and (
                    has_includes or "device_class" in new_state.attributes):
                config["pl_off"] = STATE_OFF
                config["pl_on"] = STATE_ON
                publish_config = True

            elif ent_domain == "switch":
                config["pl_off"] = STATE_OFF
                config["pl_on"] = STATE_ON
                config["cmd_t"] = f"{mybase}set"
                publish_config = True

            elif ent_domain == "device_tracker":
                publish_config = True

            elif ent_domain == "light":
                del config["json_attr_t"]
                config["cmd_t"] = f"{mybase}set_light"
                config["schema"] = "json"

                supported_features = get_supported_features(hass, entity_id)
                if supported_features & SUPPORT_BRIGHTNESS:
                    config["brightness"] = True
                if supported_features & SUPPORT_EFFECT:
                    config["effect"] = True
                if "supported_color_modes" in new_state.attributes:
                    config["color_mode"] = True
                    config["supported_color_modes"] = new_state.attributes[
                        "supported_color_modes"]

                publish_config = True

            if publish_config:
                for entry in ent_reg.entities.values():
                    if entry.entity_id != entity_id:
                        continue
                    for device in dev_reg.devices.values():
                        if device.id != entry.device_id:
                            continue
                        config["dev"] = {}
                        if device.manufacturer:
                            config["dev"]["mf"] = device.manufacturer
                        if device.model:
                            config["dev"]["mdl"] = device.model
                        if device.name:
                            config["dev"]["name"] = device.name
                        if device.sw_version:
                            config["dev"]["sw"] = device.sw_version
                        if device.identifiers:
                            config["dev"]["ids"] = [
                                id[1] for id in device.identifiers
                            ]
                        if device.connections:
                            config["dev"]["cns"] = device.connections

                encoded = json.dumps(config, cls=JSONEncoder)
                await mqtt_publish(f"{mybase}config", encoded, 1, True)
                hass.data[DOMAIN][base_topic]["conf_published"].append(
                    entity_id)

        if publish_discovery:
            if ent_domain == "light":
                payload = {
                    "state": "ON" if new_state.state == STATE_ON else "OFF",
                }
                if ("brightness" in new_state.attributes):
                    payload["brightness"] = new_state.attributes["brightness"]
                if ("color_mode" in new_state.attributes):
                    payload["color_mode"] = new_state.attributes["color_mode"]
                if ("color_temp" in new_state.attributes):
                    payload["color_temp"] = new_state.attributes["color_temp"]
                if ("effect" in new_state.attributes):
                    payload["effect"] = new_state.attributes["effect"]

                color = {}
                if ("hs_color" in new_state.attributes):
                    color["h"] = new_state.attributes["hs_color"][0]
                    color["s"] = new_state.attributes["hs_color"][1]
                if ("xy_color" in new_state.attributes):
                    color["x"] = new_state.attributes["xy_color"][0]
                    color["x"] = new_state.attributes["xy_color"][1]
                if ("rgb_color" in new_state.attributes):
                    color["r"] = new_state.attributes["rgb_color"][0]
                    color["g"] = new_state.attributes["rgb_color"][1]
                    color["b"] = new_state.attributes["rgb_color"][2]
                if color:
                    payload["color"] = color

                await mqtt_publish(f"{mybase}state",
                                   json.dumps(payload, cls=JSONEncoder), 1,
                                   True)

                payload = "offline" if new_state.state in (STATE_UNAVAILABLE,
                                                           STATE_UNKNOWN,
                                                           None) else "online"
                await mqtt_publish(f"{mybase}availability", payload, 1, True)
            else:
                payload = new_state.state
                await mqtt_publish(f"{mybase}state", payload, 1, True)

                payload = "offline" if new_state.state in (STATE_UNAVAILABLE,
                                                           STATE_UNKNOWN,
                                                           None) else "online"
                await mqtt_publish(f"{mybase}availability", payload, 1, True)

                attributes = {}
                for key, val in new_state.attributes.items():
                    attributes[key] = val
                encoded = json.dumps(attributes, cls=JSONEncoder)
                await mqtt_publish(f"{mybase}attributes", encoded, 1, True)
        else:
            payload = new_state.state
            await mqtt_publish(f"{mybase}state", payload, 1, True)