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