#pragma once #include "esphome/core/defines.h" #ifdef USE_OPENTHREAD #include "esphome/components/mdns/mdns_component.h" #include "esphome/components/network/ip_address.h" #include "esphome/core/component.h" #include #include #include #include #include #include #include namespace esphome::openthread { class InstanceLock; class OpenThreadComponent : public Component { public: OpenThreadComponent(); ~OpenThreadComponent(); void dump_config() override; void setup() override; bool teardown() override; float get_setup_priority() const override { return setup_priority::WIFI; } bool is_connected() const { return this->connected_; } /// Returns true once esp_openthread_init() has completed and the OT lock is usable. bool is_lock_initialized() const { return this->lock_initialized_; } network::IPAddresses get_ip_addresses(); std::optional get_omr_address(); void ot_main(); void on_factory_reset(std::function callback); void defer_factory_reset_external_callback(); const char *get_use_address() const { return this->use_address_; } void set_use_address(const char *use_address) { this->use_address_ = use_address; } #if CONFIG_OPENTHREAD_MTD void set_poll_period(uint32_t poll_period) { this->poll_period_ = poll_period; } #endif void set_output_power(int8_t output_power) { this->output_power_ = output_power; } protected: std::optional get_omr_address_(InstanceLock &lock); static void on_state_changed_(otChangedFlags flags, void *context); otInstance *get_openthread_instance_(); int openthread_stop_(); std::function factory_reset_external_callback_; #if CONFIG_OPENTHREAD_MTD uint32_t poll_period_{0}; #endif std::optional output_power_{}; std::atomic lock_initialized_{false}; bool teardown_started_{false}; bool teardown_complete_{false}; bool connected_{false}; private: // Stores a pointer to a string literal (static storage duration). // ONLY set from Python-generated code with string literals - never dynamic strings. const char *use_address_{""}; }; extern OpenThreadComponent *global_openthread_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) class OpenThreadSrpComponent : public Component { public: void set_mdns(esphome::mdns::MDNSComponent *mdns); // This has to run after the mdns component or else no services are available to advertise float get_setup_priority() const override { return this->mdns_->get_setup_priority() - 1.0; } void setup() override; static void srp_callback(otError err, const otSrpClientHostInfo *host_info, const otSrpClientService *services, const otSrpClientService *removed_services, void *context); static void srp_start_callback(const otSockAddr *server_socket_address, void *context); static void srp_factory_reset_callback(otError err, const otSrpClientHostInfo *host_info, const otSrpClientService *services, const otSrpClientService *removed_services, void *context); protected: esphome::mdns::MDNSComponent *mdns_{nullptr}; std::vector> memory_pool_; void *pool_alloc_(size_t size); }; class InstanceLock { public: static std::optional try_acquire(int delay); static InstanceLock acquire(); ~InstanceLock(); // Returns the global openthread instance guarded by this lock otInstance *get_instance(); private: // Use a private constructor in order to force the handling // of acquisition failure InstanceLock() {} }; } // namespace esphome::openthread #endif