9namespace packet_transport {
12static constexpr size_t PACKET_MAX_LOG_BYTES = 168;
52static const char *
const TAG =
"packet_transport";
54static size_t round4(
size_t value) {
return (value + 3) & ~3; }
61static const uint16_t MAGIC_NUMBER = 0x4553;
62static const uint16_t MAGIC_PING = 0x5048;
63static const uint32_t PREF_HASH = 0x45535043;
80static const size_t MAX_PING_KEYS = 4;
82static inline void add(std::vector<uint8_t> &vec, uint32_t data) {
83 vec.push_back(data & 0xFF);
84 vec.push_back((data >> 8) & 0xFF);
85 vec.push_back((data >> 16) & 0xFF);
86 vec.push_back((data >> 24) & 0xFF);
91 PacketDecoder(
const uint8_t *buffer,
size_t len) : buffer_(buffer), len_(
len) {}
94 if (this->position_ == this->len_)
96 auto len = this->buffer_[this->position_];
97 if (
len == 0 || this->position_ + 1 +
len > this->len_ ||
len >= maxlen)
100 memcpy(data, this->buffer_ + this->position_,
len);
102 this->position_ +=
len;
107 if (this->position_ +
sizeof(T) > this->len_)
110 for (
size_t i = 0; i !=
sizeof(T); ++i) {
111 value += this->buffer_[this->position_++] << (i * 8);
117 template<
typename T>
DecodeResult decode(uint8_t key, T &data) {
118 if (this->position_ == this->len_)
120 if (this->buffer_[this->position_] != key)
122 if (this->position_ + 1 +
sizeof(T) > this->len_)
126 for (
size_t i = 0; i !=
sizeof(T); ++i) {
127 value += this->buffer_[this->position_++] << (i * 8);
133 template<
typename T>
DecodeResult decode(uint8_t key,
char *buf,
size_t buflen, T &data) {
134 if (this->position_ == this->len_)
136 if (this->buffer_[this->position_] != key)
140 for (
size_t i = 0; i !=
sizeof(T); ++i) {
141 value += this->buffer_[this->position_++] << (i * 8);
144 return this->decode_string(buf, buflen);
148 if (this->position_ == this->len_)
150 if (this->buffer_[this->position_] != key)
156 size_t get_remaining_size()
const {
return this->len_ - this->position_; }
159 bool bump_to(
size_t boundary) {
160 auto newpos = this->position_;
161 auto offset = this->position_ % boundary;
163 newpos += boundary - offset;
165 if (newpos >= this->len_)
167 this->position_ = newpos;
171 bool decrypt(
const uint32_t *key) {
172 if (this->get_remaining_size() % 4 != 0) {
175 xxtea::decrypt((uint32_t *) (this->buffer_ + this->position_), this->get_remaining_size() / 4, key);
180 const uint8_t *buffer_;
185static inline void add(std::vector<uint8_t> &vec, uint8_t data) { vec.push_back(data); }
186static inline void add(std::vector<uint8_t> &vec, uint16_t data) {
187 vec.push_back((uint8_t) data);
188 vec.push_back((uint8_t) (data >> 8));
190static inline void add(std::vector<uint8_t> &vec,
DataKey data) { vec.push_back(data); }
191static void add(std::vector<uint8_t> &vec,
const char *str) {
192 auto len = strlen(str);
194 for (
size_t i = 0; i !=
len; i++) {
195 vec.push_back(*str++);
201 if (strlen(this->
name_) > 255) {
216 ESP_LOGV(TAG,
"Rolling code incremented, upper part now %u", (
unsigned) this->
rolling_code_[1]);
219 for (
auto &sensor : this->
sensors_) {
220 sensor.sensor->add_on_state_callback([
this, &sensor](
float x) {
222 sensor.updated =
true;
226#ifdef USE_BINARY_SENSOR
228 sensor.sensor->add_on_state_callback([
this, &sensor](
bool value) {
230 sensor.updated =
true;
235 add(this->
header_, MAGIC_NUMBER);
238 while (this->
header_.size() & 0x3)
254 add(this->
data_, pkey.second);
261 auto header_len = round4(this->
header_.size());
263 auto encode_buffer = std::vector<uint8_t>(round4(header_len +
len));
264 memcpy(encode_buffer.data(), this->header_.data(), this->header_.size());
265 memcpy(encode_buffer.data() + header_len, this->data_.data(), this->data_.size());
268 (uint32_t *) this->encryption_key_.data());
271 ESP_LOGVV(TAG,
"Sending packet %s",
format_hex_pretty_to(hex_buf, encode_buffer.data(), encode_buffer.size()));
276 auto len = 1 + 1 + 1 + strlen(
id);
277 if (round4(this->
header_.size()) + round4(this->
data_.size() +
len) > this->get_max_packet_size()) {
281 add(this->
data_, key);
282 add(this->
data_, (uint8_t) data);
283 add(this->
data_,
id);
286 FuData udata{.f32 = data};
291 auto len = 4 + 1 + 1 + strlen(
id);
292 if (round4(this->
header_.size()) + round4(this->
data_.size() +
len) > this->get_max_packet_size()) {
296 add(this->
data_, key);
297 add(this->
data_, data);
298 add(this->
data_,
id);
305 for (
auto &sensor : this->
sensors_) {
306 if (all || sensor.updated) {
307 sensor.updated =
false;
312#ifdef USE_BINARY_SENSOR
314 if (all || sensor.updated) {
315 sensor.updated =
false;
331 auto now =
millis() / 1000;
334 ESP_LOGV(TAG,
"Ping request, age %u", now - this->
last_key_time_);
337 for (
const auto &provider : this->
providers_) {
338 uint32_t key_response_age = now - provider.second.last_key_response_time;
340#ifdef USE_STATUS_SENSOR
341 if (provider.second.status_sensor !=
nullptr && provider.second.status_sensor->state) {
342 ESP_LOGI(TAG,
"Ping status for %s timeout at %u with age %u", provider.first.c_str(), now, key_response_age);
343 provider.second.status_sensor->publish_state(
false);
348 sensor.second->publish_state(NAN);
351#ifdef USE_BINARY_SENSOR
353 sensor.second->invalidate_state();
357#ifdef USE_STATUS_SENSOR
358 if (provider.second.status_sensor !=
nullptr && !provider.second.status_sensor->state) {
359 ESP_LOGI(TAG,
"Ping status for %s restored at %u with age %u", provider.first.c_str(), now, key_response_age);
360 provider.second.status_sensor->publish_state(
true);
370 if (this->
ping_keys_.count(name) == 0 && this->ping_keys_.size() == MAX_PING_KEYS) {
371 ESP_LOGW(TAG,
"Ping key from %s discarded", name);
376 ESP_LOGV(TAG,
"Ping key from %s now %X", name, (
unsigned) key);
379static bool process_rolling_code(
Provider &provider, PacketDecoder &decoder) {
380 uint32_t code0, code1;
382 ESP_LOGW(TAG,
"Rolling code requires 8 bytes");
386 ESP_LOGW(TAG,
"Rolling code for %s %08lX:%08lX is old", provider.
name, (
unsigned long) code1,
387 (
unsigned long) code0);
392 ESP_LOGV(TAG,
"Saw new rolling code for %s %08lX:%08lX", provider.
name, (
unsigned long) code1, (
unsigned long) code0);
401 PacketDecoder decoder((data.data()), data.size());
407 ESP_LOGD(TAG,
"Short buffer");
410 if (magic != MAGIC_NUMBER && magic != MAGIC_PING) {
411 ESP_LOGV(TAG,
"Bad magic %X", magic);
415 if (decoder.decode_string(namebuf,
sizeof namebuf) !=
DECODE_OK) {
416 ESP_LOGV(TAG,
"Bad hostname length");
419 if (strcmp(this->
name_, namebuf) == 0) {
420 ESP_LOGVV(TAG,
"Ignoring our own data");
423 if (magic == MAGIC_PING) {
426 ESP_LOGW(TAG,
"Bad ping request");
430 ESP_LOGV(TAG,
"Updated ping key for %s to %08X", namebuf, (
unsigned) key);
435 ESP_LOGVV(TAG,
"Unknown hostname %s", namebuf);
438 ESP_LOGV(TAG,
"Found hostname %s", namebuf);
443#ifdef USE_BINARY_SENSOR
447 if (!decoder.bump_to(4)) {
448 ESP_LOGW(TAG,
"Bad packet length %zu", data.size());
450 auto len = decoder.get_remaining_size();
452 ESP_LOGW(TAG,
"Bad payload length %zu",
len);
459 ping_key_seen =
true;
462 decoder.decrypt((
const uint32_t *) provider.
encryption_key.data());
465 ESP_LOGV(TAG,
"No key byte");
470 if (!process_rolling_code(provider, decoder))
473 ESP_LOGV(TAG,
"Expected rolling_key or data_key, got %X",
byte);
477 while (decoder.get_remaining_size() != 0) {
482 ping_key_seen =
true;
484 ESP_LOGV(TAG,
"Found good ping key %X at timestamp %" PRIu32, (
unsigned) key, provider.
last_key_response_time);
486 ESP_LOGV(TAG,
"Unknown ping key %X", (
unsigned) key);
490 if (!ping_key_seen) {
491 ESP_LOGW(TAG,
"Ping key not seen");
496 ESP_LOGV(TAG,
"Got binary sensor %s %d", namebuf,
byte);
497#ifdef USE_BINARY_SENSOR
498 if (binary_sensors.count(namebuf) != 0)
499 binary_sensors[namebuf]->publish_state(
byte != 0);
504 ESP_LOGV(TAG,
"Got sensor %s %f", namebuf, rdata.f32);
506 if (sensors.count(namebuf) != 0)
507 sensors[namebuf]->publish_state(rdata.f32);
512 ESP_LOGW(TAG,
"Unknown key %X",
byte);
514 ESP_LOGD(TAG,
"Buffer pos: %zu contents: %s", data.size() - decoder.get_remaining_size(),
523 "Packet Transport:\n"
530 ESP_LOGCONFIG(TAG,
" Sensor: %s", sensor.id);
532#ifdef USE_BINARY_SENSOR
534 ESP_LOGCONFIG(TAG,
" Binary Sensor: %s", sensor.id);
537 ESP_LOGCONFIG(TAG,
" Remote host: %s", host.first.c_str());
538 ESP_LOGCONFIG(TAG,
" Encrypted: %s", YESNO(!host.second.encryption_key.empty()));
541 ESP_LOGCONFIG(TAG,
" Sensor: %s", sensor.first.c_str());
543#ifdef USE_BINARY_SENSOR
545 ESP_LOGCONFIG(TAG,
" Binary Sensor: %s", sensor.first.c_str());
578 ESP_LOGV(TAG,
"Sent new ping request %08X", (
unsigned) this->
ping_key_);
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).