ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
ir_rf_base.h
Go to the documentation of this file.
1#pragma once
2
3// WARNING: This component is EXPERIMENTAL. The API may change at any time
4// without following the normal breaking changes policy. Use at your own risk.
5// Once the API is considered stable, this warning will be removed.
6
11
12#include <string>
13#include <vector>
14
15#if defined(USE_API) && defined(USE_IR_RF)
16namespace esphome::api {
17class APIConnection;
18} // namespace esphome::api
19#endif
20
21namespace esphome::ir_rf_base {
22
25 CAPABILITY_TRANSMITTER = 1 << 0, // Can transmit signals
26 CAPABILITY_RECEIVER = 1 << 1, // Can receive signals
27};
28
31 public:
33 const std::vector<int32_t> &get_raw_timings() const { return *this->raw_timings_; }
35 bool has_raw_timings() const {
36 return this->raw_timings_ != nullptr || this->packed_data_ != nullptr || this->base64url_ptr_ != nullptr;
37 }
39 bool is_packed() const { return this->packed_data_ != nullptr; }
41 bool is_base64url() const { return this->base64url_ptr_ != nullptr; }
43 const std::string &get_base64url_data() const { return *this->base64url_ptr_; }
45 const uint8_t *get_packed_data() const { return this->packed_data_; }
46 uint16_t get_packed_length() const { return this->packed_length_; }
47 uint16_t get_packed_count() const { return this->packed_count_; }
49 uint32_t get_repeat_count() const { return this->repeat_count_; }
50
51#if defined(USE_API) && defined(USE_IR_RF)
53 bool wants_api_reply() const { return this->api_connection_ != nullptr; }
54#endif
55
56 protected:
58#if defined(USE_API) && defined(USE_IR_RF)
60#endif
61 // Pointer to vector-based timings (caller-owned, must outlive perform())
62 const std::vector<int32_t> *raw_timings_{nullptr};
63 // Pointer to base64url-encoded string (caller-owned, must outlive perform())
64 const std::string *base64url_ptr_{nullptr};
65 // Pointer to packed protobuf buffer (caller-owned, must outlive perform())
66 const uint8_t *packed_data_{nullptr};
67 uint16_t packed_length_{0};
68 uint16_t packed_count_{0};
69};
70
71template<typename Call, typename Entity> class IrRfCall;
72
77 public:
80 void setup() override;
81 float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; }
82
85 void set_receiver(remote_base::RemoteReceiverBase *receiver) { this->receiver_ = receiver; }
87 void set_transmitter(remote_base::RemoteTransmitterBase *transmitter) { this->transmitter_ = transmitter; }
88 bool has_transmitter() const { return this->transmitter_ != nullptr; }
89 bool has_receiver() const { return this->receiver_ != nullptr; }
90
93 bool get_supports_transmitter() const { return this->supports_transmitter_; }
94 void set_supports_transmitter(bool supports) { this->supports_transmitter_ = supports; }
95 bool get_supports_receiver() const { return this->supports_receiver_; }
96 void set_supports_receiver(bool supports) { this->supports_receiver_ = supports; }
99 uint32_t flags = 0;
100 if (this->supports_transmitter_)
101 flags |= CAPABILITY_TRANSMITTER;
102 if (this->supports_receiver_)
103 flags |= CAPABILITY_RECEIVER;
104 return flags;
105 }
106
108 bool on_receive(remote_base::RemoteReceiveData data) override;
109#ifdef USE_IR_RF_TRANSMIT_COMPLETE
112 void on_transmit_complete(remote_base::RemoteTransmitterBase *transmitter, uint16_t seq, bool sent);
113#endif
114
115#if defined(USE_API) && defined(USE_IR_RF)
116 void loop() override;
119#endif
120
121 protected:
122 template<typename, typename> friend class IrRfCall;
123
125 bool transmit_raw_(const IrRfCallData &call, uint32_t carrier_frequency_hz);
126#if defined(USE_API) && defined(USE_IR_RF)
127 // One reply slot: a pacing client has at most one transmit outstanding, and a second request
128 // from an unpaced client displaces the first. Retried and expired from loop(), which only
129 // runs while a reply is pending; polling the expiry there costs nothing while idle, where a
130 // scheduler timeout would allocate per frame.
131 enum class ApiReply : uint8_t {
133 API_REPLY_WAITING, // frame handed to the transmitter, completion not reported yet
134 API_REPLY_OWED_OK, // reply refused by a full TCP buffer; loop() retries it
135 API_REPLY_OWED_FAILED // same, for a transmit that did not start
136 };
142 void settle_api_reply_(bool started) {
143#ifdef USE_IR_RF_TRANSMIT_COMPLETE
144 if (!started)
145 this->finish_api_reply_(false);
146#else
147 // no transmitter in this build reports completion, so the hand-over is the answer
148 this->finish_api_reply_(started);
149#endif
151 this->enable_loop();
152 }
153 void finish_api_reply_(bool success);
155 void api_transmit_done_(bool sent) {
157 this->finish_api_reply_(sent);
158 }
159 bool send_api_reply_();
162 this->api_reply_connection_ = nullptr;
163 this->disable_loop();
164 }
166#endif
167
170#if defined(USE_API) && defined(USE_IR_RF)
171 // 16 ms ticks: 30 s for completion (plus capped air time) or for delivering an owed reply
173#endif
174#ifdef USE_IR_RF_TRANSMIT_COMPLETE
175 uint16_t inflight_seq_{0}; // seq of the API frame this entity submitted last
176#endif
177 // short members last, so the derived traits start on the next word without a gap
180#if defined(USE_API) && defined(USE_IR_RF)
182#endif
183};
184
187template<typename Call, typename Entity> class IrRfCall : public IrRfCallData {
188 // only the concrete call may construct the CRTP base
189 friend Call;
190 explicit IrRfCall(Entity *parent) : parent_(parent) {}
191
192 public:
193 // ===== Raw Timings Methods =====
194 // All set_raw_timings_* methods store pointers/references to external data.
195 // The referenced data must remain valid until perform() completes.
196 // Safe pattern: call.set_raw_timings_xxx(data); call.perform(); // synchronous
197 // Unsafe pattern: call.set_raw_timings_xxx(data); defer([call]() { call.perform(); }); // data may be gone!
198
202 Call &set_raw_timings(const std::vector<int32_t> &timings) {
203 this->raw_timings_ = &timings;
204 this->packed_data_ = nullptr;
205 this->base64url_ptr_ = nullptr;
206 return this->self_();
207 }
208
213 Call &set_raw_timings_base64url(const std::string &base64url) {
214 this->base64url_ptr_ = &base64url;
215 this->raw_timings_ = nullptr;
216 this->packed_data_ = nullptr;
217 return this->self_();
218 }
219
223 Call &set_raw_timings_packed(const uint8_t *data, uint16_t length, uint16_t count) {
224 this->packed_data_ = data;
225 this->packed_length_ = length;
226 this->packed_count_ = count;
227 this->raw_timings_ = nullptr;
228 this->base64url_ptr_ = nullptr;
229 return this->self_();
230 }
231
234 this->repeat_count_ = count;
235 return this->self_();
236 }
237
238#if defined(USE_API) && defined(USE_IR_RF)
241 this->api_connection_ = conn;
242 return this->self_();
243 }
244#endif
245
247 bool perform() {
248 // make_call() always sets the parent
249 Entity *parent = this->parent_;
250 if (parent == nullptr)
251 return false;
252 parent->on_call_(this->self_());
253#if defined(USE_API) && defined(USE_IR_RF)
254 // Before control(): blocking transmitters report completion from inside it, and the
255 // non-blocking RMT path flushes the previous frame's completion there
256 if (this->api_connection_ != nullptr && !parent->expect_api_reply_(this->api_connection_))
257 return false;
258#endif
259 const bool started = parent->control(this->self_());
260#if defined(USE_API) && defined(USE_IR_RF)
261 if (this->api_connection_ != nullptr)
262 parent->settle_api_reply_(started);
263#endif
264 return started;
265 }
266
267 protected:
268 Call &self_() { return static_cast<Call &>(*this); }
269
270 Entity *parent_;
271};
272
273} // namespace esphome::ir_rf_base
void enable_loop()
Enable this component's loop.
Definition component.h:248
void disable_loop()
Disable this component's loop.
Raw timings of a transmit call, in one of three caller-owned forms.
Definition ir_rf_base.h:30
uint16_t get_packed_count() const
Definition ir_rf_base.h:47
const std::string & get_base64url_data() const
Get the base64url data string.
Definition ir_rf_base.h:43
const std::string * base64url_ptr_
Definition ir_rf_base.h:64
const std::vector< int32_t > * raw_timings_
Definition ir_rf_base.h:62
const uint8_t * get_packed_data() const
Get packed data (only valid if set via set_raw_timings_packed)
Definition ir_rf_base.h:45
uint16_t get_packed_length() const
Definition ir_rf_base.h:46
bool wants_api_reply() const
True for a frame an API client is waiting on.
Definition ir_rf_base.h:53
api::APIConnection * api_connection_
Definition ir_rf_base.h:59
bool is_base64url() const
Check if using base64url data format.
Definition ir_rf_base.h:41
uint32_t get_repeat_count() const
Get the repeat count.
Definition ir_rf_base.h:49
bool has_raw_timings() const
Check if raw timings have been set (any format)
Definition ir_rf_base.h:35
const std::vector< int32_t > & get_raw_timings() const
Get the raw timings (only valid if set via set_raw_timings)
Definition ir_rf_base.h:33
bool is_packed() const
Check if using packed data format.
Definition ir_rf_base.h:39
Builder for a transmit; Call is the concrete call type and Entity its entity, so the fluent setters r...
Definition ir_rf_base.h:187
Call & set_repeat_count(uint32_t count)
Set the number of times to repeat transmission (1 = transmit once, 2 = transmit twice,...
Definition ir_rf_base.h:233
Call & set_api_connection(api::APIConnection *conn)
Reply to this API client once the frame has left the transmitter (API 1.18+)
Definition ir_rf_base.h:240
Call & set_raw_timings_base64url(const std::string &base64url)
Set the raw timings from base64url-encoded little-endian int32 data.
Definition ir_rf_base.h:213
bool perform()
Perform the transmission; returns true if a frame was handed to the transmitter.
Definition ir_rf_base.h:247
Call & set_raw_timings(const std::vector< int32_t > &timings)
Set the raw timings from a vector (positive = mark, negative = space)
Definition ir_rf_base.h:202
Call & set_raw_timings_packed(const uint8_t *data, uint16_t length, uint16_t count)
Set the raw timings from packed protobuf sint32 data (zigzag + varint encoded)
Definition ir_rf_base.h:223
Everything an infrared or radio frequency entity does that does not depend on the medium: the remote_...
Definition ir_rf_base.h:76
void api_transmit_done_(bool sent)
Answers the API request for a control() override that transmits without a remote_base transmitter.
Definition ir_rf_base.h:155
void on_transmit_complete(remote_base::RemoteTransmitterBase *transmitter, uint16_t seq, bool sent)
Called for every finished frame on every transmitter; answers the API request when the frame is the o...
remote_base::RemoteReceiverBase * receiver_
Definition ir_rf_base.h:168
uint32_t get_capability_flags() const
Capability flags as reported to the API and web server.
Definition ir_rf_base.h:98
void refuse_api_call_(api::APIConnection *conn)
api::APIConnection * api_reply_connection_
Definition ir_rf_base.h:165
bool on_receive(remote_base::RemoteReceiveData data) override
Forwards a received frame to the API; never consumes it, so other listeners still run.
bool expect_api_reply_(api::APIConnection *conn)
Claims the reply slot for conn; false when it still owes a reply that cannot be sent.
remote_base::RemoteTransmitterBase * transmitter_
Definition ir_rf_base.h:169
void setup() override
Reports the configured transports, listens on the receiver and hooks the transmitter's completion; a ...
void set_supports_receiver(bool supports)
Definition ir_rf_base.h:96
void set_receiver(remote_base::RemoteReceiverBase *receiver)
Set the remote receiver component; the listener registration happens from codegen,...
Definition ir_rf_base.h:85
float get_setup_priority() const override
Definition ir_rf_base.h:81
void finish_api_reply_(bool success)
bool get_supports_transmitter() const
What the entity can do; platforms with their own hardware set these from their own setup(),...
Definition ir_rf_base.h:93
void set_supports_transmitter(bool supports)
Definition ir_rf_base.h:94
void set_transmitter(remote_base::RemoteTransmitterBase *transmitter)
Set the remote transmitter component.
Definition ir_rf_base.h:87
void settle_api_reply_(bool started)
After control(): a false start is answered now, and the loop only runs once something is pending,...
Definition ir_rf_base.h:142
bool transmit_raw_(const IrRfCallData &call, uint32_t carrier_frequency_hz)
Hands the call's timings to the transmitter; the default transmit path of both entity types.
void on_api_connection_closed(api::APIConnection *conn)
The API server calls this when a client disconnects, so no reply goes to a stale pointer.
uint16_t flags
unsigned count
Definition gif.cpp:51
IrRfCapability
Capability flags reported by infrared and radio frequency entities.
Definition ir_rf_base.h:24
constexpr float AFTER_CONNECTION
For components that should be initialized after a data connection (API/MQTT) is connected.
Definition component.h:57
static void uint32_t
uint16_t seq
uint16_t length
Definition tt21100.cpp:0