ESPHome 2026.8.0-dev
Loading...
Searching...
No Matches
provisioning.cpp
Go to the documentation of this file.
2#ifdef USE_PROVISIONING
4#include "esphome/core/log.h"
5#ifdef USE_NETWORK
7#endif
8
9#include <cinttypes>
10
12
13static const char *const TAG = "provisioning";
14
15ProvisioningManager *global_provisioning_manager = // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
16 nullptr;
17
20#ifdef USE_NETWORK
21 // Network connectivity is a built-in provisioning source. Registered here rather
22 // than from a source's setup() because connectivity is universal, not a pluggable
23 // transport; loop() latches it provisioned once the device has connected.
24 this->network_source_ = this->register_source();
25#endif
26}
27
29 if (this->source_count_ >= MAX_SOURCES) {
30 // Defensive: only a handful of sources exist in practice. Fail loudly rather
31 // than shifting past the mask width (undefined behavior). The returned index is
32 // ignored by set_source_provisioned()'s bounds check.
33 ESP_LOGE(TAG, "Too many provisioning sources (max %u)", MAX_SOURCES);
34 return this->source_count_;
35 }
36 uint8_t source = this->source_count_++;
37 this->registered_mask_ |= (1UL << source);
38 return source;
39}
40
42 // Sources register during their own setup() (at various priorities), and this
43 // loop() also runs while waiting on a slow component during setup. Evaluating the
44 // provisioning state before every source has registered could conclude
45 // "provisioned" prematurely and disable_loop() for good, defeating the window --
46 // so do nothing until all setup() calls are done.
48 return;
49
50#ifdef USE_NETWORK
51 // Latch the built-in connectivity source once the device has been reachable via
52 // any interface. network::is_connected() aggregates wifi/ethernet/modem/... (OR
53 // across interfaces), and a disabled interface never connects so it never
54 // contributes. Latched: a later link drop does not un-provision -- the RAM-only
55 // window still reopens only on reboot.
56 if ((this->provisioned_mask_ & (1UL << this->network_source_)) == 0 && network::is_connected())
57 this->set_source_provisioned(this->network_source_, true);
58#endif
59
60 // The window is resolved once the device is provisioned or the window has closed;
61 // there is nothing left to track, so stop running entirely. Config validation
62 // guarantees at least one source, so is_provisioned() is never vacuously true here.
63 if (this->closed_ || this->is_provisioned()) {
64 this->disable_loop();
65 return;
66 }
67 // The window timer runs from boot (millis since boot). The closed state is not
68 // persisted, so a reboot reopens the window.
69 if (this->timeout_ != 0 && App.get_loop_component_start_time() > this->timeout_) {
70 this->close_window_();
71 }
72}
73
75 this->closed_ = true;
76 ESP_LOGW(TAG, "Window expired; cycle power to reopen window");
77 // Notify internal consumers first (transports disconnect clients, Improv stops),
78 // then fire the user-facing automation.
79 this->closed_callback_.call();
81}
82
84 ESP_LOGCONFIG(TAG,
85 "Provisioning:\n"
86 " Timeout: %" PRIu32 "ms\n"
87 " Provisioned: %s",
88 this->timeout_, YESNO(this->is_provisioned()));
89}
90
91} // namespace esphome::provisioning
92#endif // USE_PROVISIONING
bool is_setup_complete() const
True once Application::setup() has finished walking all components and finalized the initial status f...
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
void disable_loop()
Disable this component's loop.
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Inform the parent automation that the event has triggered.
Definition automation.h:461
LazyCallbackManager< void()> closed_callback_
void set_source_provisioned(uint8_t source, bool provisioned)
ESPHOME_ALWAYS_INLINE bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
Definition util.h:28
ProvisioningManager * global_provisioning_manager
Application App
Global storage of Application pointer - only one Application can exist.