ESPHome 2026.2.3
Loading...
Searching...
No Matches
remote_base.h
Go to the documentation of this file.
1#include <utility>
2#include <vector>
3
4#pragma once
5
9#include "esphome/core/hal.h"
10
11namespace esphome {
12namespace remote_base {
13
18
19using RawTimings = std::vector<int32_t>;
20
22 public:
23 void mark(uint32_t length) { this->data_.push_back(length); }
24 void space(uint32_t length) { this->data_.push_back(-length); }
25 void item(uint32_t mark, uint32_t space) {
26 this->mark(mark);
27 this->space(space);
28 }
29 void reserve(uint32_t len) { this->data_.reserve(len); }
30 void set_carrier_frequency(uint32_t carrier_frequency) { this->carrier_frequency_ = carrier_frequency; }
31 uint32_t get_carrier_frequency() const { return this->carrier_frequency_; }
32 const RawTimings &get_data() const { return this->data_; }
33 void set_data(const RawTimings &data) { this->data_ = data; }
38 void set_data_from_packed_sint32(const uint8_t *data, size_t len, size_t count);
43 bool set_data_from_base64url(const std::string &base64url);
44 void reset() {
45 this->data_.clear();
46 this->carrier_frequency_ = 0;
47 }
48
49 protected:
51 uint32_t carrier_frequency_{0};
52};
53
55 public:
56 explicit RemoteReceiveData(const RawTimings &data, uint32_t tolerance, ToleranceMode tolerance_mode)
57 : data_(data), index_(0), tolerance_(tolerance), tolerance_mode_(tolerance_mode) {}
58
59 const RawTimings &get_raw_data() const { return this->data_; }
60 uint32_t get_index() const { return index_; }
61 int32_t operator[](uint32_t index) const { return this->data_[index]; }
62 int32_t size() const { return this->data_.size(); }
63 bool is_valid(uint32_t offset = 0) const { return this->index_ + offset < this->data_.size(); }
64 int32_t peek(uint32_t offset = 0) const { return this->data_[this->index_ + offset]; }
65 bool peek_mark(uint32_t length, uint32_t offset = 0) const;
66 bool peek_mark_at_least(uint32_t length, uint32_t offset = 0) const;
67 bool peek_mark_at_most(uint32_t length, uint32_t offset = 0) const;
68 bool peek_space(uint32_t length, uint32_t offset = 0) const;
69 bool peek_space_at_least(uint32_t length, uint32_t offset = 0) const;
70 bool peek_space_at_most(uint32_t length, uint32_t offset = 0) const;
71 bool peek_item(uint32_t mark, uint32_t space, uint32_t offset = 0) const {
72 return this->peek_space(space, offset + 1) && this->peek_mark(mark, offset);
73 }
74
75 bool expect_mark(uint32_t length);
76 bool expect_space(uint32_t length);
77 bool expect_item(uint32_t mark, uint32_t space);
78 bool expect_pulse_with_gap(uint32_t mark, uint32_t space);
79 void advance(uint32_t amount = 1) { this->index_ += amount; }
80 void reset() { this->index_ = 0; }
81
82 void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) {
83 this->tolerance_ = tolerance;
84 this->tolerance_mode_ = tolerance_mode;
85 }
86 uint32_t get_tolerance() { return tolerance_; }
88
89 protected:
90 int32_t lower_bound_(uint32_t length) const {
92 return int32_t(length - this->tolerance_);
93 } else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) {
94 return int32_t(100 - this->tolerance_) * length / 100U;
95 }
96 return 0;
97 }
98 int32_t upper_bound_(uint32_t length) const {
100 return int32_t(length + this->tolerance_);
101 } else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) {
102 return int32_t(100 + this->tolerance_) * length / 100U;
103 }
104 return 0;
105 }
106
108 uint32_t index_;
109 uint32_t tolerance_;
111};
112
114 public:
115 explicit RemoteComponentBase(InternalGPIOPin *pin) : pin_(pin){};
116
117 protected:
119};
120
121#ifdef USE_ESP32
122#include <soc/soc_caps.h>
123#if SOC_RMT_SUPPORTED
125 public:
126 void set_clock_resolution(uint32_t clock_resolution) { this->clock_resolution_ = clock_resolution; }
127 void set_rmt_symbols(uint32_t rmt_symbols) { this->rmt_symbols_ = rmt_symbols; }
128
129 protected:
130 uint32_t from_microseconds_(uint32_t us) {
131 const uint32_t ticks_per_ten_us = this->clock_resolution_ / 100000u;
132 return us * ticks_per_ten_us / 10;
133 }
134 uint32_t to_microseconds_(uint32_t ticks) {
135 const uint32_t ticks_per_ten_us = this->clock_resolution_ / 100000u;
136 return (ticks * 10) / ticks_per_ten_us;
137 }
139 uint32_t clock_resolution_{1000000};
140 uint32_t rmt_symbols_;
141};
142#endif // SOC_RMT_SUPPORTED
143#endif // USE_ESP32
144
146 public:
149 public:
150 explicit TransmitCall(RemoteTransmitterBase *parent) : parent_(parent) {}
152 void set_send_times(uint32_t send_times) { send_times_ = send_times; }
153 void set_send_wait(uint32_t send_wait) { send_wait_ = send_wait; }
154 void perform() { this->parent_->send_(this->send_times_, this->send_wait_); }
155
156 protected:
158 uint32_t send_times_{1};
159 uint32_t send_wait_{0};
160 };
161
163 this->temp_.reset();
164 return TransmitCall(this);
165 }
166 template<typename Protocol>
167 void transmit(const typename Protocol::ProtocolData &data, uint32_t send_times = 1, uint32_t send_wait = 0) {
168 auto call = this->transmit();
169 Protocol().encode(call.get_data(), data);
170 call.set_send_times(send_times);
171 call.set_send_wait(send_wait);
172 call.perform();
173 }
174
175 protected:
176 void send_(uint32_t send_times, uint32_t send_wait);
177 virtual void send_internal(uint32_t send_times, uint32_t send_wait) = 0;
178 void send_single_() { this->send_(1, 0); }
179
182};
183
185 public:
186 virtual bool on_receive(RemoteReceiveData data) = 0;
187};
188
190 public:
191 virtual bool dump(RemoteReceiveData src) = 0;
192 virtual bool is_secondary() { return false; }
193};
194
196 public:
198 void register_listener(RemoteReceiverListener *listener) { this->listeners_.push_back(listener); }
200 void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) {
201 this->tolerance_ = tolerance;
202 this->tolerance_mode_ = tolerance_mode;
203 }
204
205 protected:
206 void call_listeners_();
207 void call_dumpers_();
209 this->call_listeners_();
210 this->call_dumpers_();
211 }
212
213 std::vector<RemoteReceiverListener *> listeners_;
214 std::vector<RemoteReceiverDumperBase *> dumpers_;
215 std::vector<RemoteReceiverDumperBase *> secondary_dumpers_;
217 uint32_t tolerance_{25};
219};
220
222 public Component,
224 public:
226 void dump_config() override;
227 virtual bool matches(RemoteReceiveData src) = 0;
228 bool on_receive(RemoteReceiveData src) override;
229};
230
231/* TEMPLATES */
232
233template<typename T> class RemoteProtocol {
234 public:
235 using ProtocolData = T;
236 virtual void encode(RemoteTransmitData *dst, const ProtocolData &data) = 0;
238 virtual void dump(const ProtocolData &data) = 0;
239};
240
242 public:
244
245 protected:
246 bool matches(RemoteReceiveData src) override {
247 auto proto = T();
248 auto res = proto.decode(src);
249 return res.has_value() && *res == this->data_;
250 }
251
252 public:
253 void set_data(typename T::ProtocolData data) { data_ = data; }
254
255 protected:
256 typename T::ProtocolData data_;
257};
258
259template<typename T>
260class RemoteReceiverTrigger : public Trigger<typename T::ProtocolData>, public RemoteReceiverListener {
261 protected:
262 bool on_receive(RemoteReceiveData src) override {
263 auto proto = T();
264 auto res = proto.decode(src);
265 if (res.has_value()) {
266 this->trigger(*res);
267 return true;
268 }
269 return false;
270 }
271};
272
274 public:
277 void set_transmitter(RemoteTransmitterBase *transmitter) { this->transmitter_ = transmitter; }
278
279 protected:
280 template<typename Protocol>
281 void transmit_(const typename Protocol::ProtocolData &data, uint32_t send_times = 1, uint32_t send_wait = 0) {
282 this->transmitter_->transmit<Protocol>(data, send_times, send_wait);
283 }
285};
286
287template<typename... Ts> class RemoteTransmitterActionBase : public RemoteTransmittable, public Action<Ts...> {
288 TEMPLATABLE_VALUE(uint32_t, send_times)
289 TEMPLATABLE_VALUE(uint32_t, send_wait)
290
291 protected:
292 void play(const Ts &...x) override {
293 auto call = this->transmitter_->transmit();
294 this->encode(call.get_data(), x...);
295 call.set_send_times(this->send_times_.value_or(x..., 1));
296 call.set_send_wait(this->send_wait_.value_or(x..., 0));
297 call.perform();
298 }
299 virtual void encode(RemoteTransmitData *dst, Ts... x) = 0;
300};
301
302template<typename T> class RemoteReceiverDumper : public RemoteReceiverDumperBase {
303 public:
304 bool dump(RemoteReceiveData src) override {
305 auto proto = T();
306 auto decoded = proto.decode(src);
307 if (!decoded.has_value())
308 return false;
309 proto.dump(*decoded);
310 return true;
311 }
312};
313
314#define DECLARE_REMOTE_PROTOCOL_(prefix) \
315 using prefix##BinarySensor = RemoteReceiverBinarySensor<prefix##Protocol>; \
316 using prefix##Trigger = RemoteReceiverTrigger<prefix##Protocol>; \
317 using prefix##Dumper = RemoteReceiverDumper<prefix##Protocol>;
318#define DECLARE_REMOTE_PROTOCOL(prefix) DECLARE_REMOTE_PROTOCOL_(prefix)
319
320} // namespace remote_base
321} // namespace esphome
virtual void dump(const ProtocolData &data)=0
virtual optional< ProtocolData > decode(RemoteReceiveData src)=0
virtual void encode(RemoteTransmitData *dst, const ProtocolData &data)=0
void set_rmt_symbols(uint32_t rmt_symbols)
uint32_t to_microseconds_(uint32_t ticks)
uint32_t from_microseconds_(uint32_t us)
void set_clock_resolution(uint32_t clock_resolution)
int32_t operator[](uint32_t index) const
Definition remote_base.h:61
bool peek_mark_at_most(uint32_t length, uint32_t offset=0) const
bool expect_item(uint32_t mark, uint32_t space)
bool peek_space(uint32_t length, uint32_t offset=0) const
bool peek_space_at_most(uint32_t length, uint32_t offset=0) const
int32_t peek(uint32_t offset=0) const
Definition remote_base.h:64
bool peek_item(uint32_t mark, uint32_t space, uint32_t offset=0) const
Definition remote_base.h:71
int32_t upper_bound_(uint32_t length) const
Definition remote_base.h:98
bool is_valid(uint32_t offset=0) const
Definition remote_base.h:63
const RawTimings & get_raw_data() const
Definition remote_base.h:59
RemoteReceiveData(const RawTimings &data, uint32_t tolerance, ToleranceMode tolerance_mode)
Definition remote_base.h:56
void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode)
Definition remote_base.h:82
bool peek_space_at_least(uint32_t length, uint32_t offset=0) const
int32_t lower_bound_(uint32_t length) const
Definition remote_base.h:90
bool peek_mark(uint32_t length, uint32_t offset=0) const
bool expect_pulse_with_gap(uint32_t mark, uint32_t space)
bool peek_mark_at_least(uint32_t length, uint32_t offset=0) const
std::vector< RemoteReceiverDumperBase * > dumpers_
std::vector< RemoteReceiverListener * > listeners_
void register_dumper(RemoteReceiverDumperBase *dumper)
std::vector< RemoteReceiverDumperBase * > secondary_dumpers_
void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode)
void register_listener(RemoteReceiverListener *listener)
virtual bool matches(RemoteReceiveData src)=0
bool on_receive(RemoteReceiveData src) override
void set_data(typename T::ProtocolData data)
bool matches(RemoteReceiveData src) override
virtual bool dump(RemoteReceiveData src)=0
bool dump(RemoteReceiveData src) override
virtual bool on_receive(RemoteReceiveData data)=0
bool on_receive(RemoteReceiveData src) override
bool set_data_from_base64url(const std::string &base64url)
Set data from base64url-encoded little-endian int32 values Base64url is URL-safe: uses '-' instead of...
void set_carrier_frequency(uint32_t carrier_frequency)
Definition remote_base.h:30
void item(uint32_t mark, uint32_t space)
Definition remote_base.h:25
const RawTimings & get_data() const
Definition remote_base.h:32
void set_data(const RawTimings &data)
Definition remote_base.h:33
void set_data_from_packed_sint32(const uint8_t *data, size_t len, size_t count)
Set data from packed protobuf sint32 buffer (zigzag + varint encoded)
void set_transmitter(RemoteTransmitterBase *transmitter)
void transmit_(const typename Protocol::ProtocolData &data, uint32_t send_times=1, uint32_t send_wait=0)
RemoteTransmittable(RemoteTransmitterBase *transmitter)
virtual void encode(RemoteTransmitData *dst, Ts... x)=0
void send_(uint32_t send_times, uint32_t send_wait)
void transmit(const typename Protocol::ProtocolData &data, uint32_t send_times=1, uint32_t send_wait=0)
virtual void send_internal(uint32_t send_times, uint32_t send_wait)=0
RemoteTransmitData temp_
Use same vector for all transmits, avoids many allocations.
std::vector< int32_t > RawTimings
Definition remote_base.h:19
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:692
uint16_t length
Definition tt21100.cpp:0
uint16_t x
Definition tt21100.cpp:5