ESPHome 2026.1.3
Loading...
Searching...
No Matches
debug_esp32.cpp
Go to the documentation of this file.
1#include "debug_component.h"
2
3#ifdef USE_ESP32
5#include "esphome/core/log.h"
6#include "esphome/core/hal.h"
7#include <esp_sleep.h>
8
9#include <esp_heap_caps.h>
10#include <esp_system.h>
11#include <esp_chip_info.h>
12#include <esp_partition.h>
13
14#ifdef USE_ARDUINO
15#include <Esp.h>
16#endif
17
18namespace esphome {
19namespace debug {
20
21static const char *const TAG = "debug";
22
23// index by values returned by esp_reset_reason
24
25static const char *const RESET_REASONS[] = {
26 "unknown source",
27 "power-on event",
28 "external pin",
29 "software via esp_restart",
30 "exception/panic",
31 "interrupt watchdog",
32 "task watchdog",
33 "other watchdogs",
34 "exiting deep sleep mode",
35 "brownout",
36 "SDIO",
37 "USB peripheral",
38 "JTAG",
39 "efuse error",
40 "power glitch detected",
41 "CPU lock up",
42};
43
44static const char *const REBOOT_KEY = "reboot_source";
45static const size_t REBOOT_MAX_LEN = 24;
46
47// on shutdown, store the source of the reboot request
50 char buffer[REBOOT_MAX_LEN]{};
51 auto pref = global_preferences->make_preference(REBOOT_MAX_LEN, fnv1_hash(REBOOT_KEY + App.get_name()));
52 if (component != nullptr) {
53 strncpy(buffer, LOG_STR_ARG(component->get_component_log_str()), REBOOT_MAX_LEN - 1);
54 buffer[REBOOT_MAX_LEN - 1] = '\0';
55 }
56 ESP_LOGD(TAG, "Storing reboot source: %s", buffer);
57 pref.save(&buffer);
59}
60
61const char *DebugComponent::get_reset_reason_(std::span<char, RESET_REASON_BUFFER_SIZE> buffer) {
62 char *buf = buffer.data();
63 const size_t size = RESET_REASON_BUFFER_SIZE;
64
65 unsigned reason = esp_reset_reason();
66 if (reason < sizeof(RESET_REASONS) / sizeof(RESET_REASONS[0])) {
67 if (reason == ESP_RST_SW) {
68 auto pref = global_preferences->make_preference(REBOOT_MAX_LEN, fnv1_hash(REBOOT_KEY + App.get_name()));
69 char reboot_source[REBOOT_MAX_LEN]{};
70 if (pref.load(&reboot_source)) {
71 reboot_source[REBOOT_MAX_LEN - 1] = '\0';
72 snprintf(buf, size, "Reboot request from %s", reboot_source);
73 } else {
74 snprintf(buf, size, "%s", RESET_REASONS[reason]);
75 }
76 } else {
77 snprintf(buf, size, "%s", RESET_REASONS[reason]);
78 }
79 } else {
80 snprintf(buf, size, "unknown source");
81 }
82 ESP_LOGD(TAG, "Reset Reason: %s", buf);
83 return buf;
84}
85
86static const char *const WAKEUP_CAUSES[] = {
87 "undefined",
88 "undefined",
89 "external signal using RTC_IO",
90 "external signal using RTC_CNTL",
91 "timer",
92 "touchpad",
93 "ULP program",
94 "GPIO",
95 "UART",
96 "WIFI",
97 "COCPU int",
98 "COCPU crash",
99 "BT",
100};
101
102const char *DebugComponent::get_wakeup_cause_(std::span<char, RESET_REASON_BUFFER_SIZE> buffer) {
103 const char *wake_reason;
104 unsigned reason = esp_sleep_get_wakeup_cause();
105 if (reason < sizeof(WAKEUP_CAUSES) / sizeof(WAKEUP_CAUSES[0])) {
106 wake_reason = WAKEUP_CAUSES[reason];
107 } else {
108 wake_reason = "unknown source";
109 }
110 ESP_LOGD(TAG, "Wakeup Reason: %s", wake_reason);
111 // Return the static string directly - no need to copy to buffer
112 return wake_reason;
113}
114
116 ESP_LOGCONFIG(TAG,
117 "Partition table:\n"
118 " %-12s %-4s %-8s %-10s %-10s",
119 "Name", "Type", "Subtype", "Address", "Size");
120 esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
121 while (it != NULL) {
122 const esp_partition_t *partition = esp_partition_get(it);
123 ESP_LOGCONFIG(TAG, " %-12s %-4d %-8d 0x%08" PRIX32 " 0x%08" PRIX32, partition->label, partition->type,
124 partition->subtype, partition->address, partition->size);
125 it = esp_partition_next(it);
126 }
127 esp_partition_iterator_release(it);
128}
129
130uint32_t DebugComponent::get_free_heap_() { return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); }
131
132struct ChipFeature {
133 int bit;
134 const char *name;
135};
136
137static constexpr ChipFeature CHIP_FEATURES[] = {
138 {CHIP_FEATURE_BLE, "BLE"},
139 {CHIP_FEATURE_BT, "BT"},
140 {CHIP_FEATURE_EMB_FLASH, "EMB Flash"},
141 {CHIP_FEATURE_EMB_PSRAM, "EMB PSRAM"},
142 {CHIP_FEATURE_WIFI_BGN, "2.4GHz WiFi"},
143};
144
145size_t DebugComponent::get_device_info_(std::span<char, DEVICE_INFO_BUFFER_SIZE> buffer, size_t pos) {
146 constexpr size_t size = DEVICE_INFO_BUFFER_SIZE;
147 char *buf = buffer.data();
148
149#if defined(USE_ARDUINO)
150 const char *flash_mode;
151 switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance)
152 case FM_QIO:
153 flash_mode = "QIO";
154 break;
155 case FM_QOUT:
156 flash_mode = "QOUT";
157 break;
158 case FM_DIO:
159 flash_mode = "DIO";
160 break;
161 case FM_DOUT:
162 flash_mode = "DOUT";
163 break;
164 case FM_FAST_READ:
165 flash_mode = "FAST_READ";
166 break;
167 case FM_SLOW_READ:
168 flash_mode = "SLOW_READ";
169 break;
170 default:
171 flash_mode = "UNKNOWN";
172 }
173 uint32_t flash_size = ESP.getFlashChipSize() / 1024; // NOLINT
174 uint32_t flash_speed = ESP.getFlashChipSpeed() / 1000000; // NOLINT
175 ESP_LOGD(TAG, "Flash Chip: Size=%" PRIu32 "kB Speed=%" PRIu32 "MHz Mode=%s", flash_size, flash_speed, flash_mode);
176 pos = buf_append(buf, size, pos, "|Flash: %" PRIu32 "kB Speed:%" PRIu32 "MHz Mode:%s", flash_size, flash_speed,
177 flash_mode);
178#endif
179
180 esp_chip_info_t info;
181 esp_chip_info(&info);
182 const char *model = ESPHOME_VARIANT;
183
184 // Build features string
185 pos = buf_append(buf, size, pos, "|Chip: %s Features:", model);
186 bool first_feature = true;
187 for (const auto &feature : CHIP_FEATURES) {
188 if (info.features & feature.bit) {
189 pos = buf_append(buf, size, pos, "%s%s", first_feature ? "" : ", ", feature.name);
190 first_feature = false;
191 info.features &= ~feature.bit;
192 }
193 }
194 if (info.features != 0) {
195 pos = buf_append(buf, size, pos, "%sOther:0x%" PRIx32, first_feature ? "" : ", ", info.features);
196 }
197 ESP_LOGD(TAG, "Chip: Model=%s, Cores=%u, Revision=%u", model, info.cores, info.revision);
198 pos = buf_append(buf, size, pos, " Cores:%u Revision:%u", info.cores, info.revision);
199
200 uint32_t cpu_freq_mhz = arch_get_cpu_freq_hz() / 1000000;
201 ESP_LOGD(TAG, "CPU Frequency: %" PRIu32 " MHz", cpu_freq_mhz);
202 pos = buf_append(buf, size, pos, "|CPU Frequency: %" PRIu32 " MHz", cpu_freq_mhz);
203
204 // Framework detection
205#ifdef USE_ARDUINO
206 ESP_LOGD(TAG, "Framework: Arduino");
207 pos = buf_append(buf, size, pos, "|Framework: Arduino");
208#elif defined(USE_ESP32)
209 ESP_LOGD(TAG, "Framework: ESP-IDF");
210 pos = buf_append(buf, size, pos, "|Framework: ESP-IDF");
211#else
212 ESP_LOGW(TAG, "Framework: UNKNOWN");
213 pos = buf_append(buf, size, pos, "|Framework: UNKNOWN");
214#endif
215
216 ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version());
217 pos = buf_append(buf, size, pos, "|ESP-IDF: %s", esp_get_idf_version());
218
219 uint8_t mac[6];
221 ESP_LOGD(TAG, "EFuse MAC: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
222 pos = buf_append(buf, size, pos, "|EFuse MAC: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4],
223 mac[5]);
224
225 char reason_buffer[RESET_REASON_BUFFER_SIZE];
226 const char *reset_reason = get_reset_reason_(std::span<char, RESET_REASON_BUFFER_SIZE>(reason_buffer));
227 pos = buf_append(buf, size, pos, "|Reset: %s", reset_reason);
228
229 const char *wakeup_cause = get_wakeup_cause_(std::span<char, RESET_REASON_BUFFER_SIZE>(reason_buffer));
230 pos = buf_append(buf, size, pos, "|Wakeup: %s", wakeup_cause);
231
232 return pos;
233}
234
236#ifdef USE_SENSOR
237 if (this->block_sensor_ != nullptr) {
238 this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL));
239 }
240 if (this->psram_sensor_ != nullptr) {
241 this->psram_sensor_->publish_state(heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
242 }
243#endif
244}
245
246} // namespace debug
247} // namespace esphome
248#endif // USE_ESP32
Component * get_current_component()
const std::string & get_name() const
Get the name of this Application set by pre_setup().
virtual bool sync()=0
Commit pending writes to flash.
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
void log_partition_info_()
Logs information about the device's partition table.
size_t get_device_info_(std::span< char, DEVICE_INFO_BUFFER_SIZE > buffer, size_t pos)
const char * get_wakeup_cause_(std::span< char, RESET_REASON_BUFFER_SIZE > buffer)
const char * get_reset_reason_(std::span< char, RESET_REASON_BUFFER_SIZE > buffer)
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:76
const Component * component
Definition component.cpp:37
size_t size_t pos
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
ESPPreferences * global_preferences
uint32_t fnv1_hash(const char *str)
Calculate a FNV-1 hash of str.
Definition helpers.cpp:147
uint32_t arch_get_cpu_freq_hz()
Definition core.cpp:51
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
Application App
Global storage of Application pointer - only one Application can exist.