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());
270 auto len = 1 + 1 + 1 + strlen(
id);
271 if (
len + this->
header_.size() + this->data_.size() > this->get_max_packet_size()) {
274 add(this->
data_, key);
275 add(this->
data_, (uint8_t) data);
276 add(this->
data_,
id);
279 FuData udata{.f32 = data};
284 auto len = 4 + 1 + 1 + strlen(
id);
285 if (
len + this->
header_.size() + this->data_.size() > this->get_max_packet_size()) {
288 add(this->
data_, key);
289 add(this->
data_, data);
290 add(this->
data_,
id);
297 for (
auto &sensor : this->
sensors_) {
298 if (all || sensor.updated) {
299 sensor.updated =
false;
304#ifdef USE_BINARY_SENSOR
306 if (all || sensor.updated) {
307 sensor.updated =
false;
320 auto now =
millis() / 1000;
323 ESP_LOGV(TAG,
"Ping request, age %u", now - this->
last_key_time_);
326 for (
const auto &provider : this->
providers_) {
327 uint32_t key_response_age = now - provider.second.last_key_response_time;
329#ifdef USE_STATUS_SENSOR
330 if (provider.second.status_sensor !=
nullptr && provider.second.status_sensor->state) {
331 ESP_LOGI(TAG,
"Ping status for %s timeout at %u with age %u", provider.first.c_str(), now, key_response_age);
332 provider.second.status_sensor->publish_state(
false);
337 sensor.second->publish_state(NAN);
340#ifdef USE_BINARY_SENSOR
342 sensor.second->invalidate_state();
346#ifdef USE_STATUS_SENSOR
347 if (provider.second.status_sensor !=
nullptr && !provider.second.status_sensor->state) {
348 ESP_LOGI(TAG,
"Ping status for %s restored at %u with age %u", provider.first.c_str(), now, key_response_age);
349 provider.second.status_sensor->publish_state(
true);
359 if (this->
ping_keys_.count(name) == 0 && this->ping_keys_.size() == MAX_PING_KEYS) {
360 ESP_LOGW(TAG,
"Ping key from %s discarded", name);
365 ESP_LOGV(TAG,
"Ping key from %s now %X", name, (
unsigned) key);
368static bool process_rolling_code(
Provider &provider, PacketDecoder &decoder) {
369 uint32_t code0, code1;
371 ESP_LOGW(TAG,
"Rolling code requires 8 bytes");
375 ESP_LOGW(TAG,
"Rolling code for %s %08lX:%08lX is old", provider.
name, (
unsigned long) code1,
376 (
unsigned long) code0);
381 ESP_LOGV(TAG,
"Saw new rolling code for %s %08lX:%08lX", provider.
name, (
unsigned long) code1, (
unsigned long) code0);
390 PacketDecoder decoder((data.data()), data.size());
396 ESP_LOGD(TAG,
"Short buffer");
399 if (magic != MAGIC_NUMBER && magic != MAGIC_PING) {
400 ESP_LOGV(TAG,
"Bad magic %X", magic);
404 if (decoder.decode_string(namebuf,
sizeof namebuf) !=
DECODE_OK) {
405 ESP_LOGV(TAG,
"Bad hostname length");
408 if (strcmp(this->
name_, namebuf) == 0) {
409 ESP_LOGVV(TAG,
"Ignoring our own data");
412 if (magic == MAGIC_PING) {
415 ESP_LOGW(TAG,
"Bad ping request");
419 ESP_LOGV(TAG,
"Updated ping key for %s to %08X", namebuf, (
unsigned) key);
424 ESP_LOGVV(TAG,
"Unknown hostname %s", namebuf);
427 ESP_LOGV(TAG,
"Found hostname %s", namebuf);
432#ifdef USE_BINARY_SENSOR
436 if (!decoder.bump_to(4)) {
437 ESP_LOGW(TAG,
"Bad packet length %zu", data.size());
439 auto len = decoder.get_remaining_size();
441 ESP_LOGW(TAG,
"Bad payload length %zu",
len);
448 ping_key_seen =
true;
451 decoder.decrypt((
const uint32_t *) provider.
encryption_key.data());
454 ESP_LOGV(TAG,
"No key byte");
459 if (!process_rolling_code(provider, decoder))
462 ESP_LOGV(TAG,
"Expected rolling_key or data_key, got %X",
byte);
466 while (decoder.get_remaining_size() != 0) {
471 ping_key_seen =
true;
473 ESP_LOGV(TAG,
"Found good ping key %X at timestamp %" PRIu32, (
unsigned) key, provider.
last_key_response_time);
475 ESP_LOGV(TAG,
"Unknown ping key %X", (
unsigned) key);
479 if (!ping_key_seen) {
480 ESP_LOGW(TAG,
"Ping key not seen");
485 ESP_LOGV(TAG,
"Got binary sensor %s %d", namebuf,
byte);
486#ifdef USE_BINARY_SENSOR
487 if (binary_sensors.count(namebuf) != 0)
488 binary_sensors[namebuf]->publish_state(
byte != 0);
493 ESP_LOGV(TAG,
"Got sensor %s %f", namebuf, rdata.f32);
495 if (sensors.count(namebuf) != 0)
496 sensors[namebuf]->publish_state(rdata.f32);
501 ESP_LOGW(TAG,
"Unknown key %X",
byte);
502 ESP_LOGD(TAG,
"Buffer pos: %zu contents: %s", data.size() - decoder.get_remaining_size(),
511 "Packet Transport:\n"
518 ESP_LOGCONFIG(TAG,
" Sensor: %s", sensor.id);
520#ifdef USE_BINARY_SENSOR
522 ESP_LOGCONFIG(TAG,
" Binary Sensor: %s", sensor.id);
525 ESP_LOGCONFIG(TAG,
" Remote host: %s", host.first.c_str());
526 ESP_LOGCONFIG(TAG,
" Encrypted: %s", YESNO(!host.second.encryption_key.empty()));
529 ESP_LOGCONFIG(TAG,
" Sensor: %s", sensor.first.c_str());
531#ifdef USE_BINARY_SENSOR
533 ESP_LOGCONFIG(TAG,
" Binary Sensor: %s", sensor.first.c_str());
566 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.