mirror of
https://github.com/esphome/esphome.git
synced 2026-09-27 22:16:47 +08:00
[script] Fix array-type parameters in script.execute (#16374)
This commit is contained in:
@@ -169,6 +169,8 @@ async def script_execute_action_to_code(config, action_id, template_arg, args):
|
|||||||
return value
|
return value
|
||||||
if type == "bool":
|
if type == "bool":
|
||||||
return cg.RawExpression(str(value).lower())
|
return cg.RawExpression(str(value).lower())
|
||||||
|
if isinstance(value, (list, tuple)):
|
||||||
|
return cg.ArrayInitializer(*value)
|
||||||
return cg.RawExpression(str(value))
|
return cg.RawExpression(str(value))
|
||||||
|
|
||||||
return converter
|
return converter
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ esphome:
|
|||||||
prefix: "Test"
|
prefix: "Test"
|
||||||
param2: 0
|
param2: 0
|
||||||
param3: true
|
param3: true
|
||||||
|
- script.execute:
|
||||||
|
id: my_script_with_array_params
|
||||||
|
ints: [42, 100]
|
||||||
|
floats: [1.5, 2.5]
|
||||||
|
bools: [true, false]
|
||||||
|
strings: ["a", "b"]
|
||||||
- script.wait: my_script
|
- script.wait: my_script
|
||||||
- script.stop: my_script
|
- script.stop: my_script
|
||||||
- if:
|
- if:
|
||||||
@@ -34,6 +40,16 @@ script:
|
|||||||
mode: restart
|
mode: restart
|
||||||
then:
|
then:
|
||||||
- lambda: 'ESP_LOGD("main", "Hello World!");'
|
- lambda: 'ESP_LOGD("main", "Hello World!");'
|
||||||
|
- id: my_script_with_array_params
|
||||||
|
parameters:
|
||||||
|
ints: int[]
|
||||||
|
floats: float[]
|
||||||
|
bools: bool[]
|
||||||
|
strings: string[]
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
ESP_LOGD("main", "ints=%d floats=%f bools=%d strings=%s",
|
||||||
|
ints[0], floats[0], bools[0], strings[0].c_str());
|
||||||
- id: my_script_with_params
|
- id: my_script_with_params
|
||||||
parameters:
|
parameters:
|
||||||
prefix: string
|
prefix: string
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
esphome:
|
||||||
|
name: test-script-array-params
|
||||||
|
|
||||||
|
host:
|
||||||
|
|
||||||
|
api:
|
||||||
|
actions:
|
||||||
|
- action: run_array_script
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: array_script
|
||||||
|
ints: [42, 100]
|
||||||
|
floats: [1.5, 2.5]
|
||||||
|
bools: [true, false]
|
||||||
|
strings: ["hello", "world"]
|
||||||
|
|
||||||
|
logger:
|
||||||
|
level: DEBUG
|
||||||
|
|
||||||
|
script:
|
||||||
|
- id: array_script
|
||||||
|
parameters:
|
||||||
|
ints: int[]
|
||||||
|
floats: float[]
|
||||||
|
bools: bool[]
|
||||||
|
strings: string[]
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
ESP_LOGI("test", "ints size=%u [0]=%d [1]=%d",
|
||||||
|
(unsigned) ints.size(), ints[0], ints[1]);
|
||||||
|
ESP_LOGI("test", "floats size=%u [0]=%.2f [1]=%.2f",
|
||||||
|
(unsigned) floats.size(), floats[0], floats[1]);
|
||||||
|
ESP_LOGI("test", "bools size=%u [0]=%d [1]=%d",
|
||||||
|
(unsigned) bools.size(), (int) bools[0], (int) bools[1]);
|
||||||
|
ESP_LOGI("test", "strings size=%u [0]=%s [1]=%s",
|
||||||
|
(unsigned) strings.size(), strings[0].c_str(), strings[1].c_str());
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
"""Integration test for script array parameters (issue #16367).
|
||||||
|
|
||||||
|
Verifies that script parameters of array types (`int[]`, `float[]`, `bool[]`,
|
||||||
|
`string[]`) compile and execute correctly. Prior to the fix in
|
||||||
|
`esphome/components/script/__init__.py`, the `script.execute` codegen emitted
|
||||||
|
the Python `repr` of the list (e.g. `return [42, 100];`) instead of a C++
|
||||||
|
braced initializer, causing compile failures.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import re
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from .types import APIClientConnectedFactory, RunCompiledFunction
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_script_array_params(
|
||||||
|
yaml_config: str,
|
||||||
|
run_compiled: RunCompiledFunction,
|
||||||
|
api_client_connected: APIClientConnectedFactory,
|
||||||
|
) -> None:
|
||||||
|
"""Execute a script with int[], float[], bool[], string[] parameters."""
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
seen: dict[str, str] = {}
|
||||||
|
done = loop.create_future()
|
||||||
|
|
||||||
|
patterns = {
|
||||||
|
"ints": re.compile(r"ints size=(\d+) \[0\]=(-?\d+) \[1\]=(-?\d+)"),
|
||||||
|
"floats": re.compile(
|
||||||
|
r"floats size=(\d+) \[0\]=(-?\d+\.\d+) \[1\]=(-?\d+\.\d+)"
|
||||||
|
),
|
||||||
|
"bools": re.compile(r"bools size=(\d+) \[0\]=(\d+) \[1\]=(\d+)"),
|
||||||
|
"strings": re.compile(r"strings size=(\d+) \[0\]=(\w+) \[1\]=(\w+)"),
|
||||||
|
}
|
||||||
|
|
||||||
|
def check_output(line: str) -> None:
|
||||||
|
for key, pat in patterns.items():
|
||||||
|
if (m := pat.search(line)) and key not in seen:
|
||||||
|
seen[key] = m.group(0)
|
||||||
|
if len(seen) == len(patterns) and not done.done():
|
||||||
|
done.set_result(True)
|
||||||
|
|
||||||
|
async with (
|
||||||
|
run_compiled(yaml_config, line_callback=check_output),
|
||||||
|
api_client_connected() as client,
|
||||||
|
):
|
||||||
|
_, services = await client.list_entities_services()
|
||||||
|
service = next((s for s in services if s.name == "run_array_script"), None)
|
||||||
|
assert service is not None, "run_array_script service not found"
|
||||||
|
await client.execute_service(service, {})
|
||||||
|
|
||||||
|
try:
|
||||||
|
await asyncio.wait_for(done, timeout=5.0)
|
||||||
|
except TimeoutError:
|
||||||
|
pytest.fail(f"Did not receive all expected log lines. Saw: {seen}")
|
||||||
|
|
||||||
|
assert (m := patterns["ints"].search(seen["ints"]))
|
||||||
|
assert m.group(1) == "2" and m.group(2) == "42" and m.group(3) == "100"
|
||||||
|
|
||||||
|
assert (m := patterns["floats"].search(seen["floats"]))
|
||||||
|
assert m.group(1) == "2" and m.group(2) == "1.50" and m.group(3) == "2.50"
|
||||||
|
|
||||||
|
assert (m := patterns["bools"].search(seen["bools"]))
|
||||||
|
assert m.group(1) == "2" and m.group(2) == "1" and m.group(3) == "0"
|
||||||
|
|
||||||
|
assert (m := patterns["strings"].search(seen["strings"]))
|
||||||
|
assert m.group(1) == "2" and m.group(2) == "hello" and m.group(3) == "world"
|
||||||
Reference in New Issue
Block a user