mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 14:17:45 +00:00
Add descriptive fields to script config (#26056)
* Add descriptive fields to script config * Add script descriptions to hass.data["service_description_cache"] * Import SERVICE_DESCRIPTION_CACHE * Register script descriptions via async_set_service_schema * Add scripts test for loading and reloading service descriptions * Minor cleanup * Clean up script schema
This commit is contained in:
parent
9bcb48985b
commit
7090970436
@ -20,6 +20,7 @@ from homeassistant.helpers.entity import ToggleEntity
|
|||||||
from homeassistant.helpers.entity_component import EntityComponent
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA
|
from homeassistant.helpers.config_validation import ENTITY_SERVICE_SCHEMA
|
||||||
|
from homeassistant.helpers.service import async_set_service_schema
|
||||||
|
|
||||||
from homeassistant.helpers.script import Script
|
from homeassistant.helpers.script import Script
|
||||||
|
|
||||||
@ -31,6 +32,9 @@ ATTR_LAST_ACTION = "last_action"
|
|||||||
ATTR_LAST_TRIGGERED = "last_triggered"
|
ATTR_LAST_TRIGGERED = "last_triggered"
|
||||||
ATTR_VARIABLES = "variables"
|
ATTR_VARIABLES = "variables"
|
||||||
|
|
||||||
|
CONF_DESCRIPTION = "description"
|
||||||
|
CONF_EXAMPLE = "example"
|
||||||
|
CONF_FIELDS = "fields"
|
||||||
CONF_SEQUENCE = "sequence"
|
CONF_SEQUENCE = "sequence"
|
||||||
|
|
||||||
ENTITY_ID_FORMAT = DOMAIN + ".{}"
|
ENTITY_ID_FORMAT = DOMAIN + ".{}"
|
||||||
@ -38,7 +42,17 @@ ENTITY_ID_FORMAT = DOMAIN + ".{}"
|
|||||||
GROUP_NAME_ALL_SCRIPTS = "all scripts"
|
GROUP_NAME_ALL_SCRIPTS = "all scripts"
|
||||||
|
|
||||||
SCRIPT_ENTRY_SCHEMA = vol.Schema(
|
SCRIPT_ENTRY_SCHEMA = vol.Schema(
|
||||||
{CONF_ALIAS: cv.string, vol.Required(CONF_SEQUENCE): cv.SCRIPT_SCHEMA}
|
{
|
||||||
|
CONF_ALIAS: cv.string,
|
||||||
|
vol.Required(CONF_SEQUENCE): cv.SCRIPT_SCHEMA,
|
||||||
|
vol.Optional(CONF_DESCRIPTION, default=""): cv.string,
|
||||||
|
vol.Optional(CONF_FIELDS, default={}): {
|
||||||
|
cv.string: {
|
||||||
|
vol.Optional(CONF_DESCRIPTION): cv.string,
|
||||||
|
vol.Optional(CONF_EXAMPLE): cv.string,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema(
|
CONFIG_SCHEMA = vol.Schema(
|
||||||
@ -137,6 +151,13 @@ async def _async_process_config(hass, config, component):
|
|||||||
DOMAIN, object_id, service_handler, schema=SCRIPT_SERVICE_SCHEMA
|
DOMAIN, object_id, service_handler, schema=SCRIPT_SERVICE_SCHEMA
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Register the service description
|
||||||
|
service_desc = {
|
||||||
|
CONF_DESCRIPTION: cfg[CONF_DESCRIPTION],
|
||||||
|
CONF_FIELDS: cfg[CONF_FIELDS],
|
||||||
|
}
|
||||||
|
async_set_service_schema(hass, DOMAIN, object_id, service_desc)
|
||||||
|
|
||||||
await component.async_add_entities(scripts)
|
await component.async_add_entities(scripts)
|
||||||
|
|
||||||
|
|
||||||
|
@ -231,6 +231,20 @@ async def async_get_all_descriptions(hass):
|
|||||||
return descriptions
|
return descriptions
|
||||||
|
|
||||||
|
|
||||||
|
@ha.callback
|
||||||
|
@bind_hass
|
||||||
|
def async_set_service_schema(hass, domain, service, schema):
|
||||||
|
"""Register a description for a service."""
|
||||||
|
hass.data.setdefault(SERVICE_DESCRIPTION_CACHE, {})
|
||||||
|
|
||||||
|
description = {
|
||||||
|
"description": schema.get("description") or "",
|
||||||
|
"fields": schema.get("fields") or {},
|
||||||
|
}
|
||||||
|
|
||||||
|
hass.data[SERVICE_DESCRIPTION_CACHE]["{}.{}".format(domain, service)] = description
|
||||||
|
|
||||||
|
|
||||||
@bind_hass
|
@bind_hass
|
||||||
async def entity_service_call(
|
async def entity_service_call(
|
||||||
hass, platforms, func, call, service_name="", required_features=None
|
hass, platforms, func, call, service_name="", required_features=None
|
||||||
|
@ -17,6 +17,7 @@ from homeassistant.const import (
|
|||||||
EVENT_SCRIPT_STARTED,
|
EVENT_SCRIPT_STARTED,
|
||||||
)
|
)
|
||||||
from homeassistant.core import Context, callback, split_entity_id
|
from homeassistant.core import Context, callback, split_entity_id
|
||||||
|
from homeassistant.helpers.service import async_get_all_descriptions
|
||||||
from homeassistant.loader import bind_hass
|
from homeassistant.loader import bind_hass
|
||||||
from homeassistant.setup import setup_component, async_setup_component
|
from homeassistant.setup import setup_component, async_setup_component
|
||||||
from homeassistant.exceptions import ServiceNotFound
|
from homeassistant.exceptions import ServiceNotFound
|
||||||
@ -244,6 +245,61 @@ class TestScriptComponent(unittest.TestCase):
|
|||||||
assert self.hass.services.has_service(script.DOMAIN, "test2")
|
assert self.hass.services.has_service(script.DOMAIN, "test2")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_service_descriptions(hass):
|
||||||
|
"""Test that service descriptions are loaded and reloaded correctly."""
|
||||||
|
# Test 1: has "description" but no "fields"
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"script",
|
||||||
|
{
|
||||||
|
"script": {
|
||||||
|
"test": {
|
||||||
|
"description": "test description",
|
||||||
|
"sequence": [{"delay": {"seconds": 5}}],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
descriptions = await async_get_all_descriptions(hass)
|
||||||
|
|
||||||
|
assert descriptions[DOMAIN]["test"]["description"] == "test description"
|
||||||
|
assert not descriptions[DOMAIN]["test"]["fields"]
|
||||||
|
|
||||||
|
# Test 2: has "fields" but no "description"
|
||||||
|
await hass.services.async_call(DOMAIN, SERVICE_RELOAD, blocking=True)
|
||||||
|
with patch(
|
||||||
|
"homeassistant.config.load_yaml_config_file",
|
||||||
|
return_value={
|
||||||
|
"script": {
|
||||||
|
"test": {
|
||||||
|
"fields": {
|
||||||
|
"test_param": {
|
||||||
|
"description": "test_param description",
|
||||||
|
"example": "test_param example",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sequence": [{"delay": {"seconds": 5}}],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
):
|
||||||
|
with patch("homeassistant.config.find_config_file", return_value=""):
|
||||||
|
await hass.services.async_call(DOMAIN, SERVICE_RELOAD, blocking=True)
|
||||||
|
|
||||||
|
descriptions = await async_get_all_descriptions(hass)
|
||||||
|
|
||||||
|
assert descriptions[script.DOMAIN]["test"]["description"] == ""
|
||||||
|
assert (
|
||||||
|
descriptions[script.DOMAIN]["test"]["fields"]["test_param"]["description"]
|
||||||
|
== "test_param description"
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
descriptions[script.DOMAIN]["test"]["fields"]["test_param"]["example"]
|
||||||
|
== "test_param example"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_shared_context(hass):
|
async def test_shared_context(hass):
|
||||||
"""Test that the shared context is passed down the chain."""
|
"""Test that the shared context is passed down the chain."""
|
||||||
event = "test_event"
|
event = "test_event"
|
||||||
@ -306,3 +362,39 @@ async def test_turning_no_scripts_off(hass):
|
|||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN, SERVICE_TURN_OFF, {"entity_id": []}, blocking=True
|
DOMAIN, SERVICE_TURN_OFF, {"entity_id": []}, blocking=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_get_descriptions_script(hass):
|
||||||
|
"""Test async_set_service_schema for the script integration."""
|
||||||
|
script = hass.components.script
|
||||||
|
script_config = {
|
||||||
|
script.DOMAIN: {
|
||||||
|
"test1": {"sequence": [{"service": "homeassistant.restart"}]},
|
||||||
|
"test2": {
|
||||||
|
"description": "test2",
|
||||||
|
"fields": {
|
||||||
|
"param": {
|
||||||
|
"description": "param_description",
|
||||||
|
"example": "param_example",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sequence": [{"service": "homeassistant.restart"}],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await async_setup_component(hass, script.DOMAIN, script_config)
|
||||||
|
descriptions = await hass.helpers.service.async_get_all_descriptions()
|
||||||
|
|
||||||
|
assert descriptions[script.DOMAIN]["test1"]["description"] == ""
|
||||||
|
assert not descriptions[script.DOMAIN]["test1"]["fields"]
|
||||||
|
|
||||||
|
assert descriptions[script.DOMAIN]["test2"]["description"] == "test2"
|
||||||
|
assert (
|
||||||
|
descriptions[script.DOMAIN]["test2"]["fields"]["param"]["description"]
|
||||||
|
== "param_description"
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
descriptions[script.DOMAIN]["test2"]["fields"]["param"]["example"]
|
||||||
|
== "param_example"
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user