八 Home Assistant 集成服务操作

集成服务操作

Home Assistant为许多事情提供了现成的操作,但它并不总是涵盖所有内容。与其尝试更改Home Assistant,不如先将其作为服务操作添加到您自己的集成中。一旦我们在这些服务操作中看到一种模式,我们就可以讨论将它们通用化。

这是一个简单的“hello world”示例,用于展示注册服务操作的基础知识。要使用此示例,请创建文件<config dir>/custom_components/hello_action/__init__.py并复制以下示例代码。

操作可以从自动化以及前端的“开发者工具”中的操作中调用。

DOMAIN = "hello_action"
ATTR_NAME = "name"
DEFAULT_NAME = "World"

def setup(hass, config):
    """当Home Assistant加载我们的组件时调用setup。"""
    def handle_hello(call):
        """处理服务操作调用。"""
        name = call.data.get(ATTR_NAME, DEFAULT_NAME)
        hass.states.set("hello_action.hello", name)

    hass.services.register(DOMAIN, "hello", handle_hello)
    # 返回布尔值以指示初始化成功。
    return True

要在Home Assistant中加载集成,需要创建一个manifest.json并在configuration.yaml中添加一个条目。当您的组件加载时,应该可以调用一个新服务。

configuration.yaml条目

hello_action:

manifest.json示例

{
    "domain": "hello_action",
    "name": "Hello Action",
    "documentation": "https://developers.home-assistant.io/docs/dev_101_services",
    "iot_class": "local_push",
    "version": "0.1.0"
}

打开前端,在侧边栏中,点击开发者工具部分的第一个图标。这将打开操作开发者工具。在右侧,找到您的操作并点击它。这将自动填充正确的值。

按下“执行操作”现在将在没有任何参数的情况下调用您的服务操作。这将导致您的服务操作创建一个状态,默认名称为“World”。如果您想指定名称,必须通过服务操作数据提供参数来指定。在YAML模式下,添加以下内容并再次按下“执行服务”。

service: hello_action.hello
data:
  name: Planet

服务操作现在将用“Planet”覆盖之前的状态。

服务操作描述

添加操作只有在用户知道它们的情况下才有用。在Home Assistant中,我们使用services.yaml作为集成的一部分来描述服务操作。

操作在您的集成的域名下发布,所以在services.yaml中我们只使用服务操作名称作为基本键。

服务操作描述示例

# 示例services.yaml条目
# 服务ID
set_speed:
  # 如果服务操作接受实体ID,target允许用户通过实体、设备或区域指定实体。如果指定了`target`,则不应在`fields`映射中定义`entity_id`。默认情况下,它仅显示与操作来自同一域的实体匹配的目标,但如果需要进一步定制,target支持实体、设备和区域选择器(https://www.home-assistant.io/docs/blueprint/selectors/)。
  # 实体选择器参数将自动应用于设备和区域,设备选择器参数将自动应用于区域。
  target:
    entity:
      domain: fan
      # 如果操作域中的并非所有实体都支持某个操作,可以通过`supported_features`状态属性进一步过滤实体。只有支持至少一个列出的支持功能的实体才能被选择。
      supported_features:
        - fan.FanEntityFeature.SET_SPEED
        # 如果服务操作需要多个支持功能,该项应作为所需支持功能的列表给出。例如,如果服务操作需要SET_SPEED和OSCILLATE,则应如下表示
        - - fan.FanEntityFeature.SET_SPEED
          - fan.FanEntityFeature.OSCILLATE
  # 您的服务操作接受的不同字段
  fields:
    # 字段的键
    speed:
      # 字段是否必填(默认 = false)
      required: true
      # 高级字段仅在用户启用高级模式时显示(默认 = false)
      advanced: true
      # 可以为此字段传递的示例值
      example: "low"
      # 字段的默认值
      default: "high"
      # 选择器(https://www.home-assistant.io/docs/blueprint/selectors/),用于控制此字段的输入UI
      selector:
        select:
          translation_key: "fan_speed"
          options:
            - "off"
            - "low"
            - "medium"
            - "high"
    # 字段可以分组在可折叠部分中,这对于最初隐藏高级字段和对相关字段进行分组很有用。请注意,可折叠部分仅影响向用户的呈现,服务操作数据不会嵌套。
    advanced_fields:
      # 该部分最初是否折叠(默认 = false)
      collapsed: true
      # 此部分中的输入字段
      fields:
        speed_pct:
          selector:
            number:
              min: 0
              max: 100

服务操作的名称和描述在我们的翻译中设置,而不是在服务操作描述中。每个服务操作和服务操作字段必须有匹配的翻译定义。

服务操作字段分组

输入字段可以在视觉上分组到各个部分。按部分对输入字段进行分组仅影响向用户显示输入的方式,而不影响服务操作数据的结构。

在服务操作描述示例中,speed_pct输入字段在最初折叠的部分advanced_fields中。示例中服务的服务操作数据是{"speed_pct": 50},而不是{"advanced_fields": {"speed_pct": 50}}

过滤服务操作字段

在某些情况下,来自操作域的实体可能不支持所有服务操作字段。通过为字段描述提供filter,只有当至少一个选定实体根据配置的过滤器支持该字段时,才会显示该字段。

过滤器必须指定supported_featuresattribute,不支持同时组合两者。

supported_features过滤器由支持功能列表指定。如果至少一个选定实体支持列出的至少一个功能,则显示该字段。

attribute过滤器将一个属性与一个值列表组合。如果至少一个选定实体的属性设置为列出的属性状态之一,则显示该字段。如果属性状态是一个列表,则如果选定实体的属性状态中的至少一个项目设置为列出的属性状态之一,则显示该字段。

这是一个仅当至少一个选定实体支持ClimateEntityFeature.TARGET_TEMPERATURE时才显示的字段的部分示例:

fields:
    temperature:
      name: Temperature
      description: New target temperature for HVAC.
      filter:
        supported_features:
          - climate.ClimateEntityFeature.TARGET_TEMPERATURE

这是一个仅当至少一个选定实体的supported_color_modes属性包括light.ColorMode.COLOR_TEMPlight.ColorMode.HS时才显示的字段的部分示例:

color_temp:
      name: Color temperature
      description: Color temperature for the light in mireds.
      filter:
        attribute:
          supported_color_modes:
            - light.ColorMode.COLOR_TEMP
            - light.ColorMode.HS

图标

操作也可以有图标。这些图标在Home Assistant UI中用于在自动化和脚本编辑器等地方显示服务操作。

每个服务操作要使用的图标可以在集成文件夹中的icons.json翻译文件中定义,在services键下。键应该是服务操作名称,值应该是要使用的图标。

以下示例展示了如何为一个集成的turn_onturn_off服务操作提供图标:

{
  "services": {
    "turn_on": {"service": "mdi:lightbulb-on"},
    "turn_off": {"service": "mdi:lightbulb-off"}
  }
}

此外,可以为可折叠部分可选地指定图标。

以下示例展示了如何为advanced_options部分提供图标:

{
  "services": {
    "start_brewing": {
      "service": "mdi:flask",
      "sections": {
        "advanced_options": "mdi:test-tube"
      }
    }
  }
}

实体服务操作

有时您想提供额外的操作来控制您的实体。例如,Sonos集成提供了分组和取消分组设备的操作。实体服务操作很特殊,因为用户可以有很多不同的方式指定实体。它可以使用区域、一个组或实体列表。

您需要在您的平台中注册实体服务操作,例如<your-domain>/media_player.py。这些服务操作将在您的域下可用,而不是在平台域(例如媒体播放器域)下。如果实体服务操作有字段,可以将一个模式传递给async_register_entity_service。模式必须是以下之一:

  • 一个字典,它将自动传递给cv._make_entity_service_schema
  • cv._make_entity_service_schema返回的验证器
  • cv._make_entity_service_schema返回的验证器,包装在vol.Schema
  • cv._make_entity_service_schema返回的验证器,包装在vol.All

示例代码:

from homeassistant.helpers import config_validation as cv, entity_platform, service

async def async_setup_entry(hass, entry):
    """设置Sonos的媒体播放器平台。"""
    platform = entity_platform.async_get_current_platform()
    # 这将调用Entity.set_sleep_timer(sleep_time=VALUE)
    platform.async_register_entity_service(
        SERVICE_SET_TIMER,
        {
            vol.Required('sleep_time'): cv.time_period,
        },
        "set_sleep_timer",
    )

如果您需要对服务操作调用有更多控制,也可以传递一个异步函数,该函数将代替"set_sleep_timer"被调用:

async def custom_set_sleep_timer(entity, service_call):
    await entity.set_sleep_timer(service_call.data['sleep_time'])

响应数据

操作可能会用数据响应操作调用,以支持更高级的自动化。有一些额外的实现要求:

  • 响应数据必须是一个dict,并且可以序列化为JSON homeassistant.util.json.JsonObjectType,以便与系统的其他部分(如前端)进行交互。
  • 错误必须像任何其他服务操作调用一样作为异常抛出,因为我们不希望最终用户在脚本和自动化中需要复杂的错误处理。响应数据不应包含用于错误处理的错误代码。

示例代码:

import datetime
import voluptuous as vol
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, ServiceCall, ServiceResponse, SupportsResponse
from homeassistant.helpers import config_validation as cv, entity_platform, service
from homeassistant.util.json import JsonObjectType

SEARCH_ITEMS_SERVICE_NAME = "search_items"
SEARCH_ITEMS_SCHEMA = vol.Schema({
    vol.Required("start"): datetime.datetime,
    vol.Required("end"): datetime.datetime,
})

async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """设置平台。"""
    async def search_items(call: ServiceCall) -> ServiceResponse:
        """在日期范围内搜索并返回匹配的项目。"""
        items = await my_client.search(call.data["start"], call.data["end"])
        return {
            "items": [
                {
                    "summary": item["summary"],
                    "description": item["description"],
                } for item in items
            ],
        }

    hass.services.async_register(
        DOMAIN,
        SEARCH_ITEMS_SERVICE_NAME,
        search_items,
        schema=SEARCH_ITEMS_SCHEMA,
        supports_response=SupportsResponse.ONLY,
    )

响应数据的使用适用于不适合Home Assistant状态的情况。例如,对象的响应流。相反,响应数据不应在适合实体状态的情况下使用。例如,温度值应该只是一个传感器。

支持响应数据

操作调用注册时带有SupportsResponse值,以指示支持响应数据。

描述
OPTIONAL执行操作并可以可选地返回响应数据。服务操作应该有条件地检查ServiceCall属性return_response,以决定是否应该返回响应数据,或者None
ONLY不执行任何操作,总是返回响应数据。

总结

此页面主要介绍了Home Assistant中的集成服务操作相关内容,包括如何注册一个简单的服务操作(如“hello world”示例),通过创建特定文件和在配置文件中添加条目来加载集成,使用services.yaml描述服务操作(包括操作的各种属性、字段、分组、过滤以及图标等),实体服务操作的注册方式,以及操作的响应数据相关要求(包括如何返回响应数据、响应数据的适用场景以及如何在注册操作时表明对响应数据的支持方式等)。这些内容有助于开发者在Home Assistant中创建和定制自己的服务操作,以满足不同的自动化和控制需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值