diff --git a/esphome/components/packet_interface/radio_link.cpp b/esphome/components/packet_interface/radio_link.cpp index 2e9841e7100..b22b6b3539b 100644 --- a/esphome/components/packet_interface/radio_link.cpp +++ b/esphome/components/packet_interface/radio_link.cpp @@ -21,11 +21,17 @@ bool RadioLinkBase::may_send_(bool busy) { if (!this->listen_before_talk_.may_send(busy, now)) return false; if (busy) { - ESP_LOGD(TAG, "Radio busy for %" PRIu32 "ms, sending anyway", this->listen_before_talk_.busy_for(now)); + // The limit is longer than any packet takes, so the radio's busy indication is stuck or the channel is jammed + ESP_LOGW(TAG, "Radio busy for %" PRIu32 "ms, sending anyway", this->listen_before_talk_.busy_for(now)); } return true; } +bool RadioLinkBase::skip_empty_() const { + ESP_LOGV(TAG, "Empty packet not sent"); + return true; +} + void RadioLinkBase::radio_free_() { this->listen_before_talk_.end_busy(); this->disable_loop(); diff --git a/esphome/components/packet_interface/radio_link.h b/esphome/components/packet_interface/radio_link.h index ef038369d49..79e7a39d4c3 100644 --- a/esphome/components/packet_interface/radio_link.h +++ b/esphome/components/packet_interface/radio_link.h @@ -18,6 +18,8 @@ class RadioLinkBase : public PacketInterface { bool check_size_(size_t size) const; /// False if sending must wait, as the radio is busy; starts loop() to watch the radio. bool may_send_(bool busy); + /// Returns true for an empty packet, which the radios cannot send, so there is nothing to retry. + bool skip_empty_() const; /// Ends the busy period when loop() finds the radio free. void radio_free_(); void receive_(const std::vector &packet, float rssi, float snr); @@ -56,7 +58,7 @@ class RadioLink : public RadioLinkBase, public Listener { return false; size_t size = data.size(); if (size == 0) - return true; + return this->skip_empty_(); if (!this->check_size_(size) || !this->may_send_(this->radio_->is_receiving())) return false; if (data.is_contiguous()) { diff --git a/esphome/components/packet_interface/radio_link.py b/esphome/components/packet_interface/radio_link.py index bf8d146b370..23957f0d394 100644 --- a/esphome/components/packet_interface/radio_link.py +++ b/esphome/components/packet_interface/radio_link.py @@ -7,7 +7,7 @@ import esphome.codegen as cg from esphome.components.const import CONF_MAX_PACKET_SIZE import esphome.config_validation as cv from esphome.const import CONF_ID -from esphome.core import CORE +from esphome.core import CORE, EsphomeError from esphome.cpp_generator import MockObjClass import esphome.final_validate as fv from esphome.types import ConfigType @@ -126,8 +126,13 @@ async def new_radio_link( radio = await cg.get_variable(config[radio_id_key]) var = await new_packet_interface(config, radio, config[CONF_MAX_PACKET_SIZE]) radio_config = next( - conf - for conf in CORE.config[radio_domain] - if conf[CONF_ID] == config[radio_id_key] + ( + conf + for conf in CORE.config[radio_domain] + if conf[CONF_ID] == config[radio_id_key] + ), + None, ) + if radio_config is None: + raise EsphomeError(f"No {radio_domain} radio with id '{config[radio_id_key]}'") cg.add(var.set_max_busy(max_busy_ms(radio_config, config[CONF_MAX_PACKET_SIZE]))) diff --git a/tests/components/packet_interface/radio_link.cpp b/tests/components/packet_interface/radio_link.cpp index 46c82b7e12b..26956caf171 100644 --- a/tests/components/packet_interface/radio_link.cpp +++ b/tests/components/packet_interface/radio_link.cpp @@ -91,6 +91,12 @@ TEST_F(RadioLinkTest, BusyFlagThatNeverClearsIsSentOver) { EXPECT_EQ(this->radio_.sent[0], (Packet{1, 2, 3})); } +TEST_F(RadioLinkTest, EmptyPacketCountsAsSentWithoutTransmitting) { + static const Packet EMPTY; + EXPECT_TRUE(this->link_.send_to_interface(PacketBuffer(EMPTY), {})); + EXPECT_TRUE(this->radio_.sent.empty()); +} + TEST_F(RadioLinkTest, ReceivedPacketCarriesSignal) { Packet received; PacketMetaData meta;