diff --git a/esphome/components/ir_rf_proxy/__init__.py b/esphome/components/ir_rf_proxy/__init__.py index bc4079ede7..26a4f0d387 100644 --- a/esphome/components/ir_rf_proxy/__init__.py +++ b/esphome/components/ir_rf_proxy/__init__.py @@ -1,6 +1,9 @@ """IR/RF Proxy component - provides remote_base backend for infrared platform.""" import esphome.codegen as cg +from esphome.components import remote_base +from esphome.cpp_generator import MockObj +from esphome.types import ConfigType CODEOWNERS = ["@kbx81"] @@ -9,3 +12,10 @@ ir_rf_proxy_ns = cg.esphome_ns.namespace("ir_rf_proxy") CONF_REMOTE_RECEIVER_ID = "remote_receiver_id" CONF_REMOTE_TRANSMITTER_ID = "remote_transmitter_id" + + +async def attach_receiver(var: MockObj, config: ConfigType) -> None: + """Wire the configured remote_receiver to a proxy entity and register it as a listener.""" + receiver = await cg.get_variable(config[CONF_REMOTE_RECEIVER_ID]) + cg.add(var.set_receiver(receiver)) + remote_base.add_listener(receiver, var) diff --git a/esphome/components/ir_rf_proxy/infrared.py b/esphome/components/ir_rf_proxy/infrared.py index 54e53f52d4..80bc55d5e9 100644 --- a/esphome/components/ir_rf_proxy/infrared.py +++ b/esphome/components/ir_rf_proxy/infrared.py @@ -3,18 +3,18 @@ from typing import Any import esphome.codegen as cg -from esphome.components import ( - infrared, - remote_base, - remote_receiver, - remote_transmitter, -) +from esphome.components import infrared, remote_receiver, remote_transmitter from esphome.components.const import CONF_RECEIVER_FREQUENCY import esphome.config_validation as cv from esphome.const import CONF_CARRIER_DUTY_PERCENT, CONF_FREQUENCY import esphome.final_validate as fv -from . import CONF_REMOTE_RECEIVER_ID, CONF_REMOTE_TRANSMITTER_ID, ir_rf_proxy_ns +from . import ( + CONF_REMOTE_RECEIVER_ID, + CONF_REMOTE_TRANSMITTER_ID, + attach_receiver, + ir_rf_proxy_ns, +) CODEOWNERS = ["@kbx81"] DEPENDENCIES = ["infrared"] @@ -87,9 +87,7 @@ async def to_code(config: dict[str, Any]) -> None: # Link receiver if specified if CONF_REMOTE_RECEIVER_ID in config: - receiver = await cg.get_variable(config[CONF_REMOTE_RECEIVER_ID]) - cg.add(var.set_receiver(receiver)) - remote_base.add_listener(receiver, var) + await attach_receiver(var, config) # Set receiver demodulation frequency if specified (metadata only, no hardware effect) if CONF_RECEIVER_FREQUENCY in config: diff --git a/esphome/components/ir_rf_proxy/radio_frequency.py b/esphome/components/ir_rf_proxy/radio_frequency.py index a4971a30ee..c27100c69b 100644 --- a/esphome/components/ir_rf_proxy/radio_frequency.py +++ b/esphome/components/ir_rf_proxy/radio_frequency.py @@ -1,18 +1,18 @@ """Radio Frequency platform implementation using remote_base (remote_transmitter/receiver).""" import esphome.codegen as cg -from esphome.components import ( - radio_frequency, - remote_base, - remote_receiver, - remote_transmitter, -) +from esphome.components import radio_frequency, remote_receiver, remote_transmitter import esphome.config_validation as cv from esphome.const import CONF_CARRIER_DUTY_PERCENT, CONF_FREQUENCY import esphome.final_validate as fv from esphome.types import ConfigType -from . import CONF_REMOTE_RECEIVER_ID, CONF_REMOTE_TRANSMITTER_ID, ir_rf_proxy_ns +from . import ( + CONF_REMOTE_RECEIVER_ID, + CONF_REMOTE_TRANSMITTER_ID, + attach_receiver, + ir_rf_proxy_ns, +) CODEOWNERS = ["@kbx81"] DEPENDENCIES = ["radio_frequency"] @@ -71,6 +71,4 @@ async def to_code(config: ConfigType) -> None: cg.add(var.set_transmitter(transmitter)) if CONF_REMOTE_RECEIVER_ID in config: - receiver = await cg.get_variable(config[CONF_REMOTE_RECEIVER_ID]) - cg.add(var.set_receiver(receiver)) - remote_base.add_listener(receiver, var) + await attach_receiver(var, config) diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 140efb838c..0a3476e95b 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -231,6 +231,13 @@ DUMPER_REGISTRY = Registry() def validate_dumpers(value): if isinstance(value, str) and value.lower() == "all": return validate_dumpers(list(DUMPER_REGISTRY.keys())) + if isinstance(value, list): + # a dumper listed twice would register twice; the receiver holds one secondary dumper + value = ( + list(dict.fromkeys(value)) + if all(isinstance(v, str) for v in value) + else value + ) return cv.validate_registry("dumper", DUMPER_REGISTRY)(value) diff --git a/esphome/components/remote_base/rc_switch_protocol.cpp b/esphome/components/remote_base/rc_switch_protocol.cpp index 2565eb4fbe..3167ca0849 100644 --- a/esphome/components/remote_base/rc_switch_protocol.cpp +++ b/esphome/components/remote_base/rc_switch_protocol.cpp @@ -1,4 +1,6 @@ #include "rc_switch_protocol.h" + +#include #include "esphome/core/log.h" namespace esphome::remote_base { @@ -113,7 +115,7 @@ bool RCSwitchBase::decode(RemoteReceiveData &src, uint64_t *out_data, uint8_t *o optional RCSwitchBase::decode(RemoteReceiveData &src) const { RCSwitchData out; uint8_t out_nbits; - for (uint8_t i = 1; i <= 8; i++) { + for (uint8_t i = 1; i < std::size(RC_SWITCH_PROTOCOLS); i++) { src.reset(); const RCSwitchBase *protocol = &RC_SWITCH_PROTOCOLS[i]; if (protocol->decode(src, &out.code, &out_nbits) && out_nbits >= 3) { @@ -226,7 +228,7 @@ bool RCSwitchRawReceiver::matches(RemoteReceiveData src) { return decoded_nbits == this->nbits_ && (decoded_code & this->mask_) == (this->code_ & this->mask_); } bool RCSwitchDumper::dump(RemoteReceiveData src) { - for (uint8_t i = 1; i <= 8; i++) { + for (uint8_t i = 1; i < std::size(RC_SWITCH_PROTOCOLS); i++) { src.reset(); uint64_t out_data; uint8_t out_nbits; diff --git a/tests/components/remote_receiver/bare-common.yaml b/tests/components/remote_receiver/bare-common.yaml new file mode 100644 index 0000000000..b39a5aaef9 --- /dev/null +++ b/tests/components/remote_receiver/bare-common.yaml @@ -0,0 +1,4 @@ +# A receiver with no dumpers and no listeners compiles both lists out +remote_receiver: + - id: rcvr_bare + pin: ${pin} diff --git a/tests/components/remote_receiver/test-bare.esp32-idf.yaml b/tests/components/remote_receiver/test-bare.esp32-idf.yaml new file mode 100644 index 0000000000..152853b65f --- /dev/null +++ b/tests/components/remote_receiver/test-bare.esp32-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + pin: GPIO2 + +packages: + bare: !include bare-common.yaml