ESPHome 2025.12.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#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
62 std::string reset_reason;
63 unsigned reason = esp_reset_reason();
64 if (reason < sizeof(RESET_REASONS) / sizeof(RESET_REASONS[0])) {
65 reset_reason = RESET_REASONS[reason];
66 if (reason == ESP_RST_SW) {
67 auto pref = global_preferences->make_preference(REBOOT_MAX_LEN, fnv1_hash(REBOOT_KEY + App.get_name()));
68 char buffer[REBOOT_MAX_LEN]{};
69 if (pref.load(&buffer)) {
70 buffer[REBOOT_MAX_LEN - 1] = '\0';
71 reset_reason = "Reboot request from " + std::string(buffer);
72 }
73 }
74 } else {
75 reset_reason = "unknown source";
76 }
77 ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
78 return reset_reason;
79}
80
81static const char *const WAKEUP_CAUSES[] = {
82 "undefined",
83 "undefined",
84 "external signal using RTC_IO",
85 "external signal using RTC_CNTL",
86 "timer",
87 "touchpad",
88 "ULP program",
89 "GPIO",
90 "UART",
91 "WIFI",
92 "COCPU int",
93 "COCPU crash",
94 "BT",
95};
96
98 const char *wake_reason;
99 unsigned reason = esp_sleep_get_wakeup_cause();
100 if (reason < sizeof(WAKEUP_CAUSES) / sizeof(WAKEUP_CAUSES[0])) {
101 wake_reason = WAKEUP_CAUSES[reason];
102 } else {
103 wake_reason = "unknown source";
104 }
105 ESP_LOGD(TAG, "Wakeup Reason: %s", wake_reason);
106 return wake_reason;
107}
108
110 ESP_LOGCONFIG(TAG,
111 "Partition table:\n"
112 " %-12s %-4s %-8s %-10s %-10s",
113 "Name", "Type", "Subtype", "Address", "Size");
114 esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
115 while (it != NULL) {
116 const esp_partition_t *partition = esp_partition_get(it);
117 ESP_LOGCONFIG(TAG, " %-12s %-4d %-8d 0x%08" PRIX32 " 0x%08" PRIX32, partition->label, partition->type,
118 partition->subtype, partition->address, partition->size);
119 it = esp_partition_next(it);
120 }
121 esp_partition_iterator_release(it);
122}
123
124uint32_t DebugComponent::get_free_heap_() { return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); }
125
126struct ChipFeature {
127 int bit;
128 const char *name;
129};
130
131static constexpr ChipFeature CHIP_FEATURES[] = {
132 {CHIP_FEATURE_BLE, "BLE"},
133 {CHIP_FEATURE_BT, "BT"},
134 {CHIP_FEATURE_EMB_FLASH, "EMB Flash"},
135 {CHIP_FEATURE_EMB_PSRAM, "EMB PSRAM"},
136 {CHIP_FEATURE_WIFI_BGN, "2.4GHz WiFi"},
137};
138
139void DebugComponent::get_device_info_(std::string &device_info) {
140#if defined(USE_ARDUINO)
141 const char *flash_mode;
142 switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance)
143 case FM_QIO:
144 flash_mode = "QIO";
145 break;
146 case FM_QOUT:
147 flash_mode = "QOUT";
148 break;
149 case FM_DIO:
150 flash_mode = "DIO";
151 break;
152 case FM_DOUT:
153 flash_mode = "DOUT";
154 break;
155 case FM_FAST_READ:
156 flash_mode = "FAST_READ";
157 break;
158 case FM_SLOW_READ:
159 flash_mode = "SLOW_READ";
160 break;
161 default:
162 flash_mode = "UNKNOWN";
163 }
164 ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s",
165 ESP.getFlashChipSize() / 1024, // NOLINT
166 ESP.getFlashChipSpeed() / 1000000, flash_mode); // NOLINT
167 device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) + // NOLINT
168 "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:"; // NOLINT
169 device_info += flash_mode;
170#endif
171
172 esp_chip_info_t info;
173 esp_chip_info(&info);
174 const char *model = ESPHOME_VARIANT;
175 std::string features;
176
177 // Check each known feature bit
178 for (const auto &feature : CHIP_FEATURES) {
179 if (info.features & feature.bit) {
180 features += feature.name;
181 features += ", ";
182 info.features &= ~feature.bit;
183 }
184 }
185 if (info.features != 0)
186 features += "Other:" + format_hex(info.features);
187 ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores,
188 info.revision);
189 device_info += "|Chip: ";
190 device_info += model;
191 device_info += " Features:";
192 device_info += features;
193 device_info += " Cores:" + to_string(info.cores);
194 device_info += " Revision:" + to_string(info.revision);
195 device_info += str_sprintf("|CPU Frequency: %" PRIu32 " MHz", arch_get_cpu_freq_hz() / 1000000);
196 ESP_LOGD(TAG, "CPU Frequency: %" PRIu32 " MHz", arch_get_cpu_freq_hz() / 1000000);
197
198 // Framework detection
199 device_info += "|Framework: ";
200#ifdef USE_ARDUINO
201 ESP_LOGD(TAG, "Framework: Arduino");
202 device_info += "Arduino";
203#elif defined(USE_ESP_IDF)
204 ESP_LOGD(TAG, "Framework: ESP-IDF");
205 device_info += "ESP-IDF";
206#else
207 ESP_LOGW(TAG, "Framework: UNKNOWN");
208 device_info += "UNKNOWN";
209#endif
210
211 ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version());
212 device_info += "|ESP-IDF: ";
213 device_info += esp_get_idf_version();
214
215 std::string mac = get_mac_address_pretty();
216 ESP_LOGD(TAG, "EFuse MAC: %s", mac.c_str());
217 device_info += "|EFuse MAC: ";
218 device_info += mac;
219
220 device_info += "|Reset: ";
221 device_info += get_reset_reason_();
222
223 std::string wakeup_reason = this->get_wakeup_cause_();
224 device_info += "|Wakeup: ";
225 device_info += wakeup_reason;
226}
227
229#ifdef USE_SENSOR
230 if (this->block_sensor_ != nullptr) {
231 this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL));
232 }
233 if (this->psram_sensor_ != nullptr) {
234 this->psram_sensor_->publish_state(heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
235 }
236#endif
237}
238
239} // namespace debug
240} // namespace esphome
241#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:75
const Component * component
Definition component.cpp:37
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
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:288
ESPPreferences * global_preferences
uint32_t fnv1_hash(const char *str)
Calculate a FNV-1 hash of str.
Definition helpers.cpp:146
std::string get_mac_address_pretty()
Get the device MAC address as a string, in colon-separated uppercase hex notation.
Definition helpers.cpp:640
uint32_t arch_get_cpu_freq_hz()
Definition core.cpp:72
std::string str_sprintf(const char *fmt,...)
Definition helpers.cpp:222
Application App
Global storage of Application pointer - only one Application can exist.