ESPHome 2026.1.1
Loading...
Searching...
No Matches
helpers.h
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <cmath>
5#include <cstdint>
6#include <cstring>
7#include <functional>
8#include <iterator>
9#include <limits>
10#include <memory>
11#include <span>
12#include <string>
13#include <type_traits>
14#include <vector>
15#include <concepts>
16
18
19#ifdef USE_ESP8266
20#include <Esp.h>
21#endif
22
23#ifdef USE_RP2040
24#include <Arduino.h>
25#endif
26
27#ifdef USE_ESP32
28#include <esp_heap_caps.h>
29#endif
30
31#if defined(USE_ESP32)
32#include <freertos/FreeRTOS.h>
33#include <freertos/semphr.h>
34#elif defined(USE_LIBRETINY)
35#include <FreeRTOS.h>
36#include <semphr.h>
37#endif
38
39#ifdef USE_HOST
40#include <mutex>
41#endif
42
43#define HOT __attribute__((hot))
44#define ESPDEPRECATED(msg, when) __attribute__((deprecated(msg)))
45#define ESPHOME_ALWAYS_INLINE __attribute__((always_inline))
46#define PACKED __attribute__((packed))
47
48namespace esphome {
49
50// Forward declaration to avoid circular dependency with string_ref.h
51class StringRef;
52
55
56// Keep "using" even after the removal of our backports, to avoid breaking existing code.
57using std::to_string;
58using std::is_trivially_copyable;
59using std::make_unique;
60using std::enable_if_t;
61using std::clamp;
62using std::is_invocable;
63#if __cpp_lib_bit_cast >= 201806
64using std::bit_cast;
65#else
67template<
68 typename To, typename From,
69 enable_if_t<sizeof(To) == sizeof(From) && is_trivially_copyable<From>::value && is_trivially_copyable<To>::value,
70 int> = 0>
71To bit_cast(const From &src) {
72 To dst;
73 memcpy(&dst, &src, sizeof(To));
74 return dst;
75}
76#endif
77
78// clang-format off
79inline float lerp(float completion, float start, float end) = delete; // Please use std::lerp. Notice that it has different order on arguments!
80// clang-format on
81
82// std::byteswap from C++23
83template<typename T> constexpr T byteswap(T n) {
84 T m;
85 for (size_t i = 0; i < sizeof(T); i++)
86 reinterpret_cast<uint8_t *>(&m)[i] = reinterpret_cast<uint8_t *>(&n)[sizeof(T) - 1 - i];
87 return m;
88}
89template<> constexpr uint8_t byteswap(uint8_t n) { return n; }
90#ifdef USE_LIBRETINY
91// LibreTiny's Beken framework redefines __builtin_bswap functions as non-constexpr
92template<> inline uint16_t byteswap(uint16_t n) { return __builtin_bswap16(n); }
93template<> inline uint32_t byteswap(uint32_t n) { return __builtin_bswap32(n); }
94template<> inline uint64_t byteswap(uint64_t n) { return __builtin_bswap64(n); }
95template<> inline int8_t byteswap(int8_t n) { return n; }
96template<> inline int16_t byteswap(int16_t n) { return __builtin_bswap16(n); }
97template<> inline int32_t byteswap(int32_t n) { return __builtin_bswap32(n); }
98template<> inline int64_t byteswap(int64_t n) { return __builtin_bswap64(n); }
99#else
100template<> constexpr uint16_t byteswap(uint16_t n) { return __builtin_bswap16(n); }
101template<> constexpr uint32_t byteswap(uint32_t n) { return __builtin_bswap32(n); }
102template<> constexpr uint64_t byteswap(uint64_t n) { return __builtin_bswap64(n); }
103template<> constexpr int8_t byteswap(int8_t n) { return n; }
104template<> constexpr int16_t byteswap(int16_t n) { return __builtin_bswap16(n); }
105template<> constexpr int32_t byteswap(int32_t n) { return __builtin_bswap32(n); }
106template<> constexpr int64_t byteswap(int64_t n) { return __builtin_bswap64(n); }
107#endif
108
110
113
117
118template<typename T> class ConstVector {
119 public:
120 constexpr ConstVector(const T *data, size_t size) : data_(data), size_(size) {}
121
122 const constexpr T &operator[](size_t i) const { return data_[i]; }
123 constexpr size_t size() const { return size_; }
124 constexpr bool empty() const { return size_ == 0; }
125
126 protected:
127 const T *data_;
128 size_t size_;
129};
130
132template<typename T, size_t N> class StaticVector {
133 public:
134 using value_type = T;
135 using iterator = typename std::array<T, N>::iterator;
136 using const_iterator = typename std::array<T, N>::const_iterator;
137 using reverse_iterator = std::reverse_iterator<iterator>;
138 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
139
140 private:
141 std::array<T, N> data_{};
142 size_t count_{0};
143
144 public:
145 // Minimal vector-compatible interface - only what we actually use
146 void push_back(const T &value) {
147 if (count_ < N) {
148 data_[count_++] = value;
149 }
150 }
151
152 // Return reference to next element and increment count (with bounds checking)
154 if (count_ >= N) {
155 // Should never happen with proper size calculation
156 // Return reference to last element to avoid crash
157 return data_[N - 1];
158 }
159 return data_[count_++];
160 }
161
162 size_t size() const { return count_; }
163 bool empty() const { return count_ == 0; }
164
165 // Direct access to underlying data
166 T *data() { return data_.data(); }
167 const T *data() const { return data_.data(); }
168
169 T &operator[](size_t i) { return data_[i]; }
170 const T &operator[](size_t i) const { return data_[i]; }
171
172 // For range-based for loops
173 iterator begin() { return data_.begin(); }
174 iterator end() { return data_.begin() + count_; }
175 const_iterator begin() const { return data_.begin(); }
176 const_iterator end() const { return data_.begin() + count_; }
177
178 // Reverse iterators
183};
184
188template<typename T> class FixedVector {
189 private:
190 T *data_{nullptr};
191 size_t size_{0};
192 size_t capacity_{0};
193
194 // Helper to destroy all elements without freeing memory
195 void destroy_elements_() {
196 // Only call destructors for non-trivially destructible types
197 if constexpr (!std::is_trivially_destructible<T>::value) {
198 for (size_t i = 0; i < size_; i++) {
199 data_[i].~T();
200 }
201 }
202 }
203
204 // Helper to destroy elements and free memory
205 void cleanup_() {
206 if (data_ != nullptr) {
207 destroy_elements_();
208 // Free raw memory
209 ::operator delete(data_);
210 }
211 }
212
213 // Helper to reset pointers after cleanup
214 void reset_() {
215 data_ = nullptr;
216 capacity_ = 0;
217 size_ = 0;
218 }
219
220 // Helper to assign from initializer list (shared by constructor and assignment operator)
221 void assign_from_initializer_list_(std::initializer_list<T> init_list) {
222 init(init_list.size());
223 size_t idx = 0;
224 for (const auto &item : init_list) {
225 new (data_ + idx) T(item);
226 ++idx;
227 }
228 size_ = init_list.size();
229 }
230
231 public:
232 FixedVector() = default;
233
236 FixedVector(std::initializer_list<T> init_list) { assign_from_initializer_list_(init_list); }
237
238 ~FixedVector() { cleanup_(); }
239
240 // Disable copy operations (avoid accidental expensive copies)
241 FixedVector(const FixedVector &) = delete;
243
244 // Enable move semantics (allows use in move-only containers like std::vector)
245 FixedVector(FixedVector &&other) noexcept : data_(other.data_), size_(other.size_), capacity_(other.capacity_) {
246 other.reset_();
247 }
248
249 // Allow conversion to std::vector
250 operator std::vector<T>() const { return {data_, data_ + size_}; }
251
252 FixedVector &operator=(FixedVector &&other) noexcept {
253 if (this != &other) {
254 // Delete our current data
255 cleanup_();
256 // Take ownership of other's data
257 data_ = other.data_;
258 size_ = other.size_;
259 capacity_ = other.capacity_;
260 // Leave other in valid empty state
261 other.reset_();
262 }
263 return *this;
264 }
265
268 FixedVector &operator=(std::initializer_list<T> init_list) {
269 cleanup_();
270 reset_();
271 assign_from_initializer_list_(init_list);
272 return *this;
273 }
274
275 // Allocate capacity - can be called multiple times to reinit
276 // IMPORTANT: After calling init(), you MUST use push_back() to add elements.
277 // Direct assignment via operator[] does NOT update the size counter.
278 void init(size_t n) {
279 cleanup_();
280 reset_();
281 if (n > 0) {
282 // Allocate raw memory without calling constructors
283 // sizeof(T) is correct here for any type T (value types, pointers, etc.)
284 // NOLINTNEXTLINE(bugprone-sizeof-expression)
285 data_ = static_cast<T *>(::operator new(n * sizeof(T)));
286 capacity_ = n;
287 }
288 }
289
290 // Clear the vector (destroy all elements, reset size to 0, keep capacity)
291 void clear() {
292 destroy_elements_();
293 size_ = 0;
294 }
295
296 // Release all memory (destroys elements and frees memory)
297 void release() {
298 cleanup_();
299 reset_();
300 }
301
305 void push_back(const T &value) {
306 if (size_ < capacity_) {
307 // Use placement new to construct the object in pre-allocated memory
308 new (&data_[size_]) T(value);
309 size_++;
310 }
311 }
312
316 void push_back(T &&value) {
317 if (size_ < capacity_) {
318 // Use placement new to move-construct the object in pre-allocated memory
319 new (&data_[size_]) T(std::move(value));
320 size_++;
321 }
322 }
323
328 template<typename... Args> T &emplace_back(Args &&...args) {
329 // Use placement new to construct the object in pre-allocated memory
330 new (&data_[size_]) T(std::forward<Args>(args)...);
331 size_++;
332 return data_[size_ - 1];
333 }
334
337 T &front() { return data_[0]; }
338 const T &front() const { return data_[0]; }
339
342 T &back() { return data_[size_ - 1]; }
343 const T &back() const { return data_[size_ - 1]; }
344
345 size_t size() const { return size_; }
346 bool empty() const { return size_ == 0; }
347
350 T &operator[](size_t i) { return data_[i]; }
351 const T &operator[](size_t i) const { return data_[i]; }
352
355 T &at(size_t i) { return data_[i]; }
356 const T &at(size_t i) const { return data_[i]; }
357
358 // Iterator support for range-based for loops
359 T *begin() { return data_; }
360 T *end() { return data_ + size_; }
361 const T *begin() const { return data_; }
362 const T *end() const { return data_ + size_; }
363};
364
368template<size_t STACK_SIZE> class SmallBufferWithHeapFallback {
369 public:
370 explicit SmallBufferWithHeapFallback(size_t size) {
371 if (size <= STACK_SIZE) {
372 this->buffer_ = this->stack_buffer_;
373 } else {
374 this->heap_buffer_ = new uint8_t[size];
375 this->buffer_ = this->heap_buffer_;
376 }
377 }
378 ~SmallBufferWithHeapFallback() { delete[] this->heap_buffer_; }
379
380 // Delete copy and move operations to prevent double-delete
385
386 uint8_t *get() { return this->buffer_; }
387
388 private:
389 uint8_t stack_buffer_[STACK_SIZE];
390 uint8_t *heap_buffer_{nullptr};
391 uint8_t *buffer_;
392};
393
395
398
400template<typename T, typename U> T remap(U value, U min, U max, T min_out, T max_out) {
401 return (value - min) * (max_out - min_out) / (max - min) + min_out;
402}
403
405uint8_t crc8(const uint8_t *data, uint8_t len, uint8_t crc = 0x00, uint8_t poly = 0x8C, bool msb_first = false);
406
408uint16_t crc16(const uint8_t *data, uint16_t len, uint16_t crc = 0xffff, uint16_t reverse_poly = 0xa001,
409 bool refin = false, bool refout = false);
410uint16_t crc16be(const uint8_t *data, uint16_t len, uint16_t crc = 0, uint16_t poly = 0x1021, bool refin = false,
411 bool refout = false);
412
415uint32_t fnv1_hash(const char *str);
416inline uint32_t fnv1_hash(const std::string &str) { return fnv1_hash(str.c_str()); }
417
419constexpr uint32_t FNV1_OFFSET_BASIS = 2166136261UL;
421constexpr uint32_t FNV1_PRIME = 16777619UL;
422
424constexpr uint32_t fnv1a_hash_extend(uint32_t hash, const char *str) {
425 if (str) {
426 while (*str) {
427 hash ^= *str++;
428 hash *= FNV1_PRIME;
429 }
430 }
431 return hash;
432}
433inline uint32_t fnv1a_hash_extend(uint32_t hash, const std::string &str) {
434 return fnv1a_hash_extend(hash, str.c_str());
435}
437template<std::integral T> constexpr uint32_t fnv1a_hash_extend(uint32_t hash, T value) {
438 using UnsignedT = std::make_unsigned_t<T>;
439 UnsignedT uvalue = static_cast<UnsignedT>(value);
440 for (size_t i = 0; i < sizeof(T); i++) {
441 hash ^= (uvalue >> (i * 8)) & 0xFF;
442 hash *= FNV1_PRIME;
443 }
444 return hash;
445}
447constexpr uint32_t fnv1a_hash(const char *str) { return fnv1a_hash_extend(FNV1_OFFSET_BASIS, str); }
448inline uint32_t fnv1a_hash(const std::string &str) { return fnv1a_hash(str.c_str()); }
449
451uint32_t random_uint32();
453float random_float();
455bool random_bytes(uint8_t *data, size_t len);
456
458
461
463constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb) {
464 return (static_cast<uint16_t>(msb) << 8) | (static_cast<uint16_t>(lsb));
465}
467constexpr uint32_t encode_uint24(uint8_t byte1, uint8_t byte2, uint8_t byte3) {
468 return (static_cast<uint32_t>(byte1) << 16) | (static_cast<uint32_t>(byte2) << 8) | (static_cast<uint32_t>(byte3));
469}
471constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4) {
472 return (static_cast<uint32_t>(byte1) << 24) | (static_cast<uint32_t>(byte2) << 16) |
473 (static_cast<uint32_t>(byte3) << 8) | (static_cast<uint32_t>(byte4));
474}
475
477template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> constexpr T encode_value(const uint8_t *bytes) {
478 T val = 0;
479 for (size_t i = 0; i < sizeof(T); i++) {
480 val <<= 8;
481 val |= bytes[i];
482 }
483 return val;
484}
486template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
487constexpr T encode_value(const std::array<uint8_t, sizeof(T)> bytes) {
488 return encode_value<T>(bytes.data());
489}
491template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
492constexpr std::array<uint8_t, sizeof(T)> decode_value(T val) {
493 std::array<uint8_t, sizeof(T)> ret{};
494 for (size_t i = sizeof(T); i > 0; i--) {
495 ret[i - 1] = val & 0xFF;
496 val >>= 8;
497 }
498 return ret;
499}
500
502inline uint8_t reverse_bits(uint8_t x) {
503 x = ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
504 x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2);
505 x = ((x & 0xF0) >> 4) | ((x & 0x0F) << 4);
506 return x;
507}
509inline uint16_t reverse_bits(uint16_t x) {
510 return (reverse_bits(static_cast<uint8_t>(x & 0xFF)) << 8) | reverse_bits(static_cast<uint8_t>((x >> 8) & 0xFF));
511}
513inline uint32_t reverse_bits(uint32_t x) {
514 return (reverse_bits(static_cast<uint16_t>(x & 0xFFFF)) << 16) |
515 reverse_bits(static_cast<uint16_t>((x >> 16) & 0xFFFF));
516}
517
519template<typename T> constexpr T convert_big_endian(T val) {
520#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
521 return byteswap(val);
522#else
523 return val;
524#endif
525}
526
528template<typename T> constexpr T convert_little_endian(T val) {
529#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
530 return val;
531#else
532 return byteswap(val);
533#endif
534}
535
537
540
542bool str_equals_case_insensitive(const std::string &a, const std::string &b);
544bool str_equals_case_insensitive(StringRef a, StringRef b);
545
547bool str_startswith(const std::string &str, const std::string &start);
549bool str_endswith(const std::string &str, const std::string &end);
550
553std::string str_truncate(const std::string &str, size_t length);
554
557std::string str_until(const char *str, char ch);
559std::string str_until(const std::string &str, char ch);
560
562std::string str_lower_case(const std::string &str);
565std::string str_upper_case(const std::string &str);
566
568constexpr char to_snake_case_char(char c) { return (c == ' ') ? '_' : (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; }
571std::string str_snake_case(const std::string &str);
572
574constexpr char to_sanitized_char(char c) {
575 return (c == '-' || c == '_' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) ? c : '_';
576}
578std::string str_sanitize(const std::string &str);
579
584inline uint32_t fnv1_hash_object_id(const char *str, size_t len) {
585 uint32_t hash = FNV1_OFFSET_BASIS;
586 for (size_t i = 0; i < len; i++) {
587 hash *= FNV1_PRIME;
588 // Apply snake_case (space->underscore, uppercase->lowercase) then sanitize
589 hash ^= static_cast<uint8_t>(to_sanitized_char(to_snake_case_char(str[i])));
590 }
591 return hash;
592}
593
595std::string __attribute__((format(printf, 1, 3))) str_snprintf(const char *fmt, size_t len, ...);
596
598std::string __attribute__((format(printf, 1, 2))) str_sprintf(const char *fmt, ...);
599
608std::string make_name_with_suffix(const std::string &name, char sep, const char *suffix_ptr, size_t suffix_len);
609
618std::string make_name_with_suffix(const char *name, size_t name_len, char sep, const char *suffix_ptr,
619 size_t suffix_len);
620
630size_t make_name_with_suffix_to(char *buffer, size_t buffer_size, const char *name, size_t name_len, char sep,
631 const char *suffix_ptr, size_t suffix_len);
632
634
637
639template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
640optional<T> parse_number(const char *str) {
641 char *end = nullptr;
642 unsigned long value = ::strtoul(str, &end, 10); // NOLINT(google-runtime-int)
643 if (end == str || *end != '\0' || value > std::numeric_limits<T>::max())
644 return {};
645 return value;
646}
648template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
649optional<T> parse_number(const std::string &str) {
650 return parse_number<T>(str.c_str());
651}
653template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
654optional<T> parse_number(const char *str) {
655 char *end = nullptr;
656 signed long value = ::strtol(str, &end, 10); // NOLINT(google-runtime-int)
657 if (end == str || *end != '\0' || value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max())
658 return {};
659 return value;
660}
662template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
663optional<T> parse_number(const std::string &str) {
664 return parse_number<T>(str.c_str());
665}
667template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0> optional<T> parse_number(const char *str) {
668 char *end = nullptr;
669 float value = ::strtof(str, &end);
670 if (end == str || *end != '\0' || value == HUGE_VALF)
671 return {};
672 return value;
673}
675template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0>
676optional<T> parse_number(const std::string &str) {
677 return parse_number<T>(str.c_str());
678}
679
691size_t parse_hex(const char *str, size_t len, uint8_t *data, size_t count);
693inline bool parse_hex(const char *str, uint8_t *data, size_t count) {
694 return parse_hex(str, strlen(str), data, count) == 2 * count;
695}
697inline bool parse_hex(const std::string &str, uint8_t *data, size_t count) {
698 return parse_hex(str.c_str(), str.length(), data, count) == 2 * count;
699}
701inline bool parse_hex(const char *str, std::vector<uint8_t> &data, size_t count) {
702 data.resize(count);
703 return parse_hex(str, strlen(str), data.data(), count) == 2 * count;
704}
706inline bool parse_hex(const std::string &str, std::vector<uint8_t> &data, size_t count) {
707 data.resize(count);
708 return parse_hex(str.c_str(), str.length(), data.data(), count) == 2 * count;
709}
715template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
716optional<T> parse_hex(const char *str, size_t len) {
717 T val = 0;
718 if (len > 2 * sizeof(T) || parse_hex(str, len, reinterpret_cast<uint8_t *>(&val), sizeof(T)) == 0)
719 return {};
720 return convert_big_endian(val);
721}
723template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> optional<T> parse_hex(const char *str) {
724 return parse_hex<T>(str, strlen(str));
725}
727template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> optional<T> parse_hex(const std::string &str) {
728 return parse_hex<T>(str.c_str(), str.length());
729}
730
732constexpr uint8_t parse_hex_char(char c) {
733 if (c >= '0' && c <= '9')
734 return c - '0';
735 if (c >= 'A' && c <= 'F')
736 return c - 'A' + 10;
737 if (c >= 'a' && c <= 'f')
738 return c - 'a' + 10;
739 return 255;
740}
741
743inline char format_hex_char(uint8_t v, char base) { return v >= 10 ? base + (v - 10) : '0' + v; }
744
746inline char format_hex_char(uint8_t v) { return format_hex_char(v, 'a'); }
747
749inline char format_hex_pretty_char(uint8_t v) { return format_hex_char(v, 'A'); }
750
753inline char *int8_to_str(char *buf, int8_t val) {
754 int32_t v = val;
755 if (v < 0) {
756 *buf++ = '-';
757 v = -v;
758 }
759 if (v >= 100) {
760 *buf++ = '1'; // int8 max is 128, so hundreds digit is always 1
761 v -= 100;
762 // Must write tens digit (even if 0) after hundreds
763 int32_t tens = v / 10;
764 *buf++ = '0' + tens;
765 v -= tens * 10;
766 } else if (v >= 10) {
767 int32_t tens = v / 10;
768 *buf++ = '0' + tens;
769 v -= tens * 10;
770 }
771 *buf++ = '0' + v;
772 return buf;
773}
774
776char *format_hex_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length);
777
780template<size_t N> inline char *format_hex_to(char (&buffer)[N], const uint8_t *data, size_t length) {
781 static_assert(N >= 3, "Buffer must hold at least one hex byte (3 chars)");
782 return format_hex_to(buffer, N, data, length);
783}
784
786template<size_t N, typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
787inline char *format_hex_to(char (&buffer)[N], T val) {
788 static_assert(N >= sizeof(T) * 2 + 1, "Buffer too small for type");
790 return format_hex_to(buffer, reinterpret_cast<const uint8_t *>(&val), sizeof(T));
791}
792
794template<size_t N> inline char *format_hex_to(char (&buffer)[N], const std::vector<uint8_t> &data) {
795 return format_hex_to(buffer, data.data(), data.size());
796}
797
799template<size_t N, size_t M> inline char *format_hex_to(char (&buffer)[N], const std::array<uint8_t, M> &data) {
800 return format_hex_to(buffer, data.data(), data.size());
801}
802
804constexpr size_t format_hex_size(size_t byte_count) { return byte_count * 2 + 1; }
805
807constexpr size_t format_hex_prefixed_size(size_t byte_count) { return byte_count * 2 + 3; }
808
810template<size_t N, typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
811inline char *format_hex_prefixed_to(char (&buffer)[N], T val) {
812 static_assert(N >= sizeof(T) * 2 + 3, "Buffer too small for prefixed hex");
813 buffer[0] = '0';
814 buffer[1] = 'x';
816 format_hex_to(buffer + 2, N - 2, reinterpret_cast<const uint8_t *>(&val), sizeof(T));
817 return buffer;
818}
819
821template<size_t N> inline char *format_hex_prefixed_to(char (&buffer)[N], const uint8_t *data, size_t length) {
822 static_assert(N >= 5, "Buffer must hold at least '0x' + one hex byte + null");
823 buffer[0] = '0';
824 buffer[1] = 'x';
825 format_hex_to(buffer + 2, N - 2, data, length);
826 return buffer;
827}
828
830constexpr size_t format_hex_pretty_size(size_t byte_count) { return byte_count * 3; }
831
843char *format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator = ':');
844
846template<size_t N>
847inline char *format_hex_pretty_to(char (&buffer)[N], const uint8_t *data, size_t length, char separator = ':') {
848 static_assert(N >= 3, "Buffer must hold at least one hex byte");
849 return format_hex_pretty_to(buffer, N, data, length, separator);
850}
851
853template<size_t N>
854inline char *format_hex_pretty_to(char (&buffer)[N], const std::vector<uint8_t> &data, char separator = ':') {
855 return format_hex_pretty_to(buffer, data.data(), data.size(), separator);
856}
857
859template<size_t N, size_t M>
860inline char *format_hex_pretty_to(char (&buffer)[N], const std::array<uint8_t, M> &data, char separator = ':') {
861 return format_hex_pretty_to(buffer, data.data(), data.size(), separator);
862}
863
865constexpr size_t format_hex_pretty_uint16_size(size_t count) { return count * 5; }
866
880char *format_hex_pretty_to(char *buffer, size_t buffer_size, const uint16_t *data, size_t length, char separator = ':');
881
883template<size_t N>
884inline char *format_hex_pretty_to(char (&buffer)[N], const uint16_t *data, size_t length, char separator = ':') {
885 static_assert(N >= 5, "Buffer must hold at least one hex uint16_t");
886 return format_hex_pretty_to(buffer, N, data, length, separator);
887}
888
890static constexpr size_t MAC_ADDRESS_SIZE = 6;
892static constexpr size_t MAC_ADDRESS_PRETTY_BUFFER_SIZE = format_hex_pretty_size(MAC_ADDRESS_SIZE);
894static constexpr size_t MAC_ADDRESS_BUFFER_SIZE = MAC_ADDRESS_SIZE * 2 + 1;
895
897inline char *format_mac_addr_upper(const uint8_t *mac, char *output) {
898 return format_hex_pretty_to(output, MAC_ADDRESS_PRETTY_BUFFER_SIZE, mac, MAC_ADDRESS_SIZE, ':');
899}
900
902inline void format_mac_addr_lower_no_sep(const uint8_t *mac, char *output) {
903 format_hex_to(output, MAC_ADDRESS_BUFFER_SIZE, mac, MAC_ADDRESS_SIZE);
904}
905
909std::string format_mac_address_pretty(const uint8_t mac[6]);
913std::string format_hex(const uint8_t *data, size_t length);
917std::string format_hex(const std::vector<uint8_t> &data);
921template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> std::string format_hex(T val) {
923 return format_hex(reinterpret_cast<uint8_t *>(&val), sizeof(T));
924}
928template<std::size_t N> std::string format_hex(const std::array<uint8_t, N> &data) {
929 return format_hex(data.data(), data.size());
930}
931
957std::string format_hex_pretty(const uint8_t *data, size_t length, char separator = '.', bool show_length = true);
958
979std::string format_hex_pretty(const uint16_t *data, size_t length, char separator = '.', bool show_length = true);
980
1002std::string format_hex_pretty(const std::vector<uint8_t> &data, char separator = '.', bool show_length = true);
1003
1024std::string format_hex_pretty(const std::vector<uint16_t> &data, char separator = '.', bool show_length = true);
1025
1046std::string format_hex_pretty(const std::string &data, char separator = '.', bool show_length = true);
1047
1071template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
1072std::string format_hex_pretty(T val, char separator = '.', bool show_length = true) {
1074 return format_hex_pretty(reinterpret_cast<uint8_t *>(&val), sizeof(T), separator, show_length);
1075}
1076
1078std::string format_bin(const uint8_t *data, size_t length);
1080template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> std::string format_bin(T val) {
1082 return format_bin(reinterpret_cast<uint8_t *>(&val), sizeof(T));
1083}
1084
1093ParseOnOffState parse_on_off(const char *str, const char *on = nullptr, const char *off = nullptr);
1094
1096ESPDEPRECATED("Allocates heap memory. Use value_accuracy_to_buf() instead. Removed in 2026.7.0.", "2026.1.0")
1097std::string value_accuracy_to_string(float value, int8_t accuracy_decimals);
1098
1100static constexpr size_t VALUE_ACCURACY_MAX_LEN = 64;
1101
1103size_t value_accuracy_to_buf(std::span<char, VALUE_ACCURACY_MAX_LEN> buf, float value, int8_t accuracy_decimals);
1105size_t value_accuracy_with_uom_to_buf(std::span<char, VALUE_ACCURACY_MAX_LEN> buf, float value,
1106 int8_t accuracy_decimals, StringRef unit_of_measurement);
1107
1109int8_t step_to_accuracy_decimals(float step);
1110
1111std::string base64_encode(const uint8_t *buf, size_t buf_len);
1112std::string base64_encode(const std::vector<uint8_t> &buf);
1113
1114std::vector<uint8_t> base64_decode(const std::string &encoded_string);
1115size_t base64_decode(std::string const &encoded_string, uint8_t *buf, size_t buf_len);
1116size_t base64_decode(const uint8_t *encoded_data, size_t encoded_len, uint8_t *buf, size_t buf_len);
1117
1119
1122
1124float gamma_correct(float value, float gamma);
1126float gamma_uncorrect(float value, float gamma);
1127
1129void rgb_to_hsv(float red, float green, float blue, int &hue, float &saturation, float &value);
1131void hsv_to_rgb(int hue, float saturation, float value, float &red, float &green, float &blue);
1132
1134
1137
1139constexpr float celsius_to_fahrenheit(float value) { return value * 1.8f + 32.0f; }
1141constexpr float fahrenheit_to_celsius(float value) { return (value - 32.0f) / 1.8f; }
1142
1144
1147
1148template<typename... X> class CallbackManager;
1149
1154template<typename... Ts> class CallbackManager<void(Ts...)> {
1155 public:
1157 void add(std::function<void(Ts...)> &&callback) { this->callbacks_.push_back(std::move(callback)); }
1158
1160 void call(Ts... args) {
1161 for (auto &cb : this->callbacks_)
1162 cb(args...);
1163 }
1164 size_t size() const { return this->callbacks_.size(); }
1165
1167 void operator()(Ts... args) { call(args...); }
1168
1169 protected:
1170 std::vector<std::function<void(Ts...)>> callbacks_;
1171};
1172
1173template<typename... X> class LazyCallbackManager;
1174
1187template<typename... Ts> class LazyCallbackManager<void(Ts...)> {
1188 public:
1190 void add(std::function<void(Ts...)> &&callback) {
1191 if (!this->callbacks_) {
1192 this->callbacks_ = make_unique<CallbackManager<void(Ts...)>>();
1193 }
1194 this->callbacks_->add(std::move(callback));
1195 }
1196
1198 void call(Ts... args) {
1199 if (this->callbacks_) {
1200 this->callbacks_->call(args...);
1201 }
1202 }
1203
1205 size_t size() const { return this->callbacks_ ? this->callbacks_->size() : 0; }
1206
1208 bool empty() const { return !this->callbacks_ || this->callbacks_->size() == 0; }
1209
1211 void operator()(Ts... args) { this->call(args...); }
1212
1213 protected:
1214 std::unique_ptr<CallbackManager<void(Ts...)>> callbacks_;
1215};
1216
1218template<typename T> class Deduplicator {
1219 public:
1221 bool next(T value) {
1222 if (this->has_value_ && !this->value_unknown_ && this->last_value_ == value) {
1223 return false;
1224 }
1225 this->has_value_ = true;
1226 this->value_unknown_ = false;
1227 this->last_value_ = value;
1228 return true;
1229 }
1232 bool ret = !this->value_unknown_;
1233 this->value_unknown_ = true;
1234 return ret;
1235 }
1237 bool has_value() const { return this->has_value_; }
1238
1239 protected:
1240 bool has_value_{false};
1241 bool value_unknown_{false};
1243};
1244
1246template<typename T> class Parented {
1247 public:
1249 Parented(T *parent) : parent_(parent) {}
1250
1252 T *get_parent() const { return parent_; }
1254 void set_parent(T *parent) { parent_ = parent; }
1255
1256 protected:
1257 T *parent_{nullptr};
1258};
1259
1261
1264
1269class Mutex {
1270 public:
1271 Mutex();
1272 Mutex(const Mutex &) = delete;
1273 ~Mutex();
1274 void lock();
1275 bool try_lock();
1276 void unlock();
1277
1278 Mutex &operator=(const Mutex &) = delete;
1279
1280 private:
1281#if defined(USE_ESP32) || defined(USE_LIBRETINY)
1282 SemaphoreHandle_t handle_;
1283#else
1284 // d-pointer to store private data on new platforms
1285 void *handle_; // NOLINT(clang-diagnostic-unused-private-field)
1286#endif
1287};
1288
1294 public:
1295 LockGuard(Mutex &mutex) : mutex_(mutex) { mutex_.lock(); }
1296 ~LockGuard() { mutex_.unlock(); }
1297
1298 private:
1299 Mutex &mutex_;
1300};
1301
1323 public:
1324 InterruptLock();
1326
1327 protected:
1328#if defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_ZEPHYR)
1329 uint32_t state_;
1330#endif
1331};
1332
1341 public:
1342 LwIPLock();
1343 ~LwIPLock();
1344
1345 // Delete copy constructor and copy assignment operator to prevent accidental copying
1346 LwIPLock(const LwIPLock &) = delete;
1347 LwIPLock &operator=(const LwIPLock &) = delete;
1348};
1349
1356 public:
1358 void start();
1360 void stop();
1361
1363 static bool is_high_frequency();
1364
1365 protected:
1366 bool started_{false};
1367 static uint8_t num_requests; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
1368};
1369
1371void get_mac_address_raw(uint8_t *mac); // NOLINT(readability-non-const-parameter)
1372
1376std::string get_mac_address();
1377
1381std::string get_mac_address_pretty();
1382
1386void get_mac_address_into_buffer(std::span<char, MAC_ADDRESS_BUFFER_SIZE> buf);
1387
1391const char *get_mac_address_pretty_into_buffer(std::span<char, MAC_ADDRESS_PRETTY_BUFFER_SIZE> buf);
1392
1393#ifdef USE_ESP32
1395void set_mac_address(uint8_t *mac);
1396#endif
1397
1401
1404bool mac_address_is_valid(const uint8_t *mac);
1405
1407void delay_microseconds_safe(uint32_t us);
1408
1410
1413
1422template<class T> class RAMAllocator {
1423 public:
1424 using value_type = T;
1425
1426 enum Flags {
1427 NONE = 0, // Perform external allocation and fall back to internal memory
1428 ALLOC_EXTERNAL = 1 << 0, // Perform external allocation only.
1429 ALLOC_INTERNAL = 1 << 1, // Perform internal allocation only.
1430 ALLOW_FAILURE = 1 << 2, // Does nothing. Kept for compatibility.
1431 };
1432
1433 RAMAllocator() = default;
1435 // default is both external and internal
1437 if (flags != 0)
1438 this->flags_ = flags;
1439 }
1440 template<class U> constexpr RAMAllocator(const RAMAllocator<U> &other) : flags_{other.flags_} {}
1441
1442 T *allocate(size_t n) { return this->allocate(n, sizeof(T)); }
1443
1444 T *allocate(size_t n, size_t manual_size) {
1445 size_t size = n * manual_size;
1446 T *ptr = nullptr;
1447#ifdef USE_ESP32
1448 if (this->flags_ & Flags::ALLOC_EXTERNAL) {
1449 ptr = static_cast<T *>(heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
1450 }
1451 if (ptr == nullptr && this->flags_ & Flags::ALLOC_INTERNAL) {
1452 ptr = static_cast<T *>(heap_caps_malloc(size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
1453 }
1454#else
1455 // Ignore ALLOC_EXTERNAL/ALLOC_INTERNAL flags if external allocation is not supported
1456 ptr = static_cast<T *>(malloc(size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
1457#endif
1458 return ptr;
1459 }
1460
1461 T *reallocate(T *p, size_t n) { return this->reallocate(p, n, sizeof(T)); }
1462
1463 T *reallocate(T *p, size_t n, size_t manual_size) {
1464 size_t size = n * manual_size;
1465 T *ptr = nullptr;
1466#ifdef USE_ESP32
1467 if (this->flags_ & Flags::ALLOC_EXTERNAL) {
1468 ptr = static_cast<T *>(heap_caps_realloc(p, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
1469 }
1470 if (ptr == nullptr && this->flags_ & Flags::ALLOC_INTERNAL) {
1471 ptr = static_cast<T *>(heap_caps_realloc(p, size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
1472 }
1473#else
1474 // Ignore ALLOC_EXTERNAL/ALLOC_INTERNAL flags if external allocation is not supported
1475 ptr = static_cast<T *>(realloc(p, size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
1476#endif
1477 return ptr;
1478 }
1479
1480 void deallocate(T *p, size_t n) {
1481 free(p); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
1482 }
1483
1487 size_t get_free_heap_size() const {
1488#ifdef USE_ESP8266
1489 return ESP.getFreeHeap(); // NOLINT(readability-static-accessed-through-instance)
1490#elif defined(USE_ESP32)
1491 auto max_internal =
1492 this->flags_ & ALLOC_INTERNAL ? heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL) : 0;
1493 auto max_external =
1494 this->flags_ & ALLOC_EXTERNAL ? heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM) : 0;
1495 return max_internal + max_external;
1496#elif defined(USE_RP2040)
1497 return ::rp2040.getFreeHeap();
1498#elif defined(USE_LIBRETINY)
1499 return lt_heap_get_free();
1500#else
1501 return 100000;
1502#endif
1503 }
1504
1509#ifdef USE_ESP8266
1510 return ESP.getMaxFreeBlockSize(); // NOLINT(readability-static-accessed-through-instance)
1511#elif defined(USE_ESP32)
1512 auto max_internal =
1513 this->flags_ & ALLOC_INTERNAL ? heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL) : 0;
1514 auto max_external =
1515 this->flags_ & ALLOC_EXTERNAL ? heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM) : 0;
1516 return std::max(max_internal, max_external);
1517#else
1518 return this->get_free_heap_size();
1519#endif
1520 }
1521
1522 private:
1523 uint8_t flags_{ALLOC_INTERNAL | ALLOC_EXTERNAL};
1524};
1525
1526template<class T> using ExternalRAMAllocator = RAMAllocator<T>;
1527
1532template<typename T, typename U>
1533concept comparable_with = requires(T a, U b) {
1534 { a > b } -> std::convertible_to<bool>;
1535 { a < b } -> std::convertible_to<bool>;
1536};
1537
1538template<std::totally_ordered T, comparable_with<T> U> T clamp_at_least(T value, U min) {
1539 if (value < min)
1540 return min;
1541 return value;
1542}
1543template<std::totally_ordered T, comparable_with<T> U> T clamp_at_most(T value, U max) {
1544 if (value > max)
1545 return max;
1546 return value;
1547}
1548
1551
1556template<typename T, enable_if_t<!std::is_pointer<T>::value, int> = 0> T id(T value) { return value; }
1561template<typename T, enable_if_t<std::is_pointer<T *>::value, int> = 0> T &id(T *value) { return *value; }
1562
1564
1565} // namespace esphome
uint8_t m
Definition bl0906.h:1
void operator()(Ts... args)
Call all callbacks in this manager.
Definition helpers.h:1167
std::vector< std::function< void(Ts...)> > callbacks_
Definition helpers.h:1170
void call(Ts... args)
Call all callbacks in this manager.
Definition helpers.h:1160
void add(std::function< void(Ts...)> &&callback)
Add a callback to the list.
Definition helpers.h:1157
Lightweight read-only view over a const array stored in RODATA (will typically be in flash memory) Av...
Definition helpers.h:118
const constexpr T & operator[](size_t i) const
Definition helpers.h:122
constexpr bool empty() const
Definition helpers.h:124
constexpr ConstVector(const T *data, size_t size)
Definition helpers.h:120
constexpr size_t size() const
Definition helpers.h:123
Helper class to deduplicate items in a series of values.
Definition helpers.h:1218
bool next(T value)
Feeds the next item in the series to the deduplicator and returns false if this is a duplicate.
Definition helpers.h:1221
bool has_value() const
Returns true if this deduplicator has processed any items.
Definition helpers.h:1237
bool next_unknown()
Returns true if the deduplicator's value was previously known.
Definition helpers.h:1231
Fixed-capacity vector - allocates once at runtime, never reallocates This avoids std::vector template...
Definition helpers.h:188
const T & at(size_t i) const
Definition helpers.h:356
FixedVector(FixedVector &&other) noexcept
Definition helpers.h:245
FixedVector(std::initializer_list< T > init_list)
Constructor from initializer list - allocates exact size needed This enables brace initialization: Fi...
Definition helpers.h:236
const T * begin() const
Definition helpers.h:361
FixedVector & operator=(std::initializer_list< T > init_list)
Assignment from initializer list - avoids temporary and move overhead This enables: FixedVector<int> ...
Definition helpers.h:268
T & front()
Access first element (no bounds checking - matches std::vector behavior) Caller must ensure vector is...
Definition helpers.h:337
const T & operator[](size_t i) const
Definition helpers.h:351
T & operator[](size_t i)
Access element without bounds checking (matches std::vector behavior) Caller must ensure index is val...
Definition helpers.h:350
T & back()
Access last element (no bounds checking - matches std::vector behavior) Caller must ensure vector is ...
Definition helpers.h:342
bool empty() const
Definition helpers.h:346
FixedVector & operator=(const FixedVector &)=delete
FixedVector(const FixedVector &)=delete
void push_back(T &&value)
Add element by move without bounds checking Caller must ensure sufficient capacity was allocated via ...
Definition helpers.h:316
T & emplace_back(Args &&...args)
Emplace element without bounds checking - constructs in-place with arguments Caller must ensure suffi...
Definition helpers.h:328
size_t size() const
Definition helpers.h:345
const T & front() const
Definition helpers.h:338
const T & back() const
Definition helpers.h:343
const T * end() const
Definition helpers.h:362
FixedVector & operator=(FixedVector &&other) noexcept
Definition helpers.h:252
T & at(size_t i)
Access element with bounds checking (matches std::vector behavior) Note: No exception thrown on out o...
Definition helpers.h:355
void push_back(const T &value)
Add element without bounds checking Caller must ensure sufficient capacity was allocated via init() S...
Definition helpers.h:305
void init(size_t n)
Definition helpers.h:278
Helper class to request loop() to be called as fast as possible.
Definition helpers.h:1355
void stop()
Stop running the loop continuously.
Definition helpers.cpp:710
static bool is_high_frequency()
Check whether the loop is running continuously.
Definition helpers.cpp:716
void start()
Start running the loop continuously.
Definition helpers.cpp:704
Helper class to disable interrupts.
Definition helpers.h:1322
std::unique_ptr< CallbackManager< void(Ts...)> > callbacks_
Definition helpers.h:1214
size_t size() const
Return the number of registered callbacks.
Definition helpers.h:1205
void operator()(Ts... args)
Call all callbacks in this manager.
Definition helpers.h:1211
void add(std::function< void(Ts...)> &&callback)
Add a callback to the list. Allocates the underlying CallbackManager on first use.
Definition helpers.h:1190
void call(Ts... args)
Call all callbacks in this manager. No-op if no callbacks registered.
Definition helpers.h:1198
bool empty() const
Check if any callbacks are registered.
Definition helpers.h:1208
Helper class that wraps a mutex with a RAII-style API.
Definition helpers.h:1293
LockGuard(Mutex &mutex)
Definition helpers.h:1295
Helper class to lock the lwIP TCPIP core when making lwIP API calls from non-TCPIP threads.
Definition helpers.h:1340
LwIPLock(const LwIPLock &)=delete
LwIPLock & operator=(const LwIPLock &)=delete
Mutex implementation, with API based on the unavailable std::mutex.
Definition helpers.h:1269
void unlock()
Definition helpers.cpp:27
bool try_lock()
Definition helpers.cpp:26
Mutex(const Mutex &)=delete
Mutex & operator=(const Mutex &)=delete
Helper class to easily give an object a parent of type T.
Definition helpers.h:1246
T * get_parent() const
Get the parent of this object.
Definition helpers.h:1252
Parented(T *parent)
Definition helpers.h:1249
void set_parent(T *parent)
Set the parent of this object.
Definition helpers.h:1254
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:1422
RAMAllocator(uint8_t flags)
Definition helpers.h:1434
T * reallocate(T *p, size_t n, size_t manual_size)
Definition helpers.h:1463
size_t get_free_heap_size() const
Return the total heap space available via this allocator.
Definition helpers.h:1487
T * reallocate(T *p, size_t n)
Definition helpers.h:1461
void deallocate(T *p, size_t n)
Definition helpers.h:1480
size_t get_max_free_block_size() const
Return the maximum size block this allocator could allocate.
Definition helpers.h:1508
T * allocate(size_t n)
Definition helpers.h:1442
constexpr RAMAllocator(const RAMAllocator< U > &other)
Definition helpers.h:1440
T * allocate(size_t n, size_t manual_size)
Definition helpers.h:1444
Helper class for efficient buffer allocation - uses stack for small sizes, heap for large This is use...
Definition helpers.h:368
SmallBufferWithHeapFallback & operator=(const SmallBufferWithHeapFallback &)=delete
SmallBufferWithHeapFallback(SmallBufferWithHeapFallback &&)=delete
SmallBufferWithHeapFallback & operator=(SmallBufferWithHeapFallback &&)=delete
SmallBufferWithHeapFallback(const SmallBufferWithHeapFallback &)=delete
Minimal static vector - saves memory by avoiding std::vector overhead.
Definition helpers.h:132
const_reverse_iterator rend() const
Definition helpers.h:182
size_t size() const
Definition helpers.h:162
reverse_iterator rbegin()
Definition helpers.h:179
const T & operator[](size_t i) const
Definition helpers.h:170
reverse_iterator rend()
Definition helpers.h:180
void push_back(const T &value)
Definition helpers.h:146
bool empty() const
Definition helpers.h:163
const_reverse_iterator rbegin() const
Definition helpers.h:181
T & operator[](size_t i)
Definition helpers.h:169
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition helpers.h:138
typename std::array< T, N >::iterator iterator
Definition helpers.h:135
typename std::array< T, N >::const_iterator const_iterator
Definition helpers.h:136
std::reverse_iterator< iterator > reverse_iterator
Definition helpers.h:137
const T * data() const
Definition helpers.h:167
const_iterator end() const
Definition helpers.h:176
const_iterator begin() const
Definition helpers.h:175
struct @65::@66 __attribute__
Functions to constrain the range of arithmetic values.
Definition helpers.h:1533
uint16_t flags
uint16_t id
mopeka_std_values val[4]
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
T clamp_at_most(T value, U max)
Definition helpers.h:1543
bool random_bytes(uint8_t *data, size_t len)
Generate len number of random bytes.
Definition helpers.cpp:18
constexpr uint32_t fnv1a_hash_extend(uint32_t hash, const char *str)
Extend a FNV-1a hash with additional string data.
Definition helpers.h:424
float random_float()
Return a random float between 0 and 1.
Definition helpers.cpp:158
float gamma_uncorrect(float value, float gamma)
Reverts gamma correction of gamma to value.
Definition helpers.cpp:630
uint16_t crc16(const uint8_t *data, uint16_t len, uint16_t crc, uint16_t reverse_poly, bool refin, bool refout)
Calculate a CRC-16 checksum of data with size len.
Definition helpers.cpp:72
size_t make_name_with_suffix_to(char *buffer, size_t buffer_size, const char *name, size_t name_len, char sep, const char *suffix_ptr, size_t suffix_len)
Zero-allocation version: format name + separator + suffix directly into buffer.
Definition helpers.cpp:242
std::string value_accuracy_to_string(float value, int8_t accuracy_decimals)
Definition helpers.cpp:442
constexpr T convert_big_endian(T val)
Convert a value between host byte order and big endian (most significant byte first) order.
Definition helpers.h:519
char format_hex_pretty_char(uint8_t v)
Convert a nibble (0-15) to uppercase hex char (used for pretty printing)
Definition helpers.h:749
float gamma_correct(float value, float gamma)
Applies gamma correction of gamma to value.
Definition helpers.cpp:622
constexpr char to_sanitized_char(char c)
Sanitize a single char: keep alphanumerics, dashes, underscores; replace others with underscore.
Definition helpers.h:574
bool mac_address_is_valid(const uint8_t *mac)
Check if the MAC address is not all zeros or all ones.
Definition helpers.cpp:748
void format_mac_addr_lower_no_sep(const uint8_t *mac, char *output)
Format MAC address as xxxxxxxxxxxxxx (lowercase, no separators)
Definition helpers.h:902
constexpr uint32_t FNV1_OFFSET_BASIS
FNV-1 32-bit offset basis.
Definition helpers.h:419
void rgb_to_hsv(float red, float green, float blue, int &hue, float &saturation, float &value)
Convert red, green and blue (all 0-1) values to hue (0-360), saturation (0-1) and value (0-1).
Definition helpers.cpp:639
std::string format_hex(const uint8_t *data, size_t length)
Format the byte array data of length len in lowercased hex.
Definition helpers.cpp:326
char format_hex_char(uint8_t v, char base)
Convert a nibble (0-15) to hex char with specified base ('a' for lowercase, 'A' for uppercase)
Definition helpers.h:743
size_t value_accuracy_to_buf(std::span< char, VALUE_ACCURACY_MAX_LEN > buf, float value, int8_t accuracy_decimals)
Format value with accuracy to buffer, returns chars written (excluding null)
Definition helpers.cpp:448
std::string str_lower_case(const std::string &str)
Convert the string to lower case.
Definition helpers.cpp:193
ParseOnOffState parse_on_off(const char *str, const char *on, const char *off)
Parse a string that contains either on, off or toggle.
Definition helpers.cpp:419
std::string format_bin(const uint8_t *data, size_t length)
Format the byte array data of length len in binary.
Definition helpers.cpp:407
constexpr T convert_little_endian(T val)
Convert a value between host byte order and little endian (least significant byte first) order.
Definition helpers.h:528
std::string str_sanitize(const std::string &str)
Sanitizes the input string by removing all characters but alphanumerics, dashes and underscores.
Definition helpers.cpp:202
std::string size_t len
Definition helpers.h:595
constexpr size_t format_hex_prefixed_size(size_t byte_count)
Calculate buffer size needed for format_hex_prefixed_to: "0xXXXXXXXX...\0" = bytes * 2 + 3.
Definition helpers.h:807
constexpr uint32_t encode_uint24(uint8_t byte1, uint8_t byte2, uint8_t byte3)
Encode a 24-bit value given three bytes in most to least significant byte order.
Definition helpers.h:467
char * format_hex_prefixed_to(char(&buffer)[N], T val)
Format an unsigned integer as "0x" prefixed lowercase hex to buffer.
Definition helpers.h:811
bool has_custom_mac_address()
Check if a custom MAC address is set (ESP32 & variants)
Definition helpers.cpp:93
size_t parse_hex(const char *str, size_t length, uint8_t *data, size_t count)
Parse bytes from a hex-encoded string into a byte array.
Definition helpers.cpp:275
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).
Definition helpers.cpp:334
uint32_t fnv1_hash_object_id(const char *str, size_t len)
Calculate FNV-1 hash of a string while applying snake_case + sanitize transformations.
Definition helpers.h:584
uint32_t fnv1_hash(const char *str)
Calculate a FNV-1 hash of str.
Definition helpers.cpp:147
T clamp_at_least(T value, U min)
Definition helpers.h:1538
optional< T > parse_number(const char *str)
Parse an unsigned decimal number from a null-terminated string.
Definition helpers.h:640
std::string get_mac_address_pretty()
Get the device MAC address as a string, in colon-separated uppercase hex notation.
Definition helpers.cpp:726
std::string str_snprintf(const char *fmt, size_t len,...)
Definition helpers.cpp:209
void set_mac_address(uint8_t *mac)
Set the MAC address to use from the provided byte array (6 bytes).
Definition helpers.cpp:91
int8_t step_to_accuracy_decimals(float step)
Derive accuracy in decimals from an increment step.
Definition helpers.cpp:472
uint32_t random_uint32()
Return a random 32-bit unsigned integer.
Definition helpers.cpp:17
const char * get_mac_address_pretty_into_buffer(std::span< char, MAC_ADDRESS_PRETTY_BUFFER_SIZE > buf)
Get the device MAC address into the given buffer, in colon-separated uppercase hex notation.
Definition helpers.cpp:737
void IRAM_ATTR HOT delay_microseconds_safe(uint32_t us)
Delay for the given amount of microseconds, possibly yielding to other processes during the wait.
Definition helpers.cpp:763
std::string str_upper_case(const std::string &str)
Convert the string to upper case.
Definition helpers.cpp:194
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.
Definition helpers.cpp:382
constexpr size_t format_hex_size(size_t byte_count)
Calculate buffer size needed for format_hex_to: "XXXXXXXX...\0" = bytes * 2 + 1.
Definition helpers.h:804
bool str_equals_case_insensitive(const std::string &a, const std::string &b)
Compare strings for equality in case-insensitive manner.
Definition helpers.cpp:162
std::string str_until(const char *str, char ch)
Extract the part of the string until either the first occurrence of the specified character,...
Definition helpers.cpp:180
char * int8_to_str(char *buf, int8_t val)
Write int8 value to buffer without modulo operations.
Definition helpers.h:753
std::string format_mac_address_pretty(const uint8_t *mac)
Definition helpers.cpp:286
size_t value_accuracy_with_uom_to_buf(std::span< char, VALUE_ACCURACY_MAX_LEN > buf, float value, int8_t accuracy_decimals, StringRef unit_of_measurement)
Format value with accuracy and UOM to buffer, returns chars written (excluding null)
Definition helpers.cpp:458
constexpr size_t format_hex_pretty_size(size_t byte_count)
Calculate buffer size needed for format_hex_pretty_to with separator: "XX:XX:...:XX\0".
Definition helpers.h:830
std::string base64_encode(const std::vector< uint8_t > &buf)
Definition helpers.cpp:504
constexpr uint32_t FNV1_PRIME
FNV-1 32-bit prime.
Definition helpers.h:421
constexpr T encode_value(const uint8_t *bytes)
Encode a value from its constituent bytes (from most to least significant) in an array with length si...
Definition helpers.h:477
void hsv_to_rgb(int hue, float saturation, float value, float &red, float &green, float &blue)
Convert hue (0-360), saturation (0-1) and value (0-1) to red, green and blue (all 0-1).
Definition helpers.cpp:662
void get_mac_address_into_buffer(std::span< char, MAC_ADDRESS_BUFFER_SIZE > buf)
Get the device MAC address into the given buffer, in lowercase hex notation.
Definition helpers.cpp:731
uint16_t crc16be(const uint8_t *data, uint16_t len, uint16_t crc, uint16_t poly, bool refin, bool refout)
Definition helpers.cpp:112
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
Definition helpers.h:471
uint8_t crc8(const uint8_t *data, uint8_t len, uint8_t crc, uint8_t poly, bool msb_first)
Calculate a CRC-8 checksum of data with size len.
Definition helpers.cpp:45
constexpr float celsius_to_fahrenheit(float value)
Convert degrees Celsius to degrees Fahrenheit.
Definition helpers.h:1139
std::string str_sprintf(const char *fmt,...)
Definition helpers.cpp:223
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition helpers.h:463
void get_mac_address_raw(uint8_t *mac)
Get the device MAC address as raw bytes, written into the provided byte array (6 bytes).
Definition helpers.cpp:73
constexpr uint8_t parse_hex_char(char c)
Parse a hex character to its nibble value (0-15), returns 255 on invalid input.
Definition helpers.h:732
bool str_startswith(const std::string &str, const std::string &start)
Check whether a string starts with a value.
Definition helpers.cpp:169
constexpr std::array< uint8_t, sizeof(T)> decode_value(T val)
Decode a value into its constituent bytes (from most to least significant).
Definition helpers.h:492
std::string get_mac_address()
Get the device MAC address as a string, in lowercase hex notation.
Definition helpers.cpp:718
struct ESPDEPRECATED("Use std::index_sequence instead. Removed in 2026.6.0", "2025.12.0") seq
Definition automation.h:24
To bit_cast(const From &src)
Convert data between types, without aliasing issues or undefined behaviour.
Definition helpers.h:71
constexpr char to_snake_case_char(char c)
Convert a single char to snake_case: lowercase and space to underscore.
Definition helpers.h:568
constexpr float fahrenheit_to_celsius(float value)
Convert degrees Fahrenheit to degrees Celsius.
Definition helpers.h:1141
uint8_t reverse_bits(uint8_t x)
Reverse the order of 8 bits.
Definition helpers.h:502
char * format_hex_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length)
Format byte array as lowercase hex to buffer (base implementation).
Definition helpers.cpp:322
std::string str_snake_case(const std::string &str)
Convert the string to snake case (lowercase with underscores).
Definition helpers.cpp:195
float lerp(float completion, float start, float end)=delete
constexpr size_t format_hex_pretty_uint16_size(size_t count)
Calculate buffer size needed for format_hex_pretty_to with uint16_t data: "XXXX:XXXX:....
Definition helpers.h:865
T remap(U value, U min, U max, T min_out, T max_out)
Remap value from the range (min, max) to (min_out, max_out).
Definition helpers.h:400
bool str_endswith(const std::string &str, const std::string &end)
Check whether a string ends with a value.
Definition helpers.cpp:170
constexpr uint32_t fnv1a_hash(const char *str)
Calculate a FNV-1a hash of str.
Definition helpers.h:447
size_t base64_decode(const std::string &encoded_string, uint8_t *buf, size_t buf_len)
Definition helpers.cpp:546
ParseOnOffState
Return values for parse_on_off().
Definition helpers.h:1086
@ PARSE_ON
Definition helpers.h:1088
@ PARSE_TOGGLE
Definition helpers.h:1090
@ PARSE_OFF
Definition helpers.h:1089
@ PARSE_NONE
Definition helpers.h:1087
std::string make_name_with_suffix(const char *name, size_t name_len, char sep, const char *suffix_ptr, size_t suffix_len)
Optimized string concatenation: name + separator + suffix (const char* overload) Uses a fixed stack b...
Definition helpers.cpp:262
char * format_mac_addr_upper(const uint8_t *mac, char *output)
Format MAC address as XX:XX:XX:XX:XX:XX (uppercase, colon separators)
Definition helpers.h:897
std::string str_truncate(const std::string &str, size_t length)
Truncate a string to a specific length.
Definition helpers.cpp:177
uint8_t end[39]
Definition sun_gtil2.cpp:17
void byteswap()
uint16_t length
Definition tt21100.cpp:0
uint16_t x
Definition tt21100.cpp:5