8namespace packet_transport {
48static const char *
const TAG =
"packet_transport";
50static size_t round4(
size_t value) {
return (value + 3) & ~3; }
57static const uint16_t MAGIC_NUMBER = 0x4553;
58static const uint16_t MAGIC_PING = 0x5048;
59static const uint32_t PREF_HASH = 0x45535043;
76static const size_t MAX_PING_KEYS = 4;
78static inline void add(std::vector<uint8_t> &vec, uint32_t data) {
79 vec.push_back(data & 0xFF);
80 vec.push_back((data >> 8) & 0xFF);
81 vec.push_back((data >> 16) & 0xFF);
82 vec.push_back((data >> 24) & 0xFF);
87 PacketDecoder(
const uint8_t *buffer,
size_t len) : buffer_(buffer), len_(
len) {}
90 if (this->position_ == this->len_)
92 auto len = this->buffer_[this->position_];
93 if (
len == 0 || this->position_ + 1 +
len > this->len_ ||
len >= maxlen)
96 memcpy(data, this->buffer_ + this->position_,
len);
98 this->position_ +=
len;
103 if (this->position_ +
sizeof(T) > this->len_)
106 for (
size_t i = 0; i !=
sizeof(T); ++i) {
107 value += this->buffer_[this->position_++] << (i * 8);
113 template<
typename T>
DecodeResult decode(uint8_t key, T &data) {
114 if (this->position_ == this->len_)
116 if (this->buffer_[this->position_] != key)
118 if (this->position_ + 1 +
sizeof(T) > this->len_)
122 for (
size_t i = 0; i !=
sizeof(T); ++i) {
123 value += this->buffer_[this->position_++] << (i * 8);
129 template<
typename T>
DecodeResult decode(uint8_t key,
char *buf,
size_t buflen, T &data) {
130 if (this->position_ == this->len_)
132 if (this->buffer_[this->position_] != key)
136 for (
size_t i = 0; i !=
sizeof(T); ++i) {
137 value += this->buffer_[this->position_++] << (i * 8);
140 return this->decode_string(buf, buflen);
144 if (this->position_ == this->len_)
146 if (this->buffer_[this->position_] != key)
152 size_t get_remaining_size()
const {
return this->len_ - this->position_; }
155 bool bump_to(
size_t boundary) {
156 auto newpos = this->position_;
157 auto offset = this->position_ % boundary;
159 newpos += boundary - offset;
161 if (newpos >= this->len_)
163 this->position_ = newpos;
167 bool decrypt(
const uint32_t *key) {
168 if (this->get_remaining_size() % 4 != 0) {
171 xxtea::decrypt((uint32_t *) (this->buffer_ + this->position_), this->get_remaining_size() / 4, key);
176 const uint8_t *buffer_;
181static inline void add(std::vector<uint8_t> &vec, uint8_t data) { vec.push_back(data); }
182static inline void add(std::vector<uint8_t> &vec, uint16_t data) {
183 vec.push_back((uint8_t) data);
184 vec.push_back((uint8_t) (data >> 8));
186static inline void add(std::vector<uint8_t> &vec,
DataKey data) { vec.push_back(data); }
187static void add(std::vector<uint8_t> &vec,
const char *str) {
188 auto len = strlen(str);
190 for (
size_t i = 0; i !=
len; i++) {
191 vec.push_back(*str++);
197 if (strlen(this->
name_) > 255) {
212 ESP_LOGV(TAG,
"Rolling code incremented, upper part now %u", (
unsigned) this->
rolling_code_[1]);
215 for (
auto &sensor : this->
sensors_) {
216 sensor.sensor->add_on_state_callback([
this, &sensor](
float x) {
218 sensor.updated =
true;
222#ifdef USE_BINARY_SENSOR
224 sensor.sensor->add_on_state_callback([
this, &sensor](
bool value) {
226 sensor.updated =
true;
231 add(this->
header_, MAGIC_NUMBER);
234 while (this->
header_.size() & 0x3)
250 add(this->
data_, pkey.second);
257 auto header_len = round4(this->
header_.size());
259 auto encode_buffer = std::vector<uint8_t>(round4(header_len +
len));
260 memcpy(encode_buffer.data(), this->header_.data(), this->header_.size());
261 memcpy(encode_buffer.data() + header_len, this->data_.data(), this->data_.size());
264 (uint32_t *) this->encryption_key_.data());
266 ESP_LOGVV(TAG,
"Sending packet %s",
format_hex_pretty(encode_buffer.data(), encode_buffer.size()).c_str());
271 auto len = 1 + 1 + 1 + strlen(
id);
272 if (
len + this->
header_.size() + this->data_.size() > this->get_max_packet_size()) {
276 add(this->
data_, key);
277 add(this->
data_, (uint8_t) data);
278 add(this->
data_,
id);
281 FuData udata{.f32 = data};
286 auto len = 4 + 1 + 1 + strlen(
id);
287 if (
len + this->
header_.size() + this->data_.size() > this->get_max_packet_size()) {
291 add(this->
data_, key);
292 add(this->
data_, data);
293 add(this->
data_,
id);
300 for (
auto &sensor : this->
sensors_) {
301 if (all || sensor.updated) {
302 sensor.updated =
false;
307#ifdef USE_BINARY_SENSOR
309 if (all || sensor.updated) {
310 sensor.updated =
false;
326 auto now =
millis() / 1000;
329 ESP_LOGV(TAG,
"Ping request, age %u", now - this->
last_key_time_);
332 for (
const auto &provider : this->
providers_) {
333 uint32_t key_response_age = now - provider.second.last_key_response_time;
335#ifdef USE_STATUS_SENSOR
336 if (provider.second.status_sensor !=
nullptr && provider.second.status_sensor->state) {
337 ESP_LOGI(TAG,
"Ping status for %s timeout at %u with age %u", provider.first.c_str(), now, key_response_age);
338 provider.second.status_sensor->publish_state(
false);
343 sensor.second->publish_state(NAN);
346#ifdef USE_BINARY_SENSOR
348 sensor.second->invalidate_state();
352#ifdef USE_STATUS_SENSOR
353 if (provider.second.status_sensor !=
nullptr && !provider.second.status_sensor->state) {
354 ESP_LOGI(TAG,
"Ping status for %s restored at %u with age %u", provider.first.c_str(), now, key_response_age);
355 provider.second.status_sensor->publish_state(
true);
365 if (this->
ping_keys_.count(name) == 0 && this->ping_keys_.size() == MAX_PING_KEYS) {
366 ESP_LOGW(TAG,
"Ping key from %s discarded", name);
371 ESP_LOGV(TAG,
"Ping key from %s now %X", name, (
unsigned) key);
374static bool process_rolling_code(
Provider &provider, PacketDecoder &decoder) {
375 uint32_t code0, code1;
377 ESP_LOGW(TAG,
"Rolling code requires 8 bytes");
381 ESP_LOGW(TAG,
"Rolling code for %s %08lX:%08lX is old", provider.
name, (
unsigned long) code1,
382 (
unsigned long) code0);
387 ESP_LOGV(TAG,
"Saw new rolling code for %s %08lX:%08lX", provider.
name, (
unsigned long) code1, (
unsigned long) code0);
396 PacketDecoder decoder((data.data()), data.size());
402 ESP_LOGD(TAG,
"Short buffer");
405 if (magic != MAGIC_NUMBER && magic != MAGIC_PING) {
406 ESP_LOGV(TAG,
"Bad magic %X", magic);
410 if (decoder.decode_string(namebuf,
sizeof namebuf) !=
DECODE_OK) {
411 ESP_LOGV(TAG,
"Bad hostname length");
414 if (strcmp(this->
name_, namebuf) == 0) {
415 ESP_LOGVV(TAG,
"Ignoring our own data");
418 if (magic == MAGIC_PING) {
421 ESP_LOGW(TAG,
"Bad ping request");
425 ESP_LOGV(TAG,
"Updated ping key for %s to %08X", namebuf, (
unsigned) key);
430 ESP_LOGVV(TAG,
"Unknown hostname %s", namebuf);
433 ESP_LOGV(TAG,
"Found hostname %s", namebuf);
438#ifdef USE_BINARY_SENSOR
442 if (!decoder.bump_to(4)) {
443 ESP_LOGW(TAG,
"Bad packet length %zu", data.size());
445 auto len = decoder.get_remaining_size();
447 ESP_LOGW(TAG,
"Bad payload length %zu",
len);
454 ping_key_seen =
true;
457 decoder.decrypt((
const uint32_t *) provider.
encryption_key.data());
460 ESP_LOGV(TAG,
"No key byte");
465 if (!process_rolling_code(provider, decoder))
468 ESP_LOGV(TAG,
"Expected rolling_key or data_key, got %X",
byte);
472 while (decoder.get_remaining_size() != 0) {
477 ping_key_seen =
true;
479 ESP_LOGV(TAG,
"Found good ping key %X at timestamp %" PRIu32, (
unsigned) key, provider.
last_key_response_time);
481 ESP_LOGV(TAG,
"Unknown ping key %X", (
unsigned) key);
485 if (!ping_key_seen) {
486 ESP_LOGW(TAG,
"Ping key not seen");
491 ESP_LOGV(TAG,
"Got binary sensor %s %d", namebuf,
byte);
492#ifdef USE_BINARY_SENSOR
493 if (binary_sensors.count(namebuf) != 0)
494 binary_sensors[namebuf]->publish_state(
byte != 0);
499 ESP_LOGV(TAG,
"Got sensor %s %f", namebuf, rdata.f32);
501 if (sensors.count(namebuf) != 0)
502 sensors[namebuf]->publish_state(rdata.f32);
507 ESP_LOGW(TAG,
"Unknown key %X",
byte);
508 ESP_LOGD(TAG,
"Buffer pos: %zu contents: %s", data.size() - decoder.get_remaining_size(),
517 "Packet Transport:\n"
524 ESP_LOGCONFIG(TAG,
" Sensor: %s", sensor.id);
526#ifdef USE_BINARY_SENSOR
528 ESP_LOGCONFIG(TAG,
" Binary Sensor: %s", sensor.id);
531 ESP_LOGCONFIG(TAG,
" Remote host: %s", host.first.c_str());
532 ESP_LOGCONFIG(TAG,
" Encrypted: %s", YESNO(!host.second.encryption_key.empty()));
535 ESP_LOGCONFIG(TAG,
" Sensor: %s", sensor.first.c_str());
537#ifdef USE_BINARY_SENSOR
539 ESP_LOGCONFIG(TAG,
" Binary Sensor: %s", sensor.first.c_str());
572 ESP_LOGV(TAG,
"Sent new ping request %08X", (
unsigned) this->
ping_key_);
std::string format_hex_pretty(const uint8_t *data, size_t length, char separator, bool show_length)
Format a byte array in pretty-printed, human-readable hex format.