ESPHome  2022.6.3
debug_component.cpp
Go to the documentation of this file.
1 #include "debug_component.h"
2 
3 #include <algorithm>
4 #include "esphome/core/log.h"
5 #include "esphome/core/hal.h"
6 #include "esphome/core/helpers.h"
7 #include "esphome/core/version.h"
8 
9 #ifdef USE_ESP32
10 
11 #include <esp_heap_caps.h>
12 #include <esp_system.h>
13 
14 #if ESP_IDF_VERSION_MAJOR >= 4
15 #include <esp32/rom/rtc.h>
16 #else
17 #include <rom/rtc.h>
18 #endif
19 
20 #endif // USE_ESP32
21 
22 #ifdef USE_ARDUINO
23 #include <Esp.h>
24 #endif
25 
26 namespace esphome {
27 namespace debug {
28 
29 static const char *const TAG = "debug";
30 
31 static uint32_t get_free_heap() {
32 #if defined(USE_ESP8266)
33  return ESP.getFreeHeap(); // NOLINT(readability-static-accessed-through-instance)
34 #elif defined(USE_ESP32)
35  return heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
36 #endif
37 }
38 
40  std::string device_info;
41  device_info.reserve(256);
42 
43 #ifndef ESPHOME_LOG_HAS_DEBUG
44  ESP_LOGE(TAG, "Debug Component requires debug log level!");
45  this->status_set_error();
46  return;
47 #endif
48 
49  ESP_LOGCONFIG(TAG, "Debug component:");
50 #ifdef USE_TEXT_SENSOR
51  LOG_TEXT_SENSOR(" ", "Device info", this->device_info_);
52 #endif // USE_TEXT_SENSOR
53 #ifdef USE_SENSOR
54  LOG_SENSOR(" ", "Free space on heap", this->free_sensor_);
55  LOG_SENSOR(" ", "Largest free heap block", this->block_sensor_);
56 #if defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
57  LOG_SENSOR(" ", "Heap fragmentation", this->fragmentation_sensor_);
58 #endif // defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
59 #endif // USE_SENSOR
60 
61  ESP_LOGD(TAG, "ESPHome version %s", ESPHOME_VERSION);
62  device_info += ESPHOME_VERSION;
63 
64  this->free_heap_ = get_free_heap();
65  ESP_LOGD(TAG, "Free Heap Size: %u bytes", this->free_heap_);
66 
67 #ifdef USE_ARDUINO
68  const char *flash_mode;
69  switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance)
70  case FM_QIO:
71  flash_mode = "QIO";
72  break;
73  case FM_QOUT:
74  flash_mode = "QOUT";
75  break;
76  case FM_DIO:
77  flash_mode = "DIO";
78  break;
79  case FM_DOUT:
80  flash_mode = "DOUT";
81  break;
82 #ifdef USE_ESP32
83  case FM_FAST_READ:
84  flash_mode = "FAST_READ";
85  break;
86  case FM_SLOW_READ:
87  flash_mode = "SLOW_READ";
88  break;
89 #endif
90  default:
91  flash_mode = "UNKNOWN";
92  }
93  ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s",
94  ESP.getFlashChipSize() / 1024, // NOLINT
95  ESP.getFlashChipSpeed() / 1000000, flash_mode); // NOLINT
96  device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) + // NOLINT
97  "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:"; // NOLINT
98  device_info += flash_mode;
99 #endif // USE_ARDUINO
100 
101 #ifdef USE_ESP32
102  esp_chip_info_t info;
103  esp_chip_info(&info);
104  const char *model;
105  switch (info.model) {
106  case CHIP_ESP32:
107  model = "ESP32";
108  break;
109  default:
110  model = "UNKNOWN";
111  }
112  std::string features;
113  if (info.features & CHIP_FEATURE_EMB_FLASH) {
114  features += "EMB_FLASH,";
115  info.features &= ~CHIP_FEATURE_EMB_FLASH;
116  }
117  if (info.features & CHIP_FEATURE_WIFI_BGN) {
118  features += "WIFI_BGN,";
119  info.features &= ~CHIP_FEATURE_WIFI_BGN;
120  }
121  if (info.features & CHIP_FEATURE_BLE) {
122  features += "BLE,";
123  info.features &= ~CHIP_FEATURE_BLE;
124  }
125  if (info.features & CHIP_FEATURE_BT) {
126  features += "BT,";
127  info.features &= ~CHIP_FEATURE_BT;
128  }
129  if (info.features)
130  features += "Other:" + format_hex(info.features);
131  ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores,
132  info.revision);
133  device_info += "|Chip: ";
134  device_info += model;
135  device_info += " Features:";
136  device_info += features;
137  device_info += " Cores:" + to_string(info.cores);
138  device_info += " Revision:" + to_string(info.revision);
139 
140  ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version());
141  device_info += "|ESP-IDF: ";
142  device_info += esp_get_idf_version();
143 
144  std::string mac = get_mac_address_pretty();
145  ESP_LOGD(TAG, "EFuse MAC: %s", mac.c_str());
146  device_info += "|EFuse MAC: ";
147  device_info += mac;
148 
149  const char *reset_reason;
150  switch (rtc_get_reset_reason(0)) {
151  case POWERON_RESET:
152  reset_reason = "Power On Reset";
153  break;
154  case SW_RESET:
155  reset_reason = "Software Reset Digital Core";
156  break;
157  case OWDT_RESET:
158  reset_reason = "Watch Dog Reset Digital Core";
159  break;
160  case DEEPSLEEP_RESET:
161  reset_reason = "Deep Sleep Reset Digital Core";
162  break;
163  case SDIO_RESET:
164  reset_reason = "SLC Module Reset Digital Core";
165  break;
166  case TG0WDT_SYS_RESET:
167  reset_reason = "Timer Group 0 Watch Dog Reset Digital Core";
168  break;
169  case TG1WDT_SYS_RESET:
170  reset_reason = "Timer Group 1 Watch Dog Reset Digital Core";
171  break;
172  case RTCWDT_SYS_RESET:
173  reset_reason = "RTC Watch Dog Reset Digital Core";
174  break;
175  case INTRUSION_RESET:
176  reset_reason = "Intrusion Reset CPU";
177  break;
178  case TGWDT_CPU_RESET:
179  reset_reason = "Timer Group Reset CPU";
180  break;
181  case SW_CPU_RESET:
182  reset_reason = "Software Reset CPU";
183  break;
184  case RTCWDT_CPU_RESET:
185  reset_reason = "RTC Watch Dog Reset CPU";
186  break;
187  case EXT_CPU_RESET:
188  reset_reason = "External CPU Reset";
189  break;
190  case RTCWDT_BROWN_OUT_RESET:
191  reset_reason = "Voltage Unstable Reset";
192  break;
193  case RTCWDT_RTC_RESET:
194  reset_reason = "RTC Watch Dog Reset Digital Core And RTC Module";
195  break;
196  default:
197  reset_reason = "Unknown Reset Reason";
198  }
199  ESP_LOGD(TAG, "Reset Reason: %s", reset_reason);
200  device_info += "|Reset: ";
201  device_info += reset_reason;
202 
203  const char *wakeup_reason;
204  switch (rtc_get_wakeup_cause()) {
205  case NO_SLEEP:
206  wakeup_reason = "No Sleep";
207  break;
208  case EXT_EVENT0_TRIG:
209  wakeup_reason = "External Event 0";
210  break;
211  case EXT_EVENT1_TRIG:
212  wakeup_reason = "External Event 1";
213  break;
214  case GPIO_TRIG:
215  wakeup_reason = "GPIO";
216  break;
217  case TIMER_EXPIRE:
218  wakeup_reason = "Wakeup Timer";
219  break;
220  case SDIO_TRIG:
221  wakeup_reason = "SDIO";
222  break;
223  case MAC_TRIG:
224  wakeup_reason = "MAC";
225  break;
226  case UART0_TRIG:
227  wakeup_reason = "UART0";
228  break;
229  case UART1_TRIG:
230  wakeup_reason = "UART1";
231  break;
232  case TOUCH_TRIG:
233  wakeup_reason = "Touch";
234  break;
235  case SAR_TRIG:
236  wakeup_reason = "SAR";
237  break;
238  case BT_TRIG:
239  wakeup_reason = "BT";
240  break;
241  default:
242  wakeup_reason = "Unknown";
243  }
244  ESP_LOGD(TAG, "Wakeup Reason: %s", wakeup_reason);
245  device_info += "|Wakeup: ";
246  device_info += wakeup_reason;
247 #endif
248 
249 #if defined(USE_ESP8266) && !defined(CLANG_TIDY)
250  ESP_LOGD(TAG, "Chip ID: 0x%08X", ESP.getChipId());
251  ESP_LOGD(TAG, "SDK Version: %s", ESP.getSdkVersion());
252  ESP_LOGD(TAG, "Core Version: %s", ESP.getCoreVersion().c_str());
253  ESP_LOGD(TAG, "Boot Version=%u Mode=%u", ESP.getBootVersion(), ESP.getBootMode());
254  ESP_LOGD(TAG, "CPU Frequency: %u", ESP.getCpuFreqMHz());
255  ESP_LOGD(TAG, "Flash Chip ID=0x%08X", ESP.getFlashChipId());
256  ESP_LOGD(TAG, "Reset Reason: %s", ESP.getResetReason().c_str());
257  ESP_LOGD(TAG, "Reset Info: %s", ESP.getResetInfo().c_str());
258 
259  device_info += "|Chip: 0x" + format_hex(ESP.getChipId());
260  device_info += "|SDK: ";
261  device_info += ESP.getSdkVersion();
262  device_info += "|Core: ";
263  device_info += ESP.getCoreVersion().c_str();
264  device_info += "|Boot: ";
265  device_info += to_string(ESP.getBootVersion());
266  device_info += "|Mode: " + to_string(ESP.getBootMode());
267  device_info += "|CPU: " + to_string(ESP.getCpuFreqMHz());
268  device_info += "|Flash: 0x" + format_hex(ESP.getFlashChipId());
269  device_info += "|Reset: ";
270  device_info += ESP.getResetReason().c_str();
271  device_info += "|";
272  device_info += ESP.getResetInfo().c_str();
273 #endif
274 
275 #ifdef USE_TEXT_SENSOR
276  if (this->device_info_ != nullptr) {
277  if (device_info.length() > 255)
278  device_info.resize(255);
279  this->device_info_->publish_state(device_info);
280  }
281 #endif // USE_TEXT_SENSOR
282 }
283 
285  // log when free heap space has halved
286  uint32_t new_free_heap = get_free_heap();
287  if (new_free_heap < this->free_heap_ / 2) {
288  this->free_heap_ = new_free_heap;
289  ESP_LOGD(TAG, "Free Heap Size: %u bytes", this->free_heap_);
290  this->status_momentary_warning("heap", 1000);
291  }
292 
293 #ifdef USE_SENSOR
294  // calculate loop time - from last call to this one
295  if (this->loop_time_sensor_ != nullptr) {
296  uint32_t now = millis();
297  uint32_t loop_time = now - this->last_loop_timetag_;
298  this->max_loop_time_ = std::max(this->max_loop_time_, loop_time);
299  this->last_loop_timetag_ = now;
300  }
301 #endif // USE_SENSOR
302 }
303 
305 #ifdef USE_SENSOR
306  if (this->free_sensor_ != nullptr) {
307  this->free_sensor_->publish_state(get_free_heap());
308  }
309 
310  if (this->block_sensor_ != nullptr) {
311 #if defined(USE_ESP8266)
312  // NOLINTNEXTLINE(readability-static-accessed-through-instance)
313  this->block_sensor_->publish_state(ESP.getMaxFreeBlockSize());
314 #elif defined(USE_ESP32)
315  this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL));
316 #endif
317  }
318 
319 #if defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
320  if (this->fragmentation_sensor_ != nullptr) {
321  // NOLINTNEXTLINE(readability-static-accessed-through-instance)
322  this->fragmentation_sensor_->publish_state(ESP.getHeapFragmentation());
323  }
324 #endif
325 
326  if (this->loop_time_sensor_ != nullptr) {
328  this->max_loop_time_ = 0;
329  }
330 #endif // USE_SENSOR
331 }
332 
334 
335 } // namespace debug
336 } // namespace esphome
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:187
void status_momentary_warning(const std::string &name, uint32_t length=5000)
Definition: component.cpp:150
text_sensor::TextSensor * device_info_
const float LATE
For components that should be initialized at the very end of the setup process.
Definition: component.cpp:26
void publish_state(const std::string &state)
Definition: text_sensor.cpp:12
sensor::Sensor * loop_time_sensor_
float get_setup_priority() const override
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:26
sensor::Sensor * fragmentation_sensor_
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:70
std::string to_string(int value)
Definition: helpers.cpp:36
Definition: a4988.cpp:4
std::string get_mac_address_pretty()
Get the device MAC address as a string, in colon-separated uppercase hex notation.
Definition: helpers.cpp:391