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