diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index c9da07795c..068d015732 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -53,6 +53,9 @@ WIFI_POWER_SAVE_MODES = { "HIGH": WiFiPowerSaveMode.WIFI_POWER_SAVE_HIGH, } WiFiConnectedCondition = wifi_ns.class_("WiFiConnectedCondition", Condition) +WiFiEnabledCondition = wifi_ns.class_("WiFiEnabledCondition", Condition) +WiFiEnableAction = wifi_ns.class_("WiFiEnableAction", automation.Action) +WiFiDisableAction = wifi_ns.class_("WiFiDisableAction", automation.Action) def validate_password(value): @@ -253,6 +256,7 @@ def _validate(config): CONF_OUTPUT_POWER = "output_power" CONF_PASSIVE_SCAN = "passive_scan" +CONF_ENABLE_ON_BOOT = "enable_on_boot" CONFIG_SCHEMA = cv.All( cv.Schema( { @@ -286,6 +290,7 @@ CONFIG_SCHEMA = cv.All( "This option has been removed. Please use the [disabled] option under the " "new mdns component instead." ), + cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean, } ), _validate, @@ -385,6 +390,8 @@ async def to_code(config): if CONF_OUTPUT_POWER in config: cg.add(var.set_output_power(config[CONF_OUTPUT_POWER])) + cg.add(var.set_enable_on_boot(config[CONF_ENABLE_ON_BOOT])) + if CORE.is_esp8266: cg.add_library("ESP8266WiFi", None) elif CORE.is_esp32 and CORE.using_arduino: @@ -410,3 +417,18 @@ async def to_code(config): @automation.register_condition("wifi.connected", WiFiConnectedCondition, cv.Schema({})) async def wifi_connected_to_code(config, condition_id, template_arg, args): return cg.new_Pvariable(condition_id, template_arg) + + +@automation.register_condition("wifi.enabled", WiFiEnabledCondition, cv.Schema({})) +async def wifi_enabled_to_code(config, condition_id, template_arg, args): + return cg.new_Pvariable(condition_id, template_arg) + + +@automation.register_action("wifi.enable", WiFiEnableAction, cv.Schema({})) +async def wifi_enable_to_code(config, action_id, template_arg, args): + return cg.new_Pvariable(action_id, template_arg) + + +@automation.register_action("wifi.disable", WiFiDisableAction, cv.Schema({})) +async def wifi_disable_to_code(config, action_id, template_arg, args): + return cg.new_Pvariable(action_id, template_arg) diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index db19f9bcc0..ff621291f0 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -36,9 +36,18 @@ float WiFiComponent::get_setup_priority() const { return setup_priority::WIFI; } void WiFiComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up WiFi..."); + this->wifi_pre_setup_(); + if (this->enable_on_boot_) { + this->start(); + } else { + this->state_ = WIFI_COMPONENT_STATE_DISABLED; + } +} + +void WiFiComponent::start() { + ESP_LOGCONFIG(TAG, "Starting WiFi..."); ESP_LOGCONFIG(TAG, " Local MAC: %s", get_mac_address_pretty().c_str()); this->last_connected_ = millis(); - this->wifi_pre_setup_(); uint32_t hash = this->has_sta() ? fnv1_hash(App.get_compilation_time()) : 88491487UL; @@ -135,6 +144,8 @@ void WiFiComponent::loop() { case WIFI_COMPONENT_STATE_OFF: case WIFI_COMPONENT_STATE_AP: break; + case WIFI_COMPONENT_STATE_DISABLED: + return; } if (this->has_ap() && !this->ap_setup_) { @@ -387,6 +398,28 @@ void WiFiComponent::print_connect_params_() { #endif } +void WiFiComponent::enable() { + if (this->state_ != WIFI_COMPONENT_STATE_DISABLED) + return; + + ESP_LOGD(TAG, "Enabling WIFI..."); + this->error_from_callback_ = false; + this->state_ = WIFI_COMPONENT_STATE_OFF; + this->start(); +} + +void WiFiComponent::disable() { + if (this->state_ == WIFI_COMPONENT_STATE_DISABLED) + return; + + ESP_LOGD(TAG, "Disabling WIFI..."); + this->state_ = WIFI_COMPONENT_STATE_DISABLED; + this->wifi_disconnect_(); + this->wifi_mode_(false, false); +} + +bool WiFiComponent::is_disabled() { return this->state_ == WIFI_COMPONENT_STATE_DISABLED; } + void WiFiComponent::start_scanning() { this->action_started_ = millis(); ESP_LOGD(TAG, "Starting scan..."); @@ -608,7 +641,7 @@ void WiFiComponent::retry_connect() { } bool WiFiComponent::can_proceed() { - if (!this->has_sta()) { + if (!this->has_sta() || this->state_ == WIFI_COMPONENT_STATE_DISABLED) { return true; } return this->is_connected(); diff --git a/esphome/components/wifi/wifi_component.h b/esphome/components/wifi/wifi_component.h index d42be43b2d..d39b062990 100644 --- a/esphome/components/wifi/wifi_component.h +++ b/esphome/components/wifi/wifi_component.h @@ -47,6 +47,8 @@ struct SavedWifiSettings { enum WiFiComponentState { /** Nothing has been initialized yet. Internal AP, if configured, is disabled at this point. */ WIFI_COMPONENT_STATE_OFF = 0, + /** WiFi is disabled. */ + WIFI_COMPONENT_STATE_DISABLED, /** WiFi is in cooldown mode because something went wrong, scanning will begin after a short period of time. */ WIFI_COMPONENT_STATE_COOLDOWN, /** WiFi is in STA-only mode and currently scanning for APs. */ @@ -198,6 +200,9 @@ class WiFiComponent : public Component { void set_ap(const WiFiAP &ap); WiFiAP get_ap() { return this->ap_; } + void enable(); + void disable(); + bool is_disabled(); void start_scanning(); void check_scanning_finished(); void start_connecting(const WiFiAP &ap, bool two); @@ -224,6 +229,7 @@ class WiFiComponent : public Component { // (In most use cases you won't need these) /// Setup WiFi interface. void setup() override; + void start(); void dump_config() override; /// WIFI setup_priority. float get_setup_priority() const override; @@ -282,6 +288,8 @@ class WiFiComponent : public Component { int8_t wifi_rssi(); + void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; } + protected: static std::string format_mac_addr(const uint8_t mac[6]); void setup_ap_config_(); @@ -359,18 +367,30 @@ class WiFiComponent : public Component { bool btm_{false}; bool rrm_{false}; #endif + bool enable_on_boot_; }; extern WiFiComponent *global_wifi_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) template class WiFiConnectedCondition : public Condition { public: - bool check(Ts... x) override; + bool check(Ts... x) override { return global_wifi_component->is_connected(); } }; -template bool WiFiConnectedCondition::check(Ts... x) { - return global_wifi_component->is_connected(); -} +template class WiFiEnabledCondition : public Condition { + public: + bool check(Ts... x) override { return !global_wifi_component->is_disabled(); } +}; + +template class WiFiEnableAction : public Action { + public: + void play(Ts... x) override { global_wifi_component->enable(); } +}; + +template class WiFiDisableAction : public Action { + public: + void play(Ts... x) override { global_wifi_component->disable(); } +}; } // namespace wifi } // namespace esphome