45#include <esp_system.h>
46#include <esp_heap_caps.h>
50#include <freertos/FreeRTOS.h>
51#include <freertos/semphr.h>
52#elif defined(USE_LIBRETINY)
61#define HOT __attribute__((hot))
62#define ESPDEPRECATED(msg, when) __attribute__((deprecated(msg)))
63#define ESPHOME_ALWAYS_INLINE __attribute__((always_inline))
64#define PACKED __attribute__((packed))
76using std::is_trivially_copyable;
77using std::make_unique;
78using std::enable_if_t;
80using std::is_invocable;
81#if __cpp_lib_bit_cast >= 201806
86 typename To,
typename From,
87 enable_if_t<
sizeof(To) ==
sizeof(From) && is_trivially_copyable<From>::value && is_trivially_copyable<To>::value,
91 memcpy(&dst, &
src,
sizeof(To));
97inline float lerp(
float completion,
float start,
float end) =
delete;
103 for (
size_t i = 0; i <
sizeof(T); i++)
104 reinterpret_cast<uint8_t *
>(&
m)[i] =
reinterpret_cast<uint8_t *
>(&n)[
sizeof(T) - 1 - i];
107template<>
constexpr uint8_t
byteswap(uint8_t n) {
return n; }
110template<>
inline uint16_t
byteswap(uint16_t n) {
return __builtin_bswap16(n); }
112template<>
inline uint64_t
byteswap(uint64_t n) {
return __builtin_bswap64(n); }
113template<>
inline int8_t
byteswap(int8_t n) {
return n; }
114template<>
inline int16_t
byteswap(int16_t n) {
return __builtin_bswap16(n); }
115template<>
inline int32_t
byteswap(int32_t n) {
return __builtin_bswap32(n); }
116template<>
inline int64_t
byteswap(int64_t n) {
return __builtin_bswap64(n); }
118template<>
constexpr uint16_t
byteswap(uint16_t n) {
return __builtin_bswap16(n); }
120template<>
constexpr uint64_t
byteswap(uint64_t n) {
return __builtin_bswap64(n); }
121template<>
constexpr int8_t
byteswap(int8_t n) {
return n; }
122template<>
constexpr int16_t
byteswap(int16_t n) {
return __builtin_bswap16(n); }
123template<>
constexpr int32_t
byteswap(int32_t n) {
return __builtin_bswap32(n); }
124template<>
constexpr int64_t
byteswap(int64_t n) {
return __builtin_bswap64(n); }
157 delete[] this->
heap_;
162 if (other.is_inline_()) {
163 memcpy(this->
inline_, other.inline_, this->len_);
165 this->
heap_ = other.heap_;
166 other.heap_ =
nullptr;
173 if (
this != &other) {
175 delete[] this->
heap_;
176 this->
len_ = other.len_;
177 if (other.is_inline_()) {
178 memcpy(this->
inline_, other.inline_, this->len_);
180 this->
heap_ = other.heap_;
181 other.heap_ =
nullptr;
195 operator std::span<const uint8_t>()
const {
return std::span<const uint8_t>(this->
data(), this->
len_); }
203 delete[] this->
heap_;
204 this->
heap_ =
nullptr;
207 if (size > InlineSize && (this->
is_inline_() || size != this->len_)) {
235 using iterator =
typename std::array<T, N>::iterator;
241 std::array<T, N> data_;
250 while (first != last && count_ < N) {
251 data_[count_++] = *first++;
257 for (
const auto &
val : init) {
260 data_[count_++] =
val;
266 static_assert(M <= N,
"Source StaticVector cannot be larger than the destination");
272 data_[count_++] = value;
280 template<
typename InputIt>
void assign(InputIt first, InputIt last) {
282 while (first != last && count_ < N) {
283 data_[count_++] = *first++;
294 return data_[count_++];
297 size_t size()
const {
return count_; }
299 bool empty()
const {
return count_ == 0; }
302 T *
data() {
return data_.data(); }
303 const T *
data()
const {
return data_.data(); }
321 operator std::span<T>() {
return std::span<T>(data_.data(), count_); }
322 operator std::span<const T>()
const {
return std::span<const T>(data_.data(), count_); }
333 using index_type = std::conditional_t<(N <= std::numeric_limits<uint8_t>::max()), uint8_t, uint16_t>;
411template<typename T, size_t MAX_CAPACITY = std::numeric_limits<uint16_t>::max()>
class FixedRingBuffer {
412 using index_type = std::conditional_t<
413 (MAX_CAPACITY <= std::numeric_limits<uint8_t>::max()), uint8_t,
414 std::conditional_t<(MAX_CAPACITY <= std::numeric_limits<uint16_t>::max()), uint16_t,
uint32_t>>;
449 if constexpr (std::is_trivially_copyable<T>::value && std::is_trivially_default_constructible<T>::value) {
450 ::operator
delete(this->
data_);
452 delete[] this->
data_;
462 if constexpr (std::is_trivially_copyable<T>::value && std::is_trivially_default_constructible<T>::value) {
465 this->
data_ =
static_cast<T *
>(::operator
new(
capacity *
sizeof(T)));
533template<
typename T,
size_t N>
inline void init_array_from(std::array<T, N> &dest, std::initializer_list<T>
src) {
535 assert(
src.size() == N);
537 if constexpr (std::is_trivially_copyable_v<T>) {
538 __builtin_memcpy(dest.data(),
src.begin(), N *
sizeof(T));
541 for (
const auto &v :
src) {
550#define ESPHOME_ABORT_WITH_REASON(reason) esp_system_abort(reason)
552#define ESPHOME_ABORT_WITH_REASON(reason) abort()
565 void destroy_elements_() {
567 if constexpr (!std::is_trivially_destructible<T>::value) {
568 for (
size_t i = 0; i < size_; i++) {
576 if (data_ !=
nullptr) {
590 void assign_from_initializer_list_(std::initializer_list<T> init_list) {
591 init(init_list.size());
593 for (
const auto &item : init_list) {
594 new (data_ + idx) T(item);
597 size_ = init_list.size();
605 FixedVector(std::initializer_list<T> init_list) { assign_from_initializer_list_(init_list); }
619 operator std::vector<T>()
const {
return {data_, data_ + size_}; }
622 if (
this != &other) {
628 capacity_ = other.capacity_;
640 assign_from_initializer_list_(init_list);
650 ESPHOME_ABORT_WITH_REASON(
"FixedVector: out of memory");
659 if (n > SIZE_MAX /
sizeof(T))
663 data_ =
static_cast<T *
>(malloc(n *
sizeof(T)));
664 if (data_ ==
nullptr)
686 if (size_ < capacity_) {
688 new (&data_[size_]) T(value);
697 if (size_ < capacity_) {
699 new (&data_[size_]) T(std::move(value));
710 new (&data_[size_]) T(std::forward<Args>(args)...);
712 return data_[size_ - 1];
718 const T &
front()
const {
return data_[0]; }
722 T &
back() {
return data_[size_ - 1]; }
723 const T &
back()
const {
return data_[size_ - 1]; }
728 if constexpr (!std::is_trivially_destructible<T>::value) {
729 data_[size_ - 1].~T();
734 size_t size()
const {
return size_; }
735 bool empty()
const {
return size_ == 0; }
737 bool full()
const {
return size_ == capacity_; }
746 T &
at(
size_t i) {
return data_[i]; }
747 const T &
at(
size_t i)
const {
return data_[i]; }
751 T *
end() {
return data_ + size_; }
752 const T *
begin()
const {
return data_; }
753 const T *
end()
const {
return data_ + size_; }
764 static_assert(std::is_trivially_default_constructible_v<T> && std::is_trivially_destructible_v<T>,
765 "the heap fallback leaves elements unconstructed");
766 if (
size <= STACK_SIZE) {
767 this->buffer_ = this->stack_buffer_;
769 if (
size <= SIZE_MAX /
sizeof(T)) {
771 this->heap_buffer_ =
static_cast<T *
>(malloc(
size *
sizeof(T)));
774 if (this->heap_buffer_ ==
nullptr)
775 ESPHOME_ABORT_WITH_REASON(
"SmallBufferWithHeapFallback: out of memory");
776 this->buffer_ = this->heap_buffer_;
787 T *
get() {
return this->buffer_; }
790 T stack_buffer_[STACK_SIZE];
791 T *heap_buffer_{
nullptr};
803int8_t
ilog10(
float value);
811 for (int8_t i = 0; i < exp; i++)
814 for (int8_t i = exp; i < 0; i++)
821template<
typename T,
typename U> T
remap(U value, U min, U max, T min_out, T max_out) {
822 return (value - min) * (max_out - min_out) / (max - min) + min_out;
826uint8_t
crc8(
const uint8_t *data, uint8_t
len, uint8_t crc = 0x00, uint8_t poly = 0x8C,
bool msb_first =
false);
829uint16_t
crc16(
const uint8_t *data, uint16_t
len, uint16_t crc = 0xffff, uint16_t reverse_poly = 0xa001,
830 bool refin =
false,
bool refout =
false);
831uint16_t
crc16be(
const uint8_t *data, uint16_t
len, uint16_t crc = 0, uint16_t poly = 0x1021,
bool refin =
false,
832 bool refout =
false);
846 using UnsignedT = std::make_unsigned_t<T>;
847 UnsignedT uvalue =
static_cast<UnsignedT
>(value);
848 for (
size_t i = 0; i <
sizeof(T); i++) {
850 hash ^= (uvalue >> (i * 8)) & 0xFF;
881 using UnsignedT = std::make_unsigned_t<T>;
882 UnsignedT uvalue =
static_cast<UnsignedT
>(value);
883 for (
size_t i = 0; i <
sizeof(T); i++) {
884 hash ^= (uvalue >> (i * 8)) & 0xFF;
916 return (
static_cast<uint16_t
>(msb) << 8) | (
static_cast<uint16_t
>(lsb));
924 return (
static_cast<uint32_t>(byte1) << 24) | (
static_cast<uint32_t>(byte2) << 16) |
929template<typename T, enable_if_t<std::is_unsigned<T>::value,
int> = 0>
constexpr T
encode_value(
const uint8_t *bytes) {
931 for (
size_t i = 0; i <
sizeof(T); i++) {
938template<typename T, enable_if_t<std::is_unsigned<T>::value,
int> = 0>
943template<typename T, enable_if_t<std::is_unsigned<T>::value,
int> = 0>
945 std::array<uint8_t,
sizeof(T)>
ret{};
946 for (
size_t i =
sizeof(T); i > 0; i--) {
955 x = ((
x & 0xAA) >> 1) | ((
x & 0x55) << 1);
956 x = ((
x & 0xCC) >> 2) | ((
x & 0x33) << 2);
957 x = ((
x & 0xF0) >> 4) | ((
x & 0x0F) << 4);
966 return (
reverse_bits(
static_cast<uint16_t
>(
x & 0xFFFF)) << 16) |
972#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
981#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
1003bool str_startswith(
const std::string &str,
const std::string &start);
1026#define str_contains_ignore_case(haystack, needle) str_contains_ignore_case_p(haystack, PSTR(needle))
1030 if (!needle || !haystack) {
1037#if defined(USE_LIBRETINY) || defined(USE_RP2) || defined(USE_ZEPHYR)
1040 return strcasestr(haystack, needle) !=
nullptr;
1050constexpr char to_snake_case_char(
char c) {
return (c ==
' ') ?
'_' : (c >=
'A' && c <=
'Z') ? c + (
'a' -
'A') : c; }
1055 return (c ==
'-' || c ==
'_' || (c >=
'0' && c <=
'9') || (c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z')) ? c :
'_';
1067char *
str_sanitize_to(
char *buffer,
size_t buffer_size,
const char *str);
1082 for (
size_t i = 0; i <
len; i++) {
1114#define buf_append_printf(buf, size, pos, fmt, ...) buf_append_printf_p(buf, size, pos, PSTR(fmt), ##__VA_ARGS__)
1153 size_t remaining =
size -
pos - 1;
1154 size_t len = strnlen_P(str, remaining);
1155 memcpy_P(buf +
pos, str,
len);
1163#define buf_append_str(buf, size, pos, str) buf_append_str_p(buf, size, pos, PSTR(str))
1176 size_t remaining =
size -
pos - 1;
1178 while (
len < remaining && str[
len] !=
'\0') {
1181 memcpy(buf +
pos, str,
len);
1189static constexpr size_t MAX_NAME_WITH_SUFFIX_SIZE = 128;
1201 const char *suffix_ptr,
size_t suffix_len);
1209template<
typename T, enable_if_t<(std::is_
integral<T>::value && std::is_
unsigned<T>::value),
int> = 0>
1211 char *
end =
nullptr;
1212 unsigned long value = ::strtoul(str, &
end, 10);
1213 if (
end == str || *
end !=
'\0' || value > std::numeric_limits<T>::max())
1218template<
typename T, enable_if_t<(std::is_
integral<T>::value && std::is_
unsigned<T>::value),
int> = 0>
1223template<
typename T, enable_if_t<(std::is_
integral<T>::value && std::is_
signed<T>::value),
int> = 0>
1225 char *
end =
nullptr;
1226 signed long value = ::strtol(str, &
end, 10);
1227 if (
end == str || *
end !=
'\0' || value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max())
1232template<
typename T, enable_if_t<(std::is_
integral<T>::value && std::is_
signed<T>::value),
int> = 0>
1237template<
typename T, enable_if_t<(std::is_same<T,
float>::value),
int> = 0> optional<T>
parse_number(
const char *str) {
1238 char *
end =
nullptr;
1239 float value = ::strtof(str, &
end);
1240 if (
end == str || *
end !=
'\0' || value == HUGE_VALF)
1245template<
typename T, enable_if_t<(std::is_same<T,
float>::value),
int> = 0>
1261size_t parse_hex(
const char *str,
size_t len, uint8_t *data,
size_t count);
1263inline bool parse_hex(
const char *str, uint8_t *data,
size_t count) {
1264 return parse_hex(str, strlen(str), data, count) == 2 * count;
1267inline bool parse_hex(
const std::string &str, uint8_t *data,
size_t count) {
1268 return parse_hex(str.c_str(), str.length(), data, count) == 2 * count;
1271inline bool parse_hex(
const char *str, std::vector<uint8_t> &data,
size_t count) {
1273 return parse_hex(str, strlen(str), data.data(), count) == 2 * count;
1276inline bool parse_hex(
const std::string &str, std::vector<uint8_t> &data,
size_t count) {
1278 return parse_hex(str.c_str(), str.length(), data.data(), count) == 2 * count;
1285template<typename T, enable_if_t<std::is_unsigned<T>::value,
int> = 0>
1288 if (
len > 2 *
sizeof(T) ||
parse_hex(str,
len,
reinterpret_cast<uint8_t *
>(&
val),
sizeof(T)) == 0)
1293template<typename T, enable_if_t<std::is_unsigned<T>::value,
int> = 0> optional<T>
parse_hex(
const char *str) {
1297template<typename T, enable_if_t<std::is_unsigned<T>::value,
int> = 0> optional<T>
parse_hex(
const std::string &str) {
1303static constexpr uint8_t INVALID_HEX_CHAR = 255;
1306 if (c >=
'0' && c <=
'9')
1308 if (c >=
'A' && c <=
'F')
1309 return c -
'A' + 10;
1310 if (c >=
'a' && c <=
'f')
1311 return c -
'a' + 10;
1312 return INVALID_HEX_CHAR;
1316ESPHOME_ALWAYS_INLINE
inline char format_hex_char(uint8_t v,
char base) {
return v >= 10 ? base + (v - 10) :
'0' + v; }
1325static constexpr size_t JSON_ESCAPE_MAX_EXPANSION = 6;
1352 int32_t tens = v / 10;
1353 *buf++ =
'0' + tens;
1355 }
else if (v >= 10) {
1356 int32_t tens = v / 10;
1357 *buf++ =
'0' + tens;
1368inline char *
buf_append_sep_str(
char *buf,
size_t remaining,
char separator,
const char *str,
size_t str_len) {
1369 if (remaining < 2) {
1370 if (remaining >= 1) {
1377 size_t copy_len = std::min(str_len, remaining - 1);
1378 memcpy(buf, str, copy_len);
1388static constexpr size_t UINT32_MAX_STR_SIZE = 11;
1399 return static_cast<size_t>(
end - buf.data());
1406 while (divisor > 0) {
1407 *buf++ =
'0' +
static_cast<char>(frac / divisor);
1420 static_assert(N >= 3,
"Buffer must hold at least one hex byte (3 chars)");
1425template<size_t N, typename T, enable_if_t<std::is_unsigned<T>::value,
int> = 0>
1427 static_assert(N >=
sizeof(T) * 2 + 1,
"Buffer too small for type");
1429 return format_hex_to(buffer,
reinterpret_cast<const uint8_t *
>(&
val),
sizeof(T));
1433template<
size_t N>
inline char *
format_hex_to(
char (&buffer)[N],
const std::vector<uint8_t> &data) {
1438template<
size_t N,
size_t M>
inline char *
format_hex_to(
char (&buffer)[N],
const std::array<uint8_t, M> &data) {
1449template<size_t N, typename T, enable_if_t<std::is_unsigned<T>::value,
int> = 0>
1451 static_assert(N >=
sizeof(T) * 2 + 3,
"Buffer too small for prefixed hex");
1455 format_hex_to(buffer + 2, N - 2,
reinterpret_cast<const uint8_t *
>(&
val),
sizeof(T));
1461 static_assert(N >= 5,
"Buffer must hold at least '0x' + one hex byte + null");
1487 static_assert(N >= 3,
"Buffer must hold at least one hex byte");
1498template<
size_t N,
size_t M>
1524 static_assert(N >= 5,
"Buffer must hold at least one hex uint16_t");
1529static constexpr size_t MAC_ADDRESS_SIZE = 6;
1533static constexpr size_t MAC_ADDRESS_BUFFER_SIZE = MAC_ADDRESS_SIZE * 2 + 1;
1537 return format_hex_pretty_to(output, MAC_ADDRESS_PRETTY_BUFFER_SIZE, mac, MAC_ADDRESS_SIZE,
':');
1542 format_hex_to(output, MAC_ADDRESS_BUFFER_SIZE, mac, MAC_ADDRESS_SIZE);
1550template<typename T, enable_if_t<std::is_unsigned<T>::value,
int> = 0> std::string
format_hex(T
val) {
1552 return format_hex(
reinterpret_cast<uint8_t *
>(&
val),
sizeof(T));
1556template<std::
size_t N> std::string
format_hex(
const std::array<uint8_t, N> &data) {
1565template<typename T, enable_if_t<std::is_unsigned<T>::value,
int> = 0>
1568 return format_hex_pretty(
reinterpret_cast<uint8_t *
>(&
val),
sizeof(T), separator, show_length);
1597 static_assert(N >= 9,
"Buffer must hold at least one binary byte (9 chars)");
1617template<size_t N, typename T, enable_if_t<std::is_unsigned<T>::value,
int> = 0>
1619 static_assert(N >=
sizeof(T) * 8 + 1,
"Buffer too small for type");
1621 return format_bin_to(buffer,
reinterpret_cast<const uint8_t *
>(&
val),
sizeof(T));
1628template<typename T, enable_if_t<std::is_unsigned<T>::value,
int> = 0> std::string
format_bin(T
val) {
1630 return format_bin(
reinterpret_cast<uint8_t *
>(&
val),
sizeof(T));
1646static constexpr size_t VALUE_ACCURACY_MAX_LEN = 64;
1649size_t value_accuracy_to_buf(std::span<char, VALUE_ACCURACY_MAX_LEN> buf,
float value, int8_t accuracy_decimals);
1652 int8_t accuracy_decimals, StringRef unit_of_measurement);
1659size_t base64_decode(std::string
const &encoded_string, uint8_t *buf,
size_t buf_len);
1660size_t base64_decode(
const uint8_t *encoded_data,
size_t encoded_len, uint8_t *buf,
size_t buf_len);
1674void rgb_to_hsv(
float red,
float green,
float blue,
int &hue,
float &saturation,
float &value);
1676void hsv_to_rgb(
int hue,
float saturation,
float value,
float &red,
float &green,
float &blue);
1710 static_assert(
sizeof(
void *) ==
sizeof(std::uintptr_t),
"void* must be the same size as uintptr_t");
1712 void (*fn_)(
void *, Ts...){
nullptr};
1713 void *ctx_{
nullptr};
1716 void call(Ts... args)
const { this->fn_(this->ctx_, std::forward<Ts>(args)...); }
1721 using DecayF = std::decay_t<F>;
1722 if constexpr (
sizeof(DecayF) <=
sizeof(
void *) && std::is_trivially_copyable_v<DecayF>) {
1729 DecayF decayed = std::forward<F>(callable);
1730 __builtin_memcpy(&cb.ctx_, &decayed,
sizeof(DecayF));
1731 cb.fn_ = [](
void *c, Ts... args) {
1732 alignas(DecayF)
char buf[
sizeof(DecayF)];
1733 __builtin_memcpy(buf, &c,
sizeof(DecayF));
1734 (*std::launder(
reinterpret_cast<DecayF *
>(buf)))(args...);
1741 auto *stored =
new DecayF(std::forward<F>(callable));
1742 return {[](
void *c, Ts... args) { (*
static_cast<DecayF *
>(c))(args...); },
static_cast<void *
>(stored)};
1765 static_assert(std::is_trivially_copyable_v<CbType>,
"Callback must be trivially copyable");
1775 : data_(other.data_), size_(other.size_), capacity_(other.capacity_) {
1776 other.data_ =
nullptr;
1778 other.capacity_ = 0;
1781 std::swap(this->data_, other.data_);
1782 std::swap(this->size_, other.size_);
1783 std::swap(this->capacity_, other.capacity_);
1789 template<
typename F>
void add(F &&callback) { this->add_(CbType::create(std::forward<F>(callback))); }
1792 inline void ESPHOME_ALWAYS_INLINE
call(
const Ts &...args) {
1793 if (this->size_ != 0) {
1794 for (
auto *it = this->data_, *
end = it + this->size_; it !=
end; ++it) {
1799 uint16_t
size()
const {
return this->size_; }
1809 if (this->size_ == this->capacity_) {
1813 this->data_[this->size_++] = cb;
1817 uint16_t capacity_{0};
1834 template<
typename F>
void add(F &&callback) { this->add_(
Callback<
void(Ts...)>::create(std::forward<F>(callback))); }
1838 for (
auto &cb : this->callbacks_)
1841 size_t size()
const {
return this->callbacks_.size(); }
1883 template<
typename F>
void add(F &&callback) { this->add_(
Callback<
void(Ts...)>::create(std::forward<F>(callback))); }
1887 if (this->callbacks_) {
1888 this->callbacks_->call(args...);
1893 size_t size()
const {
return this->callbacks_ ? this->callbacks_->size() : 0; }
1896 bool empty()
const {
return !this->callbacks_ || this->callbacks_->size() == 0; }
1904 if (!this->callbacks_) {
1907 this->callbacks_->add_(cb);
1969#if defined(USE_ESP8266) || defined(USE_RP2)
1976#elif defined(USE_ESP32) || defined(USE_LIBRETINY)
1978 Mutex() { handle_ = xSemaphoreCreateMutex(); }
1980 void lock() { xSemaphoreTake(this->handle_, portMAX_DELAY); }
1981 bool try_lock() {
return xSemaphoreTake(this->handle_, 0) == pdTRUE; }
1982 void unlock() { xSemaphoreGive(this->handle_); }
1985 SemaphoreHandle_t handle_;
2038#if defined(USE_ESP8266) || defined(USE_RP2) || defined(USE_ZEPHYR)
2056#if defined(USE_ESP32) || defined(USE_RP2)
2131template<
typename T>
using RAMUniquePtr = std::unique_ptr<T, RAMDeleter<T>>;
2161 if (alloc_bits != 0) {
2162 this->flags_ = alloc_bits;
2172 size_t size = n * manual_size;
2175 const auto caps = this->get_caps_();
2176 ptr =
static_cast<T *
>(heap_caps_malloc_prefer(
size, 2, caps[0], caps[1]));
2179 ptr =
static_cast<T *
>(malloc(
size));
2187 size_t size = n * manual_size;
2190 const auto caps = this->get_caps_();
2191 ptr =
static_cast<T *
>(heap_caps_realloc_prefer(p,
size, 2, caps[0], caps[1]));
2194 ptr =
static_cast<T *
>(realloc(p,
size));
2206 static_assert(
alignof(T) <=
alignof(std::max_align_t),
"malloc storage cannot hold an over aligned type");
2216 static_assert(std::is_trivially_default_constructible_v<T>,
"elements are left unconstructed");
2217 static_assert(
alignof(T) <=
alignof(std::max_align_t),
"malloc storage cannot hold an over aligned type");
2218 if (n == 0 || n > SIZE_MAX /
sizeof(T))
2228 return ESP.getFreeHeap();
2229#elif defined(USE_ESP32)
2231 this->flags_ &
ALLOC_INTERNAL ? heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL) : 0;
2233 this->flags_ &
ALLOC_EXTERNAL ? heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM) : 0;
2234 return max_internal + max_external;
2235#elif defined(USE_RP2)
2236 return ::rp2040.getFreeHeap();
2237#elif defined(USE_LIBRETINY)
2238 return lt_heap_get_free();
2249 return ESP.getMaxFreeBlockSize();
2250#elif defined(USE_ESP32)
2252 this->flags_ &
ALLOC_INTERNAL ? heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL) : 0;
2254 this->flags_ &
ALLOC_EXTERNAL ? heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM) : 0;
2255 return std::max(max_internal, max_external);
2268 std::array<uint32_t, 2> get_caps_()
const {
2269 constexpr uint32_t external_caps = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT;
2270 constexpr uint32_t internal_caps = MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT;
2272 return {internal_caps, external_caps};
2276 return {primary, fallback};
2294 static_assert(std::is_trivially_destructible_v<T>,
"RAMUniquePtr<T[]> is for trivially destructible elements");
2302template<
typename T,
typename U>
2304 { a > b } -> std::convertible_to<bool>;
2305 { a < b } -> std::convertible_to<bool>;
2308template<std::totally_ordered T, comparable_with<T> U> T
clamp_at_least(T value, U min) {
2313template<std::totally_ordered T, comparable_with<T> U> T
clamp_at_most(T value, U max) {
2326template<typename T, enable_if_t<!std::is_pointer<T>::value,
int> = 0> T
id(T value) {
return value; }
2331template<typename T, enable_if_t<std::is_pointer<T *>::value,
int> = 0> T &
id(T *value) {
return *value; }
Heap-allocating helper functions.
void ESPHOME_ALWAYS_INLINE call(const Ts &...args)
Call all callbacks in this manager.
CallbackManager & operator=(const CallbackManager &)=delete
void operator()(const Ts &...args)
Call all callbacks in this manager.
CallbackManager & operator=(CallbackManager &&other) noexcept
friend class LazyCallbackManager
CallbackManager()=default
void add(F &&callback)
Add any callable.
CallbackManager(CallbackManager &&other) noexcept
void add_(CbType cb)
Non-template core to avoid code duplication per lambda type.
CallbackManager(const CallbackManager &)=delete
Lightweight read-only view over a const array stored in RODATA (will typically be in flash memory) Av...
const constexpr T & operator[](size_t i) const
constexpr bool empty() const
constexpr ConstVector(const T *data, size_t size)
constexpr size_t size() const
Helper class to deduplicate items in a series of values.
bool next(T value)
Feeds the next item in the series to the deduplicator and returns false if this is a duplicate.
bool has_value() const
Returns true if this deduplicator has processed any items.
bool next_unknown()
Returns true if the deduplicator's value was previously known.
const T & operator*() const
bool operator!=(const ConstIterator &other) const
ConstIterator & operator++()
ConstIterator(const FixedRingBuffer *buf, index_type pos)
bool operator!=(const Iterator &other) const
Iterator(FixedRingBuffer *buf, index_type pos)
Fixed-capacity circular buffer - allocates once at runtime, never reallocates.
FixedRingBuffer & operator=(const FixedRingBuffer &)=delete
ConstIterator begin() const
bool push(const T &value)
Push a value. Returns false if full.
index_type capacity() const
void push_overwrite(const T &value)
Push a value, overwriting the oldest if full.
void init(index_type capacity)
Allocate capacity - can only be called once.
void pop()
Remove the oldest element.
void clear()
Clear all elements (reset to empty, keep capacity)
FixedRingBuffer()=default
FixedRingBuffer(const FixedRingBuffer &)=delete
ConstIterator end() const
Fixed-capacity vector - sized once through init() or try_init(); push_back never reallocates This avo...
const T & at(size_t i) const
FixedVector(FixedVector &&other) noexcept
FixedVector(std::initializer_list< T > init_list)
Constructor from initializer list - allocates exact size needed This enables brace initialization: Fi...
FixedVector & operator=(std::initializer_list< T > init_list)
Assignment from initializer list - avoids temporary and move overhead This enables: FixedVector<int> ...
T & front()
Access first element (no bounds checking - matches std::vector behavior) Caller must ensure vector is...
const T & operator[](size_t i) const
T & operator[](size_t i)
Access element without bounds checking (matches std::vector behavior) Caller must ensure index is val...
T & back()
Access last element (no bounds checking - matches std::vector behavior) Caller must ensure vector is ...
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 ...
void pop_back()
Remove the last element in place (no reallocation, keeps capacity) Caller must ensure vector is not e...
T & emplace_back(Args &&...args)
Emplace element without bounds checking - constructs in-place with arguments Caller must ensure suffi...
FixedVector & operator=(FixedVector &&other) noexcept
T & at(size_t i)
Access element with bounds checking (matches std::vector behavior) Note: No exception thrown on out o...
void push_back(const T &value)
Add element without bounds checking Caller must ensure sufficient capacity was allocated via init() S...
Helper class to request loop() to be called as fast as possible.
static bool is_high_frequency()
Check whether the loop is running continuously.
void stop()
Stop running the loop continuously.
static uint8_t num_requests
void start()
Start running the loop continuously.
Helper class to disable interrupts.
LazyCallbackManager & operator=(const LazyCallbackManager &)=delete
LazyCallbackManager(const LazyCallbackManager &)=delete
size_t size() const
Return the number of registered callbacks.
LazyCallbackManager()=default
void add_(Callback< void(Ts...)> cb)
Non-template core to avoid code duplication per lambda type.
void add(F &&callback)
Add any callable. Allocates the underlying CallbackManager on first use.
void operator()(Ts... args)
Call all callbacks in this manager.
LazyCallbackManager & operator=(LazyCallbackManager &&)=delete
~LazyCallbackManager()
Destructor - clean up allocated CallbackManager if any.
void call(Ts... args)
Call all callbacks in this manager. No-op if no callbacks registered.
bool empty() const
Check if any callbacks are registered.
LazyCallbackManager(LazyCallbackManager &&)=delete
Helper class that wraps a mutex with a RAII-style API.
Helper class to lock the lwIP TCPIP core when making lwIP API calls from non-TCPIP threads.
LwIPLock(const LwIPLock &)=delete
LwIPLock & operator=(const LwIPLock &)=delete
Mutex implementation, with API based on the unavailable std::mutex.
Mutex(const Mutex &)=delete
Mutex & operator=(const Mutex &)=delete
Helper class to easily give an object a parent of type T.
T * get_parent() const
Get the parent of this object.
void set_parent(T *parent)
Set the parent of this object.
An STL allocator that uses SPI or internal RAM.
constexpr RAMAllocator(uint8_t flags)
T * reallocate(T *p, size_t n, size_t manual_size)
size_t get_free_heap_size() const
Return the total heap space available via this allocator.
T * reallocate(T *p, size_t n)
void deallocate(T *p, size_t n)
RAMUniquePtr< T > make_unique(Args &&...args)
Value initialize one T; empty on exhaustion.
size_t get_max_free_block_size() const
Return the maximum size block this allocator could allocate.
constexpr RAMAllocator(const RAMAllocator< U > &other)
RAMUniquePtr< T[]> make_unique_array_for_overwrite(size_t n)
n elements left uninitialized, as std::make_unique_for_overwrite does; empty on exhaustion,...
T * allocate(size_t n, size_t manual_size)
constexpr RAMAllocator()=default
Helper class for efficient buffer allocation - uses stack for small sizes, heap for large This is use...
SmallBufferWithHeapFallback(const SmallBufferWithHeapFallback &)=delete
SmallBufferWithHeapFallback & operator=(SmallBufferWithHeapFallback &&)=delete
~SmallBufferWithHeapFallback()
SmallBufferWithHeapFallback & operator=(const SmallBufferWithHeapFallback &)=delete
SmallBufferWithHeapFallback(size_t size)
SmallBufferWithHeapFallback(SmallBufferWithHeapFallback &&)=delete
Small buffer optimization - stores data inline when small, heap-allocates for large data This avoids ...
SmallInlineBuffer()=default
SmallInlineBuffer(const SmallInlineBuffer &)=delete
uint8_t * init(size_t size)
Resize to size bytes of (uninitialized) storage and return a writable pointer to fill.
void set(const uint8_t *src, size_t size)
Set buffer contents, allocating heap if needed.
SmallInlineBuffer & operator=(const SmallInlineBuffer &)=delete
uint8_t inline_[InlineSize]
SmallInlineBuffer & operator=(SmallInlineBuffer &&other) noexcept
const uint8_t * data() const
SmallInlineBuffer(SmallInlineBuffer &&other) noexcept
void add(F &&callback)
Add any callable.
void call(Ts... args)
Call all callbacks in this manager.
void add_(Callback< void(Ts...)> cb)
Non-template core to avoid code duplication per lambda type.
StaticVector< Callback< void(Ts...)>, N > callbacks_
void operator()(Ts... args)
Call all callbacks in this manager.
CallbackManager backed by StaticVector for compile-time-known callback counts.
const T & operator*() const
ConstIterator(const StaticRingBuffer *buf, index_type pos)
ConstIterator & operator++()
bool operator!=(const ConstIterator &other) const
bool operator!=(const Iterator &other) const
Iterator(StaticRingBuffer *buf, index_type pos)
Fixed-size circular buffer with FIFO semantics and iteration support.
bool push(const T &value)
ConstIterator begin() const
ConstIterator end() const
void clear()
Clear all elements (reset to empty)
Minimal static vector - saves memory by avoiding std::vector overhead.
const_reverse_iterator rend() const
reverse_iterator rbegin()
const T & operator[](size_t i) const
void push_back(const T &value)
static constexpr size_t capacity()
void assign(InputIt first, InputIt last)
const_reverse_iterator rbegin() const
std::reverse_iterator< const_iterator > const_reverse_iterator
typename std::array< T, N >::iterator iterator
typename std::array< T, N >::const_iterator const_iterator
std::reverse_iterator< iterator > reverse_iterator
const_iterator end() const
StaticVector(InputIt first, InputIt last)
StaticVector(const StaticVector< T, M > &other)
StaticVector(std::initializer_list< T > init)
const_iterator begin() const
struct @66::@67 __attribute__
Wake the main loop task from an ISR. ISR-safe.
Functions to constrain the range of arithmetic values.
size_t buf_append_str_p(char *buf, size_t size, size_t pos, PGM_P str)
Safely append a PROGMEM string to buffer, returning new position (capped at size).
T clamp_at_most(T value, U max)
bool random_bytes(uint8_t *data, size_t len)
Generate len random bytes using the platform's secure RNG (hardware RNG or OS CSPRNG).
size_t buf_append_str(char *buf, size_t size, size_t pos, const char *str)
Safely append a string to buffer, returning new position (capped at size).
constexpr uint32_t fnv1a_hash_extend(uint32_t hash, const char *str)
Extend a FNV-1a hash with additional string data.
float random_float()
Return a random float between 0 and 1.
ESPHOME_ALWAYS_INLINE 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)
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.
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)
Format name + separator + suffix directly into buffer without heap allocation.
constexpr T convert_big_endian(T val)
Convert a value between host byte order and big endian (most significant byte first) order.
bool str_contains_ignore_case(const char *haystack, const char *needle)
Case-insensitive check if needle string is contained in haystack (no heap allocation).
std::unique_ptr< T, RAMDeleter< T > > RAMUniquePtr
unique_ptr over RAMAllocator storage
constexpr char to_sanitized_char(char c)
Sanitize a single char: keep alphanumerics, dashes, underscores; replace others with underscore.
bool mac_address_is_valid(const uint8_t *mac)
Check if the MAC address is not all zeros or all ones.
ESPHOME_ALWAYS_INLINE char format_hex_pretty_char(uint8_t v)
Convert a nibble (0-15) to uppercase hex char (used for pretty printing)
void format_mac_addr_lower_no_sep(const uint8_t *mac, char *output)
Format MAC address as xxxxxxxxxxxxxx (lowercase, no separators)
constexpr uint32_t FNV1_OFFSET_BASIS
FNV-1 32-bit offset basis.
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).
std::string format_hex(const uint8_t *data, size_t length)
Format the byte array data of length len in lowercased hex.
uint16_t uint16_t size_t elem_size
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)
size_t buf_append_printf_p(char *buf, size_t size, size_t pos, PGM_P fmt,...)
Safely append formatted string to buffer, returning new position (capped at size).
ParseOnOffState parse_on_off(const char *str, const char *on, const char *off)
Parse a string that contains either on, off or toggle.
std::string format_bin(const uint8_t *data, size_t length)
Format the byte array data of length len in binary.
constexpr T convert_little_endian(T val)
Convert a value between host byte order and little endian (least significant byte first) order.
constexpr uint32_t fnv1_hash_extend(uint32_t hash, T value)
Extend a FNV-1 hash with an integer (hashes each byte).
bool base64_decode_int32_vector(const std::string &base64, std::vector< int32_t > &out)
Decode base64/base64url string directly into vector of little-endian int32 values.
constexpr size_t format_hex_prefixed_size(size_t byte_count)
Calculate buffer size needed for format_hex_prefixed_to: "0xXXXXXXXX...\0" = bytes * 2 + 3.
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.
uint32_t small_pow10(int8_t n)
Return 10^n for small non-negative n (0-3) as uint32_t, avoiding float.
std::vector< uint8_t > base64_decode(const std::string &encoded_string)
Decode a base64 string to a byte vector.
char * format_hex_prefixed_to(char(&buffer)[N], T val)
Format an unsigned integer as "0x" prefixed lowercase hex to buffer.
bool has_custom_mac_address()
Check if a custom MAC address is set (ESP32 & variants)
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.
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).
size_t uint32_to_str(std::span< char, UINT32_MAX_STR_SIZE > buf, uint32_t val)
Write unsigned 32-bit integer to buffer with compile-time size check.
bool str_contains_ignore_case_fallback(const char *haystack, const char *needle)
Fallback implementation for case insensitive substring comparison.
int8_t ilog10(float value)
Compute floor(log10(fabs(value))) using iterative comparison.
uint32_t fnv1_hash_object_id(const char *str, size_t len)
Calculate FNV-1 hash of a string while applying snake_case + sanitize transformations.
uint32_t fnv1_hash(const char *str)
Calculate a FNV-1 hash of str.
T clamp_at_least(T value, U min)
optional< T > parse_number(const char *str)
Parse an unsigned decimal number from a null-terminated string.
char * frac_to_str_unchecked(char *buf, uint32_t frac, uint32_t divisor)
Write fractional digits with leading zeros to buffer (internal, no size check).
void set_mac_address(uint8_t *mac)
Set the MAC address to use from the provided byte array (6 bytes).
int8_t step_to_accuracy_decimals(float step)
Derive accuracy in decimals from an increment step.
uint32_t random_uint32()
Return a random 32-bit unsigned integer.
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.
char * buf_append_sep_str(char *buf, size_t remaining, char separator, const char *str, size_t str_len)
Append a separator char and a string to a buffer, respecting remaining space.
void delay_microseconds_safe(uint32_t us)
Delay for the given amount of microseconds, possibly yielding to other processes during the wait.
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.
constexpr size_t format_hex_size(size_t byte_count)
Calculate buffer size needed for format_hex_to: "XXXXXXXX...\0" = bytes * 2 + 1.
bool str_equals_case_insensitive(const std::string &a, const std::string &b)
Compare strings for equality in case-insensitive manner.
bool str_endswith_ignore_case(const char *str, size_t str_len, const char *suffix, size_t suffix_len)
Case-insensitive check if string ends with suffix (no heap allocation).
char * str_sanitize_to(char *buffer, size_t buffer_size, const char *str)
Sanitize a string to buffer, keeping only alphanumerics, dashes, and underscores.
void init_array_from(std::array< T, N > &dest, std::initializer_list< T > src)
Initialize a std::array from an initializer_list.
char * int8_to_str(char *buf, int8_t val)
Write int8 value to buffer without modulo operations.
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)
const char * json_escape_into_buffer(std::span< char > buf, StringRef value, bool short_control_escapes)
Copy value into buf, escaping the characters that cannot appear raw inside a JSON string literal.
char * uint32_to_str_unchecked(char *buf, uint32_t val)
Write unsigned 32-bit integer to buffer (internal, no size check).
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".
constexpr uint32_t FNV1_PRIME
FNV-1 32-bit prime.
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...
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).
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.
uint16_t crc16be(const uint8_t *data, uint16_t len, uint16_t crc, uint16_t poly, bool refin, bool refout)
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.
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.
constexpr float celsius_to_fahrenheit(float value)
Convert degrees Celsius to degrees Fahrenheit.
size_t size_t const char va_start(args, fmt)
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
void get_mac_address_raw(uint8_t *mac)
Get the device MAC address as raw bytes, written into the provided byte array (6 bytes).
size_t size_t const char * fmt
constexpr uint8_t parse_hex_char(char c)
bool str_startswith(const std::string &str, const std::string &start)
Check whether a string starts with a value.
constexpr std::array< uint8_t, sizeof(T)> decode_value(T val)
Decode a value into its constituent bytes (from most to least significant).
constexpr size_t format_bin_size(size_t byte_count)
Calculate buffer size needed for format_bin_to: "01234567...\0" = bytes * 8 + 1.
To bit_cast(const From &src)
Convert data between types, without aliasing issues or undefined behaviour.
constexpr char to_snake_case_char(char c)
Convert a single char to snake_case: lowercase and space to underscore.
constexpr float fahrenheit_to_celsius(float value)
Convert degrees Fahrenheit to degrees Celsius.
uint8_t reverse_bits(uint8_t x)
Reverse the order of 8 bits.
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).
float lerp(float completion, float start, float end)=delete
constexpr size_t format_hex_pretty_uint16_size(size_t count)
Calculate buffer size needed for format_hex_pretty_to with uint16_t data: "XXXX:XXXX:....
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).
bool get_custom_mac_address(uint8_t *mac)
Read the custom MAC address from eFuse into the provided byte array (6 bytes).
void * callback_manager_grow(void *data, uint16_t size, uint16_t &capacity, size_t elem_size)
Grow a CallbackManager's backing array to exactly size+1. Defined in helpers.cpp.
bool str_endswith(const std::string &str, const std::string &end)
Check whether a string ends with a value.
constexpr uint32_t fnv1a_hash(const char *str)
Calculate a FNV-1a hash of str.
bool str_contains_ignore_case_p(const char *haystack, PGM_P needle)
ESP8266 internal implementation reading the needle from flash — prefer the str_contains_ignore_case m...
uint16_t uint16_t & capacity
ParseOnOffState
Return values for parse_on_off().
float pow10_int(int8_t exp)
Compute 10^exp using iterative multiplication/division.
char * format_bin_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length)
Format byte array as binary string to buffer.
char * format_mac_addr_upper(const uint8_t *mac, char *output)
Format MAC address as XX:XX:XX:XX:XX:XX (uppercase, colon separators)
static Callback create(F &&callable)
Create from any callable.
void call(Ts... args) const
Invoke the callback. Only valid on Callbacks created via create(), never on default-constructed insta...
Lightweight type-erased callback (8 bytes on 32-bit) that avoids std::function overhead.
void operator()(T *p) const
Destroys and frees RAMAllocator storage. Not convertible: free() needs the address malloc returned.
void operator()(T *p) const