13static constexpr size_t PACKET_MAX_LOG_BYTES = 168;
53static const char *
const TAG =
"packet_transport";
55static size_t round4(
size_t value) {
return (value + 3) & ~3; }
62static constexpr uint16_t MAGIC_NUMBER = 0x4553;
63static constexpr uint16_t MAGIC_PING = 0x5048;
64static constexpr uint32_t PREF_HASH = 0x45535043;
81static constexpr size_t MAX_PING_KEYS = 4;
83static inline void add(std::vector<uint8_t> &vec,
uint32_t data) {
84 vec.push_back(data & 0xFF);
85 vec.push_back((data >> 8) & 0xFF);
86 vec.push_back((data >> 16) & 0xFF);
87 vec.push_back((data >> 24) & 0xFF);
92 PacketDecoder(
const uint8_t *buffer,
size_t len) : buffer_(buffer), len_(
len) {}
95 if (this->position_ == this->len_)
97 auto len = this->buffer_[this->position_];
98 if (
len == 0 || this->position_ + 1 +
len > this->len_ ||
len >= maxlen)
101 memcpy(data, this->buffer_ + this->position_,
len);
103 this->position_ +=
len;
108 if (this->position_ +
sizeof(T) > this->len_)
111 for (
size_t i = 0; i !=
sizeof(T); ++i) {
112 value += this->buffer_[this->position_++] << (i * 8);
118 template<
typename T>
DecodeResult decode(uint8_t key, T &data) {
119 if (this->position_ == this->len_)
121 if (this->buffer_[this->position_] != key)
123 if (this->position_ + 1 +
sizeof(T) > this->len_)
127 for (
size_t i = 0; i !=
sizeof(T); ++i) {
128 value += this->buffer_[this->position_++] << (i * 8);
134 template<
typename T>
DecodeResult decode(uint8_t key,
char *buf,
size_t buflen, T &data) {
135 if (this->position_ == this->len_)
137 if (this->buffer_[this->position_] != key)
139 if (this->position_ + 1 +
sizeof(T) > this->len_)
143 for (
size_t i = 0; i !=
sizeof(T); ++i) {
144 value += this->buffer_[this->position_++] << (i * 8);
147 return this->decode_string(buf, buflen);
151 if (this->position_ == this->len_)
153 if (this->buffer_[this->position_] != key)
159 size_t get_remaining_size()
const {
return this->len_ - this->position_; }
162 bool bump_to(
size_t boundary) {
163 auto newpos = this->position_;
164 auto offset = this->position_ % boundary;
166 newpos += boundary - offset;
168 if (newpos >= this->len_)
170 this->position_ = newpos;
174 bool decrypt(
const uint32_t *key)
const {
175 if (this->get_remaining_size() % 4 != 0) {
183 const uint8_t *buffer_;
188static inline void add(std::vector<uint8_t> &vec, uint8_t data) { vec.push_back(data); }
189static inline void add(std::vector<uint8_t> &vec, uint16_t data) {
190 vec.push_back((uint8_t) data);
191 vec.push_back((uint8_t) (data >> 8));
193static inline void add(std::vector<uint8_t> &vec,
DataKey data) { vec.push_back(data); }
194static void add(std::vector<uint8_t> &vec,
const char *str) {
195 auto len = strlen(str);
197 for (
size_t i = 0; i !=
len; i++) {
198 vec.push_back(*str++);
204 if (strlen(this->
name_) > 255) {
219 ESP_LOGV(TAG,
"Rolling code incremented, upper part now %u", (
unsigned) this->
rolling_code_[1]);
222 for (
auto &sensor : this->
sensors_) {
225 sensor.sensor->add_on_state_callback([&sensor](
float x) {
226 sensor.parent->updated_ =
true;
227 sensor.updated =
true;
231#ifdef USE_BINARY_SENSOR
235 sensor.sensor->add_on_state_callback([&sensor](
bool value) {
236 sensor.parent->updated_ =
true;
237 sensor.updated =
true;
242 add(this->
header_, MAGIC_NUMBER);
245 while (this->
header_.size() & 0x3)
259 for (
auto &value : this->
ping_keys_ | std::views::values) {
261 add(this->
data_, value);
268 auto header_len = round4(this->
header_.size());
270 auto encode_buffer = std::vector<uint8_t>(round4(header_len +
len));
271 memcpy(encode_buffer.data(), this->header_.data(), this->header_.size());
272 memcpy(encode_buffer.data() + header_len, this->data_.data(), this->data_.size());
275 (
uint32_t *) this->encryption_key_.data());
278 ESP_LOGVV(TAG,
"Sending packet %s",
format_hex_pretty_to(hex_buf, encode_buffer.data(), encode_buffer.size()));
283 auto len = 1 + 1 + 1 + strlen(
id);
284 if (round4(this->
header_.size()) + round4(this->
data_.size() +
len) > this->get_max_packet_size()) {
288 add(this->
data_, key);
289 add(this->
data_, (uint8_t) data);
290 add(this->
data_,
id);
293 FuData udata{.f32 = data};
298 auto len = 4 + 1 + 1 + strlen(
id);
299 if (round4(this->
header_.size()) + round4(this->
data_.size() +
len) > this->get_max_packet_size()) {
303 add(this->
data_, key);
304 add(this->
data_, data);
305 add(this->
data_,
id);
312 for (
auto &sensor : this->
sensors_) {
313 if (all || sensor.updated) {
314 sensor.updated =
false;
319#ifdef USE_BINARY_SENSOR
321 if (all || sensor.updated) {
322 sensor.updated =
false;
342 ESP_LOGV(TAG,
"Ping request, age %" PRIu32, ping_request_age);
343 this->last_key_time_ = now;
345 for (
const auto &provider : this->
providers_) {
346 uint32_t key_response_age = now - provider.second.last_key_response_time;
348#ifdef USE_STATUS_SENSOR
349 if (provider.second.status_sensor !=
nullptr && provider.second.status_sensor->state) {
350 ESP_LOGI(TAG,
"Ping status for %s timeout at %" PRIu32
" with age %" PRIu32, provider.first.c_str(), now,
352 provider.second.status_sensor->publish_state(
false);
358 for (
auto &
val : it->second | std::views::values) {
359 val->publish_state(NAN);
363#ifdef USE_BINARY_SENSOR
366 for (
auto &
val : bs_it->second | std::views::values) {
367 val->invalidate_state();
372#ifdef USE_STATUS_SENSOR
373 if (provider.second.status_sensor !=
nullptr && !provider.second.status_sensor->state) {
374 ESP_LOGI(TAG,
"Ping status for %s restored at %" PRIu32
" with age %" PRIu32, provider.first.c_str(), now,
376 provider.second.status_sensor->publish_state(
true);
388 if (this->
ping_keys_.size() == MAX_PING_KEYS) {
389 ESP_LOGW(TAG,
"Ping key from %s discarded", name);
397 ESP_LOGV(TAG,
"Ping key from %s now %X", name, (
unsigned) key);
400static bool process_rolling_code(
Provider &provider, PacketDecoder &decoder) {
403 ESP_LOGW(TAG,
"Rolling code requires 8 bytes");
407 ESP_LOGW(TAG,
"Rolling code for %s %08lX:%08lX is old", provider.
name, (
unsigned long) code1,
408 (
unsigned long) code0);
413 ESP_LOGV(TAG,
"Saw new rolling code for %s %08lX:%08lX", provider.
name, (
unsigned long) code1, (
unsigned long) code0);
422 PacketDecoder decoder(data.data(), data.size());
428 ESP_LOGD(TAG,
"Short buffer");
431 if (magic != MAGIC_NUMBER && magic != MAGIC_PING) {
432 ESP_LOGV(TAG,
"Bad magic %X", magic);
436 if (decoder.decode_string(namebuf,
sizeof namebuf) !=
DECODE_OK) {
437 ESP_LOGV(TAG,
"Bad hostname length");
440 if (strcmp(this->
name_, namebuf) == 0) {
441 ESP_LOGVV(TAG,
"Ignoring our own data");
444 if (magic == MAGIC_PING) {
447 ESP_LOGW(TAG,
"Bad ping request");
451 ESP_LOGV(TAG,
"Updated ping key for %s to %08X", namebuf, (
unsigned) key);
457 ESP_LOGVV(TAG,
"Unknown hostname %s", namebuf);
460 auto &provider = it->second;
461 ESP_LOGV(TAG,
"Found hostname %s", namebuf);
464 auto &sensors = this->
remote_sensors_.try_emplace(namebuf).first->second;
466#ifdef USE_BINARY_SENSOR
470 if (!decoder.bump_to(4)) {
471 ESP_LOGW(TAG,
"Bad packet length %zu", data.size());
473 auto len = decoder.get_remaining_size();
475 ESP_LOGW(TAG,
"Bad payload length %zu",
len);
481 ping_key_seen =
true;
487 ESP_LOGV(TAG,
"No key byte");
492 if (!process_rolling_code(provider, decoder))
495 ESP_LOGV(TAG,
"Expected rolling_key or data_key, got %X",
byte);
499 while (decoder.get_remaining_size() != 0) {
504 ping_key_seen =
true;
506 ESP_LOGV(TAG,
"Found good ping key %X at timestamp %" PRIu32, (
unsigned) key, provider.
last_key_response_time);
508 ESP_LOGV(TAG,
"Unknown ping key %X", (
unsigned) key);
512 if (!ping_key_seen) {
513 ESP_LOGW(TAG,
"Ping key not seen");
518 ESP_LOGV(TAG,
"Got binary sensor %s %d", namebuf,
byte);
519#ifdef USE_BINARY_SENSOR
520 auto bs = binary_sensors.find(namebuf);
521 if (bs != binary_sensors.end()) {
522 bs->second->publish_state(
byte != 0);
528 ESP_LOGV(TAG,
"Got sensor %s %f", namebuf, rdata.f32);
530 auto sensor_it = sensors.find(namebuf);
531 if (sensor_it != sensors.end())
532 sensor_it->second->publish_state(rdata.f32);
537 ESP_LOGW(TAG,
"Unknown key %X",
byte);
539 ESP_LOGD(TAG,
"Buffer pos: %zu contents: %s", data.size() - decoder.get_remaining_size(),
548 "Packet Transport:\n"
554 for (
const auto &sensor : this->
sensors_)
555 ESP_LOGCONFIG(TAG,
" Sensor: %s", sensor.id);
557#ifdef USE_BINARY_SENSOR
559 ESP_LOGCONFIG(TAG,
" Binary Sensor: %s", sensor.id);
562 ESP_LOGCONFIG(TAG,
" Remote host: %s", host.first.c_str());
563 ESP_LOGCONFIG(TAG,
" Encrypted: %s", YESNO(!host.second.encryption_key.empty()));
567 for (
const auto &key : rs->second | std::views::keys)
568 ESP_LOGCONFIG(TAG,
" Sensor: %s", key.c_str());
571#ifdef USE_BINARY_SENSOR
574 for (
const auto &key : rbs->second | std::views::keys)
575 ESP_LOGCONFIG(TAG,
" Binary Sensor: %s", key.c_str());
609 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).