ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
rc_switch_protocol.cpp
Go to the documentation of this file.
2
3#include <iterator>
4#include "esphome/core/hal.h"
5#include "esphome/core/log.h"
6
7namespace esphome::remote_base {
8
9ESPHOME_LOG_TAG(TAG, "remote.rc_switch");
10
12 // entry 0 is the all-zero protocol, so an out of range index from a lambda transmits nothing
13 if (index >= std::size(RC_SWITCH_PROTOCOLS))
14 index = 0;
15 return rc_switch_protocol_copy(&RC_SWITCH_PROTOCOLS[index]);
16}
17
19 RCSwitchBase copy;
20 progmem_memcpy(&copy, protocol, sizeof(copy));
21 return copy;
22}
23
25 if (!this->inverted_) {
26 dst->mark(this->one_high_);
27 dst->space(this->one_low_);
28 } else {
29 dst->space(this->one_high_);
30 dst->mark(this->one_low_);
31 }
32}
34 if (!this->inverted_) {
35 dst->mark(this->zero_high_);
36 dst->space(this->zero_low_);
37 } else {
38 dst->space(this->zero_high_);
39 dst->mark(this->zero_low_);
40 }
41}
43 if (!this->inverted_) {
44 dst->mark(this->sync_high_);
45 dst->space(this->sync_low_);
46 } else {
47 dst->space(this->sync_high_);
48 dst->mark(this->sync_low_);
49 }
50}
51void RCSwitchBase::transmit(RemoteTransmitData *dst, uint64_t code, uint8_t len) const {
52 dst->set_carrier_frequency(38000);
53 this->sync(dst);
54 for (int16_t i = len - 1; i >= 0; i--) {
55 if (code & ((uint64_t) 1 << i)) {
56 this->one(dst);
57 } else {
58 this->zero(dst);
59 }
60 }
61}
62
64 if (!this->inverted_) {
65 if (!src.peek_mark(this->one_high_))
66 return false;
67 if (!src.peek_space(this->one_low_, 1))
68 return false;
69 } else {
70 if (!src.peek_space(this->one_high_))
71 return false;
72 if (!src.peek_mark(this->one_low_, 1))
73 return false;
74 }
75 src.advance(2);
76 return true;
77}
79 if (!this->inverted_) {
80 if (!src.peek_mark(this->zero_high_))
81 return false;
82 if (!src.peek_space(this->zero_low_, 1))
83 return false;
84 } else {
85 if (!src.peek_space(this->zero_high_))
86 return false;
87 if (!src.peek_mark(this->zero_low_, 1))
88 return false;
89 }
90 src.advance(2);
91 return true;
92}
94 if (!this->inverted_) {
95 if (!src.peek_mark(this->sync_high_))
96 return false;
97 if (!src.peek_space(this->sync_low_, 1))
98 return false;
99 } else {
100 // We can't peek a space at the beginning because signals starts with a low to high transition.
101 // this long space at the beginning is the separation between the transmissions itself, so it is actually
102 // added at the end kind of artificially (by the value given to "idle:" option by the user in the yaml)
103 if (!src.peek_mark(this->sync_low_))
104 return false;
105 src.advance(1);
106 return true;
107 }
108 src.advance(2);
109 return true;
110}
111bool RCSwitchBase::decode(RemoteReceiveData &src, uint64_t *out_data, uint8_t *out_nbits) const {
112 // ignore if sync doesn't exist
113 this->expect_sync(src);
114
115 *out_data = 0;
116 for (*out_nbits = 0; *out_nbits < 64; *out_nbits += 1) {
117 if (this->expect_zero(src)) {
118 *out_data <<= 1;
119 *out_data |= 0;
120 } else if (this->expect_one(src)) {
121 *out_data <<= 1;
122 *out_data |= 1;
123 } else {
124 return *out_nbits >= 8;
125 }
126 }
127 return true;
128}
129optional<RCSwitchData> RCSwitchBase::decode(RemoteReceiveData &src) const {
131 uint8_t out_nbits;
132 for (size_t i = 1; i < std::size(RC_SWITCH_PROTOCOLS); i++) {
133 src.reset();
134 const RCSwitchBase *protocol = &RC_SWITCH_PROTOCOLS[i];
135 if (protocol->decode(src, &out.code, &out_nbits) && out_nbits >= 3) {
136 out.protocol = static_cast<uint8_t>(i);
137 return out;
138 }
139 }
140 return {};
141}
142
143void RCSwitchBase::simple_code_to_tristate(uint16_t code, uint8_t nbits, uint64_t *out_code) {
144 *out_code = 0;
145 for (int8_t i = nbits - 1; i >= 0; i--) {
146 *out_code <<= 2;
147 if (code & (1 << i)) {
148 *out_code |= 0b01;
149 } else {
150 *out_code |= 0b00;
151 }
152 }
153}
154void RCSwitchBase::type_a_code(uint8_t switch_group, uint8_t switch_device, bool state, uint64_t *out_code,
155 uint8_t *out_nbits) {
156 uint16_t code = 0;
157 code = switch_group ^ 0b11111;
158 code <<= 5;
159 code |= switch_device ^ 0b11111;
160 code <<= 2;
161 code |= state ? 0b01 : 0b10;
162 simple_code_to_tristate(code, 12, out_code);
163 *out_nbits = 24;
164}
165void RCSwitchBase::type_b_code(uint8_t address_code, uint8_t channel_code, bool state, uint64_t *out_code,
166 uint8_t *out_nbits) {
167 uint16_t code = 0;
168 code |= (address_code == 1) ? 0 : 0b1000;
169 code |= (address_code == 2) ? 0 : 0b0100;
170 code |= (address_code == 3) ? 0 : 0b0010;
171 code |= (address_code == 4) ? 0 : 0b0001;
172 code <<= 4;
173 code |= (channel_code == 1) ? 0 : 0b1000;
174 code |= (channel_code == 2) ? 0 : 0b0100;
175 code |= (channel_code == 3) ? 0 : 0b0010;
176 code |= (channel_code == 4) ? 0 : 0b0001;
177 code <<= 4;
178 code |= 0b1110;
179 code |= state ? 0b1 : 0b0;
180 simple_code_to_tristate(code, 12, out_code);
181 *out_nbits = 24;
182}
183void RCSwitchBase::type_c_code(uint8_t family, uint8_t group, uint8_t device, bool state, uint64_t *out_code,
184 uint8_t *out_nbits) {
185 uint16_t code = 0;
186 code |= (family & 0b0001) ? 0b1000 : 0;
187 code |= (family & 0b0010) ? 0b0100 : 0;
188 code |= (family & 0b0100) ? 0b0010 : 0;
189 code |= (family & 0b1000) ? 0b0001 : 0;
190 code <<= 4;
191 code |= ((device - 1) & 0b01) ? 0b1000 : 0;
192 code |= ((device - 1) & 0b10) ? 0b0100 : 0;
193 code |= ((group - 1) & 0b01) ? 0b0010 : 0;
194 code |= ((group - 1) & 0b10) ? 0b0001 : 0;
195 code <<= 4;
196 code |= 0b0110;
197 code |= state ? 0b1 : 0b0;
198 simple_code_to_tristate(code, 12, out_code);
199 *out_nbits = 24;
200}
201void RCSwitchBase::type_d_code(uint8_t group, uint8_t device, bool state, uint64_t *out_code, uint8_t *out_nbits) {
202 *out_code = 0;
203 *out_code |= (group == 0) ? 0b11000000 : 0b01000000;
204 *out_code |= (group == 1) ? 0b00110000 : 0b00010000;
205 *out_code |= (group == 2) ? 0b00001100 : 0b00000100;
206 *out_code |= (group == 3) ? 0b00000011 : 0b00000001;
207 *out_code <<= 6;
208 *out_code |= (device == 1) ? 0b110000 : 0b010000;
209 *out_code |= (device == 2) ? 0b001100 : 0b000100;
210 *out_code |= (device == 3) ? 0b000011 : 0b000001;
211 *out_code <<= 6;
212 *out_code |= 0b000000;
213 *out_code <<= 4;
214 *out_code |= state ? 0b1100 : 0b0011;
215 *out_nbits = 24;
216}
217
218uint64_t decode_binary_string(const std::string &data) {
219 uint64_t ret = 0;
220 for (char c : data) {
221 ret <<= 1UL;
222 ret |= (c != '0');
223 }
224 return ret;
225}
226
227uint64_t decode_binary_string_mask(const std::string &data) {
228 uint64_t ret = 0;
229 for (char c : data) {
230 ret <<= 1UL;
231 ret |= (c != 'x');
232 }
233 return ret;
234}
235
237 uint64_t decoded_code;
238 uint8_t decoded_nbits;
239 if (!this->protocol_->decode(src, &decoded_code, &decoded_nbits))
240 return false;
241
242 return decoded_nbits == this->nbits_ && (decoded_code & this->mask_) == (this->code_ & this->mask_);
243}
245 for (size_t i = 1; i < std::size(RC_SWITCH_PROTOCOLS); i++) {
246 src.reset();
247 uint64_t out_data;
248 uint8_t out_nbits;
249 const RCSwitchBase *protocol = &RC_SWITCH_PROTOCOLS[i];
250 if (protocol->decode(src, &out_data, &out_nbits) && out_nbits >= 3) {
251 char buffer[65];
252 for (uint8_t j = 0; j < out_nbits; j++)
253 buffer[j] = (out_data & ((uint64_t) 1 << (out_nbits - j - 1))) ? '1' : '0';
254
255 buffer[out_nbits] = '\0';
256 ESP_LOGI(TAG, "Received RCSwitch Raw: protocol=%u data='%s'", static_cast<unsigned>(i), buffer);
257
258 // only send first decoded protocol
259 return true;
260 }
261 }
262 return false;
263}
264
265} // namespace esphome::remote_base
void zero(RemoteTransmitData *dst) const
static void type_b_code(uint8_t address_code, uint8_t channel_code, bool state, uint64_t *out_code, uint8_t *out_nbits)
bool expect_one(RemoteReceiveData &src) const
bool expect_zero(RemoteReceiveData &src) const
bool decode(RemoteReceiveData &src, uint64_t *out_data, uint8_t *out_nbits) const
static void type_c_code(uint8_t family, uint8_t group, uint8_t device, bool state, uint64_t *out_code, uint8_t *out_nbits)
void transmit(RemoteTransmitData *dst, uint64_t code, uint8_t len) const
static void type_a_code(uint8_t switch_group, uint8_t switch_device, bool state, uint64_t *out_code, uint8_t *out_nbits)
void one(RemoteTransmitData *dst) const
void sync(RemoteTransmitData *dst) const
bool expect_sync(RemoteReceiveData &src) const
static void type_d_code(uint8_t group, uint8_t device, bool state, uint64_t *out_code, uint8_t *out_nbits)
static void simple_code_to_tristate(uint16_t code, uint8_t nbits, uint64_t *out_code)
bool dump(RemoteReceiveData src) override
bool matches(RemoteReceiveData src) override
bool peek_mark(uint32_t length, uint32_t offset=0) const
void set_carrier_frequency(uint32_t carrier_frequency)
Definition remote_base.h:64
bool state
Definition fan.h:2
std::vector< uint8_t > & out
Definition gif.cpp:49
uint32_t buffer
Definition gif.cpp:50
int ret
uint64_t decode_binary_string_mask(const std::string &data)
RCSwitchBase rc_switch_protocol_copy(const RCSwitchBase *protocol)
RAM copy of a protocol stored in flash, made with progmem_memcpy (own name: rc_switch_protocol(0) sta...
ESPHOME_LOG_TAG(TAG, "remote.abbwelcome")
uint64_t decode_binary_string(const std::string &data)
RCSwitchBase rc_switch_protocol(uint8_t index)
RAM copy of RC_SWITCH_PROTOCOLS[index] (0 when out of range) for the transmit actions and the dumper,...
void progmem_memcpy(void *dst, const void *src, size_t len)
Definition hal.h:56
const void size_t len
Definition hal.h:68
const void * src
Definition hal.h:68
uint16_t sync
Definition sun_gtil2.cpp:0