ESPHome 2025.12.4
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
381uint32_t fnv1_hash(const char *str);
382inline uint32_t fnv1_hash(const std::string &str) { return fnv1_hash(str.c_str()); }
383
385uint32_t random_uint32();
387float random_float();
389bool random_bytes(uint8_t *data, size_t len);
390
392
395
397constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb) {
398 return (static_cast<uint16_t>(msb) << 8) | (static_cast<uint16_t>(lsb));
399}
401constexpr uint32_t encode_uint24(uint8_t byte1, uint8_t byte2, uint8_t byte3) {
402 return (static_cast<uint32_t>(byte1) << 16) | (static_cast<uint32_t>(byte2) << 8) | (static_cast<uint32_t>(byte3));
403}
405constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4) {
406 return (static_cast<uint32_t>(byte1) << 24) | (static_cast<uint32_t>(byte2) << 16) |
407 (static_cast<uint32_t>(byte3) << 8) | (static_cast<uint32_t>(byte4));
408}
409
411template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> constexpr T encode_value(const uint8_t *bytes) {
412 T val = 0;
413 for (size_t i = 0; i < sizeof(T); i++) {
414 val <<= 8;
415 val |= bytes[i];
416 }
417 return val;
418}
420template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
421constexpr T encode_value(const std::array<uint8_t, sizeof(T)> bytes) {
422 return encode_value<T>(bytes.data());
423}
425template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
426constexpr std::array<uint8_t, sizeof(T)> decode_value(T val) {
427 std::array<uint8_t, sizeof(T)> ret{};
428 for (size_t i = sizeof(T); i > 0; i--) {
429 ret[i - 1] = val & 0xFF;
430 val >>= 8;
431 }
432 return ret;
433}
434
436inline uint8_t reverse_bits(uint8_t x) {
437 x = ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
438 x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2);
439 x = ((x & 0xF0) >> 4) | ((x & 0x0F) << 4);
440 return x;
441}
443inline uint16_t reverse_bits(uint16_t x) {
444 return (reverse_bits(static_cast<uint8_t>(x & 0xFF)) << 8) | reverse_bits(static_cast<uint8_t>((x >> 8) & 0xFF));
445}
447inline uint32_t reverse_bits(uint32_t x) {
448 return (reverse_bits(static_cast<uint16_t>(x & 0xFFFF)) << 16) |
449 reverse_bits(static_cast<uint16_t>((x >> 16) & 0xFFFF));
450}
451
453template<typename T> constexpr T convert_big_endian(T val) {
454#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
455 return byteswap(val);
456#else
457 return val;
458#endif
459}
460
462template<typename T> constexpr T convert_little_endian(T val) {
463#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
464 return val;
465#else
466 return byteswap(val);
467#endif
468}
469
471
474
476bool str_equals_case_insensitive(const std::string &a, const std::string &b);
477
479bool str_startswith(const std::string &str, const std::string &start);
481bool str_endswith(const std::string &str, const std::string &end);
482
484std::string str_truncate(const std::string &str, size_t length);
485
488std::string str_until(const char *str, char ch);
490std::string str_until(const std::string &str, char ch);
491
493std::string str_lower_case(const std::string &str);
495std::string str_upper_case(const std::string &str);
497std::string str_snake_case(const std::string &str);
498
500std::string str_sanitize(const std::string &str);
501
503std::string __attribute__((format(printf, 1, 3))) str_snprintf(const char *fmt, size_t len, ...);
504
506std::string __attribute__((format(printf, 1, 2))) str_sprintf(const char *fmt, ...);
507
516std::string make_name_with_suffix(const std::string &name, char sep, const char *suffix_ptr, size_t suffix_len);
517
526std::string make_name_with_suffix(const char *name, size_t name_len, char sep, const char *suffix_ptr,
527 size_t suffix_len);
528
530
533
535template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
536optional<T> parse_number(const char *str) {
537 char *end = nullptr;
538 unsigned long value = ::strtoul(str, &end, 10); // NOLINT(google-runtime-int)
539 if (end == str || *end != '\0' || value > std::numeric_limits<T>::max())
540 return {};
541 return value;
542}
544template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
545optional<T> parse_number(const std::string &str) {
546 return parse_number<T>(str.c_str());
547}
549template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
550optional<T> parse_number(const char *str) {
551 char *end = nullptr;
552 signed long value = ::strtol(str, &end, 10); // NOLINT(google-runtime-int)
553 if (end == str || *end != '\0' || value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max())
554 return {};
555 return value;
556}
558template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
559optional<T> parse_number(const std::string &str) {
560 return parse_number<T>(str.c_str());
561}
563template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0> optional<T> parse_number(const char *str) {
564 char *end = nullptr;
565 float value = ::strtof(str, &end);
566 if (end == str || *end != '\0' || value == HUGE_VALF)
567 return {};
568 return value;
569}
571template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0>
572optional<T> parse_number(const std::string &str) {
573 return parse_number<T>(str.c_str());
574}
575
587size_t parse_hex(const char *str, size_t len, uint8_t *data, size_t count);
589inline bool parse_hex(const char *str, uint8_t *data, size_t count) {
590 return parse_hex(str, strlen(str), data, count) == 2 * count;
591}
593inline bool parse_hex(const std::string &str, uint8_t *data, size_t count) {
594 return parse_hex(str.c_str(), str.length(), data, count) == 2 * count;
595}
597inline bool parse_hex(const char *str, std::vector<uint8_t> &data, size_t count) {
598 data.resize(count);
599 return parse_hex(str, strlen(str), data.data(), count) == 2 * count;
600}
602inline bool parse_hex(const std::string &str, std::vector<uint8_t> &data, size_t count) {
603 data.resize(count);
604 return parse_hex(str.c_str(), str.length(), data.data(), count) == 2 * count;
605}
611template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
612optional<T> parse_hex(const char *str, size_t len) {
613 T val = 0;
614 if (len > 2 * sizeof(T) || parse_hex(str, len, reinterpret_cast<uint8_t *>(&val), sizeof(T)) == 0)
615 return {};
616 return convert_big_endian(val);
617}
619template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> optional<T> parse_hex(const char *str) {
620 return parse_hex<T>(str, strlen(str));
621}
623template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> optional<T> parse_hex(const std::string &str) {
624 return parse_hex<T>(str.c_str(), str.length());
625}
626
628inline char format_hex_char(uint8_t v) { return v >= 10 ? 'a' + (v - 10) : '0' + v; }
629
632inline char format_hex_pretty_char(uint8_t v) { return v >= 10 ? 'A' + (v - 10) : '0' + v; }
633
635inline void format_mac_addr_upper(const uint8_t *mac, char *output) {
636 for (size_t i = 0; i < 6; i++) {
637 uint8_t byte = mac[i];
638 output[i * 3] = format_hex_pretty_char(byte >> 4);
639 output[i * 3 + 1] = format_hex_pretty_char(byte & 0x0F);
640 if (i < 5)
641 output[i * 3 + 2] = ':';
642 }
643 output[17] = '\0';
644}
645
647inline void format_mac_addr_lower_no_sep(const uint8_t *mac, char *output) {
648 for (size_t i = 0; i < 6; i++) {
649 uint8_t byte = mac[i];
650 output[i * 2] = format_hex_char(byte >> 4);
651 output[i * 2 + 1] = format_hex_char(byte & 0x0F);
652 }
653 output[12] = '\0';
654}
655
657std::string format_mac_address_pretty(const uint8_t mac[6]);
659std::string format_hex(const uint8_t *data, size_t length);
661std::string format_hex(const std::vector<uint8_t> &data);
663template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> std::string format_hex(T val) {
665 return format_hex(reinterpret_cast<uint8_t *>(&val), sizeof(T));
666}
667template<std::size_t N> std::string format_hex(const std::array<uint8_t, N> &data) {
668 return format_hex(data.data(), data.size());
669}
670
696std::string format_hex_pretty(const uint8_t *data, size_t length, char separator = '.', bool show_length = true);
697
718std::string format_hex_pretty(const uint16_t *data, size_t length, char separator = '.', bool show_length = true);
719
741std::string format_hex_pretty(const std::vector<uint8_t> &data, char separator = '.', bool show_length = true);
742
763std::string format_hex_pretty(const std::vector<uint16_t> &data, char separator = '.', bool show_length = true);
764
785std::string format_hex_pretty(const std::string &data, char separator = '.', bool show_length = true);
786
810template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
811std::string format_hex_pretty(T val, char separator = '.', bool show_length = true) {
813 return format_hex_pretty(reinterpret_cast<uint8_t *>(&val), sizeof(T), separator, show_length);
814}
815
817std::string format_bin(const uint8_t *data, size_t length);
819template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> std::string format_bin(T val) {
821 return format_bin(reinterpret_cast<uint8_t *>(&val), sizeof(T));
822}
823
832ParseOnOffState parse_on_off(const char *str, const char *on = nullptr, const char *off = nullptr);
833
835std::string value_accuracy_to_string(float value, int8_t accuracy_decimals);
837std::string value_accuracy_with_uom_to_string(float value, int8_t accuracy_decimals, StringRef unit_of_measurement);
838
840int8_t step_to_accuracy_decimals(float step);
841
842std::string base64_encode(const uint8_t *buf, size_t buf_len);
843std::string base64_encode(const std::vector<uint8_t> &buf);
844
845std::vector<uint8_t> base64_decode(const std::string &encoded_string);
846size_t base64_decode(std::string const &encoded_string, uint8_t *buf, size_t buf_len);
847
849
852
854float gamma_correct(float value, float gamma);
856float gamma_uncorrect(float value, float gamma);
857
859void rgb_to_hsv(float red, float green, float blue, int &hue, float &saturation, float &value);
861void hsv_to_rgb(int hue, float saturation, float value, float &red, float &green, float &blue);
862
864
867
869constexpr float celsius_to_fahrenheit(float value) { return value * 1.8f + 32.0f; }
871constexpr float fahrenheit_to_celsius(float value) { return (value - 32.0f) / 1.8f; }
872
874
877
878template<typename... X> class CallbackManager;
879
884template<typename... Ts> class CallbackManager<void(Ts...)> {
885 public:
887 void add(std::function<void(Ts...)> &&callback) { this->callbacks_.push_back(std::move(callback)); }
888
890 void call(Ts... args) {
891 for (auto &cb : this->callbacks_)
892 cb(args...);
893 }
894 size_t size() const { return this->callbacks_.size(); }
895
897 void operator()(Ts... args) { call(args...); }
898
899 protected:
900 std::vector<std::function<void(Ts...)>> callbacks_;
901};
902
904template<typename T> class Deduplicator {
905 public:
907 bool next(T value) {
908 if (this->has_value_ && !this->value_unknown_ && this->last_value_ == value) {
909 return false;
910 }
911 this->has_value_ = true;
912 this->value_unknown_ = false;
913 this->last_value_ = value;
914 return true;
915 }
918 bool ret = !this->value_unknown_;
919 this->value_unknown_ = true;
920 return ret;
921 }
923 bool has_value() const { return this->has_value_; }
924
925 protected:
926 bool has_value_{false};
927 bool value_unknown_{false};
929};
930
932template<typename T> class Parented {
933 public:
935 Parented(T *parent) : parent_(parent) {}
936
938 T *get_parent() const { return parent_; }
940 void set_parent(T *parent) { parent_ = parent; }
941
942 protected:
943 T *parent_{nullptr};
944};
945
947
950
955class Mutex {
956 public:
957 Mutex();
958 Mutex(const Mutex &) = delete;
959 ~Mutex();
960 void lock();
961 bool try_lock();
962 void unlock();
963
964 Mutex &operator=(const Mutex &) = delete;
965
966 private:
967#if defined(USE_ESP32) || defined(USE_LIBRETINY)
968 SemaphoreHandle_t handle_;
969#else
970 // d-pointer to store private data on new platforms
971 void *handle_; // NOLINT(clang-diagnostic-unused-private-field)
972#endif
973};
974
980 public:
981 LockGuard(Mutex &mutex) : mutex_(mutex) { mutex_.lock(); }
982 ~LockGuard() { mutex_.unlock(); }
983
984 private:
985 Mutex &mutex_;
986};
987
1009 public:
1010 InterruptLock();
1012
1013 protected:
1014#if defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_ZEPHYR)
1015 uint32_t state_;
1016#endif
1017};
1018
1027 public:
1028 LwIPLock();
1029 ~LwIPLock();
1030
1031 // Delete copy constructor and copy assignment operator to prevent accidental copying
1032 LwIPLock(const LwIPLock &) = delete;
1033 LwIPLock &operator=(const LwIPLock &) = delete;
1034};
1035
1042 public:
1044 void start();
1046 void stop();
1047
1049 static bool is_high_frequency();
1050
1051 protected:
1052 bool started_{false};
1053 static uint8_t num_requests; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
1054};
1055
1057void get_mac_address_raw(uint8_t *mac); // NOLINT(readability-non-const-parameter)
1058
1060constexpr size_t MAC_ADDRESS_BUFFER_SIZE = 13;
1061
1064
1066std::string get_mac_address();
1067
1069std::string get_mac_address_pretty();
1070
1074void get_mac_address_into_buffer(std::span<char, MAC_ADDRESS_BUFFER_SIZE> buf);
1075
1079const char *get_mac_address_pretty_into_buffer(std::span<char, MAC_ADDRESS_PRETTY_BUFFER_SIZE> buf);
1080
1081#ifdef USE_ESP32
1083void set_mac_address(uint8_t *mac);
1084#endif
1085
1089
1092bool mac_address_is_valid(const uint8_t *mac);
1093
1095void delay_microseconds_safe(uint32_t us);
1096
1098
1101
1110template<class T> class RAMAllocator {
1111 public:
1112 using value_type = T;
1113
1114 enum Flags {
1115 NONE = 0, // Perform external allocation and fall back to internal memory
1116 ALLOC_EXTERNAL = 1 << 0, // Perform external allocation only.
1117 ALLOC_INTERNAL = 1 << 1, // Perform internal allocation only.
1118 ALLOW_FAILURE = 1 << 2, // Does nothing. Kept for compatibility.
1119 };
1120
1121 RAMAllocator() = default;
1123 // default is both external and internal
1125 if (flags != 0)
1126 this->flags_ = flags;
1127 }
1128 template<class U> constexpr RAMAllocator(const RAMAllocator<U> &other) : flags_{other.flags_} {}
1129
1130 T *allocate(size_t n) { return this->allocate(n, sizeof(T)); }
1131
1132 T *allocate(size_t n, size_t manual_size) {
1133 size_t size = n * manual_size;
1134 T *ptr = nullptr;
1135#ifdef USE_ESP32
1136 if (this->flags_ & Flags::ALLOC_EXTERNAL) {
1137 ptr = static_cast<T *>(heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
1138 }
1139 if (ptr == nullptr && this->flags_ & Flags::ALLOC_INTERNAL) {
1140 ptr = static_cast<T *>(heap_caps_malloc(size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
1141 }
1142#else
1143 // Ignore ALLOC_EXTERNAL/ALLOC_INTERNAL flags if external allocation is not supported
1144 ptr = static_cast<T *>(malloc(size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
1145#endif
1146 return ptr;
1147 }
1148
1149 T *reallocate(T *p, size_t n) { return this->reallocate(p, n, sizeof(T)); }
1150
1151 T *reallocate(T *p, size_t n, size_t manual_size) {
1152 size_t size = n * manual_size;
1153 T *ptr = nullptr;
1154#ifdef USE_ESP32
1155 if (this->flags_ & Flags::ALLOC_EXTERNAL) {
1156 ptr = static_cast<T *>(heap_caps_realloc(p, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
1157 }
1158 if (ptr == nullptr && this->flags_ & Flags::ALLOC_INTERNAL) {
1159 ptr = static_cast<T *>(heap_caps_realloc(p, size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
1160 }
1161#else
1162 // Ignore ALLOC_EXTERNAL/ALLOC_INTERNAL flags if external allocation is not supported
1163 ptr = static_cast<T *>(realloc(p, size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
1164#endif
1165 return ptr;
1166 }
1167
1168 void deallocate(T *p, size_t n) {
1169 free(p); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
1170 }
1171
1175 size_t get_free_heap_size() const {
1176#ifdef USE_ESP8266
1177 return ESP.getFreeHeap(); // NOLINT(readability-static-accessed-through-instance)
1178#elif defined(USE_ESP32)
1179 auto max_internal =
1180 this->flags_ & ALLOC_INTERNAL ? heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL) : 0;
1181 auto max_external =
1182 this->flags_ & ALLOC_EXTERNAL ? heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM) : 0;
1183 return max_internal + max_external;
1184#elif defined(USE_RP2040)
1185 return ::rp2040.getFreeHeap();
1186#elif defined(USE_LIBRETINY)
1187 return lt_heap_get_free();
1188#else
1189 return 100000;
1190#endif
1191 }
1192
1197#ifdef USE_ESP8266
1198 return ESP.getMaxFreeBlockSize(); // NOLINT(readability-static-accessed-through-instance)
1199#elif defined(USE_ESP32)
1200 auto max_internal =
1201 this->flags_ & ALLOC_INTERNAL ? heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL) : 0;
1202 auto max_external =
1203 this->flags_ & ALLOC_EXTERNAL ? heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM) : 0;
1204 return std::max(max_internal, max_external);
1205#else
1206 return this->get_free_heap_size();
1207#endif
1208 }
1209
1210 private:
1211 uint8_t flags_{ALLOC_INTERNAL | ALLOC_EXTERNAL};
1212};
1213
1214template<class T> using ExternalRAMAllocator = RAMAllocator<T>;
1215
1220template<typename T, typename U>
1221concept comparable_with = requires(T a, U b) {
1222 { a > b } -> std::convertible_to<bool>;
1223 { a < b } -> std::convertible_to<bool>;
1224};
1225
1226template<std::totally_ordered T, comparable_with<T> U> T clamp_at_least(T value, U min) {
1227 if (value < min)
1228 return min;
1229 return value;
1230}
1231template<std::totally_ordered T, comparable_with<T> U> T clamp_at_most(T value, U max) {
1232 if (value > max)
1233 return max;
1234 return value;
1235}
1236
1239
1244template<typename T, enable_if_t<!std::is_pointer<T>::value, int> = 0> T id(T value) { return value; }
1249template<typename T, enable_if_t<std::is_pointer<T *>::value, int> = 0> T &id(T *value) { return *value; }
1250
1252
1253} // namespace esphome
uint8_t m
Definition bl0906.h:1
void operator()(Ts... args)
Call all callbacks in this manager.
Definition helpers.h:897
std::vector< std::function< void(Ts...)> > callbacks_
Definition helpers.h:900
void call(Ts... args)
Call all callbacks in this manager.
Definition helpers.h:890
void add(std::function< void(Ts...)> &&callback)
Add a callback to the list.
Definition helpers.h:887
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:904
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:907
bool has_value() const
Returns true if this deduplicator has processed any items.
Definition helpers.h:923
bool next_unknown()
Returns true if the deduplicator's value was previously known.
Definition helpers.h:917
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:1041
void stop()
Stop running the loop continuously.
Definition helpers.cpp:642
static bool is_high_frequency()
Check whether the loop is running continuously.
Definition helpers.cpp:648
void start()
Start running the loop continuously.
Definition helpers.cpp:636
Helper class to disable interrupts.
Definition helpers.h:1008
Helper class that wraps a mutex with a RAII-style API.
Definition helpers.h:979
LockGuard(Mutex &mutex)
Definition helpers.h:981
Helper class to lock the lwIP TCPIP core when making lwIP API calls from non-TCPIP threads.
Definition helpers.h:1026
LwIPLock(const LwIPLock &)=delete
LwIPLock & operator=(const LwIPLock &)=delete
Mutex implementation, with API based on the unavailable std::mutex.
Definition helpers.h:955
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:932
T * get_parent() const
Get the parent of this object.
Definition helpers.h:938
Parented(T *parent)
Definition helpers.h:935
void set_parent(T *parent)
Set the parent of this object.
Definition helpers.h:940
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:1110
RAMAllocator(uint8_t flags)
Definition helpers.h:1122
T * reallocate(T *p, size_t n, size_t manual_size)
Definition helpers.h:1151
size_t get_free_heap_size() const
Return the total heap space available via this allocator.
Definition helpers.h:1175
T * reallocate(T *p, size_t n)
Definition helpers.h:1149
void deallocate(T *p, size_t n)
Definition helpers.h:1168
size_t get_max_free_block_size() const
Return the maximum size block this allocator could allocate.
Definition helpers.h:1196
T * allocate(size_t n)
Definition helpers.h:1130
constexpr RAMAllocator(const RAMAllocator< U > &other)
Definition helpers.h:1128
T * allocate(size_t n, size_t manual_size)
Definition helpers.h:1132
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:1221
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:1231
bool random_bytes(uint8_t *data, size_t len)
Generate len number of random bytes.
Definition helpers.cpp:18
float random_float()
Return a random float between 0 and 1.
Definition helpers.cpp:157
float gamma_uncorrect(float value, float gamma)
Reverts gamma correction of gamma to value.
Definition helpers.cpp:562
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
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:388
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:453
char format_hex_pretty_char(uint8_t v)
Convert a nibble (0-15) to uppercase hex char (used for pretty printing) This always uses uppercase (...
Definition helpers.h:632
float gamma_correct(float value, float gamma)
Applies gamma correction of gamma to value.
Definition helpers.cpp:554
void format_mac_addr_upper(const uint8_t *mac, char *output)
Format MAC address as XX:XX:XX:XX:XX:XX (uppercase)
Definition helpers.h:635
bool mac_address_is_valid(const uint8_t *mac)
Check if the MAC address is not all zeros or all ones.
Definition helpers.cpp:680
void format_mac_addr_lower_no_sep(const uint8_t *mac, char *output)
Format MAC address as xxxxxxxxxxxxxx (lowercase, no separators)
Definition helpers.h:647
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:571
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:292
std::string str_lower_case(const std::string &str)
Convert the string to lower case.
Definition helpers.cpp:189
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:365
constexpr size_t MAC_ADDRESS_PRETTY_BUFFER_SIZE
Buffer size for MAC address in colon-separated uppercase hex notation (17 chars + null terminator)
Definition helpers.h:1063
std::string format_bin(const uint8_t *data, size_t length)
Format the byte array data of length len in binary.
Definition helpers.cpp:353
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:462
std::string str_sanitize(const std::string &str)
Sanitizes the input string by removing all characters but alphanumerics, dashes and underscores.
Definition helpers.cpp:198
std::string size_t len
Definition helpers.h:503
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:401
bool has_custom_mac_address()
Check if a custom MAC address is set (ESP32 & variants)
Definition helpers.cpp:93
std::string value_accuracy_with_uom_to_string(float value, int8_t accuracy_decimals, StringRef unit_of_measurement)
Create a string from a value, an accuracy in decimals, and a unit of measurement.
Definition helpers.cpp:395
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:268
uint32_t fnv1_hash(const char *str)
Calculate a FNV-1 hash of str.
Definition helpers.cpp:146
T clamp_at_least(T value, U min)
Definition helpers.h:1226
optional< T > parse_number(const char *str)
Parse an unsigned decimal number from a null-terminated string.
Definition helpers.h:536
constexpr size_t MAC_ADDRESS_BUFFER_SIZE
Buffer size for MAC address in lowercase hex notation (12 hex chars + null terminator)
Definition helpers.h:1060
std::string get_mac_address_pretty()
Get the device MAC address as a string, in colon-separated uppercase hex notation.
Definition helpers.cpp:658
std::string str_snprintf(const char *fmt, size_t len,...)
Definition helpers.cpp:208
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:408
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:669
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:695
std::string str_upper_case(const std::string &str)
Convert the string to upper case.
Definition helpers.cpp:190
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:321
bool str_equals_case_insensitive(const std::string &a, const std::string &b)
Compare strings for equality in case-insensitive manner.
Definition helpers.cpp:161
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:176
std::string format_mac_address_pretty(const uint8_t *mac)
Definition helpers.cpp:286
std::string base64_encode(const std::vector< uint8_t > &buf)
Definition helpers.cpp:440
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:411
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:594
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:663
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:405
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:869
std::string str_sprintf(const char *fmt,...)
Definition helpers.cpp:222
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:397
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
bool str_startswith(const std::string &str, const std::string &start)
Check whether a string starts with a value.
Definition helpers.cpp:165
char format_hex_char(uint8_t v)
Convert a nibble (0-15) to lowercase hex char.
Definition helpers.h:628
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:426
std::string get_mac_address()
Get the device MAC address as a string, in lowercase hex notation.
Definition helpers.cpp:650
To bit_cast(const From &src)
Convert data between types, without aliasing issues or undefined behaviour.
Definition helpers.h:71
constexpr float fahrenheit_to_celsius(float value)
Convert degrees Fahrenheit to degrees Celsius.
Definition helpers.h:871
uint8_t reverse_bits(uint8_t x)
Reverse the order of 8 bits.
Definition helpers.h:436
std::string str_snake_case(const std::string &str)
Convert the string to snake case (lowercase with underscores).
Definition helpers.cpp:191
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:166
size_t base64_decode(const std::string &encoded_string, uint8_t *buf, size_t buf_len)
Definition helpers.cpp:482
ParseOnOffState
Return values for parse_on_off().
Definition helpers.h:825
@ PARSE_ON
Definition helpers.h:827
@ PARSE_TOGGLE
Definition helpers.h:829
@ PARSE_OFF
Definition helpers.h:828
@ PARSE_NONE
Definition helpers.h:826
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:241
void init()
Definition core.cpp:109
std::string str_truncate(const std::string &str, size_t length)
Truncate a string to a specific length.
Definition helpers.cpp:173
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