ESPHome 2025.5.0
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
11#if defined(USE_ESP32) && ESP_IDF_VERSION_MAJOR < 5
12#include <driver/rmt.h>
13#endif
14
15namespace esphome {
16namespace remote_base {
17
22
23using RawTimings = std::vector<int32_t>;
24
26 public:
27 void mark(uint32_t length) { this->data_.push_back(length); }
28 void space(uint32_t length) { this->data_.push_back(-length); }
29 void item(uint32_t mark, uint32_t space) {
30 this->mark(mark);
31 this->space(space);
32 }
33 void reserve(uint32_t len) { this->data_.reserve(len); }
34 void set_carrier_frequency(uint32_t carrier_frequency) { this->carrier_frequency_ = carrier_frequency; }
35 uint32_t get_carrier_frequency() const { return this->carrier_frequency_; }
36 const RawTimings &get_data() const { return this->data_; }
37 void set_data(const RawTimings &data) { this->data_ = data; }
38 void reset() {
39 this->data_.clear();
40 this->carrier_frequency_ = 0;
41 }
42
43 protected:
45 uint32_t carrier_frequency_{0};
46};
47
49 public:
50 explicit RemoteReceiveData(const RawTimings &data, uint32_t tolerance, ToleranceMode tolerance_mode)
51 : data_(data), index_(0), tolerance_(tolerance), tolerance_mode_(tolerance_mode) {}
52
53 const RawTimings &get_raw_data() const { return this->data_; }
54 uint32_t get_index() const { return index_; }
55 int32_t operator[](uint32_t index) const { return this->data_[index]; }
56 int32_t size() const { return this->data_.size(); }
57 bool is_valid(uint32_t offset = 0) const { return this->index_ + offset < this->data_.size(); }
58 int32_t peek(uint32_t offset = 0) const { return this->data_[this->index_ + offset]; }
59 bool peek_mark(uint32_t length, uint32_t offset = 0) const;
60 bool peek_space(uint32_t length, uint32_t offset = 0) const;
61 bool peek_space_at_least(uint32_t length, uint32_t offset = 0) const;
62 bool peek_item(uint32_t mark, uint32_t space, uint32_t offset = 0) const {
63 return this->peek_space(space, offset + 1) && this->peek_mark(mark, offset);
64 }
65
66 bool expect_mark(uint32_t length);
67 bool expect_space(uint32_t length);
68 bool expect_item(uint32_t mark, uint32_t space);
69 bool expect_pulse_with_gap(uint32_t mark, uint32_t space);
70 void advance(uint32_t amount = 1) { this->index_ += amount; }
71 void reset() { this->index_ = 0; }
72
73 void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) {
74 this->tolerance_ = tolerance;
75 this->tolerance_mode_ = tolerance_mode;
76 }
77 uint32_t get_tolerance() { return tolerance_; }
79
80 protected:
81 int32_t lower_bound_(uint32_t length) const {
83 return int32_t(length - this->tolerance_);
84 } else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) {
85 return int32_t(100 - this->tolerance_) * length / 100U;
86 }
87 return 0;
88 }
89 int32_t upper_bound_(uint32_t length) const {
91 return int32_t(length + this->tolerance_);
92 } else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) {
93 return int32_t(100 + this->tolerance_) * length / 100U;
94 }
95 return 0;
96 }
97
99 uint32_t index_;
100 uint32_t tolerance_;
102};
103
105 public:
106 explicit RemoteComponentBase(InternalGPIOPin *pin) : pin_(pin){};
107
108 protected:
110};
111
112#ifdef USE_ESP32
114 public:
115#if ESP_IDF_VERSION_MAJOR >= 5
116 void set_clock_resolution(uint32_t clock_resolution) { this->clock_resolution_ = clock_resolution; }
117 void set_rmt_symbols(uint32_t rmt_symbols) { this->rmt_symbols_ = rmt_symbols; }
118#else
119 explicit RemoteRMTChannel(uint8_t mem_block_num = 1);
120 explicit RemoteRMTChannel(rmt_channel_t channel, uint8_t mem_block_num = 1);
121
122 void config_rmt(rmt_config_t &rmt);
123 void set_clock_divider(uint8_t clock_divider) { this->clock_divider_ = clock_divider; }
124#endif
125
126 protected:
127 uint32_t from_microseconds_(uint32_t us) {
128#if ESP_IDF_VERSION_MAJOR >= 5
129 const uint32_t ticks_per_ten_us = this->clock_resolution_ / 100000u;
130#else
131 const uint32_t ticks_per_ten_us = 80000000u / this->clock_divider_ / 100000u;
132#endif
133 return us * ticks_per_ten_us / 10;
134 }
135 uint32_t to_microseconds_(uint32_t ticks) {
136#if ESP_IDF_VERSION_MAJOR >= 5
137 const uint32_t ticks_per_ten_us = this->clock_resolution_ / 100000u;
138#else
139 const uint32_t ticks_per_ten_us = 80000000u / this->clock_divider_ / 100000u;
140#endif
141 return (ticks * 10) / ticks_per_ten_us;
142 }
144#if ESP_IDF_VERSION_MAJOR >= 5
145 uint32_t clock_resolution_{1000000};
146 uint32_t rmt_symbols_;
147#else
148 rmt_channel_t channel_{RMT_CHANNEL_0};
150 uint8_t clock_divider_{80};
151#endif
152};
153#endif
154
156 public:
159 public:
160 explicit TransmitCall(RemoteTransmitterBase *parent) : parent_(parent) {}
162 void set_send_times(uint32_t send_times) { send_times_ = send_times; }
163 void set_send_wait(uint32_t send_wait) { send_wait_ = send_wait; }
164 void perform() { this->parent_->send_(this->send_times_, this->send_wait_); }
165
166 protected:
168 uint32_t send_times_{1};
169 uint32_t send_wait_{0};
170 };
171
173 this->temp_.reset();
174 return TransmitCall(this);
175 }
176 template<typename Protocol>
177 void transmit(const typename Protocol::ProtocolData &data, uint32_t send_times = 1, uint32_t send_wait = 0) {
178 auto call = this->transmit();
179 Protocol().encode(call.get_data(), data);
180 call.set_send_times(send_times);
181 call.set_send_wait(send_wait);
182 call.perform();
183 }
184
185 protected:
186 void send_(uint32_t send_times, uint32_t send_wait);
187 virtual void send_internal(uint32_t send_times, uint32_t send_wait) = 0;
188 void send_single_() { this->send_(1, 0); }
189
192};
193
195 public:
196 virtual bool on_receive(RemoteReceiveData data) = 0;
197};
198
200 public:
201 virtual bool dump(RemoteReceiveData src) = 0;
202 virtual bool is_secondary() { return false; }
203};
204
206 public:
208 void register_listener(RemoteReceiverListener *listener) { this->listeners_.push_back(listener); }
210 void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) {
211 this->tolerance_ = tolerance;
212 this->tolerance_mode_ = tolerance_mode;
213 }
214
215 protected:
216 void call_listeners_();
217 void call_dumpers_();
219 this->call_listeners_();
220 this->call_dumpers_();
221 }
222
223 std::vector<RemoteReceiverListener *> listeners_;
224 std::vector<RemoteReceiverDumperBase *> dumpers_;
225 std::vector<RemoteReceiverDumperBase *> secondary_dumpers_;
227 uint32_t tolerance_{25};
229};
230
232 public Component,
234 public:
236 void dump_config() override;
237 virtual bool matches(RemoteReceiveData src) = 0;
238 bool on_receive(RemoteReceiveData src) override;
239};
240
241/* TEMPLATES */
242
243template<typename T> class RemoteProtocol {
244 public:
245 using ProtocolData = T;
246 virtual void encode(RemoteTransmitData *dst, const ProtocolData &data) = 0;
248 virtual void dump(const ProtocolData &data) = 0;
249};
250
252 public:
254
255 protected:
256 bool matches(RemoteReceiveData src) override {
257 auto proto = T();
258 auto res = proto.decode(src);
259 return res.has_value() && *res == this->data_;
260 }
261
262 public:
263 void set_data(typename T::ProtocolData data) { data_ = data; }
264
265 protected:
266 typename T::ProtocolData data_;
267};
268
269template<typename T>
270class RemoteReceiverTrigger : public Trigger<typename T::ProtocolData>, public RemoteReceiverListener {
271 protected:
272 bool on_receive(RemoteReceiveData src) override {
273 auto proto = T();
274 auto res = proto.decode(src);
275 if (res.has_value()) {
276 this->trigger(*res);
277 return true;
278 }
279 return false;
280 }
281};
282
284 public:
287 void set_transmitter(RemoteTransmitterBase *transmitter) { this->transmitter_ = transmitter; }
288
289 protected:
290 template<typename Protocol>
291 void transmit_(const typename Protocol::ProtocolData &data, uint32_t send_times = 1, uint32_t send_wait = 0) {
292 this->transmitter_->transmit<Protocol>(data, send_times, send_wait);
293 }
295};
296
297template<typename... Ts> class RemoteTransmitterActionBase : public RemoteTransmittable, public Action<Ts...> {
298 TEMPLATABLE_VALUE(uint32_t, send_times)
299 TEMPLATABLE_VALUE(uint32_t, send_wait)
300
301 protected:
302 void play(Ts... x) override {
303 auto call = this->transmitter_->transmit();
304 this->encode(call.get_data(), x...);
305 call.set_send_times(this->send_times_.value_or(x..., 1));
306 call.set_send_wait(this->send_wait_.value_or(x..., 0));
307 call.perform();
308 }
309 virtual void encode(RemoteTransmitData *dst, Ts... x) = 0;
310};
311
312template<typename T> class RemoteReceiverDumper : public RemoteReceiverDumperBase {
313 public:
314 bool dump(RemoteReceiveData src) override {
315 auto proto = T();
316 auto decoded = proto.decode(src);
317 if (!decoded.has_value())
318 return false;
319 proto.dump(*decoded);
320 return true;
321 }
322};
323
324#define DECLARE_REMOTE_PROTOCOL_(prefix) \
325 using prefix##BinarySensor = RemoteReceiverBinarySensor<prefix##Protocol>; \
326 using prefix##Trigger = RemoteReceiverTrigger<prefix##Protocol>; \
327 using prefix##Dumper = RemoteReceiverDumper<prefix##Protocol>;
328#define DECLARE_REMOTE_PROTOCOL(prefix) DECLARE_REMOTE_PROTOCOL_(prefix)
329
330} // namespace remote_base
331} // 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)
RemoteRMTChannel(uint8_t mem_block_num=1)
void set_clock_divider(uint8_t clock_divider)
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:55
bool expect_item(uint32_t mark, uint32_t space)
bool peek_space(uint32_t length, uint32_t offset=0) const
int32_t peek(uint32_t offset=0) const
Definition remote_base.h:58
bool peek_item(uint32_t mark, uint32_t space, uint32_t offset=0) const
Definition remote_base.h:62
int32_t upper_bound_(uint32_t length) const
Definition remote_base.h:89
bool is_valid(uint32_t offset=0) const
Definition remote_base.h:57
const RawTimings & get_raw_data() const
Definition remote_base.h:53
RemoteReceiveData(const RawTimings &data, uint32_t tolerance, ToleranceMode tolerance_mode)
Definition remote_base.h:50
void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode)
Definition remote_base.h:73
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:81
bool peek_mark(uint32_t length, uint32_t offset=0) const
bool expect_pulse_with_gap(uint32_t mark, uint32_t space)
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
void set_carrier_frequency(uint32_t carrier_frequency)
Definition remote_base.h:34
void item(uint32_t mark, uint32_t space)
Definition remote_base.h:29
const RawTimings & get_data() const
Definition remote_base.h:36
void set_data(const RawTimings &data)
Definition remote_base.h:37
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:23
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:301
uint16_t length
Definition tt21100.cpp:0
uint16_t x
Definition tt21100.cpp:5