ESPHome 2026.1.0-dev
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 T &operator[](size_t i) { return data_[i]; }
166 const T &operator[](size_t i) const { return data_[i]; }
167
168 // For range-based for loops
169 iterator begin() { return data_.begin(); }
170 iterator end() { return data_.begin() + count_; }
171 const_iterator begin() const { return data_.begin(); }
172 const_iterator end() const { return data_.begin() + count_; }
173
174 // Reverse iterators
179};
180
184template<typename T> class FixedVector {
185 private:
186 T *data_{nullptr};
187 size_t size_{0};
188 size_t capacity_{0};
189
190 // Helper to destroy all elements without freeing memory
191 void destroy_elements_() {
192 // Only call destructors for non-trivially destructible types
193 if constexpr (!std::is_trivially_destructible<T>::value) {
194 for (size_t i = 0; i < size_; i++) {
195 data_[i].~T();
196 }
197 }
198 }
199
200 // Helper to destroy elements and free memory
201 void cleanup_() {
202 if (data_ != nullptr) {
203 destroy_elements_();
204 // Free raw memory
205 ::operator delete(data_);
206 }
207 }
208
209 // Helper to reset pointers after cleanup
210 void reset_() {
211 data_ = nullptr;
212 capacity_ = 0;
213 size_ = 0;
214 }
215
216 // Helper to assign from initializer list (shared by constructor and assignment operator)
217 void assign_from_initializer_list_(std::initializer_list<T> init_list) {
218 init(init_list.size());
219 size_t idx = 0;
220 for (const auto &item : init_list) {
221 new (data_ + idx) T(item);
222 ++idx;
223 }
224 size_ = init_list.size();
225 }
226
227 public:
228 FixedVector() = default;
229
232 FixedVector(std::initializer_list<T> init_list) { assign_from_initializer_list_(init_list); }
233
234 ~FixedVector() { cleanup_(); }
235
236 // Disable copy operations (avoid accidental expensive copies)
237 FixedVector(const FixedVector &) = delete;
239
240 // Enable move semantics (allows use in move-only containers like std::vector)
241 FixedVector(FixedVector &&other) noexcept : data_(other.data_), size_(other.size_), capacity_(other.capacity_) {
242 other.reset_();
243 }
244
245 // Allow conversion to std::vector
246 operator std::vector<T>() const { return {data_, data_ + size_}; }
247
248 FixedVector &operator=(FixedVector &&other) noexcept {
249 if (this != &other) {
250 // Delete our current data
251 cleanup_();
252 // Take ownership of other's data
253 data_ = other.data_;
254 size_ = other.size_;
255 capacity_ = other.capacity_;
256 // Leave other in valid empty state
257 other.reset_();
258 }
259 return *this;
260 }
261
264 FixedVector &operator=(std::initializer_list<T> init_list) {
265 cleanup_();
266 reset_();
267 assign_from_initializer_list_(init_list);
268 return *this;
269 }
270
271 // Allocate capacity - can be called multiple times to reinit
272 // IMPORTANT: After calling init(), you MUST use push_back() to add elements.
273 // Direct assignment via operator[] does NOT update the size counter.
274 void init(size_t n) {
275 cleanup_();
276 reset_();
277 if (n > 0) {
278 // Allocate raw memory without calling constructors
279 // sizeof(T) is correct here for any type T (value types, pointers, etc.)
280 // NOLINTNEXTLINE(bugprone-sizeof-expression)
281 data_ = static_cast<T *>(::operator new(n * sizeof(T)));
282 capacity_ = n;
283 }
284 }
285
286 // Clear the vector (destroy all elements, reset size to 0, keep capacity)
287 void clear() {
288 destroy_elements_();
289 size_ = 0;
290 }
291
292 // Shrink capacity to fit current size (frees all memory)
294 cleanup_();
295 reset_();
296 }
297
301 void push_back(const T &value) {
302 if (size_ < capacity_) {
303 // Use placement new to construct the object in pre-allocated memory
304 new (&data_[size_]) T(value);
305 size_++;
306 }
307 }
308
312 void push_back(T &&value) {
313 if (size_ < capacity_) {
314 // Use placement new to move-construct the object in pre-allocated memory
315 new (&data_[size_]) T(std::move(value));
316 size_++;
317 }
318 }
319
324 template<typename... Args> T &emplace_back(Args &&...args) {
325 // Use placement new to construct the object in pre-allocated memory
326 new (&data_[size_]) T(std::forward<Args>(args)...);
327 size_++;
328 return data_[size_ - 1];
329 }
330
333 T &front() { return data_[0]; }
334 const T &front() const { return data_[0]; }
335
338 T &back() { return data_[size_ - 1]; }
339 const T &back() const { return data_[size_ - 1]; }
340
341 size_t size() const { return size_; }
342 bool empty() const { return size_ == 0; }
343
346 T &operator[](size_t i) { return data_[i]; }
347 const T &operator[](size_t i) const { return data_[i]; }
348
351 T &at(size_t i) { return data_[i]; }
352 const T &at(size_t i) const { return data_[i]; }
353
354 // Iterator support for range-based for loops
355 T *begin() { return data_; }
356 T *end() { return data_ + size_; }
357 const T *begin() const { return data_; }
358 const T *end() const { return data_ + size_; }
359};
360
362
365
367template<typename T, typename U> T remap(U value, U min, U max, T min_out, T max_out) {
368 return (value - min) * (max_out - min_out) / (max - min) + min_out;
369}
370
372uint8_t crc8(const uint8_t *data, uint8_t len, uint8_t crc = 0x00, uint8_t poly = 0x8C, bool msb_first = false);
373
375uint16_t crc16(const uint8_t *data, uint16_t len, uint16_t crc = 0xffff, uint16_t reverse_poly = 0xa001,
376 bool refin = false, bool refout = false);
377uint16_t crc16be(const uint8_t *data, uint16_t len, uint16_t crc = 0, uint16_t poly = 0x1021, bool refin = false,
378 bool refout = false);
379
382uint32_t fnv1_hash(const char *str);
383inline uint32_t fnv1_hash(const std::string &str) { return fnv1_hash(str.c_str()); }
384
386constexpr uint32_t FNV1_OFFSET_BASIS = 2166136261UL;
388constexpr uint32_t FNV1_PRIME = 16777619UL;
389
391constexpr uint32_t fnv1a_hash_extend(uint32_t hash, const char *str) {
392 if (str) {
393 while (*str) {
394 hash ^= *str++;
395 hash *= FNV1_PRIME;
396 }
397 }
398 return hash;
399}
400inline uint32_t fnv1a_hash_extend(uint32_t hash, const std::string &str) {
401 return fnv1a_hash_extend(hash, str.c_str());
402}
404constexpr uint32_t fnv1a_hash(const char *str) { return fnv1a_hash_extend(FNV1_OFFSET_BASIS, str); }
405inline uint32_t fnv1a_hash(const std::string &str) { return fnv1a_hash(str.c_str()); }
406
408uint32_t random_uint32();
410float random_float();
412bool random_bytes(uint8_t *data, size_t len);
413
415
418
420constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb) {
421 return (static_cast<uint16_t>(msb) << 8) | (static_cast<uint16_t>(lsb));
422}
424constexpr uint32_t encode_uint24(uint8_t byte1, uint8_t byte2, uint8_t byte3) {
425 return (static_cast<uint32_t>(byte1) << 16) | (static_cast<uint32_t>(byte2) << 8) | (static_cast<uint32_t>(byte3));
426}
428constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4) {
429 return (static_cast<uint32_t>(byte1) << 24) | (static_cast<uint32_t>(byte2) << 16) |
430 (static_cast<uint32_t>(byte3) << 8) | (static_cast<uint32_t>(byte4));
431}
432
434template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> constexpr T encode_value(const uint8_t *bytes) {
435 T val = 0;
436 for (size_t i = 0; i < sizeof(T); i++) {
437 val <<= 8;
438 val |= bytes[i];
439 }
440 return val;
441}
443template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
444constexpr T encode_value(const std::array<uint8_t, sizeof(T)> bytes) {
445 return encode_value<T>(bytes.data());
446}
448template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
449constexpr std::array<uint8_t, sizeof(T)> decode_value(T val) {
450 std::array<uint8_t, sizeof(T)> ret{};
451 for (size_t i = sizeof(T); i > 0; i--) {
452 ret[i - 1] = val & 0xFF;
453 val >>= 8;
454 }
455 return ret;
456}
457
459inline uint8_t reverse_bits(uint8_t x) {
460 x = ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
461 x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2);
462 x = ((x & 0xF0) >> 4) | ((x & 0x0F) << 4);
463 return x;
464}
466inline uint16_t reverse_bits(uint16_t x) {
467 return (reverse_bits(static_cast<uint8_t>(x & 0xFF)) << 8) | reverse_bits(static_cast<uint8_t>((x >> 8) & 0xFF));
468}
470inline uint32_t reverse_bits(uint32_t x) {
471 return (reverse_bits(static_cast<uint16_t>(x & 0xFFFF)) << 16) |
472 reverse_bits(static_cast<uint16_t>((x >> 16) & 0xFFFF));
473}
474
476template<typename T> constexpr T convert_big_endian(T val) {
477#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
478 return byteswap(val);
479#else
480 return val;
481#endif
482}
483
485template<typename T> constexpr T convert_little_endian(T val) {
486#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
487 return val;
488#else
489 return byteswap(val);
490#endif
491}
492
494
497
499bool str_equals_case_insensitive(const std::string &a, const std::string &b);
500
502bool str_startswith(const std::string &str, const std::string &start);
504bool str_endswith(const std::string &str, const std::string &end);
505
507std::string str_truncate(const std::string &str, size_t length);
508
511std::string str_until(const char *str, char ch);
513std::string str_until(const std::string &str, char ch);
514
516std::string str_lower_case(const std::string &str);
518std::string str_upper_case(const std::string &str);
519
521constexpr char to_snake_case_char(char c) { return (c == ' ') ? '_' : (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; }
523std::string str_snake_case(const std::string &str);
524
526constexpr char to_sanitized_char(char c) {
527 return (c == '-' || c == '_' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) ? c : '_';
528}
530std::string str_sanitize(const std::string &str);
531
533std::string __attribute__((format(printf, 1, 3))) str_snprintf(const char *fmt, size_t len, ...);
534
536std::string __attribute__((format(printf, 1, 2))) str_sprintf(const char *fmt, ...);
537
546std::string make_name_with_suffix(const std::string &name, char sep, const char *suffix_ptr, size_t suffix_len);
547
556std::string make_name_with_suffix(const char *name, size_t name_len, char sep, const char *suffix_ptr,
557 size_t suffix_len);
558
568size_t make_name_with_suffix_to(char *buffer, size_t buffer_size, const char *name, size_t name_len, char sep,
569 const char *suffix_ptr, size_t suffix_len);
570
572
575
577template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
578optional<T> parse_number(const char *str) {
579 char *end = nullptr;
580 unsigned long value = ::strtoul(str, &end, 10); // NOLINT(google-runtime-int)
581 if (end == str || *end != '\0' || value > std::numeric_limits<T>::max())
582 return {};
583 return value;
584}
586template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
587optional<T> parse_number(const std::string &str) {
588 return parse_number<T>(str.c_str());
589}
591template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
592optional<T> parse_number(const char *str) {
593 char *end = nullptr;
594 signed long value = ::strtol(str, &end, 10); // NOLINT(google-runtime-int)
595 if (end == str || *end != '\0' || value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max())
596 return {};
597 return value;
598}
600template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
601optional<T> parse_number(const std::string &str) {
602 return parse_number<T>(str.c_str());
603}
605template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0> optional<T> parse_number(const char *str) {
606 char *end = nullptr;
607 float value = ::strtof(str, &end);
608 if (end == str || *end != '\0' || value == HUGE_VALF)
609 return {};
610 return value;
611}
613template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0>
614optional<T> parse_number(const std::string &str) {
615 return parse_number<T>(str.c_str());
616}
617
629size_t parse_hex(const char *str, size_t len, uint8_t *data, size_t count);
631inline bool parse_hex(const char *str, uint8_t *data, size_t count) {
632 return parse_hex(str, strlen(str), data, count) == 2 * count;
633}
635inline bool parse_hex(const std::string &str, uint8_t *data, size_t count) {
636 return parse_hex(str.c_str(), str.length(), data, count) == 2 * count;
637}
639inline bool parse_hex(const char *str, std::vector<uint8_t> &data, size_t count) {
640 data.resize(count);
641 return parse_hex(str, strlen(str), data.data(), count) == 2 * count;
642}
644inline bool parse_hex(const std::string &str, std::vector<uint8_t> &data, size_t count) {
645 data.resize(count);
646 return parse_hex(str.c_str(), str.length(), data.data(), count) == 2 * count;
647}
653template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
654optional<T> parse_hex(const char *str, size_t len) {
655 T val = 0;
656 if (len > 2 * sizeof(T) || parse_hex(str, len, reinterpret_cast<uint8_t *>(&val), sizeof(T)) == 0)
657 return {};
658 return convert_big_endian(val);
659}
661template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> optional<T> parse_hex(const char *str) {
662 return parse_hex<T>(str, strlen(str));
663}
665template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> optional<T> parse_hex(const std::string &str) {
666 return parse_hex<T>(str.c_str(), str.length());
667}
668
670constexpr uint8_t parse_hex_char(char c) {
671 if (c >= '0' && c <= '9')
672 return c - '0';
673 if (c >= 'A' && c <= 'F')
674 return c - 'A' + 10;
675 if (c >= 'a' && c <= 'f')
676 return c - 'a' + 10;
677 return 255;
678}
679
681inline char format_hex_char(uint8_t v, char base) { return v >= 10 ? base + (v - 10) : '0' + v; }
682
684inline char format_hex_char(uint8_t v) { return format_hex_char(v, 'a'); }
685
687inline char format_hex_pretty_char(uint8_t v) { return format_hex_char(v, 'A'); }
688
691inline char *int8_to_str(char *buf, int8_t val) {
692 int32_t v = val;
693 if (v < 0) {
694 *buf++ = '-';
695 v = -v;
696 }
697 if (v >= 100) {
698 *buf++ = '1'; // int8 max is 128, so hundreds digit is always 1
699 v -= 100;
700 // Must write tens digit (even if 0) after hundreds
701 int32_t tens = v / 10;
702 *buf++ = '0' + tens;
703 v -= tens * 10;
704 } else if (v >= 10) {
705 int32_t tens = v / 10;
706 *buf++ = '0' + tens;
707 v -= tens * 10;
708 }
709 *buf++ = '0' + v;
710 return buf;
711}
712
714char *format_hex_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length);
715
718template<size_t N> inline char *format_hex_to(char (&buffer)[N], const uint8_t *data, size_t length) {
719 static_assert(N >= 3, "Buffer must hold at least one hex byte (3 chars)");
720 return format_hex_to(buffer, N, data, length);
721}
722
724template<size_t N, typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
725inline char *format_hex_to(char (&buffer)[N], T val) {
726 static_assert(N >= sizeof(T) * 2 + 1, "Buffer too small for type");
728 return format_hex_to(buffer, reinterpret_cast<const uint8_t *>(&val), sizeof(T));
729}
730
732constexpr size_t format_hex_pretty_size(size_t byte_count) { return byte_count * 3; }
733
745char *format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator = ':');
746
748template<size_t N>
749inline char *format_hex_pretty_to(char (&buffer)[N], const uint8_t *data, size_t length, char separator = ':') {
750 static_assert(N >= 3, "Buffer must hold at least one hex byte");
751 return format_hex_pretty_to(buffer, N, data, length, separator);
752}
753
755static constexpr size_t MAC_ADDRESS_SIZE = 6;
757static constexpr size_t MAC_ADDRESS_PRETTY_BUFFER_SIZE = format_hex_pretty_size(MAC_ADDRESS_SIZE);
759static constexpr size_t MAC_ADDRESS_BUFFER_SIZE = MAC_ADDRESS_SIZE * 2 + 1;
760
762inline void format_mac_addr_upper(const uint8_t *mac, char *output) {
763 format_hex_pretty_to(output, MAC_ADDRESS_PRETTY_BUFFER_SIZE, mac, MAC_ADDRESS_SIZE, ':');
764}
765
767inline void format_mac_addr_lower_no_sep(const uint8_t *mac, char *output) {
768 format_hex_to(output, MAC_ADDRESS_BUFFER_SIZE, mac, MAC_ADDRESS_SIZE);
769}
770
772std::string format_mac_address_pretty(const uint8_t mac[6]);
774std::string format_hex(const uint8_t *data, size_t length);
776std::string format_hex(const std::vector<uint8_t> &data);
778template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> std::string format_hex(T val) {
780 return format_hex(reinterpret_cast<uint8_t *>(&val), sizeof(T));
781}
782template<std::size_t N> std::string format_hex(const std::array<uint8_t, N> &data) {
783 return format_hex(data.data(), data.size());
784}
785
811std::string format_hex_pretty(const uint8_t *data, size_t length, char separator = '.', bool show_length = true);
812
833std::string format_hex_pretty(const uint16_t *data, size_t length, char separator = '.', bool show_length = true);
834
856std::string format_hex_pretty(const std::vector<uint8_t> &data, char separator = '.', bool show_length = true);
857
878std::string format_hex_pretty(const std::vector<uint16_t> &data, char separator = '.', bool show_length = true);
879
900std::string format_hex_pretty(const std::string &data, char separator = '.', bool show_length = true);
901
925template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
926std::string format_hex_pretty(T val, char separator = '.', bool show_length = true) {
928 return format_hex_pretty(reinterpret_cast<uint8_t *>(&val), sizeof(T), separator, show_length);
929}
930
932std::string format_bin(const uint8_t *data, size_t length);
934template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> std::string format_bin(T val) {
936 return format_bin(reinterpret_cast<uint8_t *>(&val), sizeof(T));
937}
938
947ParseOnOffState parse_on_off(const char *str, const char *on = nullptr, const char *off = nullptr);
948
950std::string value_accuracy_to_string(float value, int8_t accuracy_decimals);
951
953static constexpr size_t VALUE_ACCURACY_MAX_LEN = 64;
954
956size_t value_accuracy_to_buf(std::span<char, VALUE_ACCURACY_MAX_LEN> buf, float value, int8_t accuracy_decimals);
958size_t value_accuracy_with_uom_to_buf(std::span<char, VALUE_ACCURACY_MAX_LEN> buf, float value,
959 int8_t accuracy_decimals, StringRef unit_of_measurement);
960
962int8_t step_to_accuracy_decimals(float step);
963
964std::string base64_encode(const uint8_t *buf, size_t buf_len);
965std::string base64_encode(const std::vector<uint8_t> &buf);
966
967std::vector<uint8_t> base64_decode(const std::string &encoded_string);
968size_t base64_decode(std::string const &encoded_string, uint8_t *buf, size_t buf_len);
969size_t base64_decode(const uint8_t *encoded_data, size_t encoded_len, uint8_t *buf, size_t buf_len);
970
972
975
977float gamma_correct(float value, float gamma);
979float gamma_uncorrect(float value, float gamma);
980
982void rgb_to_hsv(float red, float green, float blue, int &hue, float &saturation, float &value);
984void hsv_to_rgb(int hue, float saturation, float value, float &red, float &green, float &blue);
985
987
990
992constexpr float celsius_to_fahrenheit(float value) { return value * 1.8f + 32.0f; }
994constexpr float fahrenheit_to_celsius(float value) { return (value - 32.0f) / 1.8f; }
995
997
1000
1001template<typename... X> class CallbackManager;
1002
1007template<typename... Ts> class CallbackManager<void(Ts...)> {
1008 public:
1010 void add(std::function<void(Ts...)> &&callback) { this->callbacks_.push_back(std::move(callback)); }
1011
1013 void call(Ts... args) {
1014 for (auto &cb : this->callbacks_)
1015 cb(args...);
1016 }
1017 size_t size() const { return this->callbacks_.size(); }
1018
1020 void operator()(Ts... args) { call(args...); }
1021
1022 protected:
1023 std::vector<std::function<void(Ts...)>> callbacks_;
1024};
1025
1026template<typename... X> class LazyCallbackManager;
1027
1040template<typename... Ts> class LazyCallbackManager<void(Ts...)> {
1041 public:
1043 void add(std::function<void(Ts...)> &&callback) {
1044 if (!this->callbacks_) {
1045 this->callbacks_ = make_unique<CallbackManager<void(Ts...)>>();
1046 }
1047 this->callbacks_->add(std::move(callback));
1048 }
1049
1051 void call(Ts... args) {
1052 if (this->callbacks_) {
1053 this->callbacks_->call(args...);
1054 }
1055 }
1056
1058 size_t size() const { return this->callbacks_ ? this->callbacks_->size() : 0; }
1059
1061 bool empty() const { return !this->callbacks_ || this->callbacks_->size() == 0; }
1062
1064 void operator()(Ts... args) { this->call(args...); }
1065
1066 protected:
1067 std::unique_ptr<CallbackManager<void(Ts...)>> callbacks_;
1068};
1069
1071template<typename T> class Deduplicator {
1072 public:
1074 bool next(T value) {
1075 if (this->has_value_ && !this->value_unknown_ && this->last_value_ == value) {
1076 return false;
1077 }
1078 this->has_value_ = true;
1079 this->value_unknown_ = false;
1080 this->last_value_ = value;
1081 return true;
1082 }
1085 bool ret = !this->value_unknown_;
1086 this->value_unknown_ = true;
1087 return ret;
1088 }
1090 bool has_value() const { return this->has_value_; }
1091
1092 protected:
1093 bool has_value_{false};
1094 bool value_unknown_{false};
1096};
1097
1099template<typename T> class Parented {
1100 public:
1102 Parented(T *parent) : parent_(parent) {}
1103
1105 T *get_parent() const { return parent_; }
1107 void set_parent(T *parent) { parent_ = parent; }
1108
1109 protected:
1110 T *parent_{nullptr};
1111};
1112
1114
1117
1122class Mutex {
1123 public:
1124 Mutex();
1125 Mutex(const Mutex &) = delete;
1126 ~Mutex();
1127 void lock();
1128 bool try_lock();
1129 void unlock();
1130
1131 Mutex &operator=(const Mutex &) = delete;
1132
1133 private:
1134#if defined(USE_ESP32) || defined(USE_LIBRETINY)
1135 SemaphoreHandle_t handle_;
1136#else
1137 // d-pointer to store private data on new platforms
1138 void *handle_; // NOLINT(clang-diagnostic-unused-private-field)
1139#endif
1140};
1141
1147 public:
1148 LockGuard(Mutex &mutex) : mutex_(mutex) { mutex_.lock(); }
1149 ~LockGuard() { mutex_.unlock(); }
1150
1151 private:
1152 Mutex &mutex_;
1153};
1154
1176 public:
1177 InterruptLock();
1179
1180 protected:
1181#if defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_ZEPHYR)
1182 uint32_t state_;
1183#endif
1184};
1185
1194 public:
1195 LwIPLock();
1196 ~LwIPLock();
1197
1198 // Delete copy constructor and copy assignment operator to prevent accidental copying
1199 LwIPLock(const LwIPLock &) = delete;
1200 LwIPLock &operator=(const LwIPLock &) = delete;
1201};
1202
1209 public:
1211 void start();
1213 void stop();
1214
1216 static bool is_high_frequency();
1217
1218 protected:
1219 bool started_{false};
1220 static uint8_t num_requests; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
1221};
1222
1224void get_mac_address_raw(uint8_t *mac); // NOLINT(readability-non-const-parameter)
1225
1227std::string get_mac_address();
1228
1230std::string get_mac_address_pretty();
1231
1235void get_mac_address_into_buffer(std::span<char, MAC_ADDRESS_BUFFER_SIZE> buf);
1236
1240const char *get_mac_address_pretty_into_buffer(std::span<char, MAC_ADDRESS_PRETTY_BUFFER_SIZE> buf);
1241
1242#ifdef USE_ESP32
1244void set_mac_address(uint8_t *mac);
1245#endif
1246
1250
1253bool mac_address_is_valid(const uint8_t *mac);
1254
1256void delay_microseconds_safe(uint32_t us);
1257
1259
1262
1271template<class T> class RAMAllocator {
1272 public:
1273 using value_type = T;
1274
1275 enum Flags {
1276 NONE = 0, // Perform external allocation and fall back to internal memory
1277 ALLOC_EXTERNAL = 1 << 0, // Perform external allocation only.
1278 ALLOC_INTERNAL = 1 << 1, // Perform internal allocation only.
1279 ALLOW_FAILURE = 1 << 2, // Does nothing. Kept for compatibility.
1280 };
1281
1282 RAMAllocator() = default;
1284 // default is both external and internal
1286 if (flags != 0)
1287 this->flags_ = flags;
1288 }
1289 template<class U> constexpr RAMAllocator(const RAMAllocator<U> &other) : flags_{other.flags_} {}
1290
1291 T *allocate(size_t n) { return this->allocate(n, sizeof(T)); }
1292
1293 T *allocate(size_t n, size_t manual_size) {
1294 size_t size = n * manual_size;
1295 T *ptr = nullptr;
1296#ifdef USE_ESP32
1297 if (this->flags_ & Flags::ALLOC_EXTERNAL) {
1298 ptr = static_cast<T *>(heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
1299 }
1300 if (ptr == nullptr && this->flags_ & Flags::ALLOC_INTERNAL) {
1301 ptr = static_cast<T *>(heap_caps_malloc(size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
1302 }
1303#else
1304 // Ignore ALLOC_EXTERNAL/ALLOC_INTERNAL flags if external allocation is not supported
1305 ptr = static_cast<T *>(malloc(size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
1306#endif
1307 return ptr;
1308 }
1309
1310 T *reallocate(T *p, size_t n) { return this->reallocate(p, n, sizeof(T)); }
1311
1312 T *reallocate(T *p, size_t n, size_t manual_size) {
1313 size_t size = n * manual_size;
1314 T *ptr = nullptr;
1315#ifdef USE_ESP32
1316 if (this->flags_ & Flags::ALLOC_EXTERNAL) {
1317 ptr = static_cast<T *>(heap_caps_realloc(p, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
1318 }
1319 if (ptr == nullptr && this->flags_ & Flags::ALLOC_INTERNAL) {
1320 ptr = static_cast<T *>(heap_caps_realloc(p, size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
1321 }
1322#else
1323 // Ignore ALLOC_EXTERNAL/ALLOC_INTERNAL flags if external allocation is not supported
1324 ptr = static_cast<T *>(realloc(p, size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
1325#endif
1326 return ptr;
1327 }
1328
1329 void deallocate(T *p, size_t n) {
1330 free(p); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
1331 }
1332
1336 size_t get_free_heap_size() const {
1337#ifdef USE_ESP8266
1338 return ESP.getFreeHeap(); // NOLINT(readability-static-accessed-through-instance)
1339#elif defined(USE_ESP32)
1340 auto max_internal =
1341 this->flags_ & ALLOC_INTERNAL ? heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL) : 0;
1342 auto max_external =
1343 this->flags_ & ALLOC_EXTERNAL ? heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM) : 0;
1344 return max_internal + max_external;
1345#elif defined(USE_RP2040)
1346 return ::rp2040.getFreeHeap();
1347#elif defined(USE_LIBRETINY)
1348 return lt_heap_get_free();
1349#else
1350 return 100000;
1351#endif
1352 }
1353
1358#ifdef USE_ESP8266
1359 return ESP.getMaxFreeBlockSize(); // NOLINT(readability-static-accessed-through-instance)
1360#elif defined(USE_ESP32)
1361 auto max_internal =
1362 this->flags_ & ALLOC_INTERNAL ? heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL) : 0;
1363 auto max_external =
1364 this->flags_ & ALLOC_EXTERNAL ? heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM) : 0;
1365 return std::max(max_internal, max_external);
1366#else
1367 return this->get_free_heap_size();
1368#endif
1369 }
1370
1371 private:
1372 uint8_t flags_{ALLOC_INTERNAL | ALLOC_EXTERNAL};
1373};
1374
1375template<class T> using ExternalRAMAllocator = RAMAllocator<T>;
1376
1381template<typename T, typename U>
1382concept comparable_with = requires(T a, U b) {
1383 { a > b } -> std::convertible_to<bool>;
1384 { a < b } -> std::convertible_to<bool>;
1385};
1386
1387template<std::totally_ordered T, comparable_with<T> U> T clamp_at_least(T value, U min) {
1388 if (value < min)
1389 return min;
1390 return value;
1391}
1392template<std::totally_ordered T, comparable_with<T> U> T clamp_at_most(T value, U max) {
1393 if (value > max)
1394 return max;
1395 return value;
1396}
1397
1400
1405template<typename T, enable_if_t<!std::is_pointer<T>::value, int> = 0> T id(T value) { return value; }
1410template<typename T, enable_if_t<std::is_pointer<T *>::value, int> = 0> T &id(T *value) { return *value; }
1411
1413
1414} // namespace esphome
uint8_t m
Definition bl0906.h:1
void operator()(Ts... args)
Call all callbacks in this manager.
Definition helpers.h:1020
std::vector< std::function< void(Ts...)> > callbacks_
Definition helpers.h:1023
void call(Ts... args)
Call all callbacks in this manager.
Definition helpers.h:1013
void add(std::function< void(Ts...)> &&callback)
Add a callback to the list.
Definition helpers.h:1010
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:1071
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:1074
bool has_value() const
Returns true if this deduplicator has processed any items.
Definition helpers.h:1090
bool next_unknown()
Returns true if the deduplicator's value was previously known.
Definition helpers.h:1084
Fixed-capacity vector - allocates once at runtime, never reallocates This avoids std::vector template...
Definition helpers.h:184
const T & at(size_t i) const
Definition helpers.h:352
FixedVector(FixedVector &&other) noexcept
Definition helpers.h:241
FixedVector(std::initializer_list< T > init_list)
Constructor from initializer list - allocates exact size needed This enables brace initialization: Fi...
Definition helpers.h:232
const T * begin() const
Definition helpers.h:357
FixedVector & operator=(std::initializer_list< T > init_list)
Assignment from initializer list - avoids temporary and move overhead This enables: FixedVector<int> ...
Definition helpers.h:264
T & front()
Access first element (no bounds checking - matches std::vector behavior) Caller must ensure vector is...
Definition helpers.h:333
const T & operator[](size_t i) const
Definition helpers.h:347
T & operator[](size_t i)
Access element without bounds checking (matches std::vector behavior) Caller must ensure index is val...
Definition helpers.h:346
T & back()
Access last element (no bounds checking - matches std::vector behavior) Caller must ensure vector is ...
Definition helpers.h:338
bool empty() const
Definition helpers.h:342
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:312
T & emplace_back(Args &&...args)
Emplace element without bounds checking - constructs in-place with arguments Caller must ensure suffi...
Definition helpers.h:324
size_t size() const
Definition helpers.h:341
const T & front() const
Definition helpers.h:334
const T & back() const
Definition helpers.h:339
const T * end() const
Definition helpers.h:358
FixedVector & operator=(FixedVector &&other) noexcept
Definition helpers.h:248
T & at(size_t i)
Access element with bounds checking (matches std::vector behavior) Note: No exception thrown on out o...
Definition helpers.h:351
void push_back(const T &value)
Add element without bounds checking Caller must ensure sufficient capacity was allocated via init() S...
Definition helpers.h:301
void init(size_t n)
Definition helpers.h:274
Helper class to request loop() to be called as fast as possible.
Definition helpers.h:1208
void stop()
Stop running the loop continuously.
Definition helpers.cpp:683
static bool is_high_frequency()
Check whether the loop is running continuously.
Definition helpers.cpp:689
void start()
Start running the loop continuously.
Definition helpers.cpp:677
Helper class to disable interrupts.
Definition helpers.h:1175
std::unique_ptr< CallbackManager< void(Ts...)> > callbacks_
Definition helpers.h:1067
size_t size() const
Return the number of registered callbacks.
Definition helpers.h:1058
void operator()(Ts... args)
Call all callbacks in this manager.
Definition helpers.h:1064
void add(std::function< void(Ts...)> &&callback)
Add a callback to the list. Allocates the underlying CallbackManager on first use.
Definition helpers.h:1043
void call(Ts... args)
Call all callbacks in this manager. No-op if no callbacks registered.
Definition helpers.h:1051
bool empty() const
Check if any callbacks are registered.
Definition helpers.h:1061
Helper class that wraps a mutex with a RAII-style API.
Definition helpers.h:1146
LockGuard(Mutex &mutex)
Definition helpers.h:1148
Helper class to lock the lwIP TCPIP core when making lwIP API calls from non-TCPIP threads.
Definition helpers.h:1193
LwIPLock(const LwIPLock &)=delete
LwIPLock & operator=(const LwIPLock &)=delete
Mutex implementation, with API based on the unavailable std::mutex.
Definition helpers.h:1122
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:1099
T * get_parent() const
Get the parent of this object.
Definition helpers.h:1105
Parented(T *parent)
Definition helpers.h:1102
void set_parent(T *parent)
Set the parent of this object.
Definition helpers.h:1107
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:1271
RAMAllocator(uint8_t flags)
Definition helpers.h:1283
T * reallocate(T *p, size_t n, size_t manual_size)
Definition helpers.h:1312
size_t get_free_heap_size() const
Return the total heap space available via this allocator.
Definition helpers.h:1336
T * reallocate(T *p, size_t n)
Definition helpers.h:1310
void deallocate(T *p, size_t n)
Definition helpers.h:1329
size_t get_max_free_block_size() const
Return the maximum size block this allocator could allocate.
Definition helpers.h:1357
T * allocate(size_t n)
Definition helpers.h:1291
constexpr RAMAllocator(const RAMAllocator< U > &other)
Definition helpers.h:1289
T * allocate(size_t n, size_t manual_size)
Definition helpers.h:1293
Minimal static vector - saves memory by avoiding std::vector overhead.
Definition helpers.h:132
const_reverse_iterator rend() const
Definition helpers.h:178
size_t size() const
Definition helpers.h:162
reverse_iterator rbegin()
Definition helpers.h:175
const T & operator[](size_t i) const
Definition helpers.h:166
reverse_iterator rend()
Definition helpers.h:176
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:177
T & operator[](size_t i)
Definition helpers.h:165
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_iterator end() const
Definition helpers.h:172
const_iterator begin() const
Definition helpers.h:171
struct @65::@66 __attribute__
Functions to constrain the range of arithmetic values.
Definition helpers.h:1382
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:1392
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:391
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:603
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:239
std::string value_accuracy_to_string(float value, int8_t accuracy_decimals)
Create a string from a value and an accuracy in decimals.
Definition helpers.cpp:415
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:476
char format_hex_pretty_char(uint8_t v)
Convert a nibble (0-15) to uppercase hex char (used for pretty printing)
Definition helpers.h:687
float gamma_correct(float value, float gamma)
Applies gamma correction of gamma to value.
Definition helpers.cpp:595
void 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:762
constexpr char to_sanitized_char(char c)
Sanitize a single char: keep alphanumerics, dashes, underscores; replace others with underscore.
Definition helpers.h:526
bool mac_address_is_valid(const uint8_t *mac)
Check if the MAC address is not all zeros or all ones.
Definition helpers.cpp:721
void format_mac_addr_lower_no_sep(const uint8_t *mac, char *output)
Format MAC address as xxxxxxxxxxxxxx (lowercase, no separators)
Definition helpers.h:767
constexpr uint32_t FNV1_OFFSET_BASIS
FNV-1 32-bit offset basis.
Definition helpers.h:386
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:612
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:323
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:681
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:421
std::string str_lower_case(const std::string &str)
Convert the string to lower case.
Definition helpers.cpp:190
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:392
std::string format_bin(const uint8_t *data, size_t length)
Format the byte array data of length len in binary.
Definition helpers.cpp:380
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:485
std::string str_sanitize(const std::string &str)
Sanitizes the input string by removing all characters but alphanumerics, dashes and underscores.
Definition helpers.cpp:199
std::string size_t len
Definition helpers.h:533
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:424
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:272
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:331
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:1387
optional< T > parse_number(const char *str)
Parse an unsigned decimal number from a null-terminated string.
Definition helpers.h:578
std::string get_mac_address_pretty()
Get the device MAC address as a string, in colon-separated uppercase hex notation.
Definition helpers.cpp:699
std::string str_snprintf(const char *fmt, size_t len,...)
Definition helpers.cpp:206
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:445
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:710
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:736
std::string str_upper_case(const std::string &str)
Convert the string to upper case.
Definition helpers.cpp:191
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:348
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:177
char * int8_to_str(char *buf, int8_t val)
Write int8 value to buffer without modulo operations.
Definition helpers.h:691
std::string format_mac_address_pretty(const uint8_t *mac)
Definition helpers.cpp:283
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:431
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:732
std::string base64_encode(const std::vector< uint8_t > &buf)
Definition helpers.cpp:477
constexpr uint32_t FNV1_PRIME
FNV-1 32-bit prime.
Definition helpers.h:388
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:434
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:635
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:704
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:428
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:992
std::string str_sprintf(const char *fmt,...)
Definition helpers.cpp:220
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:420
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:670
bool str_startswith(const std::string &str, const std::string &start)
Check whether a string starts with a value.
Definition helpers.cpp:166
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:449
std::string get_mac_address()
Get the device MAC address as a string, in lowercase hex notation.
Definition helpers.cpp:691
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:521
constexpr float fahrenheit_to_celsius(float value)
Convert degrees Fahrenheit to degrees Celsius.
Definition helpers.h:994
uint8_t reverse_bits(uint8_t x)
Reverse the order of 8 bits.
Definition helpers.h:459
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:319
std::string str_snake_case(const std::string &str)
Convert the string to snake case (lowercase with underscores).
Definition helpers.cpp:192
float lerp(float completion, float start, float end)=delete
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:367
bool str_endswith(const std::string &str, const std::string &end)
Check whether a string ends with a value.
Definition helpers.cpp:167
constexpr uint32_t fnv1a_hash(const char *str)
Calculate a FNV-1a hash of str.
Definition helpers.h:404
size_t base64_decode(const std::string &encoded_string, uint8_t *buf, size_t buf_len)
Definition helpers.cpp:519
ParseOnOffState
Return values for parse_on_off().
Definition helpers.h:940
@ PARSE_ON
Definition helpers.h:942
@ PARSE_TOGGLE
Definition helpers.h:944
@ PARSE_OFF
Definition helpers.h:943
@ PARSE_NONE
Definition helpers.h:941
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:259
std::string str_truncate(const std::string &str, size_t length)
Truncate a string to a specific length.
Definition helpers.cpp:174
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