11namespace packet_transport {
14static constexpr size_t PACKET_MAX_LOG_BYTES = 168;
54static const char *
const TAG =
"packet_transport";
56static size_t round4(
size_t value) {
return (value + 3) & ~3; }
63static constexpr uint16_t MAGIC_NUMBER = 0x4553;
64static constexpr uint16_t MAGIC_PING = 0x5048;
65static constexpr uint32_t PREF_HASH = 0x45535043;
82static constexpr size_t MAX_PING_KEYS = 4;
84static inline void add(std::vector<uint8_t> &vec,
uint32_t data) {
85 vec.push_back(data & 0xFF);
86 vec.push_back((data >> 8) & 0xFF);
87 vec.push_back((data >> 16) & 0xFF);
88 vec.push_back((data >> 24) & 0xFF);
93 PacketDecoder(
const uint8_t *buffer,
size_t len) : buffer_(buffer), len_(
len) {}
96 if (this->position_ == this->len_)
98 auto len = this->buffer_[this->position_];
99 if (
len == 0 || this->position_ + 1 +
len > this->len_ ||
len >= maxlen)
102 memcpy(data, this->buffer_ + this->position_,
len);
104 this->position_ +=
len;
109 if (this->position_ +
sizeof(T) > this->len_)
112 for (
size_t i = 0; i !=
sizeof(T); ++i) {
113 value += this->buffer_[this->position_++] << (i * 8);
119 template<
typename T>
DecodeResult decode(uint8_t key, T &data) {
120 if (this->position_ == this->len_)
122 if (this->buffer_[this->position_] != key)
124 if (this->position_ + 1 +
sizeof(T) > this->len_)
128 for (
size_t i = 0; i !=
sizeof(T); ++i) {
129 value += this->buffer_[this->position_++] << (i * 8);
135 template<
typename T>
DecodeResult decode(uint8_t key,
char *buf,
size_t buflen, T &data) {
136 if (this->position_ == this->len_)
138 if (this->buffer_[this->position_] != key)
140 if (this->position_ + 1 +
sizeof(T) > this->len_)
144 for (
size_t i = 0; i !=
sizeof(T); ++i) {
145 value += this->buffer_[this->position_++] << (i * 8);
148 return this->decode_string(buf, buflen);
152 if (this->position_ == this->len_)
154 if (this->buffer_[this->position_] != key)
160 size_t get_remaining_size()
const {
return this->len_ - this->position_; }
163 bool bump_to(
size_t boundary) {
164 auto newpos = this->position_;
165 auto offset = this->position_ % boundary;
167 newpos += boundary - offset;
169 if (newpos >= this->len_)
171 this->position_ = newpos;
175 bool decrypt(
const uint32_t *key)
const {
176 if (this->get_remaining_size() % 4 != 0) {
184 const uint8_t *buffer_;
189static inline void add(std::vector<uint8_t> &vec, uint8_t data) { vec.push_back(data); }
190static inline void add(std::vector<uint8_t> &vec, uint16_t data) {
191 vec.push_back((uint8_t) data);
192 vec.push_back((uint8_t) (data >> 8));
194static inline void add(std::vector<uint8_t> &vec,
DataKey data) { vec.push_back(data); }
195static void add(std::vector<uint8_t> &vec,
const char *str) {
196 auto len = strlen(str);
198 for (
size_t i = 0; i !=
len; i++) {
199 vec.push_back(*str++);
205 if (strlen(this->
name_) > 255) {
220 ESP_LOGV(TAG,
"Rolling code incremented, upper part now %u", (
unsigned) this->
rolling_code_[1]);
223 for (
auto &sensor : this->
sensors_) {
226 sensor.sensor->add_on_state_callback([&sensor](
float x) {
227 sensor.parent->updated_ =
true;
228 sensor.updated =
true;
232#ifdef USE_BINARY_SENSOR
236 sensor.sensor->add_on_state_callback([&sensor](
bool value) {
237 sensor.parent->updated_ =
true;
238 sensor.updated =
true;
243 add(this->
header_, MAGIC_NUMBER);
246 while (this->
header_.size() & 0x3)
260 for (
auto &value : this->
ping_keys_ | std::views::values) {
262 add(this->
data_, value);
269 auto header_len = round4(this->
header_.size());
271 auto encode_buffer = std::vector<uint8_t>(round4(header_len +
len));
272 memcpy(encode_buffer.data(), this->header_.data(), this->header_.size());
273 memcpy(encode_buffer.data() + header_len, this->data_.data(), this->data_.size());
276 (
uint32_t *) this->encryption_key_.data());
279 ESP_LOGVV(TAG,
"Sending packet %s",
format_hex_pretty_to(hex_buf, encode_buffer.data(), encode_buffer.size()));
284 auto len = 1 + 1 + 1 + strlen(
id);
285 if (round4(this->
header_.size()) + round4(this->
data_.size() +
len) > this->get_max_packet_size()) {
289 add(this->
data_, key);
290 add(this->
data_, (uint8_t) data);
291 add(this->
data_,
id);
294 FuData udata{.f32 = data};
299 auto len = 4 + 1 + 1 + strlen(
id);
300 if (round4(this->
header_.size()) + round4(this->
data_.size() +
len) > this->get_max_packet_size()) {
304 add(this->
data_, key);
305 add(this->
data_, data);
306 add(this->
data_,
id);
313 for (
auto &sensor : this->
sensors_) {
314 if (all || sensor.updated) {
315 sensor.updated =
false;
320#ifdef USE_BINARY_SENSOR
322 if (all || sensor.updated) {
323 sensor.updated =
false;
343 ESP_LOGV(TAG,
"Ping request, age %" PRIu32, ping_request_age);
344 this->last_key_time_ = now;
346 for (
const auto &provider : this->
providers_) {
347 uint32_t key_response_age = now - provider.second.last_key_response_time;
349#ifdef USE_STATUS_SENSOR
350 if (provider.second.status_sensor !=
nullptr && provider.second.status_sensor->state) {
351 ESP_LOGI(TAG,
"Ping status for %s timeout at %" PRIu32
" with age %" PRIu32, provider.first.c_str(), now,
353 provider.second.status_sensor->publish_state(
false);
359 for (
auto &
val : it->second | std::views::values) {
360 val->publish_state(NAN);
364#ifdef USE_BINARY_SENSOR
367 for (
auto &
val : bs_it->second | std::views::values) {
368 val->invalidate_state();
373#ifdef USE_STATUS_SENSOR
374 if (provider.second.status_sensor !=
nullptr && !provider.second.status_sensor->state) {
375 ESP_LOGI(TAG,
"Ping status for %s restored at %" PRIu32
" with age %" PRIu32, provider.first.c_str(), now,
377 provider.second.status_sensor->publish_state(
true);
389 if (this->
ping_keys_.size() == MAX_PING_KEYS) {
390 ESP_LOGW(TAG,
"Ping key from %s discarded", name);
398 ESP_LOGV(TAG,
"Ping key from %s now %X", name, (
unsigned) key);
401static bool process_rolling_code(
Provider &provider, PacketDecoder &decoder) {
404 ESP_LOGW(TAG,
"Rolling code requires 8 bytes");
408 ESP_LOGW(TAG,
"Rolling code for %s %08lX:%08lX is old", provider.
name, (
unsigned long) code1,
409 (
unsigned long) code0);
414 ESP_LOGV(TAG,
"Saw new rolling code for %s %08lX:%08lX", provider.
name, (
unsigned long) code1, (
unsigned long) code0);
423 PacketDecoder decoder(data.data(), data.size());
429 ESP_LOGD(TAG,
"Short buffer");
432 if (magic != MAGIC_NUMBER && magic != MAGIC_PING) {
433 ESP_LOGV(TAG,
"Bad magic %X", magic);
437 if (decoder.decode_string(namebuf,
sizeof namebuf) !=
DECODE_OK) {
438 ESP_LOGV(TAG,
"Bad hostname length");
441 if (strcmp(this->
name_, namebuf) == 0) {
442 ESP_LOGVV(TAG,
"Ignoring our own data");
445 if (magic == MAGIC_PING) {
448 ESP_LOGW(TAG,
"Bad ping request");
452 ESP_LOGV(TAG,
"Updated ping key for %s to %08X", namebuf, (
unsigned) key);
458 ESP_LOGVV(TAG,
"Unknown hostname %s", namebuf);
461 auto &provider = it->second;
462 ESP_LOGV(TAG,
"Found hostname %s", namebuf);
465 auto &sensors = this->
remote_sensors_.try_emplace(namebuf).first->second;
467#ifdef USE_BINARY_SENSOR
471 if (!decoder.bump_to(4)) {
472 ESP_LOGW(TAG,
"Bad packet length %zu", data.size());
474 auto len = decoder.get_remaining_size();
476 ESP_LOGW(TAG,
"Bad payload length %zu",
len);
482 ping_key_seen =
true;
488 ESP_LOGV(TAG,
"No key byte");
493 if (!process_rolling_code(provider, decoder))
496 ESP_LOGV(TAG,
"Expected rolling_key or data_key, got %X",
byte);
500 while (decoder.get_remaining_size() != 0) {
505 ping_key_seen =
true;
507 ESP_LOGV(TAG,
"Found good ping key %X at timestamp %" PRIu32, (
unsigned) key, provider.
last_key_response_time);
509 ESP_LOGV(TAG,
"Unknown ping key %X", (
unsigned) key);
513 if (!ping_key_seen) {
514 ESP_LOGW(TAG,
"Ping key not seen");
519 ESP_LOGV(TAG,
"Got binary sensor %s %d", namebuf,
byte);
520#ifdef USE_BINARY_SENSOR
521 auto bs = binary_sensors.find(namebuf);
522 if (bs != binary_sensors.end()) {
523 bs->second->publish_state(
byte != 0);
529 ESP_LOGV(TAG,
"Got sensor %s %f", namebuf, rdata.f32);
531 auto sensor_it = sensors.find(namebuf);
532 if (sensor_it != sensors.end())
533 sensor_it->second->publish_state(rdata.f32);
538 ESP_LOGW(TAG,
"Unknown key %X",
byte);
540 ESP_LOGD(TAG,
"Buffer pos: %zu contents: %s", data.size() - decoder.get_remaining_size(),
549 "Packet Transport:\n"
555 for (
const auto &sensor : this->
sensors_)
556 ESP_LOGCONFIG(TAG,
" Sensor: %s", sensor.id);
558#ifdef USE_BINARY_SENSOR
560 ESP_LOGCONFIG(TAG,
" Binary Sensor: %s", sensor.id);
563 ESP_LOGCONFIG(TAG,
" Remote host: %s", host.first.c_str());
564 ESP_LOGCONFIG(TAG,
" Encrypted: %s", YESNO(!host.second.encryption_key.empty()));
568 for (
const auto &key : rs->second | std::views::keys)
569 ESP_LOGCONFIG(TAG,
" Sensor: %s", key.c_str());
572#ifdef USE_BINARY_SENSOR
575 for (
const auto &key : rbs->second | std::views::keys)
576 ESP_LOGCONFIG(TAG,
" Binary Sensor: %s", key.c_str());
610 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).