Add mode info attributes to script and automation (#37815)
Co-authored-by: J. Nick Koston <nick@koston.org>pull/37853/head
parent
ac0dbb17af
commit
7d77fa92c2
|
@ -590,9 +590,8 @@ class ScriptCapabilities(AlexaEntity):
|
||||||
|
|
||||||
def interfaces(self):
|
def interfaces(self):
|
||||||
"""Yield the supported interfaces."""
|
"""Yield the supported interfaces."""
|
||||||
can_cancel = bool(self.entity.attributes.get("can_cancel"))
|
|
||||||
return [
|
return [
|
||||||
AlexaSceneController(self.entity, supports_deactivation=can_cancel),
|
AlexaSceneController(self.entity, supports_deactivation=True),
|
||||||
Alexa(self.hass),
|
Alexa(self.hass),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,9 @@ from homeassistant.helpers.entity import ToggleEntity
|
||||||
from homeassistant.helpers.entity_component import EntityComponent
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
from homeassistant.helpers.restore_state import RestoreEntity
|
from homeassistant.helpers.restore_state import RestoreEntity
|
||||||
from homeassistant.helpers.script import (
|
from homeassistant.helpers.script import (
|
||||||
|
ATTR_CUR,
|
||||||
|
ATTR_MAX,
|
||||||
|
ATTR_MODE,
|
||||||
CONF_MAX,
|
CONF_MAX,
|
||||||
SCRIPT_MODE_PARALLEL,
|
SCRIPT_MODE_PARALLEL,
|
||||||
Script,
|
Script,
|
||||||
|
@ -276,7 +279,15 @@ class AutomationEntity(ToggleEntity, RestoreEntity):
|
||||||
@property
|
@property
|
||||||
def state_attributes(self):
|
def state_attributes(self):
|
||||||
"""Return the entity state attributes."""
|
"""Return the entity state attributes."""
|
||||||
return {ATTR_LAST_TRIGGERED: self._last_triggered}
|
attrs = {
|
||||||
|
ATTR_LAST_TRIGGERED: self._last_triggered,
|
||||||
|
ATTR_MODE: self.action_script.script_mode,
|
||||||
|
}
|
||||||
|
if self.action_script.supports_max:
|
||||||
|
attrs[ATTR_MAX] = self.action_script.max_runs
|
||||||
|
if self.is_on:
|
||||||
|
attrs[ATTR_CUR] = self.action_script.runs
|
||||||
|
return attrs
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
def is_on(self) -> bool:
|
||||||
|
|
|
@ -9,7 +9,6 @@ from pyhap.const import (
|
||||||
CATEGORY_SWITCH,
|
CATEGORY_SWITCH,
|
||||||
)
|
)
|
||||||
|
|
||||||
from homeassistant.components.script import ATTR_CAN_CANCEL
|
|
||||||
from homeassistant.components.switch import DOMAIN
|
from homeassistant.components.switch import DOMAIN
|
||||||
from homeassistant.components.vacuum import (
|
from homeassistant.components.vacuum import (
|
||||||
DOMAIN as VACUUM_DOMAIN,
|
DOMAIN as VACUUM_DOMAIN,
|
||||||
|
@ -111,11 +110,8 @@ class Switch(HomeAccessory):
|
||||||
|
|
||||||
def is_activate(self, state):
|
def is_activate(self, state):
|
||||||
"""Check if entity is activate only."""
|
"""Check if entity is activate only."""
|
||||||
can_cancel = state.attributes.get(ATTR_CAN_CANCEL)
|
|
||||||
if self._domain == "scene":
|
if self._domain == "scene":
|
||||||
return True
|
return True
|
||||||
if self._domain == "script" and not can_cancel:
|
|
||||||
return True
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def reset_switch(self, *args):
|
def reset_switch(self, *args):
|
||||||
|
|
|
@ -24,6 +24,9 @@ from homeassistant.helpers.config_validation import make_entity_service_schema
|
||||||
from homeassistant.helpers.entity import ToggleEntity
|
from homeassistant.helpers.entity import ToggleEntity
|
||||||
from homeassistant.helpers.entity_component import EntityComponent
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
from homeassistant.helpers.script import (
|
from homeassistant.helpers.script import (
|
||||||
|
ATTR_CUR,
|
||||||
|
ATTR_MAX,
|
||||||
|
ATTR_MODE,
|
||||||
CONF_MAX,
|
CONF_MAX,
|
||||||
SCRIPT_MODE_SINGLE,
|
SCRIPT_MODE_SINGLE,
|
||||||
Script,
|
Script,
|
||||||
|
@ -35,7 +38,7 @@ from homeassistant.loader import bind_hass
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DOMAIN = "script"
|
DOMAIN = "script"
|
||||||
ATTR_CAN_CANCEL = "can_cancel"
|
|
||||||
ATTR_LAST_ACTION = "last_action"
|
ATTR_LAST_ACTION = "last_action"
|
||||||
ATTR_LAST_TRIGGERED = "last_triggered"
|
ATTR_LAST_TRIGGERED = "last_triggered"
|
||||||
ATTR_VARIABLES = "variables"
|
ATTR_VARIABLES = "variables"
|
||||||
|
@ -272,9 +275,14 @@ class ScriptEntity(ToggleEntity):
|
||||||
@property
|
@property
|
||||||
def state_attributes(self):
|
def state_attributes(self):
|
||||||
"""Return the state attributes."""
|
"""Return the state attributes."""
|
||||||
attrs = {ATTR_LAST_TRIGGERED: self.script.last_triggered}
|
attrs = {
|
||||||
if self.script.can_cancel:
|
ATTR_LAST_TRIGGERED: self.script.last_triggered,
|
||||||
attrs[ATTR_CAN_CANCEL] = self.script.can_cancel
|
ATTR_MODE: self.script.script_mode,
|
||||||
|
}
|
||||||
|
if self.script.supports_max:
|
||||||
|
attrs[ATTR_MAX] = self.script.max_runs
|
||||||
|
if self.is_on:
|
||||||
|
attrs[ATTR_CUR] = self.script.runs
|
||||||
if self.script.last_action:
|
if self.script.last_action:
|
||||||
attrs[ATTR_LAST_ACTION] = self.script.last_action
|
attrs[ATTR_LAST_ACTION] = self.script.last_action
|
||||||
return attrs
|
return attrs
|
||||||
|
|
|
@ -69,6 +69,10 @@ DEFAULT_SCRIPT_MODE = SCRIPT_MODE_SINGLE
|
||||||
CONF_MAX = "max"
|
CONF_MAX = "max"
|
||||||
DEFAULT_MAX = 10
|
DEFAULT_MAX = 10
|
||||||
|
|
||||||
|
ATTR_CUR = "current"
|
||||||
|
ATTR_MAX = "max"
|
||||||
|
ATTR_MODE = "mode"
|
||||||
|
|
||||||
_LOG_EXCEPTION = logging.ERROR + 1
|
_LOG_EXCEPTION = logging.ERROR + 1
|
||||||
_TIMEOUT_MSG = "Timeout reached, abort script."
|
_TIMEOUT_MSG = "Timeout reached, abort script."
|
||||||
|
|
||||||
|
@ -561,7 +565,7 @@ class Script:
|
||||||
template.attach(hass, self.sequence)
|
template.attach(hass, self.sequence)
|
||||||
self.name = name
|
self.name = name
|
||||||
self.change_listener = change_listener
|
self.change_listener = change_listener
|
||||||
self._script_mode = script_mode
|
self.script_mode = script_mode
|
||||||
if logger:
|
if logger:
|
||||||
self._logger = logger
|
self._logger = logger
|
||||||
else:
|
else:
|
||||||
|
@ -573,10 +577,9 @@ class Script:
|
||||||
|
|
||||||
self.last_action = None
|
self.last_action = None
|
||||||
self.last_triggered: Optional[datetime] = None
|
self.last_triggered: Optional[datetime] = None
|
||||||
self.can_cancel = True
|
|
||||||
|
|
||||||
self._runs: List[_ScriptRun] = []
|
self._runs: List[_ScriptRun] = []
|
||||||
self._max_runs = max_runs
|
self.max_runs = max_runs
|
||||||
if script_mode == SCRIPT_MODE_QUEUED:
|
if script_mode == SCRIPT_MODE_QUEUED:
|
||||||
self._queue_lck = asyncio.Lock()
|
self._queue_lck = asyncio.Lock()
|
||||||
self._config_cache: Dict[Set[Tuple], Callable[..., bool]] = {}
|
self._config_cache: Dict[Set[Tuple], Callable[..., bool]] = {}
|
||||||
|
@ -601,6 +604,16 @@ class Script:
|
||||||
"""Return true if script is on."""
|
"""Return true if script is on."""
|
||||||
return len(self._runs) > 0
|
return len(self._runs) > 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def runs(self) -> int:
|
||||||
|
"""Return the number of current runs."""
|
||||||
|
return len(self._runs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def supports_max(self) -> bool:
|
||||||
|
"""Return true if the current mode support max."""
|
||||||
|
return self.script_mode in (SCRIPT_MODE_PARALLEL, SCRIPT_MODE_QUEUED)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def referenced_devices(self):
|
def referenced_devices(self):
|
||||||
"""Return a set of referenced devices."""
|
"""Return a set of referenced devices."""
|
||||||
|
@ -668,17 +681,17 @@ class Script:
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Run script."""
|
"""Run script."""
|
||||||
if self.is_running:
|
if self.is_running:
|
||||||
if self._script_mode == SCRIPT_MODE_SINGLE:
|
if self.script_mode == SCRIPT_MODE_SINGLE:
|
||||||
self._log("Already running", level=logging.WARNING)
|
self._log("Already running", level=logging.WARNING)
|
||||||
return
|
return
|
||||||
if self._script_mode == SCRIPT_MODE_RESTART:
|
if self.script_mode == SCRIPT_MODE_RESTART:
|
||||||
self._log("Restarting")
|
self._log("Restarting")
|
||||||
await self.async_stop(update_state=False)
|
await self.async_stop(update_state=False)
|
||||||
elif len(self._runs) == self._max_runs:
|
elif len(self._runs) == self.max_runs:
|
||||||
self._log("Maximum number of runs exceeded", level=logging.WARNING)
|
self._log("Maximum number of runs exceeded", level=logging.WARNING)
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._script_mode != SCRIPT_MODE_QUEUED:
|
if self.script_mode != SCRIPT_MODE_QUEUED:
|
||||||
cls = _ScriptRun
|
cls = _ScriptRun
|
||||||
else:
|
else:
|
||||||
cls = _QueuedScriptRun
|
cls = _QueuedScriptRun
|
||||||
|
|
|
@ -306,25 +306,6 @@ async def test_script(hass):
|
||||||
assert appliance["displayCategories"][0] == "ACTIVITY_TRIGGER"
|
assert appliance["displayCategories"][0] == "ACTIVITY_TRIGGER"
|
||||||
assert appliance["friendlyName"] == "Test script"
|
assert appliance["friendlyName"] == "Test script"
|
||||||
|
|
||||||
capabilities = assert_endpoint_capabilities(
|
|
||||||
appliance, "Alexa.SceneController", "Alexa"
|
|
||||||
)
|
|
||||||
scene_capability = get_capability(capabilities, "Alexa.SceneController")
|
|
||||||
assert not scene_capability["supportsDeactivation"]
|
|
||||||
|
|
||||||
await assert_scene_controller_works("script#test", "script.turn_on", None, hass)
|
|
||||||
|
|
||||||
|
|
||||||
async def test_cancelable_script(hass):
|
|
||||||
"""Test cancalable script discovery."""
|
|
||||||
device = (
|
|
||||||
"script.test_2",
|
|
||||||
"off",
|
|
||||||
{"friendly_name": "Test script 2", "can_cancel": True},
|
|
||||||
)
|
|
||||||
appliance = await discovery_test(device, hass)
|
|
||||||
|
|
||||||
assert appliance["endpointId"] == "script#test_2"
|
|
||||||
capabilities = assert_endpoint_capabilities(
|
capabilities = assert_endpoint_capabilities(
|
||||||
appliance, "Alexa.SceneController", "Alexa"
|
appliance, "Alexa.SceneController", "Alexa"
|
||||||
)
|
)
|
||||||
|
@ -332,7 +313,7 @@ async def test_cancelable_script(hass):
|
||||||
assert scene_capability["supportsDeactivation"]
|
assert scene_capability["supportsDeactivation"]
|
||||||
|
|
||||||
await assert_scene_controller_works(
|
await assert_scene_controller_works(
|
||||||
"script#test_2", "script.turn_on", "script.turn_off", hass
|
"script#test", "script.turn_on", "script.turn_off", hass
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ from homeassistant.components.homekit.type_switches import (
|
||||||
Switch,
|
Switch,
|
||||||
Valve,
|
Valve,
|
||||||
)
|
)
|
||||||
from homeassistant.components.script import ATTR_CAN_CANCEL
|
|
||||||
from homeassistant.components.vacuum import (
|
from homeassistant.components.vacuum import (
|
||||||
DOMAIN as VACUUM_DOMAIN,
|
DOMAIN as VACUUM_DOMAIN,
|
||||||
SERVICE_RETURN_TO_BASE,
|
SERVICE_RETURN_TO_BASE,
|
||||||
|
@ -80,7 +79,7 @@ async def test_outlet_set_state(hass, hk_driver, events):
|
||||||
("automation.test", {}),
|
("automation.test", {}),
|
||||||
("input_boolean.test", {}),
|
("input_boolean.test", {}),
|
||||||
("remote.test", {}),
|
("remote.test", {}),
|
||||||
("script.test", {ATTR_CAN_CANCEL: True}),
|
("script.test", {}),
|
||||||
("switch.test", {}),
|
("switch.test", {}),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -240,19 +239,12 @@ async def test_vacuum_set_state(hass, hk_driver, events):
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
async def test_reset_switch(hass, hk_driver, events):
|
||||||
"entity_id, attrs",
|
|
||||||
[
|
|
||||||
("scene.test", {}),
|
|
||||||
("script.test", {}),
|
|
||||||
("script.test", {ATTR_CAN_CANCEL: False}),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
async def test_reset_switch(hass, hk_driver, entity_id, attrs, events):
|
|
||||||
"""Test if switch accessory is reset correctly."""
|
"""Test if switch accessory is reset correctly."""
|
||||||
domain = split_entity_id(entity_id)[0]
|
domain = "scene"
|
||||||
|
entity_id = "scene.test"
|
||||||
|
|
||||||
hass.states.async_set(entity_id, None, attrs)
|
hass.states.async_set(entity_id, None)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc = Switch(hass, hk_driver, "Switch", entity_id, 2, None)
|
acc = Switch(hass, hk_driver, "Switch", entity_id, 2, None)
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
|
@ -295,12 +287,8 @@ async def test_reset_switch_reload(hass, hk_driver, events):
|
||||||
await acc.run_handler()
|
await acc.run_handler()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert acc.activate_only is True
|
|
||||||
|
|
||||||
hass.states.async_set(entity_id, None, {ATTR_CAN_CANCEL: True})
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
assert acc.activate_only is False
|
assert acc.activate_only is False
|
||||||
|
|
||||||
hass.states.async_set(entity_id, None, {ATTR_CAN_CANCEL: False})
|
hass.states.async_set(entity_id, None)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert acc.activate_only is True
|
assert acc.char_on.value is False
|
||||||
|
|
|
@ -93,15 +93,12 @@ async def test_firing_event_basic(hass):
|
||||||
sequence = cv.SCRIPT_SCHEMA({"event": event, "event_data": {"hello": "world"}})
|
sequence = cv.SCRIPT_SCHEMA({"event": event, "event_data": {"hello": "world"}})
|
||||||
script_obj = script.Script(hass, sequence)
|
script_obj = script.Script(hass, sequence)
|
||||||
|
|
||||||
assert script_obj.can_cancel
|
|
||||||
|
|
||||||
await script_obj.async_run(context=context)
|
await script_obj.async_run(context=context)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
assert events[0].context is context
|
assert events[0].context is context
|
||||||
assert events[0].data.get("hello") == "world"
|
assert events[0].data.get("hello") == "world"
|
||||||
assert script_obj.can_cancel
|
|
||||||
|
|
||||||
|
|
||||||
async def test_firing_event_template(hass):
|
async def test_firing_event_template(hass):
|
||||||
|
@ -125,8 +122,6 @@ async def test_firing_event_template(hass):
|
||||||
)
|
)
|
||||||
script_obj = script.Script(hass, sequence)
|
script_obj = script.Script(hass, sequence)
|
||||||
|
|
||||||
assert script_obj.can_cancel
|
|
||||||
|
|
||||||
await script_obj.async_run({"is_world": "yes"}, context=context)
|
await script_obj.async_run({"is_world": "yes"}, context=context)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
@ -146,8 +141,6 @@ async def test_calling_service_basic(hass):
|
||||||
sequence = cv.SCRIPT_SCHEMA({"service": "test.script", "data": {"hello": "world"}})
|
sequence = cv.SCRIPT_SCHEMA({"service": "test.script", "data": {"hello": "world"}})
|
||||||
script_obj = script.Script(hass, sequence)
|
script_obj = script.Script(hass, sequence)
|
||||||
|
|
||||||
assert script_obj.can_cancel
|
|
||||||
|
|
||||||
await script_obj.async_run(context=context)
|
await script_obj.async_run(context=context)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
@ -182,8 +175,6 @@ async def test_calling_service_template(hass):
|
||||||
)
|
)
|
||||||
script_obj = script.Script(hass, sequence)
|
script_obj = script.Script(hass, sequence)
|
||||||
|
|
||||||
assert script_obj.can_cancel
|
|
||||||
|
|
||||||
await script_obj.async_run({"is_world": "yes"}, context=context)
|
await script_obj.async_run({"is_world": "yes"}, context=context)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
@ -267,8 +258,6 @@ async def test_activating_scene(hass):
|
||||||
sequence = cv.SCRIPT_SCHEMA({"scene": "scene.hello"})
|
sequence = cv.SCRIPT_SCHEMA({"scene": "scene.hello"})
|
||||||
script_obj = script.Script(hass, sequence)
|
script_obj = script.Script(hass, sequence)
|
||||||
|
|
||||||
assert script_obj.can_cancel
|
|
||||||
|
|
||||||
await script_obj.async_run(context=context)
|
await script_obj.async_run(context=context)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
@ -328,8 +317,6 @@ async def test_delay_basic(hass, mock_timeout):
|
||||||
script_obj = script.Script(hass, sequence)
|
script_obj = script.Script(hass, sequence)
|
||||||
delay_started_flag = async_watch_for_action(script_obj, delay_alias)
|
delay_started_flag = async_watch_for_action(script_obj, delay_alias)
|
||||||
|
|
||||||
assert script_obj.can_cancel
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
hass.async_create_task(script_obj.async_run())
|
hass.async_create_task(script_obj.async_run())
|
||||||
await asyncio.wait_for(delay_started_flag.wait(), 1)
|
await asyncio.wait_for(delay_started_flag.wait(), 1)
|
||||||
|
@ -394,8 +381,6 @@ async def test_delay_template_ok(hass, mock_timeout):
|
||||||
script_obj = script.Script(hass, sequence)
|
script_obj = script.Script(hass, sequence)
|
||||||
delay_started_flag = async_watch_for_action(script_obj, "delay")
|
delay_started_flag = async_watch_for_action(script_obj, "delay")
|
||||||
|
|
||||||
assert script_obj.can_cancel
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
hass.async_create_task(script_obj.async_run())
|
hass.async_create_task(script_obj.async_run())
|
||||||
await asyncio.wait_for(delay_started_flag.wait(), 1)
|
await asyncio.wait_for(delay_started_flag.wait(), 1)
|
||||||
|
@ -444,8 +429,6 @@ async def test_delay_template_complex_ok(hass, mock_timeout):
|
||||||
script_obj = script.Script(hass, sequence)
|
script_obj = script.Script(hass, sequence)
|
||||||
delay_started_flag = async_watch_for_action(script_obj, "delay")
|
delay_started_flag = async_watch_for_action(script_obj, "delay")
|
||||||
|
|
||||||
assert script_obj.can_cancel
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
hass.async_create_task(script_obj.async_run())
|
hass.async_create_task(script_obj.async_run())
|
||||||
await asyncio.wait_for(delay_started_flag.wait(), 1)
|
await asyncio.wait_for(delay_started_flag.wait(), 1)
|
||||||
|
@ -530,8 +513,6 @@ async def test_wait_template_basic(hass):
|
||||||
script_obj = script.Script(hass, sequence)
|
script_obj = script.Script(hass, sequence)
|
||||||
wait_started_flag = async_watch_for_action(script_obj, wait_alias)
|
wait_started_flag = async_watch_for_action(script_obj, wait_alias)
|
||||||
|
|
||||||
assert script_obj.can_cancel
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
hass.states.async_set("switch.test", "on")
|
hass.states.async_set("switch.test", "on")
|
||||||
hass.async_create_task(script_obj.async_run())
|
hass.async_create_task(script_obj.async_run())
|
||||||
|
@ -687,8 +668,6 @@ async def test_wait_template_variables(hass):
|
||||||
script_obj = script.Script(hass, sequence)
|
script_obj = script.Script(hass, sequence)
|
||||||
wait_started_flag = async_watch_for_action(script_obj, "wait")
|
wait_started_flag = async_watch_for_action(script_obj, "wait")
|
||||||
|
|
||||||
assert script_obj.can_cancel
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
hass.states.async_set("switch.test", "on")
|
hass.states.async_set("switch.test", "on")
|
||||||
hass.async_create_task(script_obj.async_run({"data": "switch.test"}))
|
hass.async_create_task(script_obj.async_run({"data": "switch.test"}))
|
||||||
|
@ -721,8 +700,6 @@ async def test_condition_basic(hass):
|
||||||
)
|
)
|
||||||
script_obj = script.Script(hass, sequence)
|
script_obj = script.Script(hass, sequence)
|
||||||
|
|
||||||
assert script_obj.can_cancel
|
|
||||||
|
|
||||||
hass.states.async_set("test.entity", "hello")
|
hass.states.async_set("test.entity", "hello")
|
||||||
await script_obj.async_run()
|
await script_obj.async_run()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
Loading…
Reference in New Issue