mirror of
https://github.com/esphome/esphome.git
synced 2026-01-18 17:16:25 -07:00
Compare commits
37 Commits
pipsolar_t
...
integratio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7efb72c511 | ||
|
|
07a731b97d | ||
|
|
db37ae0e3c | ||
|
|
d2bf991bfb | ||
|
|
f8b33562c1 | ||
|
|
cf17a079b7 | ||
|
|
a451625120 | ||
|
|
c180d0c49c | ||
|
|
bacc4ed4e5 | ||
|
|
7acde0ab60 | ||
|
|
98c8142f86 | ||
|
|
4ed68c6884 | ||
|
|
680e92a226 | ||
|
|
6ab321db1a | ||
|
|
c1cba269b3 | ||
|
|
0e2f0bae21 | ||
|
|
7175299cae | ||
|
|
db0b32bfc9 | ||
|
|
21794e28e5 | ||
|
|
42ad20c231 | ||
|
|
ae5a3e616a | ||
|
|
59eeeb5fe5 | ||
|
|
759278191b | ||
|
|
03eaec853a | ||
|
|
4549e375c1 | ||
|
|
a8b07af2a3 | ||
|
|
f011dc658d | ||
|
|
728236270c | ||
|
|
01cdc4ed58 | ||
|
|
d6a0c8ffbb | ||
|
|
f003fac5d8 | ||
|
|
4cc0f874f7 | ||
|
|
ed58b9372f | ||
|
|
ee2a81923b | ||
|
|
0a1e7ee50b | ||
|
|
4d4283bcfa | ||
|
|
6b02f5dfbd |
@@ -135,8 +135,8 @@ void BluetoothConnection::loop() {
|
||||
// - For V3_WITH_CACHE: Services are never sent, disable after INIT state
|
||||
// - For V3_WITHOUT_CACHE: Disable only after service discovery is complete
|
||||
// (send_service_ == DONE_SENDING_SERVICES, which is only set after services are sent)
|
||||
if (this->state_ != espbt::ClientState::INIT && (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
|
||||
this->send_service_ == DONE_SENDING_SERVICES)) {
|
||||
if (this->state() != espbt::ClientState::INIT && (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
|
||||
this->send_service_ == DONE_SENDING_SERVICES)) {
|
||||
this->disable_loop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,21 +3,80 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include <Esp.h>
|
||||
|
||||
extern "C" {
|
||||
#include <user_interface.h>
|
||||
|
||||
// Global reset info struct populated by SDK at boot
|
||||
extern struct rst_info resetInfo;
|
||||
|
||||
// Core version - either a string pointer or a version number to format as hex
|
||||
extern uint32_t core_version;
|
||||
extern const char *core_release;
|
||||
}
|
||||
|
||||
namespace esphome {
|
||||
namespace debug {
|
||||
|
||||
static const char *const TAG = "debug";
|
||||
|
||||
// Get reset reason string from reason code (no heap allocation)
|
||||
// Returns LogString* pointing to flash (PROGMEM) on ESP8266
|
||||
static const LogString *get_reset_reason_str(uint32_t reason) {
|
||||
switch (reason) {
|
||||
case REASON_DEFAULT_RST:
|
||||
return LOG_STR("Power On");
|
||||
case REASON_WDT_RST:
|
||||
return LOG_STR("Hardware Watchdog");
|
||||
case REASON_EXCEPTION_RST:
|
||||
return LOG_STR("Exception");
|
||||
case REASON_SOFT_WDT_RST:
|
||||
return LOG_STR("Software Watchdog");
|
||||
case REASON_SOFT_RESTART:
|
||||
return LOG_STR("Software/System restart");
|
||||
case REASON_DEEP_SLEEP_AWAKE:
|
||||
return LOG_STR("Deep-Sleep Wake");
|
||||
case REASON_EXT_SYS_RST:
|
||||
return LOG_STR("External System");
|
||||
default:
|
||||
return LOG_STR("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
// Size for core version hex buffer
|
||||
static constexpr size_t CORE_VERSION_BUFFER_SIZE = 12;
|
||||
|
||||
// Get core version string (no heap allocation)
|
||||
// Returns either core_release directly or formats core_version as hex into provided buffer
|
||||
static const char *get_core_version_str(std::span<char, CORE_VERSION_BUFFER_SIZE> buffer) {
|
||||
if (core_release != nullptr) {
|
||||
return core_release;
|
||||
}
|
||||
snprintf_P(buffer.data(), CORE_VERSION_BUFFER_SIZE, PSTR("%08x"), core_version);
|
||||
return buffer.data();
|
||||
}
|
||||
|
||||
// Size for reset info buffer
|
||||
static constexpr size_t RESET_INFO_BUFFER_SIZE = 200;
|
||||
|
||||
// Get detailed reset info string (no heap allocation)
|
||||
// For watchdog/exception resets, includes detailed exception info
|
||||
static const char *get_reset_info_str(std::span<char, RESET_INFO_BUFFER_SIZE> buffer, uint32_t reason) {
|
||||
if (reason >= REASON_WDT_RST && reason <= REASON_SOFT_WDT_RST) {
|
||||
snprintf_P(buffer.data(), RESET_INFO_BUFFER_SIZE,
|
||||
PSTR("Fatal exception:%d flag:%d (%s) epc1:0x%08x epc2:0x%08x epc3:0x%08x excvaddr:0x%08x depc:0x%08x"),
|
||||
static_cast<int>(resetInfo.exccause), static_cast<int>(reason),
|
||||
LOG_STR_ARG(get_reset_reason_str(reason)), resetInfo.epc1, resetInfo.epc2, resetInfo.epc3,
|
||||
resetInfo.excvaddr, resetInfo.depc);
|
||||
return buffer.data();
|
||||
}
|
||||
return LOG_STR_ARG(get_reset_reason_str(reason));
|
||||
}
|
||||
|
||||
const char *DebugComponent::get_reset_reason_(std::span<char, RESET_REASON_BUFFER_SIZE> buffer) {
|
||||
char *buf = buffer.data();
|
||||
#if !defined(CLANG_TIDY)
|
||||
String reason = ESP.getResetReason(); // NOLINT
|
||||
snprintf_P(buf, RESET_REASON_BUFFER_SIZE, PSTR("%s"), reason.c_str());
|
||||
return buf;
|
||||
#else
|
||||
buf[0] = '\0';
|
||||
return buf;
|
||||
#endif
|
||||
// Copy from flash to provided buffer
|
||||
strncpy_P(buffer.data(), (PGM_P) get_reset_reason_str(resetInfo.reason), RESET_REASON_BUFFER_SIZE - 1);
|
||||
buffer[RESET_REASON_BUFFER_SIZE - 1] = '\0';
|
||||
return buffer.data();
|
||||
}
|
||||
|
||||
const char *DebugComponent::get_wakeup_cause_(std::span<char, RESET_REASON_BUFFER_SIZE> buffer) {
|
||||
@@ -33,37 +92,42 @@ size_t DebugComponent::get_device_info_(std::span<char, DEVICE_INFO_BUFFER_SIZE>
|
||||
constexpr size_t size = DEVICE_INFO_BUFFER_SIZE;
|
||||
char *buf = buffer.data();
|
||||
|
||||
const char *flash_mode;
|
||||
const LogString *flash_mode;
|
||||
switch (ESP.getFlashChipMode()) { // NOLINT(readability-static-accessed-through-instance)
|
||||
case FM_QIO:
|
||||
flash_mode = "QIO";
|
||||
flash_mode = LOG_STR("QIO");
|
||||
break;
|
||||
case FM_QOUT:
|
||||
flash_mode = "QOUT";
|
||||
flash_mode = LOG_STR("QOUT");
|
||||
break;
|
||||
case FM_DIO:
|
||||
flash_mode = "DIO";
|
||||
flash_mode = LOG_STR("DIO");
|
||||
break;
|
||||
case FM_DOUT:
|
||||
flash_mode = "DOUT";
|
||||
flash_mode = LOG_STR("DOUT");
|
||||
break;
|
||||
default:
|
||||
flash_mode = "UNKNOWN";
|
||||
flash_mode = LOG_STR("UNKNOWN");
|
||||
}
|
||||
uint32_t flash_size = ESP.getFlashChipSize() / 1024; // NOLINT
|
||||
uint32_t flash_speed = ESP.getFlashChipSpeed() / 1000000; // NOLINT
|
||||
ESP_LOGD(TAG, "Flash Chip: Size=%" PRIu32 "kB Speed=%" PRIu32 "MHz Mode=%s", flash_size, flash_speed, flash_mode);
|
||||
uint32_t flash_size = ESP.getFlashChipSize() / 1024; // NOLINT(readability-static-accessed-through-instance)
|
||||
uint32_t flash_speed = ESP.getFlashChipSpeed() / 1000000; // NOLINT(readability-static-accessed-through-instance)
|
||||
ESP_LOGD(TAG, "Flash Chip: Size=%" PRIu32 "kB Speed=%" PRIu32 "MHz Mode=%s", flash_size, flash_speed,
|
||||
LOG_STR_ARG(flash_mode));
|
||||
pos = buf_append_printf(buf, size, pos, "|Flash: %" PRIu32 "kB Speed:%" PRIu32 "MHz Mode:%s", flash_size, flash_speed,
|
||||
flash_mode);
|
||||
LOG_STR_ARG(flash_mode));
|
||||
|
||||
#if !defined(CLANG_TIDY)
|
||||
char reason_buffer[RESET_REASON_BUFFER_SIZE];
|
||||
const char *reset_reason = get_reset_reason_(std::span<char, RESET_REASON_BUFFER_SIZE>(reason_buffer));
|
||||
const char *reset_reason = get_reset_reason_(reason_buffer);
|
||||
char core_version_buffer[CORE_VERSION_BUFFER_SIZE];
|
||||
char reset_info_buffer[RESET_INFO_BUFFER_SIZE];
|
||||
// NOLINTBEGIN(readability-static-accessed-through-instance)
|
||||
uint32_t chip_id = ESP.getChipId();
|
||||
uint8_t boot_version = ESP.getBootVersion();
|
||||
uint8_t boot_mode = ESP.getBootMode();
|
||||
uint8_t cpu_freq = ESP.getCpuFreqMHz();
|
||||
uint32_t flash_chip_id = ESP.getFlashChipId();
|
||||
const char *sdk_version = ESP.getSdkVersion();
|
||||
// NOLINTEND(readability-static-accessed-through-instance)
|
||||
|
||||
ESP_LOGD(TAG,
|
||||
"Chip ID: 0x%08" PRIX32 "\n"
|
||||
@@ -74,19 +138,18 @@ size_t DebugComponent::get_device_info_(std::span<char, DEVICE_INFO_BUFFER_SIZE>
|
||||
"Flash Chip ID=0x%08" PRIX32 "\n"
|
||||
"Reset Reason: %s\n"
|
||||
"Reset Info: %s",
|
||||
chip_id, ESP.getSdkVersion(), ESP.getCoreVersion().c_str(), boot_version, boot_mode, cpu_freq, flash_chip_id,
|
||||
reset_reason, ESP.getResetInfo().c_str());
|
||||
chip_id, sdk_version, get_core_version_str(core_version_buffer), boot_version, boot_mode, cpu_freq,
|
||||
flash_chip_id, reset_reason, get_reset_info_str(reset_info_buffer, resetInfo.reason));
|
||||
|
||||
pos = buf_append_printf(buf, size, pos, "|Chip: 0x%08" PRIX32, chip_id);
|
||||
pos = buf_append_printf(buf, size, pos, "|SDK: %s", ESP.getSdkVersion());
|
||||
pos = buf_append_printf(buf, size, pos, "|Core: %s", ESP.getCoreVersion().c_str());
|
||||
pos = buf_append_printf(buf, size, pos, "|SDK: %s", sdk_version);
|
||||
pos = buf_append_printf(buf, size, pos, "|Core: %s", get_core_version_str(core_version_buffer));
|
||||
pos = buf_append_printf(buf, size, pos, "|Boot: %u", boot_version);
|
||||
pos = buf_append_printf(buf, size, pos, "|Mode: %u", boot_mode);
|
||||
pos = buf_append_printf(buf, size, pos, "|CPU: %u", cpu_freq);
|
||||
pos = buf_append_printf(buf, size, pos, "|Flash: 0x%08" PRIX32, flash_chip_id);
|
||||
pos = buf_append_printf(buf, size, pos, "|Reset: %s", reset_reason);
|
||||
pos = buf_append_printf(buf, size, pos, "|%s", ESP.getResetInfo().c_str());
|
||||
#endif
|
||||
pos = buf_append_printf(buf, size, pos, "|%s", get_reset_info_str(reset_info_buffer, resetInfo.reason));
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ void BLEClientBase::loop() {
|
||||
this->set_state(espbt::ClientState::INIT);
|
||||
return;
|
||||
}
|
||||
if (this->state_ == espbt::ClientState::INIT) {
|
||||
if (this->state() == espbt::ClientState::INIT) {
|
||||
auto ret = esp_ble_gattc_app_register(this->app_id);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "gattc app register failed. app_id=%d code=%d", this->app_id, ret);
|
||||
@@ -60,7 +60,7 @@ void BLEClientBase::loop() {
|
||||
}
|
||||
// If idle, we can disable the loop as connect()
|
||||
// will enable it again when a connection is needed.
|
||||
else if (this->state_ == espbt::ClientState::IDLE) {
|
||||
else if (this->state() == espbt::ClientState::IDLE) {
|
||||
this->disable_loop();
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ bool BLEClientBase::parse_device(const espbt::ESPBTDevice &device) {
|
||||
return false;
|
||||
if (this->address_ == 0 || device.address_uint64() != this->address_)
|
||||
return false;
|
||||
if (this->state_ != espbt::ClientState::IDLE)
|
||||
if (this->state() != espbt::ClientState::IDLE)
|
||||
return false;
|
||||
|
||||
this->log_event_("Found device");
|
||||
@@ -102,10 +102,10 @@ bool BLEClientBase::parse_device(const espbt::ESPBTDevice &device) {
|
||||
|
||||
void BLEClientBase::connect() {
|
||||
// Prevent duplicate connection attempts
|
||||
if (this->state_ == espbt::ClientState::CONNECTING || this->state_ == espbt::ClientState::CONNECTED ||
|
||||
this->state_ == espbt::ClientState::ESTABLISHED) {
|
||||
if (this->state() == espbt::ClientState::CONNECTING || this->state() == espbt::ClientState::CONNECTED ||
|
||||
this->state() == espbt::ClientState::ESTABLISHED) {
|
||||
ESP_LOGW(TAG, "[%d] [%s] Connection already in progress, state=%s", this->connection_index_, this->address_str_,
|
||||
espbt::client_state_to_string(this->state_));
|
||||
espbt::client_state_to_string(this->state()));
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "[%d] [%s] 0x%02x Connecting", this->connection_index_, this->address_str_, this->remote_addr_type_);
|
||||
@@ -133,12 +133,12 @@ void BLEClientBase::connect() {
|
||||
esp_err_t BLEClientBase::pair() { return esp_ble_set_encryption(this->remote_bda_, ESP_BLE_SEC_ENCRYPT); }
|
||||
|
||||
void BLEClientBase::disconnect() {
|
||||
if (this->state_ == espbt::ClientState::IDLE || this->state_ == espbt::ClientState::DISCONNECTING) {
|
||||
if (this->state() == espbt::ClientState::IDLE || this->state() == espbt::ClientState::DISCONNECTING) {
|
||||
ESP_LOGI(TAG, "[%d] [%s] Disconnect requested, but already %s", this->connection_index_, this->address_str_,
|
||||
espbt::client_state_to_string(this->state_));
|
||||
espbt::client_state_to_string(this->state()));
|
||||
return;
|
||||
}
|
||||
if (this->state_ == espbt::ClientState::CONNECTING || this->conn_id_ == UNSET_CONN_ID) {
|
||||
if (this->state() == espbt::ClientState::CONNECTING || this->conn_id_ == UNSET_CONN_ID) {
|
||||
ESP_LOGD(TAG, "[%d] [%s] Disconnect before connected, disconnect scheduled", this->connection_index_,
|
||||
this->address_str_);
|
||||
this->want_disconnect_ = true;
|
||||
@@ -150,7 +150,7 @@ void BLEClientBase::disconnect() {
|
||||
void BLEClientBase::unconditional_disconnect() {
|
||||
// Disconnect without checking the state.
|
||||
ESP_LOGI(TAG, "[%d] [%s] Disconnecting (conn_id: %d).", this->connection_index_, this->address_str_, this->conn_id_);
|
||||
if (this->state_ == espbt::ClientState::DISCONNECTING) {
|
||||
if (this->state() == espbt::ClientState::DISCONNECTING) {
|
||||
this->log_error_("Already disconnecting");
|
||||
return;
|
||||
}
|
||||
@@ -170,7 +170,7 @@ void BLEClientBase::unconditional_disconnect() {
|
||||
this->log_gattc_warning_("esp_ble_gattc_close", err);
|
||||
}
|
||||
|
||||
if (this->state_ == espbt::ClientState::DISCOVERED) {
|
||||
if (this->state() == espbt::ClientState::DISCOVERED) {
|
||||
this->set_address(0);
|
||||
this->set_state(espbt::ClientState::IDLE);
|
||||
} else {
|
||||
@@ -295,18 +295,18 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
// ESP-IDF's BLE stack may send ESP_GATTC_OPEN_EVT after esp_ble_gattc_open() returns an
|
||||
// error, if the error occurred at the BTA/GATT layer. This can result in the event
|
||||
// arriving after we've already transitioned to IDLE state.
|
||||
if (this->state_ == espbt::ClientState::IDLE) {
|
||||
if (this->state() == espbt::ClientState::IDLE) {
|
||||
ESP_LOGD(TAG, "[%d] [%s] ESP_GATTC_OPEN_EVT in IDLE state (status=%d), ignoring", this->connection_index_,
|
||||
this->address_str_, param->open.status);
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->state_ != espbt::ClientState::CONNECTING) {
|
||||
if (this->state() != espbt::ClientState::CONNECTING) {
|
||||
// This should not happen but lets log it in case it does
|
||||
// because it means we have a bad assumption about how the
|
||||
// ESP BT stack works.
|
||||
ESP_LOGE(TAG, "[%d] [%s] ESP_GATTC_OPEN_EVT in %s state (status=%d)", this->connection_index_,
|
||||
this->address_str_, espbt::client_state_to_string(this->state_), param->open.status);
|
||||
this->address_str_, espbt::client_state_to_string(this->state()), param->open.status);
|
||||
}
|
||||
if (param->open.status != ESP_GATT_OK && param->open.status != ESP_GATT_ALREADY_OPEN) {
|
||||
this->log_gattc_warning_("Connection open", param->open.status);
|
||||
@@ -327,7 +327,7 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE) {
|
||||
// Cached connections already connected with medium parameters, no update needed
|
||||
// only set our state, subclients might have more stuff to do yet.
|
||||
this->state_ = espbt::ClientState::ESTABLISHED;
|
||||
this->set_state_internal_(espbt::ClientState::ESTABLISHED);
|
||||
break;
|
||||
}
|
||||
// For V3_WITHOUT_CACHE, we already set fast params before connecting
|
||||
@@ -356,7 +356,7 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
return false;
|
||||
// Check if we were disconnected while waiting for service discovery
|
||||
if (param->disconnect.reason == ESP_GATT_CONN_TERMINATE_PEER_USER &&
|
||||
this->state_ == espbt::ClientState::CONNECTED) {
|
||||
this->state() == espbt::ClientState::CONNECTED) {
|
||||
this->log_warning_("Remote closed during discovery");
|
||||
} else {
|
||||
ESP_LOGD(TAG, "[%d] [%s] ESP_GATTC_DISCONNECT_EVT, reason 0x%02x", this->connection_index_, this->address_str_,
|
||||
@@ -433,7 +433,7 @@ bool BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
#endif
|
||||
}
|
||||
ESP_LOGI(TAG, "[%d] [%s] Service discovery complete", this->connection_index_, this->address_str_);
|
||||
this->state_ = espbt::ClientState::ESTABLISHED;
|
||||
this->set_state_internal_(espbt::ClientState::ESTABLISHED);
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_READ_DESCR_EVT: {
|
||||
|
||||
@@ -44,7 +44,7 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
|
||||
void unconditional_disconnect();
|
||||
void release_services();
|
||||
|
||||
bool connected() { return this->state_ == espbt::ClientState::ESTABLISHED; }
|
||||
bool connected() { return this->state() == espbt::ClientState::ESTABLISHED; }
|
||||
|
||||
void set_auto_connect(bool auto_connect) { this->auto_connect_ = auto_connect; }
|
||||
|
||||
|
||||
@@ -105,15 +105,13 @@ void ESP32BLETracker::loop() {
|
||||
}
|
||||
|
||||
// Check for scan timeout - moved here from scheduler to avoid false reboots
|
||||
// when the loop is blocked
|
||||
// when the loop is blocked. This must run every iteration for safety.
|
||||
if (this->scanner_state_ == ScannerState::RUNNING) {
|
||||
switch (this->scan_timeout_state_) {
|
||||
case ScanTimeoutState::MONITORING: {
|
||||
uint32_t now = App.get_loop_component_start_time();
|
||||
uint32_t timeout_ms = this->scan_duration_ * 2000;
|
||||
// Robust time comparison that handles rollover correctly
|
||||
// This works because unsigned arithmetic wraps around predictably
|
||||
if ((now - this->scan_start_time_) > timeout_ms) {
|
||||
if ((App.get_loop_component_start_time() - this->scan_start_time_) > this->scan_timeout_ms_) {
|
||||
// First time we've seen the timeout exceeded - wait one more loop iteration
|
||||
// This ensures all components have had a chance to process pending events
|
||||
// This is because esp32_ble may not have run yet and called
|
||||
@@ -128,13 +126,31 @@ void ESP32BLETracker::loop() {
|
||||
ESP_LOGE(TAG, "Scan never terminated, rebooting");
|
||||
App.reboot();
|
||||
break;
|
||||
|
||||
case ScanTimeoutState::INACTIVE:
|
||||
// This case should be unreachable - scanner and timeout states are always synchronized
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Fast path: skip expensive client state counting and processing
|
||||
// if no state has changed since last loop iteration.
|
||||
//
|
||||
// How state changes ensure we reach the code below:
|
||||
// - handle_scanner_failure_(): scanner_state_ becomes FAILED via set_scanner_state_(), or
|
||||
// scan_set_param_failed_ requires scanner_state_==RUNNING which can only be reached via
|
||||
// set_scanner_state_(RUNNING) in gap_scan_start_complete_() (scan params are set during
|
||||
// STARTING, not RUNNING, so version is always incremented before this condition is true)
|
||||
// - start_scan_(): scanner_state_ becomes IDLE via set_scanner_state_() in cleanup_scan_state_()
|
||||
// - try_promote_discovered_clients_(): client enters DISCOVERED via set_state(), or
|
||||
// connecting client finishes (state change), or scanner reaches RUNNING/IDLE
|
||||
//
|
||||
// All conditions that affect the logic below are tied to state changes that increment
|
||||
// state_version_, so the fast path is safe.
|
||||
if (this->state_version_ == this->last_processed_version_) {
|
||||
return;
|
||||
}
|
||||
this->last_processed_version_ = this->state_version_;
|
||||
|
||||
// State changed - do full processing
|
||||
ClientStateCounts counts = this->count_client_states_();
|
||||
if (counts != this->client_state_counts_) {
|
||||
this->client_state_counts_ = counts;
|
||||
@@ -142,6 +158,7 @@ void ESP32BLETracker::loop() {
|
||||
this->client_state_counts_.discovered, this->client_state_counts_.disconnecting);
|
||||
}
|
||||
|
||||
// Scanner failure: reached when set_scanner_state_(FAILED) or scan_set_param_failed_ set
|
||||
if (this->scanner_state_ == ScannerState::FAILED ||
|
||||
(this->scan_set_param_failed_ && this->scanner_state_ == ScannerState::RUNNING)) {
|
||||
this->handle_scanner_failure_();
|
||||
@@ -160,6 +177,8 @@ void ESP32BLETracker::loop() {
|
||||
|
||||
*/
|
||||
|
||||
// Start scan: reached when scanner_state_ becomes IDLE (via set_scanner_state_()) and
|
||||
// all clients are idle (their state changes increment version when they finish)
|
||||
if (this->scanner_state_ == ScannerState::IDLE && !counts.connecting && !counts.disconnecting && !counts.discovered) {
|
||||
#ifdef USE_ESP32_BLE_SOFTWARE_COEXISTENCE
|
||||
this->update_coex_preference_(false);
|
||||
@@ -168,8 +187,9 @@ void ESP32BLETracker::loop() {
|
||||
this->start_scan_(false); // first = false
|
||||
}
|
||||
}
|
||||
// If there is a discovered client and no connecting
|
||||
// clients, then promote the discovered client to ready to connect.
|
||||
// Promote discovered clients: reached when a client's state becomes DISCOVERED (via set_state()),
|
||||
// or when a blocking condition clears (connecting client finishes, scanner reaches RUNNING/IDLE).
|
||||
// All these trigger state_version_ increment, so we'll process and check promotion eligibility.
|
||||
// We check both RUNNING and IDLE states because:
|
||||
// - RUNNING: gap_scan_event_handler initiates stop_scan_() but promotion can happen immediately
|
||||
// - IDLE: Scanner has already stopped (naturally or by gap_scan_event_handler)
|
||||
@@ -236,6 +256,7 @@ void ESP32BLETracker::start_scan_(bool first) {
|
||||
// Start timeout monitoring in loop() instead of using scheduler
|
||||
// This prevents false reboots when the loop is blocked
|
||||
this->scan_start_time_ = App.get_loop_component_start_time();
|
||||
this->scan_timeout_ms_ = this->scan_duration_ * 2000;
|
||||
this->scan_timeout_state_ = ScanTimeoutState::MONITORING;
|
||||
|
||||
esp_err_t err = esp_ble_gap_set_scan_params(&this->scan_params_);
|
||||
@@ -253,6 +274,10 @@ void ESP32BLETracker::start_scan_(bool first) {
|
||||
void ESP32BLETracker::register_client(ESPBTClient *client) {
|
||||
#ifdef ESPHOME_ESP32_BLE_TRACKER_CLIENT_COUNT
|
||||
client->app_id = ++this->app_id_;
|
||||
// Give client a pointer to our state_version_ so it can notify us of state changes.
|
||||
// This enables loop() fast-path optimization - we skip expensive work when no state changed.
|
||||
// Safe because ESP32BLETracker (singleton) outlives all registered clients.
|
||||
client->set_tracker_state_version(&this->state_version_);
|
||||
this->clients_.push_back(client);
|
||||
this->recalculate_advertisement_parser_types();
|
||||
#endif
|
||||
@@ -382,6 +407,7 @@ void ESP32BLETracker::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_i
|
||||
|
||||
void ESP32BLETracker::set_scanner_state_(ScannerState state) {
|
||||
this->scanner_state_ = state;
|
||||
this->state_version_++;
|
||||
for (auto *listener : this->scanner_state_listeners_) {
|
||||
listener->on_scanner_state(state);
|
||||
}
|
||||
|
||||
@@ -216,6 +216,19 @@ enum class ConnectionType : uint8_t {
|
||||
V3_WITHOUT_CACHE
|
||||
};
|
||||
|
||||
/// Base class for BLE GATT clients that connect to remote devices.
|
||||
///
|
||||
/// State Change Tracking Design:
|
||||
/// -----------------------------
|
||||
/// ESP32BLETracker::loop() needs to know when client states change to avoid
|
||||
/// expensive polling. Rather than checking all clients every iteration (~7000/min),
|
||||
/// we use a version counter owned by ESP32BLETracker that clients increment on
|
||||
/// state changes. The tracker compares versions to skip work when nothing changed.
|
||||
///
|
||||
/// Ownership: ESP32BLETracker owns state_version_. Clients hold a non-owning
|
||||
/// pointer (tracker_state_version_) set during register_client(). Clients
|
||||
/// increment the counter through this pointer when their state changes.
|
||||
/// The pointer may be null if the client is not registered with a tracker.
|
||||
class ESPBTClient : public ESPBTDeviceListener {
|
||||
public:
|
||||
virtual bool gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||
@@ -225,26 +238,49 @@ class ESPBTClient : public ESPBTDeviceListener {
|
||||
virtual void disconnect() = 0;
|
||||
bool disconnect_pending() const { return this->want_disconnect_; }
|
||||
void cancel_pending_disconnect() { this->want_disconnect_ = false; }
|
||||
|
||||
/// Set the client state with IDLE handling (clears want_disconnect_).
|
||||
/// Notifies the tracker of state change for loop optimization.
|
||||
virtual void set_state(ClientState st) {
|
||||
this->state_ = st;
|
||||
this->set_state_internal_(st);
|
||||
if (st == ClientState::IDLE) {
|
||||
this->want_disconnect_ = false;
|
||||
}
|
||||
}
|
||||
ClientState state() const { return state_; }
|
||||
ClientState state() const { return this->state_; }
|
||||
|
||||
/// Called by ESP32BLETracker::register_client() to enable state change notifications.
|
||||
/// The pointer must remain valid for the lifetime of the client (guaranteed since
|
||||
/// ESP32BLETracker is a singleton that outlives all clients).
|
||||
void set_tracker_state_version(uint8_t *version) { this->tracker_state_version_ = version; }
|
||||
|
||||
// Memory optimized layout
|
||||
uint8_t app_id; // App IDs are small integers assigned sequentially
|
||||
|
||||
protected:
|
||||
// Group 1: 1-byte types
|
||||
ClientState state_{ClientState::INIT};
|
||||
/// Set state without IDLE handling - use for direct state transitions.
|
||||
/// Increments the tracker's state version counter to signal that loop()
|
||||
/// should do full processing on the next iteration.
|
||||
void set_state_internal_(ClientState st) {
|
||||
this->state_ = st;
|
||||
// Notify tracker that state changed (tracker_state_version_ is owned by ESP32BLETracker)
|
||||
if (this->tracker_state_version_ != nullptr) {
|
||||
(*this->tracker_state_version_)++;
|
||||
}
|
||||
}
|
||||
|
||||
// want_disconnect_ is set to true when a disconnect is requested
|
||||
// while the client is connecting. This is used to disconnect the
|
||||
// client as soon as we get the connection id (conn_id_) from the
|
||||
// ESP_GATTC_OPEN_EVT event.
|
||||
bool want_disconnect_{false};
|
||||
// 2 bytes used, 2 bytes padding
|
||||
|
||||
private:
|
||||
ClientState state_{ClientState::INIT};
|
||||
/// Non-owning pointer to ESP32BLETracker::state_version_. When this client's
|
||||
/// state changes, we increment the tracker's counter to signal that loop()
|
||||
/// should perform full processing. Null if client not registered with tracker.
|
||||
uint8_t *tracker_state_version_{nullptr};
|
||||
};
|
||||
|
||||
class ESP32BLETracker : public Component,
|
||||
@@ -380,6 +416,16 @@ class ESP32BLETracker : public Component,
|
||||
// Group 4: 1-byte types (enums, uint8_t, bool)
|
||||
uint8_t app_id_{0};
|
||||
uint8_t scan_start_fail_count_{0};
|
||||
/// Version counter for loop() fast-path optimization. Incremented when:
|
||||
/// - Scanner state changes (via set_scanner_state_())
|
||||
/// - Any registered client's state changes (clients hold pointer to this counter)
|
||||
/// Owned by this class; clients receive non-owning pointer via register_client().
|
||||
/// When loop() sees state_version_ == last_processed_version_, it skips expensive
|
||||
/// client state counting and takes the fast path (just timeout check + return).
|
||||
uint8_t state_version_{0};
|
||||
/// Last state_version_ value when loop() did full processing. Compared against
|
||||
/// state_version_ to detect if any state changed since last iteration.
|
||||
uint8_t last_processed_version_{0};
|
||||
ScannerState scanner_state_{ScannerState::IDLE};
|
||||
bool scan_continuous_;
|
||||
bool scan_active_;
|
||||
@@ -396,6 +442,8 @@ class ESP32BLETracker : public Component,
|
||||
EXCEEDED_WAIT, // Timeout exceeded, waiting one loop before reboot
|
||||
};
|
||||
uint32_t scan_start_time_{0};
|
||||
/// Precomputed timeout value: scan_duration_ * 2000
|
||||
uint32_t scan_timeout_ms_{0};
|
||||
ScanTimeoutState scan_timeout_state_{ScanTimeoutState::INACTIVE};
|
||||
};
|
||||
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "preferences.h"
|
||||
#include <Arduino.h>
|
||||
#include <Esp.h>
|
||||
#include <core_esp8266_features.h>
|
||||
|
||||
extern "C" {
|
||||
#include <user_interface.h>
|
||||
}
|
||||
|
||||
namespace esphome {
|
||||
|
||||
@@ -16,23 +20,19 @@ void IRAM_ATTR HOT delay(uint32_t ms) { ::delay(ms); }
|
||||
uint32_t IRAM_ATTR HOT micros() { return ::micros(); }
|
||||
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); }
|
||||
void arch_restart() {
|
||||
ESP.restart(); // NOLINT(readability-static-accessed-through-instance)
|
||||
system_restart();
|
||||
// restart() doesn't always end execution
|
||||
while (true) { // NOLINT(clang-diagnostic-unreachable-code)
|
||||
yield();
|
||||
}
|
||||
}
|
||||
void arch_init() {}
|
||||
void IRAM_ATTR HOT arch_feed_wdt() {
|
||||
ESP.wdtFeed(); // NOLINT(readability-static-accessed-through-instance)
|
||||
}
|
||||
void IRAM_ATTR HOT arch_feed_wdt() { system_soft_wdt_feed(); }
|
||||
|
||||
uint8_t progmem_read_byte(const uint8_t *addr) {
|
||||
return pgm_read_byte(addr); // NOLINT
|
||||
}
|
||||
uint32_t IRAM_ATTR HOT arch_get_cpu_cycle_count() {
|
||||
return ESP.getCycleCount(); // NOLINT(readability-static-accessed-through-instance)
|
||||
}
|
||||
uint32_t IRAM_ATTR HOT arch_get_cpu_cycle_count() { return esp_get_cycle_count(); }
|
||||
uint32_t arch_get_cpu_freq_hz() { return F_CPU; }
|
||||
|
||||
void force_link_symbols() {
|
||||
|
||||
@@ -6,6 +6,7 @@ from esphome.const import (
|
||||
CONF_INITIAL_VALUE,
|
||||
CONF_RESTORE_VALUE,
|
||||
CONF_TYPE,
|
||||
CONF_UPDATE_INTERVAL,
|
||||
CONF_VALUE,
|
||||
)
|
||||
from esphome.core import CoroPriority, coroutine_with_priority
|
||||
@@ -13,25 +14,37 @@ from esphome.core import CoroPriority, coroutine_with_priority
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
globals_ns = cg.esphome_ns.namespace("globals")
|
||||
GlobalsComponent = globals_ns.class_("GlobalsComponent", cg.Component)
|
||||
RestoringGlobalsComponent = globals_ns.class_("RestoringGlobalsComponent", cg.Component)
|
||||
RestoringGlobalsComponent = globals_ns.class_(
|
||||
"RestoringGlobalsComponent", cg.PollingComponent
|
||||
)
|
||||
RestoringGlobalStringComponent = globals_ns.class_(
|
||||
"RestoringGlobalStringComponent", cg.Component
|
||||
"RestoringGlobalStringComponent", cg.PollingComponent
|
||||
)
|
||||
GlobalVarSetAction = globals_ns.class_("GlobalVarSetAction", automation.Action)
|
||||
|
||||
CONF_MAX_RESTORE_DATA_LENGTH = "max_restore_data_length"
|
||||
|
||||
|
||||
def validate_update_interval(config):
|
||||
if CONF_UPDATE_INTERVAL in config and not config.get(CONF_RESTORE_VALUE, False):
|
||||
raise cv.Invalid("update_interval requires restore_value to be true")
|
||||
return config
|
||||
|
||||
|
||||
MULTI_CONF = True
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.declare_id(GlobalsComponent),
|
||||
cv.Required(CONF_TYPE): cv.string_strict,
|
||||
cv.Optional(CONF_INITIAL_VALUE): cv.string_strict,
|
||||
cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_MAX_RESTORE_DATA_LENGTH): cv.int_range(0, 254),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.declare_id(GlobalsComponent),
|
||||
cv.Required(CONF_TYPE): cv.string_strict,
|
||||
cv.Optional(CONF_INITIAL_VALUE): cv.string_strict,
|
||||
cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_MAX_RESTORE_DATA_LENGTH): cv.int_range(0, 254),
|
||||
cv.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
validate_update_interval,
|
||||
)
|
||||
|
||||
|
||||
# Run with low priority so that namespaces are registered first
|
||||
@@ -65,6 +78,8 @@ async def to_code(config):
|
||||
value = value.encode()
|
||||
hash_ = int(hashlib.md5(value).hexdigest()[:8], 16)
|
||||
cg.add(glob.set_name_hash(hash_))
|
||||
if CONF_UPDATE_INTERVAL in config:
|
||||
cg.add(glob.set_update_interval(config[CONF_UPDATE_INTERVAL]))
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace esphome {
|
||||
namespace globals {
|
||||
namespace esphome::globals {
|
||||
|
||||
template<typename T> class GlobalsComponent : public Component {
|
||||
public:
|
||||
@@ -24,13 +23,14 @@ template<typename T> class GlobalsComponent : public Component {
|
||||
T value_{};
|
||||
};
|
||||
|
||||
template<typename T> class RestoringGlobalsComponent : public Component {
|
||||
template<typename T> class RestoringGlobalsComponent : public PollingComponent {
|
||||
public:
|
||||
using value_type = T;
|
||||
explicit RestoringGlobalsComponent() = default;
|
||||
explicit RestoringGlobalsComponent(T initial_value) : value_(initial_value) {}
|
||||
explicit RestoringGlobalsComponent() : PollingComponent(1000) {}
|
||||
explicit RestoringGlobalsComponent(T initial_value) : PollingComponent(1000), value_(initial_value) {}
|
||||
explicit RestoringGlobalsComponent(
|
||||
std::array<typename std::remove_extent<T>::type, std::extent<T>::value> initial_value) {
|
||||
std::array<typename std::remove_extent<T>::type, std::extent<T>::value> initial_value)
|
||||
: PollingComponent(1000) {
|
||||
memcpy(this->value_, initial_value.data(), sizeof(T));
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ template<typename T> class RestoringGlobalsComponent : public Component {
|
||||
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||
|
||||
void loop() override { store_value_(); }
|
||||
void update() override { store_value_(); }
|
||||
|
||||
void on_shutdown() override { store_value_(); }
|
||||
|
||||
@@ -66,13 +66,14 @@ template<typename T> class RestoringGlobalsComponent : public Component {
|
||||
};
|
||||
|
||||
// Use with string or subclasses of strings
|
||||
template<typename T, uint8_t SZ> class RestoringGlobalStringComponent : public Component {
|
||||
template<typename T, uint8_t SZ> class RestoringGlobalStringComponent : public PollingComponent {
|
||||
public:
|
||||
using value_type = T;
|
||||
explicit RestoringGlobalStringComponent() = default;
|
||||
explicit RestoringGlobalStringComponent(T initial_value) { this->value_ = initial_value; }
|
||||
explicit RestoringGlobalStringComponent() : PollingComponent(1000) {}
|
||||
explicit RestoringGlobalStringComponent(T initial_value) : PollingComponent(1000) { this->value_ = initial_value; }
|
||||
explicit RestoringGlobalStringComponent(
|
||||
std::array<typename std::remove_extent<T>::type, std::extent<T>::value> initial_value) {
|
||||
std::array<typename std::remove_extent<T>::type, std::extent<T>::value> initial_value)
|
||||
: PollingComponent(1000) {
|
||||
memcpy(this->value_, initial_value.data(), sizeof(T));
|
||||
}
|
||||
|
||||
@@ -90,7 +91,7 @@ template<typename T, uint8_t SZ> class RestoringGlobalStringComponent : public C
|
||||
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||
|
||||
void loop() override { store_value_(); }
|
||||
void update() override { store_value_(); }
|
||||
|
||||
void on_shutdown() override { store_value_(); }
|
||||
|
||||
@@ -144,5 +145,4 @@ template<typename T> T &id(GlobalsComponent<T> *value) { return value->value();
|
||||
template<typename T> T &id(RestoringGlobalsComponent<T> *value) { return value->value(); }
|
||||
template<typename T, uint8_t SZ> T &id(RestoringGlobalStringComponent<T, SZ> *value) { return value->value(); }
|
||||
|
||||
} // namespace globals
|
||||
} // namespace esphome
|
||||
} // namespace esphome::globals
|
||||
|
||||
@@ -271,9 +271,9 @@ class ServerRegister {
|
||||
|
||||
// Formats a raw value into a string representation based on the value type for debugging
|
||||
std::string format_value(int64_t value) const {
|
||||
// max 48: float with %.1f can be up to 42 chars (3.4e38 → 38 integer digits + decimal + 1 digit + sign + null)
|
||||
// int64_t max is 20 chars + sign + null = 22, so 48 covers both
|
||||
char buf[48];
|
||||
// max 44: float with %.1f can be up to 42 chars (3.4e38 → 39 integer digits + sign + decimal + 1 digit)
|
||||
// plus null terminator = 43, rounded to 44 for 4-byte alignment
|
||||
char buf[44];
|
||||
switch (this->value_type) {
|
||||
case SensorValueType::U_WORD:
|
||||
case SensorValueType::U_DWORD:
|
||||
|
||||
@@ -7,14 +7,14 @@ DEPENDENCIES = ["network"]
|
||||
|
||||
status_ns = cg.esphome_ns.namespace("status")
|
||||
StatusBinarySensor = status_ns.class_(
|
||||
"StatusBinarySensor", binary_sensor.BinarySensor, cg.Component
|
||||
"StatusBinarySensor", binary_sensor.BinarySensor, cg.PollingComponent
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(
|
||||
StatusBinarySensor,
|
||||
device_class=DEVICE_CLASS_CONNECTIVITY,
|
||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
).extend(cv.polling_component_schema("1s"))
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
|
||||
@@ -10,12 +10,11 @@
|
||||
#include "esphome/components/api/api_server.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace status {
|
||||
namespace esphome::status {
|
||||
|
||||
static const char *const TAG = "status";
|
||||
|
||||
void StatusBinarySensor::loop() {
|
||||
void StatusBinarySensor::update() {
|
||||
bool status = network::is_connected();
|
||||
#ifdef USE_MQTT
|
||||
if (mqtt::global_mqtt_client != nullptr) {
|
||||
@@ -33,5 +32,4 @@ void StatusBinarySensor::loop() {
|
||||
void StatusBinarySensor::setup() { this->publish_initial_state(false); }
|
||||
void StatusBinarySensor::dump_config() { LOG_BINARY_SENSOR("", "Status Binary Sensor", this); }
|
||||
|
||||
} // namespace status
|
||||
} // namespace esphome
|
||||
} // namespace esphome::status
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace status {
|
||||
namespace esphome::status {
|
||||
|
||||
class StatusBinarySensor : public binary_sensor::BinarySensor, public Component {
|
||||
class StatusBinarySensor : public binary_sensor::BinarySensor, public PollingComponent {
|
||||
public:
|
||||
void loop() override;
|
||||
void update() override;
|
||||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
@@ -16,5 +15,4 @@ class StatusBinarySensor : public binary_sensor::BinarySensor, public Component
|
||||
bool is_status_binary_sensor() const override { return true; }
|
||||
};
|
||||
|
||||
} // namespace status
|
||||
} // namespace esphome
|
||||
} // namespace esphome::status
|
||||
|
||||
@@ -920,7 +920,16 @@ bssid_t WiFiComponent::wifi_bssid() {
|
||||
}
|
||||
return bssid;
|
||||
}
|
||||
std::string WiFiComponent::wifi_ssid() { return WiFi.SSID().c_str(); }
|
||||
std::string WiFiComponent::wifi_ssid() {
|
||||
struct station_config conf {};
|
||||
if (!wifi_station_get_config(&conf)) {
|
||||
return "";
|
||||
}
|
||||
// conf.ssid is uint8[32], not null-terminated if full
|
||||
auto *ssid_s = reinterpret_cast<const char *>(conf.ssid);
|
||||
size_t len = strnlen(ssid_s, sizeof(conf.ssid));
|
||||
return {ssid_s, len};
|
||||
}
|
||||
const char *WiFiComponent::wifi_ssid_to(std::span<char, SSID_BUFFER_SIZE> buffer) {
|
||||
struct station_config conf {};
|
||||
if (!wifi_station_get_config(&conf)) {
|
||||
@@ -934,16 +943,24 @@ const char *WiFiComponent::wifi_ssid_to(std::span<char, SSID_BUFFER_SIZE> buffer
|
||||
return buffer.data();
|
||||
}
|
||||
int8_t WiFiComponent::wifi_rssi() {
|
||||
if (WiFi.status() != WL_CONNECTED)
|
||||
if (wifi_station_get_connect_status() != STATION_GOT_IP)
|
||||
return WIFI_RSSI_DISCONNECTED;
|
||||
int8_t rssi = WiFi.RSSI();
|
||||
sint8 rssi = wifi_station_get_rssi();
|
||||
// Values >= 31 are error codes per NONOS SDK API, not valid RSSI readings
|
||||
return rssi >= 31 ? WIFI_RSSI_DISCONNECTED : rssi;
|
||||
}
|
||||
int32_t WiFiComponent::get_wifi_channel() { return WiFi.channel(); }
|
||||
network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {(const ip_addr_t *) WiFi.subnetMask()}; }
|
||||
network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {(const ip_addr_t *) WiFi.gatewayIP()}; }
|
||||
network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return {(const ip_addr_t *) WiFi.dnsIP(num)}; }
|
||||
int32_t WiFiComponent::get_wifi_channel() { return wifi_get_channel(); }
|
||||
network::IPAddress WiFiComponent::wifi_subnet_mask_() {
|
||||
struct ip_info ip {};
|
||||
wifi_get_ip_info(STATION_IF, &ip);
|
||||
return network::IPAddress(&ip.netmask);
|
||||
}
|
||||
network::IPAddress WiFiComponent::wifi_gateway_ip_() {
|
||||
struct ip_info ip {};
|
||||
wifi_get_ip_info(STATION_IF, &ip);
|
||||
return network::IPAddress(&ip.gw);
|
||||
}
|
||||
network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return network::IPAddress(dns_getserver(num)); }
|
||||
void WiFiComponent::wifi_loop_() {}
|
||||
|
||||
} // namespace esphome::wifi
|
||||
|
||||
Reference in New Issue
Block a user