ESPHome 2025.9.0-dev
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; }
34 void reset() {
35 this->data_.clear();
36 this->carrier_frequency_ = 0;
37 }
38
39 protected:
41 uint32_t carrier_frequency_{0};
42};
43
45 public:
46 explicit RemoteReceiveData(const RawTimings &data, uint32_t tolerance, ToleranceMode tolerance_mode)
47 : data_(data), index_(0), tolerance_(tolerance), tolerance_mode_(tolerance_mode) {}
48
49 const RawTimings &get_raw_data() const { return this->data_; }
50 uint32_t get_index() const { return index_; }
51 int32_t operator[](uint32_t index) const { return this->data_[index]; }
52 int32_t size() const { return this->data_.size(); }
53 bool is_valid(uint32_t offset = 0) const { return this->index_ + offset < this->data_.size(); }
54 int32_t peek(uint32_t offset = 0) const { return this->data_[this->index_ + offset]; }
55 bool peek_mark(uint32_t length, uint32_t offset = 0) const;
56 bool peek_mark_at_least(uint32_t length, uint32_t offset = 0) const;
57 bool peek_mark_at_most(uint32_t length, uint32_t offset = 0) const;
58 bool peek_space(uint32_t length, uint32_t offset = 0) const;
59 bool peek_space_at_least(uint32_t length, uint32_t offset = 0) const;
60 bool peek_space_at_most(uint32_t length, uint32_t offset = 0) const;
61 bool peek_item(uint32_t mark, uint32_t space, uint32_t offset = 0) const {
62 return this->peek_space(space, offset + 1) && this->peek_mark(mark, offset);
63 }
64
65 bool expect_mark(uint32_t length);
66 bool expect_space(uint32_t length);
67 bool expect_item(uint32_t mark, uint32_t space);
68 bool expect_pulse_with_gap(uint32_t mark, uint32_t space);
69 void advance(uint32_t amount = 1) { this->index_ += amount; }
70 void reset() { this->index_ = 0; }
71
72 void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) {
73 this->tolerance_ = tolerance;
74 this->tolerance_mode_ = tolerance_mode;
75 }
76 uint32_t get_tolerance() { return tolerance_; }
78
79 protected:
80 int32_t lower_bound_(uint32_t length) const {
82 return int32_t(length - this->tolerance_);
83 } else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) {
84 return int32_t(100 - this->tolerance_) * length / 100U;
85 }
86 return 0;
87 }
88 int32_t upper_bound_(uint32_t length) const {
90 return int32_t(length + this->tolerance_);
91 } else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) {
92 return int32_t(100 + this->tolerance_) * length / 100U;
93 }
94 return 0;
95 }
96
98 uint32_t index_;
99 uint32_t tolerance_;
101};
102
104 public:
105 explicit RemoteComponentBase(InternalGPIOPin *pin) : pin_(pin){};
106
107 protected:
109};
110
111#ifdef USE_ESP32
113 public:
114 void set_clock_resolution(uint32_t clock_resolution) { this->clock_resolution_ = clock_resolution; }
115 void set_rmt_symbols(uint32_t rmt_symbols) { this->rmt_symbols_ = rmt_symbols; }
116
117 protected:
118 uint32_t from_microseconds_(uint32_t us) {
119 const uint32_t ticks_per_ten_us = this->clock_resolution_ / 100000u;
120 return us * ticks_per_ten_us / 10;
121 }
122 uint32_t to_microseconds_(uint32_t ticks) {
123 const uint32_t ticks_per_ten_us = this->clock_resolution_ / 100000u;
124 return (ticks * 10) / ticks_per_ten_us;
125 }
127 uint32_t clock_resolution_{1000000};
128 uint32_t rmt_symbols_;
129};
130#endif
131
133 public:
136 public:
137 explicit TransmitCall(RemoteTransmitterBase *parent) : parent_(parent) {}
139 void set_send_times(uint32_t send_times) { send_times_ = send_times; }
140 void set_send_wait(uint32_t send_wait) { send_wait_ = send_wait; }
141 void perform() { this->parent_->send_(this->send_times_, this->send_wait_); }
142
143 protected:
145 uint32_t send_times_{1};
146 uint32_t send_wait_{0};
147 };
148
150 this->temp_.reset();
151 return TransmitCall(this);
152 }
153 template<typename Protocol>
154 void transmit(const typename Protocol::ProtocolData &data, uint32_t send_times = 1, uint32_t send_wait = 0) {
155 auto call = this->transmit();
156 Protocol().encode(call.get_data(), data);
157 call.set_send_times(send_times);
158 call.set_send_wait(send_wait);
159 call.perform();
160 }
161
162 protected:
163 void send_(uint32_t send_times, uint32_t send_wait);
164 virtual void send_internal(uint32_t send_times, uint32_t send_wait) = 0;
165 void send_single_() { this->send_(1, 0); }
166
169};
170
172 public:
173 virtual bool on_receive(RemoteReceiveData data) = 0;
174};
175
177 public:
178 virtual bool dump(RemoteReceiveData src) = 0;
179 virtual bool is_secondary() { return false; }
180};
181
183 public:
185 void register_listener(RemoteReceiverListener *listener) { this->listeners_.push_back(listener); }
187 void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) {
188 this->tolerance_ = tolerance;
189 this->tolerance_mode_ = tolerance_mode;
190 }
191
192 protected:
193 void call_listeners_();
194 void call_dumpers_();
196 this->call_listeners_();
197 this->call_dumpers_();
198 }
199
200 std::vector<RemoteReceiverListener *> listeners_;
201 std::vector<RemoteReceiverDumperBase *> dumpers_;
202 std::vector<RemoteReceiverDumperBase *> secondary_dumpers_;
204 uint32_t tolerance_{25};
206};
207
209 public Component,
211 public:
213 void dump_config() override;
214 virtual bool matches(RemoteReceiveData src) = 0;
215 bool on_receive(RemoteReceiveData src) override;
216};
217
218/* TEMPLATES */
219
220template<typename T> class RemoteProtocol {
221 public:
222 using ProtocolData = T;
223 virtual void encode(RemoteTransmitData *dst, const ProtocolData &data) = 0;
225 virtual void dump(const ProtocolData &data) = 0;
226};
227
229 public:
231
232 protected:
233 bool matches(RemoteReceiveData src) override {
234 auto proto = T();
235 auto res = proto.decode(src);
236 return res.has_value() && *res == this->data_;
237 }
238
239 public:
240 void set_data(typename T::ProtocolData data) { data_ = data; }
241
242 protected:
243 typename T::ProtocolData data_;
244};
245
246template<typename T>
247class RemoteReceiverTrigger : public Trigger<typename T::ProtocolData>, public RemoteReceiverListener {
248 protected:
249 bool on_receive(RemoteReceiveData src) override {
250 auto proto = T();
251 auto res = proto.decode(src);
252 if (res.has_value()) {
253 this->trigger(*res);
254 return true;
255 }
256 return false;
257 }
258};
259
261 public:
264 void set_transmitter(RemoteTransmitterBase *transmitter) { this->transmitter_ = transmitter; }
265
266 protected:
267 template<typename Protocol>
268 void transmit_(const typename Protocol::ProtocolData &data, uint32_t send_times = 1, uint32_t send_wait = 0) {
269 this->transmitter_->transmit<Protocol>(data, send_times, send_wait);
270 }
272};
273
274template<typename... Ts> class RemoteTransmitterActionBase : public RemoteTransmittable, public Action<Ts...> {
275 TEMPLATABLE_VALUE(uint32_t, send_times)
276 TEMPLATABLE_VALUE(uint32_t, send_wait)
277
278 protected:
279 void play(Ts... x) override {
280 auto call = this->transmitter_->transmit();
281 this->encode(call.get_data(), x...);
282 call.set_send_times(this->send_times_.value_or(x..., 1));
283 call.set_send_wait(this->send_wait_.value_or(x..., 0));
284 call.perform();
285 }
286 virtual void encode(RemoteTransmitData *dst, Ts... x) = 0;
287};
288
289template<typename T> class RemoteReceiverDumper : public RemoteReceiverDumperBase {
290 public:
291 bool dump(RemoteReceiveData src) override {
292 auto proto = T();
293 auto decoded = proto.decode(src);
294 if (!decoded.has_value())
295 return false;
296 proto.dump(*decoded);
297 return true;
298 }
299};
300
301#define DECLARE_REMOTE_PROTOCOL_(prefix) \
302 using prefix##BinarySensor = RemoteReceiverBinarySensor<prefix##Protocol>; \
303 using prefix##Trigger = RemoteReceiverTrigger<prefix##Protocol>; \
304 using prefix##Dumper = RemoteReceiverDumper<prefix##Protocol>;
305#define DECLARE_REMOTE_PROTOCOL(prefix) DECLARE_REMOTE_PROTOCOL_(prefix)
306
307} // namespace remote_base
308} // 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:51
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:54
bool peek_item(uint32_t mark, uint32_t space, uint32_t offset=0) const
Definition remote_base.h:61
int32_t upper_bound_(uint32_t length) const
Definition remote_base.h:88
bool is_valid(uint32_t offset=0) const
Definition remote_base.h:53
const RawTimings & get_raw_data() const
Definition remote_base.h:49
RemoteReceiveData(const RawTimings &data, uint32_t tolerance, ToleranceMode tolerance_mode)
Definition remote_base.h:46
void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode)
Definition remote_base.h:72
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:80
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
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_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:279
uint16_t length
Definition tt21100.cpp:0
uint16_t x
Definition tt21100.cpp:5