Compare commits

..
Author SHA1 Message Date
J. Nick Koston 63b8dfdd79 [modbus] Remove deprecated send() 2026-09-10 16:00:33 -05:00
24 changed files with 53 additions and 333 deletions
-15
View File
@@ -2697,21 +2697,6 @@ message InfraredRFReceiveEvent {
repeated sint32 timings = 3 [packed = true, (container_pointer_no_template) = "std::vector<int32_t>"]; // Raw timings in microseconds (zigzag-encoded): alternating mark/space periods
}
// Sent only to the client that issued an InfraredRFTransmitRawTimingsRequest, once the
// transmitter reports that the transmission (all repeats) has finished, or immediately with
// success=false if it could not be started (unknown key, no transmitter, no or invalid timings).
// Lets clients pace requests instead of estimating durations (since API 1.18)
message InfraredRFTransmitCompleteResponse {
option (id) = 153;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_IR_RF || USE_RADIO_FREQUENCY";
option (no_delay) = true;
uint32 device_id = 1 [(field_ifdef) = "USE_DEVICES"];
fixed32 key = 2 [(force) = true]; // Key of the transmitter entity from the request
bool success = 3; // false if the transmit never started
}
// ==================== RADIO FREQUENCY ====================
// Lists available radio frequency entity instances
+4 -25
View File
@@ -1516,18 +1516,6 @@ uint16_t APIConnection::try_send_event_info(EntityBase *entity, APIConnection *c
#if defined(USE_IR_RF) || defined(USE_RADIO_FREQUENCY)
void APIConnection::on_infrared_rf_transmit_raw_timings_request(const InfraredRFTransmitRawTimingsRequest &msg) {
#ifdef USE_DEVICES
const uint32_t device_id = msg.device_id;
#else
const uint32_t device_id = 0;
#endif
// Register before perform(): blocking transmitters report completion from inside it, and the
// non-blocking RMT path flushes the previous frame's completion there
const bool want_reply = this->client_supports_api_version(1, 18);
if (want_reply) {
this->parent_->register_pending_ir_rf_transmit(device_id, msg.key, this);
}
bool started = false;
// Dispatch by key: infrared entities are checked first, then radio frequency entities.
// The key is unique across all entity instances on a device, so at most one lookup will succeed.
#ifdef USE_INFRARED
@@ -1537,7 +1525,8 @@ void APIConnection::on_infrared_rf_transmit_raw_timings_request(const InfraredRF
call.set_carrier_frequency(msg.carrier_frequency);
call.set_raw_timings_packed(msg.timings_data_, msg.timings_length_, msg.timings_count_);
call.set_repeat_count(msg.repeat_count);
started = call.perform();
call.perform();
return;
}
#endif
#ifdef USE_RADIO_FREQUENCY
@@ -1548,12 +1537,9 @@ void APIConnection::on_infrared_rf_transmit_raw_timings_request(const InfraredRF
call.set_modulation(static_cast<radio_frequency::RadioFrequencyModulation>(msg.modulation));
call.set_repeat_count(msg.repeat_count);
call.set_raw_timings_packed(msg.timings_data_, msg.timings_length_, msg.timings_count_);
started = call.perform();
call.perform();
}
#endif
if (want_reply && !started) {
this->parent_->fail_pending_ir_rf_transmit(device_id, msg.key, this);
}
}
#endif
@@ -1565,13 +1551,6 @@ void APIConnection::send_infrared_rf_receive_event(const InfraredRFReceiveEvent
ESP_LOGV(TAG, "IR/RF event dropped, TCP buffer full");
}
}
void APIConnection::send_infrared_rf_transmit_complete_response(const InfraredRFTransmitCompleteResponse &msg) {
if (!this->send_message(msg)) {
// a lost reply stalls the client's pacing until the server side expiry
API_LOG_MSG_DROPPED(TAG, "IR/RF transmit complete");
}
}
#endif
#ifdef USE_SERIAL_PROXY
@@ -1834,7 +1813,7 @@ bool APIConnection::send_hello_response_(const HelloRequest &msg) {
HelloResponse resp;
resp.api_version_major = 1;
resp.api_version_minor = 18;
resp.api_version_minor = 17;
// Send only the version string - the client only logs this for debugging and doesn't use it otherwise
resp.server_info = ESPHOME_VERSION_REF;
resp.name = StringRef(App.get_name());
-1
View File
@@ -236,7 +236,6 @@ class APIConnection final : public APIServerConnectionBase {
#if defined(USE_IR_RF) || defined(USE_RADIO_FREQUENCY)
void on_infrared_rf_transmit_raw_timings_request(const InfraredRFTransmitRawTimingsRequest &msg);
void send_infrared_rf_receive_event(const InfraredRFReceiveEvent &msg);
void send_infrared_rf_transmit_complete_response(const InfraredRFTransmitCompleteResponse &msg);
#endif
#ifdef USE_SERIAL_PROXY
-18
View File
@@ -4082,24 +4082,6 @@ InfraredRFReceiveEvent::calculate_size() const {
}
return size;
}
uint8_t *InfraredRFTransmitCompleteResponse::encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_PARAM) const {
uint8_t *__restrict__ pos = buffer.get_pos();
#ifdef USE_DEVICES
ProtoEncode::encode_uint32(pos PROTO_ENCODE_DEBUG_ARG, 1, this->device_id);
#endif
ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, this->key);
ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 3, this->success);
return pos;
}
uint32_t InfraredRFTransmitCompleteResponse::calculate_size() const {
uint32_t size = 0;
#ifdef USE_DEVICES
size += ProtoSize::calc_uint32(1, this->device_id);
#endif
size += 5;
size += ProtoSize::calc_bool(1, this->success);
return size;
}
#endif
#ifdef USE_RADIO_FREQUENCY
uint8_t *ListEntitiesRadioFrequencyResponse::encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_PARAM) const {
-20
View File
@@ -3241,26 +3241,6 @@ class InfraredRFReceiveEvent final : public ProtoMessage {
protected:
};
class InfraredRFTransmitCompleteResponse final : public ProtoMessage {
public:
static constexpr uint16_t MESSAGE_TYPE = 153;
static constexpr uint8_t ESTIMATED_SIZE = 11;
#ifdef HAS_PROTO_MESSAGE_DUMP
const LogString *message_name() const override { return LOG_STR("infrared_rf_transmit_complete_response"); }
#endif
#ifdef USE_DEVICES
uint32_t device_id{0};
#endif
uint32_t key{0};
bool success{false};
uint8_t *encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_PARAM) const;
uint32_t calculate_size() const;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *dump_to(DumpBuffer &out) const override;
#endif
protected:
};
#endif
#ifdef USE_RADIO_FREQUENCY
class ListEntitiesRadioFrequencyResponse final : public InfoResponseProtoMessage {
-9
View File
@@ -2740,15 +2740,6 @@ const char *InfraredRFReceiveEvent::dump_to(DumpBuffer &out) const {
}
return out.c_str();
}
const char *InfraredRFTransmitCompleteResponse::dump_to(DumpBuffer &out) const {
MessageDumpHelper helper(out, ESPHOME_PSTR("InfraredRFTransmitCompleteResponse"));
#ifdef USE_DEVICES
dump_field(out, ESPHOME_PSTR("device_id"), this->device_id);
#endif
dump_field(out, ESPHOME_PSTR("key"), this->key);
dump_field(out, ESPHOME_PSTR("success"), this->success);
return out.c_str();
}
#endif
#ifdef USE_RADIO_FREQUENCY
const char *ListEntitiesRadioFrequencyResponse::dump_to(DumpBuffer &out) const {
-90
View File
@@ -193,9 +193,6 @@ void APIServer::remove_client_(uint8_t client_index) {
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
this->unregister_active_action_calls_for_connection(client.get());
#endif
#if defined(USE_IR_RF) || defined(USE_RADIO_FREQUENCY)
this->unregister_pending_ir_rf_transmits_for_connection_(client.get());
#endif
ESP_LOGV(TAG, "Remove connection %s", client->get_name());
@@ -420,93 +417,6 @@ void APIServer::send_infrared_rf_receive_event([[maybe_unused]] uint32_t device_
for (auto &c : this->active_clients())
c->send_infrared_rf_receive_event(resp);
}
// Safety net for transmitters that never report completion (for example a failed component)
static constexpr uint32_t IR_RF_TRANSMIT_TIMEOUT_MS = 30000;
static constexpr char IR_RF_TRANSMIT_TIMEOUT[] = "ir_rf_tx";
void APIServer::register_pending_ir_rf_transmit(uint32_t device_id, uint32_t key, APIConnection *conn) {
if (this->pending_ir_rf_count_ == this->pending_ir_rf_transmits_.size()) {
// only an unpaced client gets here; its oldest request is answered as not started
this->complete_pending_ir_rf_transmit_(0, false);
}
this->pending_ir_rf_transmits_[this->pending_ir_rf_count_++] = {device_id, key, App.get_loop_component_start_time(),
conn};
if (this->pending_ir_rf_count_ == 1) {
this->set_timeout(IR_RF_TRANSMIT_TIMEOUT, IR_RF_TRANSMIT_TIMEOUT_MS,
[this]() { this->expire_pending_ir_rf_transmits_(); });
}
}
void APIServer::fail_pending_ir_rf_transmit(uint32_t device_id, uint32_t key, APIConnection *conn) {
auto &pending = this->pending_ir_rf_transmits_;
for (size_t i = this->pending_ir_rf_count_; i-- > 0;) {
if (pending[i].connection == conn && pending[i].key == key && pending[i].device_id == device_id) {
this->complete_pending_ir_rf_transmit_(i, false);
return;
}
}
}
void APIServer::send_infrared_rf_transmit_complete(const EntityBase &entity) {
uint32_t device_id = 0;
#ifdef USE_DEVICES
device_id = entity.get_device_id();
#endif
const uint32_t key = entity.get_object_id_hash();
auto &pending = this->pending_ir_rf_transmits_;
for (size_t i = 0; i < this->pending_ir_rf_count_; i++) {
if (pending[i].key == key && pending[i].device_id == device_id) {
this->complete_pending_ir_rf_transmit_(i, true);
return;
}
}
}
void APIServer::complete_pending_ir_rf_transmit_(size_t index, bool success) {
const auto &entry = this->pending_ir_rf_transmits_[index];
InfraredRFTransmitCompleteResponse resp{};
#ifdef USE_DEVICES
resp.device_id = entry.device_id;
#endif
resp.key = entry.key;
resp.success = success;
entry.connection->send_infrared_rf_transmit_complete_response(resp);
this->erase_pending_ir_rf_transmit_(index);
}
void APIServer::erase_pending_ir_rf_transmit_(size_t index) {
auto &pending = this->pending_ir_rf_transmits_;
for (size_t i = index + 1; i < this->pending_ir_rf_count_; i++) {
pending[i - 1] = pending[i];
}
this->pending_ir_rf_count_--;
}
void APIServer::unregister_pending_ir_rf_transmits_for_connection_(APIConnection *conn) {
auto &pending = this->pending_ir_rf_transmits_;
uint8_t kept = 0;
for (size_t i = 0; i < this->pending_ir_rf_count_; i++) {
if (pending[i].connection != conn) {
pending[kept++] = pending[i];
}
}
this->pending_ir_rf_count_ = kept;
}
// A timer firing on an empty list is harmless, so nothing cancels it
void APIServer::expire_pending_ir_rf_transmits_() {
const uint32_t now = App.get_loop_component_start_time();
auto &pending = this->pending_ir_rf_transmits_;
while (this->pending_ir_rf_count_ != 0 && now - pending[0].registered_ms >= IR_RF_TRANSMIT_TIMEOUT_MS) {
ESP_LOGW(TAG, "IR/RF transmit %" PRIu32 " never reported completion", pending[0].key);
this->complete_pending_ir_rf_transmit_(0, false);
}
if (this->pending_ir_rf_count_ != 0) {
this->set_timeout(IR_RF_TRANSMIT_TIMEOUT, IR_RF_TRANSMIT_TIMEOUT_MS - (now - pending[0].registered_ms),
[this]() { this->expire_pending_ir_rf_transmits_(); });
}
}
#endif
#ifdef USE_ALARM_CONTROL_PANEL
-22
View File
@@ -196,10 +196,6 @@ class APIServer final : public Component,
#endif
#if defined(USE_IR_RF) || defined(USE_RADIO_FREQUENCY)
void send_infrared_rf_receive_event(uint32_t device_id, uint32_t key, const std::vector<int32_t> *timings);
// Completion replies for InfraredRFTransmitRawTimingsRequest (API 1.18+); register before perform()
void register_pending_ir_rf_transmit(uint32_t device_id, uint32_t key, APIConnection *conn);
void fail_pending_ir_rf_transmit(uint32_t device_id, uint32_t key, APIConnection *conn);
void send_infrared_rf_transmit_complete(const EntityBase &entity);
#endif
bool is_connected() const { return this->api_connection_count_ != 0; }
@@ -346,24 +342,6 @@ class APIServer final : public Component,
uint32_t next_action_call_id_{1}; // Counter for generating unique action_call_ids
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES
#endif
#if defined(USE_IR_RF) || defined(USE_RADIO_FREQUENCY)
struct PendingIrRfTransmit {
uint32_t device_id;
uint32_t key;
uint32_t registered_ms;
APIConnection *connection;
};
// FIFO per entity: entities forward only completions of frames they submitted, and each
// completion pops the oldest match, so entries are never reordered. One slot per connection:
// a pacing client has at most one transmit outstanding. Unlike action calls, transmits share
// one named expiry timer, since a scheduler item per entry would churn the heap.
std::array<PendingIrRfTransmit, MAX_API_CONNECTIONS> pending_ir_rf_transmits_{};
uint8_t pending_ir_rf_count_{0};
void complete_pending_ir_rf_transmit_(size_t index, bool success);
void erase_pending_ir_rf_transmit_(size_t index);
void unregister_pending_ir_rf_transmits_for_connection_(APIConnection *conn);
void expire_pending_ir_rf_transmits_();
#endif
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
struct PendingActionResponse {
uint32_t call_id;
+10 -24
View File
@@ -47,7 +47,11 @@ InfraredCall &InfraredCall::set_repeat_count(uint32_t count) {
return *this;
}
bool InfraredCall::perform() { return this->parent_ != nullptr && this->parent_->control(*this); }
void InfraredCall::perform() {
if (this->parent_ != nullptr) {
this->parent_->control(*this);
}
}
// ========== Infrared ==========
@@ -60,15 +64,6 @@ void Infrared::setup() {
if (this->receiver_ != nullptr) {
this->receiver_->register_listener(this);
}
#if defined(USE_API) && defined(USE_IR_RF)
if (this->transmitter_ != nullptr) {
// only frames this entity submitted; YAML automations share the transmitter
this->transmitter_->set_on_complete_callback([this](uint32_t seq) {
if (seq == this->inflight_seq_)
this->notify_transmit_complete_();
});
}
#endif
}
void Infrared::dump_config() {
@@ -80,15 +75,15 @@ void Infrared::dump_config() {
YESNO(this->traits_.get_supports_receiver()));
}
bool Infrared::control(const InfraredCall &call) {
void Infrared::control(const InfraredCall &call) {
if (this->transmitter_ == nullptr) {
ESP_LOGW(TAG, "No transmitter configured");
return false;
return;
}
if (!call.has_raw_timings()) {
ESP_LOGE(TAG, "No raw timings provided");
return false;
return;
}
// Create transmit data object
@@ -112,7 +107,7 @@ bool Infrared::control(const InfraredCall &call) {
// Decode base64url (URL-safe) into transmit buffer
if (!transmit_data->set_data_from_base64url(call.get_base64url_data())) {
ESP_LOGE(TAG, "Invalid base64url data");
return false;
return;
}
// Sanity check: validate timing values are within reasonable bounds
constexpr int32_t max_timing_us = 500000; // 500ms absolute max
@@ -120,7 +115,7 @@ bool Infrared::control(const InfraredCall &call) {
int32_t abs_timing = timing < 0 ? -timing : timing;
if (abs_timing > max_timing_us) {
ESP_LOGE(TAG, "Invalid timing value: %" PRId32 " µs (max %" PRId32 ")", timing, max_timing_us);
return false;
return;
}
}
ESP_LOGD(TAG, "Transmitting base64url raw timings: count=%zu, repeat=%" PRIu32, transmit_data->get_data().size(),
@@ -138,16 +133,7 @@ bool Infrared::control(const InfraredCall &call) {
}
// Perform transmission
this->inflight_seq_ = transmit_call.get_seq();
transmit_call.perform();
return true;
}
void Infrared::notify_transmit_complete_() {
#if defined(USE_API) && defined(USE_IR_RF)
if (api::global_api_server != nullptr)
api::global_api_server->send_infrared_rf_transmit_complete(*this);
#endif
}
uint32_t Infrared::get_capability_flags() const {
+4 -7
View File
@@ -54,8 +54,8 @@ class InfraredCall {
/// Set the number of times to repeat transmission (1 = transmit once, 2 = transmit twice, etc.)
InfraredCall &set_repeat_count(uint32_t count);
/// Perform the transmission; returns true if a frame was handed to the transmitter
bool perform();
/// Perform the transmission
void perform();
/// Get the carrier frequency
const optional<uint32_t> &get_carrier_frequency() const { return this->carrier_frequency_; }
@@ -145,11 +145,8 @@ class Infrared : public Component, public EntityBase, public remote_base::Remote
protected:
friend class InfraredCall;
/// Perform the actual transmission (called by InfraredCall); false if nothing was transmitted
virtual bool control(const InfraredCall &call);
/// Forwards the transmitter's completion to the API server
void notify_transmit_complete_();
uint32_t inflight_seq_{0}; // seq of the frame this entity submitted last
/// Perform the actual transmission (called by InfraredCall)
virtual void control(const InfraredCall &call);
// Underlying hardware components
remote_base::RemoteReceiverBase *receiver_{nullptr};
+10 -21
View File
@@ -12,16 +12,16 @@ static const char *const TAG = "ir_rf_proxy";
// Static template: all instantiations occur in this translation unit.
template<typename CallT>
static bool transmit_raw_timings(remote_base::RemoteTransmitterBase *transmitter, uint32_t carrier_frequency,
const CallT &call, uint32_t &inflight_seq) {
static void transmit_raw_timings(remote_base::RemoteTransmitterBase *transmitter, uint32_t carrier_frequency,
const CallT &call) {
if (transmitter == nullptr) {
ESP_LOGW(TAG, "No transmitter configured");
return false;
return;
}
if (!call.has_raw_timings()) {
ESP_LOGE(TAG, "No raw timings provided");
return false;
return;
}
auto transmit_call = transmitter->transmit();
@@ -36,14 +36,14 @@ static bool transmit_raw_timings(remote_base::RemoteTransmitterBase *transmitter
} else if (call.is_base64url()) {
if (!transmit_data->set_data_from_base64url(call.get_base64url_data())) {
ESP_LOGE(TAG, "Invalid base64url data");
return false;
return;
}
constexpr int32_t max_timing_us = 500000;
for (int32_t timing : transmit_data->get_data()) {
int32_t abs_timing = timing < 0 ? -timing : timing;
if (abs_timing > max_timing_us) {
ESP_LOGE(TAG, "Invalid timing value: %" PRId32 " µs (max %" PRId32 ")", timing, max_timing_us);
return false;
return;
}
}
ESP_LOGD(TAG, "Transmitting base64url raw timings: count=%zu, repeat=%" PRIu32, transmit_data->get_data().size(),
@@ -58,9 +58,7 @@ static bool transmit_raw_timings(remote_base::RemoteTransmitterBase *transmitter
transmit_call.set_send_times(call.get_repeat_count());
}
inflight_seq = transmit_call.get_seq();
transmit_call.perform();
return true;
}
// ========== IrRfProxy (Infrared platform) ==========
@@ -82,9 +80,9 @@ void IrRfProxy::dump_config() {
}
}
bool IrRfProxy::control(const infrared::InfraredCall &call) {
void IrRfProxy::control(const infrared::InfraredCall &call) {
uint32_t carrier = call.get_carrier_frequency().value_or(0);
return transmit_raw_timings(this->transmitter_, carrier, call, this->inflight_seq_);
transmit_raw_timings(this->transmitter_, carrier, call);
}
#endif // USE_IR_RF
@@ -103,15 +101,6 @@ void RfProxy::setup() {
if (this->receiver_ != nullptr) {
this->receiver_->register_listener(this);
}
#if defined(USE_API) && defined(USE_RADIO_FREQUENCY)
if (this->transmitter_ != nullptr) {
// only frames this entity submitted; YAML automations share the transmitter
this->transmitter_->set_on_complete_callback([this](uint32_t seq) {
if (seq == this->inflight_seq_)
this->notify_transmit_complete_();
});
}
#endif
}
void RfProxy::dump_config() {
@@ -133,11 +122,11 @@ void RfProxy::dump_config() {
}
}
bool RfProxy::control(const radio_frequency::RadioFrequencyCall &call) {
void RfProxy::control(const radio_frequency::RadioFrequencyCall &call) {
// RF: no IR carrier modulation. Any RF front-end coordination (state turnaround, retuning)
// happens via the radio_frequency entity's on_control trigger and remote_transmitter's
// on_transmit/on_complete triggers — wired up in user YAML.
return transmit_raw_timings(this->transmitter_, 0, call, this->inflight_seq_);
transmit_raw_timings(this->transmitter_, 0, call);
}
#endif // USE_RADIO_FREQUENCY
+2 -2
View File
@@ -35,7 +35,7 @@ class IrRfProxy final : public infrared::Infrared {
void set_receiver_frequency(uint32_t frequency_hz) { this->get_traits().set_receiver_frequency_hz(frequency_hz); }
protected:
bool control(const infrared::InfraredCall &call) override;
void control(const infrared::InfraredCall &call) override;
// RF frequency in kHz (Hz / 1000); 0 = infrared, non-zero = RF
uint32_t frequency_khz_{0};
@@ -63,7 +63,7 @@ class RfProxy final : public radio_frequency::RadioFrequency {
void set_frequency_hz(uint32_t freq_hz) { this->traits_.set_fixed_frequency_hz(freq_hz); }
protected:
bool control(const radio_frequency::RadioFrequencyCall &call) override;
void control(const radio_frequency::RadioFrequencyCall &call) override;
remote_base::RemoteTransmitterBase *transmitter_{nullptr};
remote_base::RemoteReceiverBase *receiver_{nullptr};
-8
View File
@@ -243,14 +243,6 @@ class ModbusClientHub : public Modbus {
void set_turnaround_time(uint16_t time_in_ms) { this->turnaround_delay_us_ = time_in_ms * 1000UL; }
bool tx_buffer_empty();
bool tx_blocked() override;
ESPDEPRECATED("Use queue_pdu() with create_client_pdu() instead. Removed in 2026.10.0", "2026.4.0")
void send(uint8_t address, uint8_t function_code, uint16_t start_address, uint16_t number_of_entities,
uint8_t payload_len = 0, const uint8_t *payload = nullptr, ModbusClientDevice *device = nullptr) {
this->queue_pdu(address,
helpers::create_client_pdu((FunctionCode) function_code, start_address, number_of_entities, payload,
payload_len),
device);
};
/// Queue a request. True = accepted: it resolves in exactly one terminal callback (a broadcast,
/// address 0, gets only on_sent()). False = refused, and no callback of any kind follows.
/// Neither means anything reached the wire - on_sent() reports that.
@@ -52,15 +52,14 @@ RadioFrequencyCall &RadioFrequencyCall::set_repeat_count(uint32_t count) {
return *this;
}
bool RadioFrequencyCall::perform() {
if (this->parent_ == nullptr) {
return false;
void RadioFrequencyCall::perform() {
if (this->parent_ != nullptr) {
// Fire any on_control hooks (user-wired automations) before handing off to
// the platform-specific control() — gives users a chance to react to call
// parameters (e.g. retune an external RF front-end based on call.get_frequency()).
this->parent_->control_callback_.call(*this);
this->parent_->control(*this);
}
// Fire any on_control hooks (user-wired automations) before handing off to
// the platform-specific control() — gives users a chance to react to call
// parameters (e.g. retune an external RF front-end based on call.get_frequency()).
this->parent_->control_callback_.call(*this);
return this->parent_->control(*this);
}
// ========== RadioFrequency ==========
@@ -109,11 +108,4 @@ bool RadioFrequency::on_receive(remote_base::RemoteReceiveData data) {
return false; // Don't consume the event, allow other listeners to process it
}
void RadioFrequency::notify_transmit_complete_() {
#if defined(USE_API) && defined(USE_RADIO_FREQUENCY)
if (api::global_api_server != nullptr)
api::global_api_server->send_infrared_rf_transmit_complete(*this);
#endif
}
} // namespace esphome::radio_frequency
@@ -64,8 +64,8 @@ class RadioFrequencyCall {
/// Set the number of times to repeat transmission (1 = transmit once, 2 = transmit twice, etc.)
RadioFrequencyCall &set_repeat_count(uint32_t count);
/// Perform the transmission; returns true if a frame was handed to the transmitter
bool perform();
/// Perform the transmission
void perform();
/// Get the frequency in Hz
const optional<uint32_t> &get_frequency() const { return this->frequency_hz_; }
@@ -184,11 +184,7 @@ class RadioFrequency : public Component, public EntityBase, public remote_base::
/// Perform the actual transmission (called by RadioFrequencyCall::perform())
/// Platforms must override this to implement hardware-specific transmission.
/// Returns false if nothing was transmitted.
virtual bool control(const RadioFrequencyCall &call) = 0;
/// Forwards the transmitter's completion to the API server; platforms hook their transmitter to it
void notify_transmit_complete_();
uint32_t inflight_seq_{0}; // seq of the frame this entity submitted last
virtual void control(const RadioFrequencyCall &call) = 0;
// Traits describing capabilities
RadioFrequencyTraits traits_;
@@ -163,7 +163,7 @@ bool RemoteTransmitData::set_data_from_base64url(const std::string &base64url) {
/* RemoteTransmitterBase */
void RemoteTransmitterBase::send_(uint32_t send_times, uint32_t send_wait, uint32_t seq) {
void RemoteTransmitterBase::send_(uint32_t send_times, uint32_t send_wait) {
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
const auto &vec = this->temp_.get_data();
char buffer[256];
@@ -195,7 +195,6 @@ void RemoteTransmitterBase::send_(uint32_t send_times, uint32_t send_wait, uint3
ESP_LOGVV(TAG, "%s", buffer);
}
#endif
this->current_seq_ = seq;
this->send_internal(send_times, send_wait);
}
} // namespace esphome::remote_base
+5 -29
View File
@@ -146,24 +146,21 @@ class RemoteTransmitterBase : public RemoteComponentBase {
RemoteTransmitterBase(InternalGPIOPin *pin) : RemoteComponentBase(pin) {}
class TransmitCall {
public:
TransmitCall(RemoteTransmitterBase *parent, uint32_t seq) : parent_(parent), seq_(seq) {}
explicit TransmitCall(RemoteTransmitterBase *parent) : parent_(parent) {}
RemoteTransmitData *get_data() { return &this->parent_->temp_; }
void set_send_times(uint32_t send_times) { send_times_ = send_times; }
void set_send_wait(uint32_t send_wait) { send_wait_ = send_wait; }
/// Identifies this transmission in the completion callback
uint32_t get_seq() const { return this->seq_; }
void perform() { this->parent_->send_(this->send_times_, this->send_wait_, this->seq_); }
void perform() { this->parent_->send_(this->send_times_, this->send_wait_); }
protected:
RemoteTransmitterBase *parent_;
uint32_t send_times_{1};
uint32_t send_wait_{0};
uint32_t seq_;
};
TransmitCall transmit() {
this->temp_.reset();
return TransmitCall(this, ++this->next_seq_);
return TransmitCall(this);
}
template<typename Protocol>
void transmit(const Protocol::ProtocolData &data, uint32_t send_times = 1, uint32_t send_wait = 0) {
@@ -173,32 +170,11 @@ class RemoteTransmitterBase : public RemoteComponentBase {
call.set_send_wait(send_wait);
call.perform();
}
#if defined(USE_IR_RF) || defined(USE_RADIO_FREQUENCY)
/// Called with the TransmitCall's seq once that transmission has finished, after the last
/// repeat and before the on_complete trigger. One slot: a transmitter is driven by a single
/// infrared or radio_frequency entity.
template<typename F> void set_on_complete_callback(F &&callback) {
this->complete_callback_ = Callback<void(uint32_t)>::create(std::forward<F>(callback));
}
#endif
protected:
void send_(uint32_t send_times, uint32_t send_wait, uint32_t seq);
void send_(uint32_t send_times, uint32_t send_wait);
virtual void send_internal(uint32_t send_times, uint32_t send_wait) = 0;
void send_single_() { this->send_(1, 0, ++this->next_seq_); }
#if defined(USE_IR_RF) || defined(USE_RADIO_FREQUENCY)
void notify_complete_(uint32_t seq) {
if (this->complete_callback_.fn_ != nullptr)
this->complete_callback_.call(seq);
}
Callback<void(uint32_t)> complete_callback_{};
#else
void notify_complete_(uint32_t seq) {}
#endif
// seq handed to the platform by send_(); platforms copy it when they accept the frame
uint32_t next_seq_{0};
uint32_t current_seq_{0};
void send_single_() { this->send_(1, 0); }
/// Use same vector for all transmits, avoids many allocations
RemoteTransmitData temp_;
@@ -80,7 +80,6 @@ void RemoteTransmitterComponent::digital_write(bool value) { this->pin_->digital
void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) {
ESP_LOGD(TAG, "Sending remote code");
this->inflight_seq_ = this->current_seq_;
uint32_t on_time, off_time;
this->calculate_on_off_time_(this->temp_.get_carrier_frequency(), &on_time, &off_time);
this->transmit_trigger_.trigger();
@@ -115,7 +114,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
}
}
}
this->fire_complete_();
this->complete_trigger_.trigger();
}
} // namespace esphome::remote_transmitter
@@ -82,12 +82,6 @@ class RemoteTransmitterComponent final : public remote_base::RemoteTransmitterBa
protected:
void send_internal(uint32_t send_times, uint32_t send_wait) override;
// completion callbacks run before the user's on_complete automation
void fire_complete_() {
this->notify_complete_(this->inflight_seq_);
this->complete_trigger_.trigger();
}
uint32_t inflight_seq_{0}; // seq of the frame whose completion is still to be reported
#if defined(USE_ESP8266) || \
(defined(USE_LIBRETINY) && !defined(USE_LIBRETINY_VARIANT_RTL8720C) && !defined(REMOTE_TRANSMITTER_BK_PWM)) || \
defined(USE_RP2) || (defined(USE_ESP32) && !SOC_RMT_SUPPORTED)
@@ -110,7 +110,7 @@ void RemoteTransmitterComponent::deliver_completion_() {
if (!this->stall_aborted_)
this->status_clear_warning();
this->complete_pending_ = false;
this->fire_complete_();
this->complete_trigger_.trigger();
}
// Waits until no chain is in flight, delivering any deferred completions; a completion
@@ -137,7 +137,6 @@ void RemoteTransmitterComponent::wait_until_idle_() {
// Stages the repeat schedule and stall deadline, then starts the interrupt chain
void RemoteTransmitterComponent::arm_chain_(uint32_t send_times, uint32_t send_wait) {
this->inflight_seq_ = this->current_seq_;
this->isr_repeats_left_ = send_times;
this->isr_send_wait_ = send_wait;
this->isr_index_ = 0;
@@ -213,7 +213,7 @@ void RemoteTransmitterComponent::wait_for_rmt_() {
this->status_set_warning();
}
this->fire_complete_();
this->complete_trigger_.trigger();
}
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 1)
@@ -228,7 +228,6 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
if (this->non_blocking_ && this->cancel_timeout("complete")) {
this->wait_for_rmt_();
}
this->inflight_seq_ = this->current_seq_;
if (this->current_carrier_frequency_ != this->temp_.get_carrier_frequency()) {
this->current_carrier_frequency_ = this->temp_.get_carrier_frequency();
@@ -301,7 +300,6 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) {
if (this->is_failed())
return;
this->inflight_seq_ = this->current_seq_;
if (this->current_carrier_frequency_ != this->temp_.get_carrier_frequency()) {
this->current_carrier_frequency_ = this->temp_.get_carrier_frequency();
@@ -366,7 +364,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
if (i + 1 < send_times)
delayMicroseconds(send_wait);
}
this->fire_complete_();
this->complete_trigger_.trigger();
}
#endif
@@ -149,7 +149,6 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
return;
}
ESP_LOGD(TAG, "Sending remote code");
this->inflight_seq_ = this->current_seq_;
const uint32_t carrier_frequency = this->temp_.get_carrier_frequency();
// unmodulated protocols (no carrier or 100% duty) drive the pin constantly during marks
float mark_duty =
@@ -195,7 +194,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
}
}
}
this->fire_complete_();
this->complete_trigger_.trigger();
}
#endif // USE_LIBRETINY_VARIANT_RTL8720C
@@ -19,7 +19,7 @@ class InfraredCall {
return *this;
}
InfraredCall &set_repeat_count(uint32_t /*count*/) { return *this; }
bool perform() { return false; }
void perform() {}
protected:
Infrared *parent_;
@@ -23,7 +23,7 @@ class RadioFrequencyCall {
RadioFrequencyCall &set_raw_timings_packed(const uint8_t * /*data*/, uint16_t /*length*/, uint16_t /*count*/) {
return *this;
}
bool perform() { return false; }
void perform() {}
protected:
RadioFrequency *parent_;