[remote_base] Add tests for transmit_raw and rc_switch transmit code generation (#22000)

This commit is contained in:
J. Nick Koston authored and GitHub committed 2026-10-31 08:45:49 -04:00
1 parent 1f70f86b47
commit 05949b7e3a
3 files changed
+287

No files matched your search

@@ -0,0 +1,117 @@
esphome:
name: test
esp8266:
board: esp01_1m
remote_transmitter:
id: tx
pin: GPIO4
carrier_duty_percent: 50%
script:
- id: send_scaled
parameters:
x: int
then:
- remote_transmitter.transmit_raw:
code: !lambda |-
x *= 2;
return {x, -1000};
carrier_frequency: !lambda return x *= 1000;
repeat:
times: !lambda return x *= 1;
wait_time: !lambda x *= 3; return x;
- remote_transmitter.transmit_rc_switch_type_b:
address: !lambda x *= 2; return x;
channel: !lambda return x *= 1;
state: !lambda return x > 0;
protocol: !lambda x *= 1; return remote_base::rc_switch_protocol(x);
button:
- platform: template
name: Raw static
on_press:
- remote_transmitter.transmit_raw:
code: [1000, -1000, 500, -500]
- platform: template
name: Raw static repeat
on_press:
- remote_transmitter.transmit_raw:
code: [1000, -1000, 500, -500]
carrier_frequency: 38kHz
repeat:
times: 2
wait_time: 10ms
- platform: template
name: Raw lambda
on_press:
- remote_transmitter.transmit_raw:
code: !lambda return {2000, -1000};
- platform: template
name: RC switch raw
on_press:
- remote_transmitter.transmit_rc_switch_raw:
code: "00101001100111110101xxxx"
protocol: 2
- platform: template
name: RC switch raw lambda
on_press:
- remote_transmitter.transmit_rc_switch_raw:
code: !lambda return std::string("0010100110");
repeat:
times: 2
wait_time: 10ms
- platform: template
name: RC switch type A
on_press:
- remote_transmitter.transmit_rc_switch_type_a:
group: "11001"
device: "01000"
state: true
protocol:
pulse_length: 175
- platform: template
name: RC switch type A lambda
on_press:
- remote_transmitter.transmit_rc_switch_type_a:
group: !lambda return std::string("11001");
device: !lambda return std::string("01000");
state: !lambda return false;
- platform: template
name: RC switch type B
on_press:
- remote_transmitter.transmit_rc_switch_type_b:
address: 4
channel: 2
state: true
- platform: template
name: RC switch type C
on_press:
- remote_transmitter.transmit_rc_switch_type_c:
family: "c"
group: 1
device: 2
state: true
- platform: template
name: RC switch type C lambda
on_press:
- remote_transmitter.transmit_rc_switch_type_c:
family: !lambda return std::string("C");
group: !lambda return 1;
device: !lambda return 2;
state: !lambda return true;
- platform: template
name: RC switch type D
on_press:
- remote_transmitter.transmit_rc_switch_type_d:
group: "b"
device: 3
state: false
- platform: template
name: RC switch type D lambda
on_press:
- remote_transmitter.transmit_rc_switch_type_d:
group: !lambda return std::string("b");
device: !lambda return 3;
state: !lambda return false;
@@ -0,0 +1,135 @@
"""transmit_raw and the rc_switch transmit actions as generated code."""
from collections.abc import Callable
from pathlib import Path
import re
import pytest
CONFIG = "raw_rc_switch_actions.yaml"
@pytest.fixture
def main_cpp(
generate_main: Callable[[str | Path], str],
component_config_path: Callable[[str], Path],
) -> str:
# Without the #line directives a lambda body is the user's text alone
main = generate_main(component_config_path(CONFIG))
return re.sub(r"\n *(#line .*|// ESPHOME_LINE_DIRECTIVE_RESET)(?=\n)", "", main)
def _action(main_cpp: str, action_id: str) -> str:
"""The setup statements of one action object."""
marker = f"new({action_id}) "
start = main_cpp.index(marker)
# Ends at the next object constructed, or at the end of the file
end = main_cpp.find("new(", start + len(marker))
return main_cpp[start : end if end != -1 else len(main_cpp)]
def test_raw_static_code_in_flash(main_cpp: str) -> None:
raw = _action(main_cpp, "remote_base_rawaction_id_2")
assert (
"static constexpr int32_t int32_t_id_2[] PROGMEM = {1000, -1000, 500, -500};"
in raw
)
assert "->set_code_static(int32_t_id_2, 4);" in raw
assert "->set_carrier_frequency([]() -> uint32_t {\n return 0;\n});" in raw
# Without repeat the call sends once
assert "set_send_times" not in raw
assert "set_send_wait" not in raw
def test_raw_repeat_and_carrier(main_cpp: str) -> None:
raw = _action(main_cpp, "remote_base_rawaction_id_3")
assert "->set_send_times([]() -> uint32_t {\n return 2;\n});" in raw
assert "->set_send_wait([]() -> uint32_t {\n return 10000;\n});" in raw
assert "->set_carrier_frequency([]() -> uint32_t {\n return 38000;\n});" in raw
def test_raw_lambda_code(main_cpp: str) -> None:
raw = _action(main_cpp, "remote_base_rawaction_id_4")
assert (
"->set_code_template([]() -> std::vector<int32_t> {\n"
" return {2000, -1000};\n"
"});"
) in raw
def test_rc_switch_raw(main_cpp: str) -> None:
constant = _action(main_cpp, "remote_base_rcswitchrawaction_id")
assert "return remote_base::rc_switch_protocol(2);" in constant
assert '->set_code(ESPHOME_F("00101001100111110101xxxx"));' in constant
# The rc_switch actions also send once without repeat
assert "set_send_times" not in constant
lambda_ = _action(main_cpp, "remote_base_rcswitchrawaction_id_2")
assert "return remote_base::rc_switch_protocol(1);" in lambda_
assert ' return std::string("0010100110");' in lambda_
assert "->set_send_times([]() -> uint32_t {\n return 2;\n});" in lambda_
assert "->set_send_wait([]() -> uint32_t {\n return 10000;\n});" in lambda_
def test_rc_switch_type_a(main_cpp: str) -> None:
constant = _action(main_cpp, "remote_base_rcswitchtypeaaction_id")
assert (
"return remote_base::rc_switch_protocol_copy(rc_switch_custom_protocol);"
in constant
)
assert '->set_group(ESPHOME_F("11001"));' in constant
assert '->set_device(ESPHOME_F("01000"));' in constant
assert "->set_state([]() -> bool {\n return true;\n});" in constant
lambda_ = _action(main_cpp, "remote_base_rcswitchtypeaaction_id_2")
assert '->set_group([]() -> std::string {\n return std::string("11001");' in (
lambda_
)
assert '->set_device([]() -> std::string {\n return std::string("01000");' in (
lambda_
)
assert "->set_state([]() -> bool {\n return false;" in lambda_
def test_rc_switch_type_b(main_cpp: str) -> None:
constant = _action(main_cpp, "remote_base_rcswitchtypebaction_id_2")
assert "->set_address([]() -> uint8_t {\n return 4;\n});" in constant
assert "->set_channel([]() -> uint8_t {\n return 2;\n});" in constant
assert "->set_state([]() -> bool {\n return true;\n});" in constant
def test_rc_switch_type_c(main_cpp: str) -> None:
constant = _action(main_cpp, "remote_base_rcswitchtypecaction_id")
assert '->set_family(ESPHOME_F("c"));' in constant
assert "->set_group([]() -> uint8_t {\n return 1;\n});" in constant
assert "->set_device([]() -> uint8_t {\n return 2;\n});" in constant
lambda_ = _action(main_cpp, "remote_base_rcswitchtypecaction_id_2")
assert '->set_family([]() -> std::string {\n return std::string("C");' in (
lambda_
)
def test_rc_switch_type_d(main_cpp: str) -> None:
constant = _action(main_cpp, "remote_base_rcswitchtypedaction_id")
assert '->set_group(ESPHOME_F("b"));' in constant
assert "->set_device([]() -> uint8_t {\n return 3;\n});" in constant
assert "->set_state([]() -> bool {\n return false;\n});" in constant
lambda_ = _action(main_cpp, "remote_base_rcswitchtypedaction_id_2")
assert '->set_group([]() -> std::string {\n return std::string("b");' in lambda_
def test_lambdas_take_args_by_value(main_cpp: str) -> None:
"""User lambdas get the script argument by value, so they may modify it."""
raw = _action(main_cpp, "remote_base_rawaction_id")
assert (
"[](int x) -> std::vector<int32_t> {\n x *= 2;\n return {x, -1000};\n}"
in raw
)
assert "[](int x) -> uint32_t {\n return x *= 1000;\n}" in raw
assert "[](int x) -> uint32_t {\n return x *= 1;\n}" in raw
assert "[](int x) -> uint32_t {\n x *= 3; return x;\n}" in raw
type_b = _action(main_cpp, "remote_base_rcswitchtypebaction_id")
assert "[](int x) -> uint8_t {\n x *= 2; return x;\n}" in type_b
assert "[](int x) -> uint8_t {\n return x *= 1;\n}" in type_b
assert (
"[](int x) -> remote_base::RCSwitchBase {\n"
" x *= 1; return remote_base::rc_switch_protocol(x);\n}"
) in type_b
@@ -1059,3 +1059,38 @@ button:
- remote_transmitter.transmit_raw:
code: [1000, -1000]
carrier_frequency: !lambda return 38000;
script:
# The lambdas modify their by-value argument
- id: remote_transmitter_send_scaled
parameters:
x: int
then:
- remote_transmitter.transmit_raw:
code: !lambda |-
x *= 2;
return {x, -1000};
carrier_frequency: !lambda return x *= 1000;
repeat:
times: !lambda return x *= 1;
wait_time: !lambda x *= 3; return x;
- remote_transmitter.transmit_rc_switch_raw:
code: !lambda x *= 1; return std::string(x, '1');
- remote_transmitter.transmit_rc_switch_type_a:
group: !lambda x *= 1; return std::string("11001");
device: !lambda return std::string(x *= 1, '0');
state: !lambda return (x *= 1) > 0;
- remote_transmitter.transmit_rc_switch_type_b:
address: !lambda x *= 2; return x;
channel: !lambda return x *= 1;
state: !lambda return x > 0;
protocol: !lambda x *= 1; return remote_base::rc_switch_protocol(x);
- remote_transmitter.transmit_rc_switch_type_c:
family: !lambda x *= 1; return std::string("a");
group: !lambda return x *= 1;
device: !lambda x += 1; return x;
state: !lambda return x > 0;
- remote_transmitter.transmit_rc_switch_type_d:
group: !lambda x *= 1; return std::string("a");
device: !lambda return x *= 1;
state: !lambda x *= 1; return true;