ESPHome 2025.5.0
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 }
57 ESP_LOGD(TAG, "Storing reboot source: %s", buffer);
58 pref.save(&buffer);
60}
61
63 std::string reset_reason;
64 unsigned reason = esp_reset_reason();
65 if (reason < sizeof(RESET_REASONS) / sizeof(RESET_REASONS[0])) {
66 reset_reason = RESET_REASONS[reason];
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 buffer[REBOOT_MAX_LEN]{};
70 if (pref.load(&buffer)) {
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, "Partition table:");
111 ESP_LOGCONFIG(TAG, " %-12s %-4s %-8s %-10s %-10s", "Name", "Type", "Subtype", "Address", "Size");
112 esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
113 while (it != NULL) {
114 const esp_partition_t *partition = esp_partition_get(it);
115 ESP_LOGCONFIG(TAG, " %-12s %-4d %-8d 0x%08" PRIX32 " 0x%08" PRIX32, partition->label, partition->type,
116 partition->subtype, partition->address, partition->size);
117 it = esp_partition_next(it);
118 }
119 esp_partition_iterator_release(it);
120}
121
122uint32_t DebugComponent::get_free_heap_() { return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); }
123
124static const std::map<int, const char *> CHIP_FEATURES = {
125 {CHIP_FEATURE_BLE, "BLE"},
126 {CHIP_FEATURE_BT, "BT"},
127 {CHIP_FEATURE_EMB_FLASH, "EMB Flash"},
128 {CHIP_FEATURE_EMB_PSRAM, "EMB PSRAM"},
129 {CHIP_FEATURE_WIFI_BGN, "2.4GHz WiFi"},
130};
131
132void DebugComponent::get_device_info_(std::string &device_info) {
133#if defined(USE_ARDUINO)
134 const char *flash_mode;
135 switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance)
136 case FM_QIO:
137 flash_mode = "QIO";
138 break;
139 case FM_QOUT:
140 flash_mode = "QOUT";
141 break;
142 case FM_DIO:
143 flash_mode = "DIO";
144 break;
145 case FM_DOUT:
146 flash_mode = "DOUT";
147 break;
148 case FM_FAST_READ:
149 flash_mode = "FAST_READ";
150 break;
151 case FM_SLOW_READ:
152 flash_mode = "SLOW_READ";
153 break;
154 default:
155 flash_mode = "UNKNOWN";
156 }
157 ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s",
158 ESP.getFlashChipSize() / 1024, // NOLINT
159 ESP.getFlashChipSpeed() / 1000000, flash_mode); // NOLINT
160 device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) + // NOLINT
161 "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:"; // NOLINT
162 device_info += flash_mode;
163#endif
164
165 esp_chip_info_t info;
166 esp_chip_info(&info);
167 const char *model = ESPHOME_VARIANT;
168 std::string features;
169 for (auto feature : CHIP_FEATURES) {
170 if (info.features & feature.first) {
171 features += feature.second;
172 features += ", ";
173 info.features &= ~feature.first;
174 }
175 }
176 if (info.features != 0)
177 features += "Other:" + format_hex(info.features);
178 ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores,
179 info.revision);
180 device_info += "|Chip: ";
181 device_info += model;
182 device_info += " Features:";
183 device_info += features;
184 device_info += " Cores:" + to_string(info.cores);
185 device_info += " Revision:" + to_string(info.revision);
186 device_info += str_sprintf("|CPU Frequency: %" PRIu32 " MHz", arch_get_cpu_freq_hz() / 1000000);
187 ESP_LOGD(TAG, "CPU Frequency: %" PRIu32 " MHz", arch_get_cpu_freq_hz() / 1000000);
188
189 // Framework detection
190 device_info += "|Framework: ";
191#ifdef USE_ARDUINO
192 ESP_LOGD(TAG, "Framework: Arduino");
193 device_info += "Arduino";
194#elif defined(USE_ESP_IDF)
195 ESP_LOGD(TAG, "Framework: ESP-IDF");
196 device_info += "ESP-IDF";
197#else
198 ESP_LOGW(TAG, "Framework: UNKNOWN");
199 device_info += "UNKNOWN";
200#endif
201
202 ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version());
203 device_info += "|ESP-IDF: ";
204 device_info += esp_get_idf_version();
205
206 std::string mac = get_mac_address_pretty();
207 ESP_LOGD(TAG, "EFuse MAC: %s", mac.c_str());
208 device_info += "|EFuse MAC: ";
209 device_info += mac;
210
211 device_info += "|Reset: ";
212 device_info += get_reset_reason_();
213
214 std::string wakeup_reason = this->get_wakeup_cause_();
215 device_info += "|Wakeup: ";
216 device_info += wakeup_reason;
217}
218
220#ifdef USE_SENSOR
221 if (this->block_sensor_ != nullptr) {
222 this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL));
223 }
224 if (this->psram_sensor_ != nullptr) {
225 this->psram_sensor_->publish_state(heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
226 }
227#endif
228}
229
230} // namespace debug
231} // namespace esphome
232#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:39
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:186
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:360
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:732
uint32_t arch_get_cpu_freq_hz()
Definition core.cpp:63
std::string to_string(int value)
Definition helpers.cpp:82
std::string str_sprintf(const char *fmt,...)
Definition helpers.cpp:323
Application App
Global storage of Application pointer - only one Application can exist.