ESPHome  1.15.2
helpers.cpp
Go to the documentation of this file.
1 #include "esphome/core/helpers.h"
2 #include <cstdio>
3 #include <algorithm>
4 
5 #ifdef ARDUINO_ARCH_ESP8266
6 #include <ESP8266WiFi.h>
7 #else
8 #include <Esp.h>
9 #endif
10 
11 #include "esphome/core/log.h"
12 #include "esphome/core/esphal.h"
13 
14 namespace esphome {
15 
16 static const char *TAG = "helpers";
17 
18 std::string get_mac_address() {
19  char tmp[20];
20  uint8_t mac[6];
21 #ifdef ARDUINO_ARCH_ESP32
22  esp_efuse_mac_get_default(mac);
23 #endif
24 #ifdef ARDUINO_ARCH_ESP8266
25  WiFi.macAddress(mac);
26 #endif
27  sprintf(tmp, "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
28  return std::string(tmp);
29 }
30 
31 std::string get_mac_address_pretty() {
32  char tmp[20];
33  uint8_t mac[6];
34 #ifdef ARDUINO_ARCH_ESP32
35  esp_efuse_mac_get_default(mac);
36 #endif
37 #ifdef ARDUINO_ARCH_ESP8266
38  WiFi.macAddress(mac);
39 #endif
40  sprintf(tmp, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
41  return std::string(tmp);
42 }
43 
44 std::string generate_hostname(const std::string &base) { return base + std::string("-") + get_mac_address(); }
45 
46 uint32_t random_uint32() {
47 #ifdef ARDUINO_ARCH_ESP32
48  return esp_random();
49 #else
50  return os_random();
51 #endif
52 }
53 
54 double random_double() { return random_uint32() / double(UINT32_MAX); }
55 
56 float random_float() { return float(random_double()); }
57 
58 static uint32_t fast_random_seed = 0;
59 
60 void fast_random_set_seed(uint32_t seed) { fast_random_seed = seed; }
61 uint32_t fast_random_32() {
62  fast_random_seed = (fast_random_seed * 2654435769ULL) + 40503ULL;
63  return fast_random_seed;
64 }
65 uint16_t fast_random_16() {
66  uint32_t rand32 = fast_random_32();
67  return (rand32 & 0xFFFF) + (rand32 >> 16);
68 }
69 uint8_t fast_random_8() {
70  uint8_t rand32 = fast_random_32();
71  return (rand32 & 0xFF) + ((rand32 >> 8) & 0xFF);
72 }
73 
74 float gamma_correct(float value, float gamma) {
75  if (value <= 0.0f)
76  return 0.0f;
77  if (gamma <= 0.0f)
78  return value;
79 
80  return powf(value, gamma);
81 }
82 std::string to_lowercase_underscore(std::string s) {
83  std::transform(s.begin(), s.end(), s.begin(), ::tolower);
84  std::replace(s.begin(), s.end(), ' ', '_');
85  return s;
86 }
87 
88 std::string sanitize_string_allowlist(const std::string &s, const std::string &allowlist) {
89  std::string out(s);
90  out.erase(std::remove_if(out.begin(), out.end(),
91  [&allowlist](const char &c) { return allowlist.find(c) == std::string::npos; }),
92  out.end());
93  return out;
94 }
95 
96 std::string sanitize_hostname(const std::string &hostname) {
98  return truncate_string(s, 63);
99 }
100 
101 std::string truncate_string(const std::string &s, size_t length) {
102  if (s.length() > length)
103  return s.substr(0, length);
104  return s;
105 }
106 
107 std::string value_accuracy_to_string(float value, int8_t accuracy_decimals) {
108  auto multiplier = float(pow10(accuracy_decimals));
109  float value_rounded = roundf(value * multiplier) / multiplier;
110  char tmp[32]; // should be enough, but we should maybe improve this at some point.
111  dtostrf(value_rounded, 0, uint8_t(std::max(0, int(accuracy_decimals))), tmp);
112  return std::string(tmp);
113 }
114 std::string uint64_to_string(uint64_t num) {
115  char buffer[17];
116  auto *address16 = reinterpret_cast<uint16_t *>(&num);
117  snprintf(buffer, sizeof(buffer), "%04X%04X%04X%04X", address16[3], address16[2], address16[1], address16[0]);
118  return std::string(buffer);
119 }
120 std::string uint32_to_string(uint32_t num) {
121  char buffer[9];
122  auto *address16 = reinterpret_cast<uint16_t *>(&num);
123  snprintf(buffer, sizeof(buffer), "%04X%04X", address16[1], address16[0]);
124  return std::string(buffer);
125 }
126 static char *global_json_build_buffer = nullptr;
127 static size_t global_json_build_buffer_size = 0;
128 
129 void reserve_global_json_build_buffer(size_t required_size) {
130  if (global_json_build_buffer_size == 0 || global_json_build_buffer_size < required_size) {
131  delete[] global_json_build_buffer;
132  global_json_build_buffer_size = std::max(required_size, global_json_build_buffer_size * 2);
133 
134  size_t remainder = global_json_build_buffer_size % 16U;
135  if (remainder != 0)
136  global_json_build_buffer_size += 16 - remainder;
137 
138  global_json_build_buffer = new char[global_json_build_buffer_size];
139  }
140 }
141 
142 ParseOnOffState parse_on_off(const char *str, const char *on, const char *off) {
143  if (on == nullptr && strcasecmp(str, "on") == 0)
144  return PARSE_ON;
145  if (on != nullptr && strcasecmp(str, on) == 0)
146  return PARSE_ON;
147  if (off == nullptr && strcasecmp(str, "off") == 0)
148  return PARSE_OFF;
149  if (off != nullptr && strcasecmp(str, off) == 0)
150  return PARSE_OFF;
151  if (strcasecmp(str, "toggle") == 0)
152  return PARSE_TOGGLE;
153 
154  return PARSE_NONE;
155 }
156 
157 const char *HOSTNAME_CHARACTER_ALLOWLIST = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
158 
159 uint8_t crc8(uint8_t *data, uint8_t len) {
160  uint8_t crc = 0;
161 
162  while ((len--) != 0u) {
163  uint8_t inbyte = *data++;
164  for (uint8_t i = 8; i != 0u; i--) {
165  bool mix = (crc ^ inbyte) & 0x01;
166  crc >>= 1;
167  if (mix)
168  crc ^= 0x8C;
169  inbyte >>= 1;
170  }
171  }
172  return crc;
173 }
174 void delay_microseconds_accurate(uint32_t usec) {
175  if (usec == 0)
176  return;
177 
178  if (usec <= 16383UL) {
179  delayMicroseconds(usec);
180  } else {
181  delay(usec / 16383UL);
182  delayMicroseconds(usec % 16383UL);
183  }
184 }
185 
186 uint8_t reverse_bits_8(uint8_t x) {
187  x = ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
188  x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2);
189  x = ((x & 0xF0) >> 4) | ((x & 0x0F) << 4);
190  return x;
191 }
192 
193 uint16_t reverse_bits_16(uint16_t x) {
194  return uint16_t(reverse_bits_8(x & 0xFF) << 8) | uint16_t(reverse_bits_8(x >> 8));
195 }
196 std::string to_string(const std::string &val) { return val; }
197 std::string to_string(int val) {
198  char buf[64];
199  sprintf(buf, "%d", val);
200  return buf;
201 }
202 std::string to_string(long val) {
203  char buf[64];
204  sprintf(buf, "%ld", val);
205  return buf;
206 }
207 std::string to_string(long long val) {
208  char buf[64];
209  sprintf(buf, "%lld", val);
210  return buf;
211 }
212 std::string to_string(unsigned val) {
213  char buf[64];
214  sprintf(buf, "%u", val);
215  return buf;
216 }
217 std::string to_string(unsigned long val) {
218  char buf[64];
219  sprintf(buf, "%lu", val);
220  return buf;
221 }
222 std::string to_string(unsigned long long val) {
223  char buf[64];
224  sprintf(buf, "%llu", val);
225  return buf;
226 }
227 std::string to_string(float val) {
228  char buf[64];
229  sprintf(buf, "%f", val);
230  return buf;
231 }
232 std::string to_string(double val) {
233  char buf[64];
234  sprintf(buf, "%f", val);
235  return buf;
236 }
237 std::string to_string(long double val) {
238  char buf[64];
239  sprintf(buf, "%Lf", val);
240  return buf;
241 }
242 optional<float> parse_float(const std::string &str) {
243  char *end;
244  float value = ::strtof(str.c_str(), &end);
245  if (end == nullptr || end != str.end().base())
246  return {};
247  return value;
248 }
249 uint32_t fnv1_hash(const std::string &str) {
250  uint32_t hash = 2166136261UL;
251  for (char c : str) {
252  hash *= 16777619UL;
253  hash ^= c;
254  }
255  return hash;
256 }
257 bool str_equals_case_insensitive(const std::string &a, const std::string &b) {
258  return strcasecmp(a.c_str(), b.c_str()) == 0;
259 }
260 
261 template<uint32_t> uint32_t reverse_bits(uint32_t x) {
262  return uint32_t(reverse_bits_16(x & 0xFFFF) << 16) | uint32_t(reverse_bits_16(x >> 16));
263 }
264 
265 static int high_freq_num_requests = 0;
266 
268  if (this->started_)
269  return;
270  high_freq_num_requests++;
271  this->started_ = true;
272 }
274  if (!this->started_)
275  return;
276  high_freq_num_requests--;
277  this->started_ = false;
278 }
279 bool HighFrequencyLoopRequester::is_high_frequency() { return high_freq_num_requests > 0; }
280 
281 float clamp(float val, float min, float max) {
282  if (val < min)
283  return min;
284  if (val > max)
285  return max;
286  return val;
287 }
288 float lerp(float completion, float start, float end) { return start + (end - start) * completion; }
289 
290 bool str_startswith(const std::string &full, const std::string &start) { return full.rfind(start, 0) == 0; }
291 bool str_endswith(const std::string &full, const std::string &ending) {
292  return full.rfind(ending) == (full.size() - ending.size());
293 }
294 
295 uint16_t encode_uint16(uint8_t msb, uint8_t lsb) { return (uint16_t(msb) << 8) | uint16_t(lsb); }
296 std::array<uint8_t, 2> decode_uint16(uint16_t value) {
297  uint8_t msb = (value >> 8) & 0xFF;
298  uint8_t lsb = (value >> 0) & 0xFF;
299  return {msb, lsb};
300 }
301 
302 std::string hexencode(const uint8_t *data, uint32_t len) {
303  char buf[20];
304  std::string res;
305  for (size_t i = 0; i < len; i++) {
306  if (i + 1 != len) {
307  sprintf(buf, "%02X.", data[i]);
308  } else {
309  sprintf(buf, "%02X ", data[i]);
310  }
311  res += buf;
312  }
313  sprintf(buf, "(%u)", len);
314  res += buf;
315  return res;
316 }
317 
318 #ifdef ARDUINO_ARCH_ESP8266
319 ICACHE_RAM_ATTR InterruptLock::InterruptLock() { xt_state_ = xt_rsil(15); }
320 ICACHE_RAM_ATTR InterruptLock::~InterruptLock() { xt_wsr_ps(xt_state_); }
321 #endif
322 #ifdef ARDUINO_ARCH_ESP32
323 ICACHE_RAM_ATTR InterruptLock::InterruptLock() { portDISABLE_INTERRUPTS(); }
324 ICACHE_RAM_ATTR InterruptLock::~InterruptLock() { portENABLE_INTERRUPTS(); }
325 #endif
326 
327 } // namespace esphome
uint16_t fast_random_16()
Definition: helpers.cpp:65
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:107
const char * HOSTNAME_CHARACTER_ALLOWLIST
The characters that are allowed in a hostname.
Definition: helpers.cpp:157
const char * TAG
Definition: tm1637.cpp:8
uint8_t reverse_bits_8(uint8_t x)
Definition: helpers.cpp:186
uint32_t random_uint32()
Return a random 32 bit unsigned integer.
Definition: helpers.cpp:46
std::string generate_hostname(const std::string &base)
Definition: helpers.cpp:44
uint8_t crc8(uint8_t *data, uint8_t len)
Calculate a crc8 of data with the provided data length.
Definition: helpers.cpp:159
void fast_random_set_seed(uint32_t seed)
Definition: helpers.cpp:60
uint8_t fast_random_8()
Definition: helpers.cpp:69
uint32_t reverse_bits(uint32_t x)
Definition: helpers.cpp:261
std::string to_string(const std::string &val)
Definition: helpers.cpp:196
std::string sanitize_string_allowlist(const std::string &s, const std::string &allowlist)
Sanitizes the input string with the allowlist.
Definition: helpers.cpp:88
std::string truncate_string(const std::string &s, size_t length)
Truncate a string to a specific length.
Definition: helpers.cpp:101
float lerp(float completion, float start, float end)
Linearly interpolate between end start and end by completion.
Definition: helpers.cpp:288
uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit unsigned integer given a most and least-significant byte.
Definition: helpers.cpp:295
float clamp(float val, float min, float max)
Clamp the value between min and max.
Definition: helpers.cpp:281
std::string uint32_to_string(uint32_t num)
Convert a uint32_t to a hex string.
Definition: helpers.cpp:120
void delay_microseconds_accurate(uint32_t usec)
Definition: helpers.cpp:174
uint16_t reverse_bits_16(uint16_t x)
Definition: helpers.cpp:193
ParseOnOffState
Definition: helpers.h:172
float gamma_correct(float value, float gamma)
Applies gamma correction with the provided gamma to value.
Definition: helpers.cpp:74
std::string sanitize_hostname(const std::string &hostname)
Sanitize the hostname by removing characters that are not in the allowlist and truncating it to 63 ch...
Definition: helpers.cpp:96
bool str_startswith(const std::string &full, const std::string &start)
Definition: helpers.cpp:290
std::string get_mac_address()
Gets the MAC address as a string, this can be used as way to identify this ESP.
Definition: helpers.cpp:18
std::string hexencode(const uint8_t *data, uint32_t len)
Definition: helpers.cpp:302
uint32_t fast_random_32()
Definition: helpers.cpp:61
ParseOnOffState parse_on_off(const char *str, const char *on, const char *off)
Definition: helpers.cpp:142
uint32_t fnv1_hash(const std::string &str)
Definition: helpers.cpp:249
std::array< uint8_t, 2 > decode_uint16(uint16_t value)
Decode a 16-bit unsigned integer into an array of two values: most significant byte, least significant byte.
Definition: helpers.cpp:296
std::string to_lowercase_underscore(std::string s)
Convert the string to lowercase_underscore.
Definition: helpers.cpp:82
Definition: a4988.cpp:4
double random_double()
Returns a random double between 0 and 1.
Definition: helpers.cpp:54
std::string get_mac_address_pretty()
Definition: helpers.cpp:31
bool str_endswith(const std::string &full, const std::string &ending)
Definition: helpers.cpp:291
optional< float > parse_float(const std::string &str)
Definition: helpers.cpp:242
std::string uint64_to_string(uint64_t num)
Convert a uint64_t to a hex string.
Definition: helpers.cpp:114
float random_float()
Returns a random float between 0 and 1. Essentially just casts random_double() to a float...
Definition: helpers.cpp:56
void reserve_global_json_build_buffer(size_t required_size)
Definition: helpers.cpp:129
bool str_equals_case_insensitive(const std::string &a, const std::string &b)
Compare string a to string b (ignoring case) and return whether they are equal.
Definition: helpers.cpp:257