ESPHome 2026.5.3
Loading...
Searching...
No Matches
debug_esp8266.cpp
Go to the documentation of this file.
1#include "debug_component.h"
2#ifdef USE_ESP8266
3#include "esphome/core/log.h"
5#include <Esp.h>
6
7extern "C" {
8#include <user_interface.h>
9
10// Global reset info struct populated by SDK at boot
11extern struct rst_info resetInfo;
12
13// Core version - either a string pointer or a version number to format as hex
15extern const char *core_release;
16}
17
18namespace esphome::debug {
19
20static const char *const TAG = "debug";
21
22// PROGMEM string table for reset reasons, indexed by reason code (0-6), with "Unknown" as fallback
23// clang-format off
24PROGMEM_STRING_TABLE(ResetReasonStrings,
25 "Power On", // 0 = REASON_DEFAULT_RST
26 "Hardware Watchdog", // 1 = REASON_WDT_RST
27 "Exception", // 2 = REASON_EXCEPTION_RST
28 "Software Watchdog", // 3 = REASON_SOFT_WDT_RST
29 "Software/System restart", // 4 = REASON_SOFT_RESTART
30 "Deep-Sleep Wake", // 5 = REASON_DEEP_SLEEP_AWAKE
31 "External System", // 6 = REASON_EXT_SYS_RST
32 "Unknown" // 7 = fallback
33);
34// clang-format on
35static_assert(REASON_DEFAULT_RST == 0, "Reset reason enum values must match table indices");
36static_assert(REASON_WDT_RST == 1, "Reset reason enum values must match table indices");
37static_assert(REASON_EXCEPTION_RST == 2, "Reset reason enum values must match table indices");
38static_assert(REASON_SOFT_WDT_RST == 3, "Reset reason enum values must match table indices");
39static_assert(REASON_SOFT_RESTART == 4, "Reset reason enum values must match table indices");
40static_assert(REASON_DEEP_SLEEP_AWAKE == 5, "Reset reason enum values must match table indices");
41static_assert(REASON_EXT_SYS_RST == 6, "Reset reason enum values must match table indices");
42
43// PROGMEM string table for flash chip modes, indexed by mode code (0-3), with "UNKNOWN" as fallback
44PROGMEM_STRING_TABLE(FlashModeStrings, "QIO", "QOUT", "DIO", "DOUT", "UNKNOWN");
45static_assert(FM_QIO == 0, "Flash mode enum values must match table indices");
46static_assert(FM_QOUT == 1, "Flash mode enum values must match table indices");
47static_assert(FM_DIO == 2, "Flash mode enum values must match table indices");
48static_assert(FM_DOUT == 3, "Flash mode enum values must match table indices");
49
50// Get reset reason string from reason code (no heap allocation)
51// Returns LogString* pointing to flash (PROGMEM) on ESP8266
52static const LogString *get_reset_reason_str(uint32_t reason) {
53 return ResetReasonStrings::get_log_str(static_cast<uint8_t>(reason), ResetReasonStrings::LAST_INDEX);
54}
55
56// Size for core version hex buffer
57static constexpr size_t CORE_VERSION_BUFFER_SIZE = 12;
58
59// Get core version string (no heap allocation)
60// Returns either core_release directly or formats core_version as hex into provided buffer
61static const char *get_core_version_str(std::span<char, CORE_VERSION_BUFFER_SIZE> buffer) {
62 if (core_release != nullptr) {
63 return core_release;
64 }
65 snprintf_P(buffer.data(), CORE_VERSION_BUFFER_SIZE, PSTR("%08x"), core_version);
66 return buffer.data();
67}
68
69// Size for reset info buffer
70static constexpr size_t RESET_INFO_BUFFER_SIZE = 200;
71
72// Get detailed reset info string (no heap allocation)
73// For watchdog/exception resets, includes detailed exception info
74static const char *get_reset_info_str(std::span<char, RESET_INFO_BUFFER_SIZE> buffer, uint32_t reason) {
75 if (reason >= REASON_WDT_RST && reason <= REASON_SOFT_WDT_RST) {
76 snprintf_P(buffer.data(), RESET_INFO_BUFFER_SIZE,
77 PSTR("Fatal exception:%d flag:%d (%s) epc1:0x%08x epc2:0x%08x epc3:0x%08x excvaddr:0x%08x depc:0x%08x"),
78 static_cast<int>(resetInfo.exccause), static_cast<int>(reason),
79 LOG_STR_ARG(get_reset_reason_str(reason)), resetInfo.epc1, resetInfo.epc2, resetInfo.epc3,
80 resetInfo.excvaddr, resetInfo.depc);
81 return buffer.data();
82 }
83 return LOG_STR_ARG(get_reset_reason_str(reason));
84}
85
86const char *DebugComponent::get_reset_reason_(std::span<char, RESET_REASON_BUFFER_SIZE> buffer) {
87 // Copy from flash to provided buffer
88 strncpy_P(buffer.data(), (PGM_P) get_reset_reason_str(resetInfo.reason), RESET_REASON_BUFFER_SIZE - 1);
89 buffer[RESET_REASON_BUFFER_SIZE - 1] = '\0';
90 return buffer.data();
91}
92
93const char *DebugComponent::get_wakeup_cause_(std::span<char, WAKEUP_CAUSE_BUFFER_SIZE> buffer) {
94 // ESP8266 doesn't have detailed wakeup cause like ESP32
95 return "";
96}
97
99 return ESP.getFreeHeap(); // NOLINT(readability-static-accessed-through-instance)
100}
101
102size_t DebugComponent::get_device_info_(std::span<char, DEVICE_INFO_BUFFER_SIZE> buffer, size_t pos) {
103 constexpr size_t size = DEVICE_INFO_BUFFER_SIZE;
104 char *buf = buffer.data();
105
106 const LogString *flash_mode = FlashModeStrings::get_log_str(
107 static_cast<uint8_t>(ESP.getFlashChipMode()), // NOLINT(readability-static-accessed-through-instance)
108 FlashModeStrings::LAST_INDEX);
109 uint32_t flash_size = ESP.getFlashChipSize() / 1024; // NOLINT(readability-static-accessed-through-instance)
110 uint32_t flash_speed = ESP.getFlashChipSpeed() / 1000000; // NOLINT(readability-static-accessed-through-instance)
111 ESP_LOGD(TAG, "Flash Chip: Size=%" PRIu32 "kB Speed=%" PRIu32 "MHz Mode=%s", flash_size, flash_speed,
112 LOG_STR_ARG(flash_mode));
113 pos = buf_append_printf(buf, size, pos, "|Flash: %" PRIu32 "kB Speed:%" PRIu32 "MHz Mode:%s", flash_size, flash_speed,
114 LOG_STR_ARG(flash_mode));
115
116 char reason_buffer[RESET_REASON_BUFFER_SIZE];
117 const char *reset_reason = get_reset_reason_(reason_buffer);
118 char core_version_buffer[CORE_VERSION_BUFFER_SIZE];
119 char reset_info_buffer[RESET_INFO_BUFFER_SIZE];
120 // NOLINTBEGIN(readability-static-accessed-through-instance)
121 uint32_t chip_id = ESP.getChipId();
122 uint8_t boot_version = ESP.getBootVersion();
123 uint8_t boot_mode = ESP.getBootMode();
124 uint8_t cpu_freq = ESP.getCpuFreqMHz();
125 uint32_t flash_chip_id = ESP.getFlashChipId();
126 const char *sdk_version = ESP.getSdkVersion();
127 // NOLINTEND(readability-static-accessed-through-instance)
128
129 ESP_LOGD(TAG,
130 "ESP8266 debug info:\n"
131 " Chip ID: 0x%08" PRIX32 "\n"
132 " SDK Version: %s\n"
133 " Core Version: %s\n"
134 " Boot Version: %u\n"
135 " Boot Mode: %u\n"
136 " CPU Frequency: %u\n"
137 " Flash Chip ID: 0x%08" PRIX32 "\n"
138 " Reset Reason: %s\n"
139 " Reset Info: %s",
140 chip_id, sdk_version, get_core_version_str(core_version_buffer), boot_version, boot_mode, cpu_freq,
141 flash_chip_id, reset_reason, get_reset_info_str(reset_info_buffer, resetInfo.reason));
142
143 pos = buf_append_printf(buf, size, pos, "|Chip: 0x%08" PRIX32, chip_id);
144 pos = buf_append_printf(buf, size, pos, "|SDK: %s", sdk_version);
145 pos = buf_append_printf(buf, size, pos, "|Core: %s", get_core_version_str(core_version_buffer));
146 pos = buf_append_printf(buf, size, pos, "|Boot: %u", boot_version);
147 pos = buf_append_printf(buf, size, pos, "|Mode: %u", boot_mode);
148 pos = buf_append_printf(buf, size, pos, "|CPU: %u", cpu_freq);
149 pos = buf_append_printf(buf, size, pos, "|Flash: 0x%08" PRIX32, flash_chip_id);
150 pos = buf_append_printf(buf, size, pos, "|Reset: %s", reset_reason);
151 pos = buf_append_printf(buf, size, pos, "|%s", get_reset_info_str(reset_info_buffer, resetInfo.reason));
152
153 return pos;
154}
155
157#ifdef USE_SENSOR
158 if (this->block_sensor_ != nullptr) {
159 // NOLINTNEXTLINE(readability-static-accessed-through-instance)
160 this->block_sensor_->publish_state(ESP.getMaxFreeBlockSize());
161 }
162#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
163 if (this->fragmentation_sensor_ != nullptr) {
164 // NOLINTNEXTLINE(readability-static-accessed-through-instance)
165 this->fragmentation_sensor_->publish_state(ESP.getHeapFragmentation());
166 }
167#endif
168
169#endif
170}
171
172} // namespace esphome::debug
173#endif
const char * get_wakeup_cause_(std::span< char, WAKEUP_CAUSE_BUFFER_SIZE > buffer)
size_t get_device_info_(std::span< char, DEVICE_INFO_BUFFER_SIZE > buffer, size_t pos)
sensor::Sensor * fragmentation_sensor_
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:68
struct rst_info resetInfo
uint32_t core_version
const char * core_release
PROGMEM_STRING_TABLE(ResetReasonStrings, "Power On", "Hardware Watchdog", "Exception", "Software Watchdog", "Software/System restart", "Deep-Sleep Wake", "External System", "Unknown")
uint16_t size
Definition helpers.cpp:25
size_t size_t pos
Definition helpers.h:1038
static void uint32_t