diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 0a3476e95b..2d8bdcfd56 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -233,11 +233,16 @@ def validate_dumpers(value): 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 - ) + seen: set[str] = set() + deduped = [] + for item in value: + key = item if isinstance(item, str) else next(iter(item), None) + if isinstance(key, str): + if key in seen: + continue + seen.add(key) + deduped.append(item) + value = deduped return cv.validate_registry("dumper", DUMPER_REGISTRY)(value) diff --git a/esphome/components/remote_base/remote_base.cpp b/esphome/components/remote_base/remote_base.cpp index c922891aaf..2e3f292940 100644 --- a/esphome/components/remote_base/remote_base.cpp +++ b/esphome/components/remote_base/remote_base.cpp @@ -99,13 +99,30 @@ bool RemoteReceiverBinarySensorBase::on_receive(RemoteReceiveData src) { /* RemoteReceiverBase */ +// Slots are counted at code generation; a registration from C++ setup() has none +#ifdef REMOTE_BASE_LISTENER_COUNT +void RemoteReceiverBase::register_listener(RemoteReceiverListener *listener) { + if (this->listeners_.size() == REMOTE_BASE_LISTENER_COUNT) { + ESP_LOGE(TAG, "No %s slot: register it from to_code() with remote_base.add_%s", LOG_STR_LITERAL("listener"), + LOG_STR_LITERAL("listener")); + return; + } + this->listeners_.push_back(listener); +} +#endif + #ifdef REMOTE_BASE_DUMPER_COUNT void RemoteReceiverBase::register_dumper(RemoteReceiverDumperBase *dumper) { if (dumper->is_secondary()) { this->secondary_dumper_ = dumper; - } else { - this->dumpers_.push_back(dumper); + return; } + if (this->dumpers_.size() == REMOTE_BASE_DUMPER_COUNT) { + ESP_LOGE(TAG, "No %s slot: register it from to_code() with remote_base.add_%s", LOG_STR_LITERAL("dumper"), + LOG_STR_LITERAL("dumper")); + return; + } + this->dumpers_.push_back(dumper); } #endif diff --git a/esphome/components/remote_base/remote_base.h b/esphome/components/remote_base/remote_base.h index f9d9a5f886..4136e960fd 100644 --- a/esphome/components/remote_base/remote_base.h +++ b/esphome/components/remote_base/remote_base.h @@ -213,7 +213,7 @@ class RemoteReceiverBase : public RemoteComponentBase { public: RemoteReceiverBase(InternalGPIOPin *pin) : RemoteComponentBase(pin) {} #ifdef REMOTE_BASE_LISTENER_COUNT - void register_listener(RemoteReceiverListener *listener) { this->listeners_.push_back(listener); } + void register_listener(RemoteReceiverListener *listener); #endif #ifdef REMOTE_BASE_DUMPER_COUNT void register_dumper(RemoteReceiverDumperBase *dumper); diff --git a/tests/components/remote_receiver/bare-common.yaml b/tests/components/remote_receiver/bare-common.yaml index b39a5aaef9..c100c5c2da 100644 --- a/tests/components/remote_receiver/bare-common.yaml +++ b/tests/components/remote_receiver/bare-common.yaml @@ -1,4 +1,6 @@ -# A receiver with no dumpers and no listeners compiles both lists out +# A receiver with no dumpers and no listeners compiles both lists out. +# Only built while remote_receiver is tested in isolation: the counts are global defines, +# so this variant cannot be merged with configs that register any. remote_receiver: - id: rcvr_bare pin: ${pin}