mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	[esp32_improv] Add triggers for various states (#7461)
Co-authored-by: NP v/d Spek <github_mail@lumensoft.nl>
This commit is contained in:
		| @@ -1,7 +1,8 @@ | |||||||
|  | from esphome import automation | ||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| from esphome.components import binary_sensor, esp32_ble_server, output | from esphome.components import binary_sensor, esp32_ble_server, output | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.const import CONF_ID | from esphome.const import CONF_ID, CONF_ON_STATE, CONF_TRIGGER_ID | ||||||
|  |  | ||||||
| AUTO_LOAD = ["esp32_ble_server"] | AUTO_LOAD = ["esp32_ble_server"] | ||||||
| CODEOWNERS = ["@jesserockz"] | CODEOWNERS = ["@jesserockz"] | ||||||
| @@ -11,13 +12,36 @@ CONF_AUTHORIZED_DURATION = "authorized_duration" | |||||||
| CONF_AUTHORIZER = "authorizer" | CONF_AUTHORIZER = "authorizer" | ||||||
| CONF_BLE_SERVER_ID = "ble_server_id" | CONF_BLE_SERVER_ID = "ble_server_id" | ||||||
| CONF_IDENTIFY_DURATION = "identify_duration" | CONF_IDENTIFY_DURATION = "identify_duration" | ||||||
|  | CONF_ON_PROVISIONED = "on_provisioned" | ||||||
|  | CONF_ON_PROVISIONING = "on_provisioning" | ||||||
|  | CONF_ON_START = "on_start" | ||||||
|  | CONF_ON_STOP = "on_stop" | ||||||
| CONF_STATUS_INDICATOR = "status_indicator" | CONF_STATUS_INDICATOR = "status_indicator" | ||||||
| CONF_WIFI_TIMEOUT = "wifi_timeout" | CONF_WIFI_TIMEOUT = "wifi_timeout" | ||||||
|  |  | ||||||
|  | improv_ns = cg.esphome_ns.namespace("improv") | ||||||
|  | Error = improv_ns.enum("Error") | ||||||
|  | State = improv_ns.enum("State") | ||||||
|  |  | ||||||
| esp32_improv_ns = cg.esphome_ns.namespace("esp32_improv") | esp32_improv_ns = cg.esphome_ns.namespace("esp32_improv") | ||||||
| ESP32ImprovComponent = esp32_improv_ns.class_( | ESP32ImprovComponent = esp32_improv_ns.class_( | ||||||
|     "ESP32ImprovComponent", cg.Component, esp32_ble_server.BLEServiceComponent |     "ESP32ImprovComponent", cg.Component, esp32_ble_server.BLEServiceComponent | ||||||
| ) | ) | ||||||
|  | ESP32ImprovProvisionedTrigger = esp32_improv_ns.class_( | ||||||
|  |     "ESP32ImprovProvisionedTrigger", automation.Trigger.template() | ||||||
|  | ) | ||||||
|  | ESP32ImprovProvisioningTrigger = esp32_improv_ns.class_( | ||||||
|  |     "ESP32ImprovProvisioningTrigger", automation.Trigger.template() | ||||||
|  | ) | ||||||
|  | ESP32ImprovStartTrigger = esp32_improv_ns.class_( | ||||||
|  |     "ESP32ImprovStartTrigger", automation.Trigger.template() | ||||||
|  | ) | ||||||
|  | ESP32ImprovStateTrigger = esp32_improv_ns.class_( | ||||||
|  |     "ESP32ImprovStateTrigger", automation.Trigger.template() | ||||||
|  | ) | ||||||
|  | ESP32ImprovStoppedTrigger = esp32_improv_ns.class_( | ||||||
|  |     "ESP32ImprovStoppedTrigger", automation.Trigger.template() | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.Schema( | CONFIG_SCHEMA = cv.Schema( | ||||||
| @@ -37,6 +61,37 @@ CONFIG_SCHEMA = cv.Schema( | |||||||
|         cv.Optional( |         cv.Optional( | ||||||
|             CONF_WIFI_TIMEOUT, default="1min" |             CONF_WIFI_TIMEOUT, default="1min" | ||||||
|         ): cv.positive_time_period_milliseconds, |         ): cv.positive_time_period_milliseconds, | ||||||
|  |         cv.Optional(CONF_ON_PROVISIONED): automation.validate_automation( | ||||||
|  |             { | ||||||
|  |                 cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( | ||||||
|  |                     ESP32ImprovProvisionedTrigger | ||||||
|  |                 ), | ||||||
|  |             } | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_ON_PROVISIONING): automation.validate_automation( | ||||||
|  |             { | ||||||
|  |                 cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( | ||||||
|  |                     ESP32ImprovProvisioningTrigger | ||||||
|  |                 ), | ||||||
|  |             } | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_ON_START): automation.validate_automation( | ||||||
|  |             { | ||||||
|  |                 cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESP32ImprovStartTrigger), | ||||||
|  |             } | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_ON_STATE): automation.validate_automation( | ||||||
|  |             { | ||||||
|  |                 cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESP32ImprovStateTrigger), | ||||||
|  |             } | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_ON_STOP): automation.validate_automation( | ||||||
|  |             { | ||||||
|  |                 cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id( | ||||||
|  |                     ESP32ImprovStoppedTrigger | ||||||
|  |                 ), | ||||||
|  |             } | ||||||
|  |         ), | ||||||
|     } |     } | ||||||
| ).extend(cv.COMPONENT_SCHEMA) | ).extend(cv.COMPONENT_SCHEMA) | ||||||
|  |  | ||||||
| @@ -63,3 +118,29 @@ async def to_code(config): | |||||||
|     if CONF_STATUS_INDICATOR in config: |     if CONF_STATUS_INDICATOR in config: | ||||||
|         status_indicator = await cg.get_variable(config[CONF_STATUS_INDICATOR]) |         status_indicator = await cg.get_variable(config[CONF_STATUS_INDICATOR]) | ||||||
|         cg.add(var.set_status_indicator(status_indicator)) |         cg.add(var.set_status_indicator(status_indicator)) | ||||||
|  |  | ||||||
|  |     use_state_callback = False | ||||||
|  |     for conf in config.get(CONF_ON_PROVISIONED, []): | ||||||
|  |         trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) | ||||||
|  |         await automation.build_automation(trigger, [], conf) | ||||||
|  |         use_state_callback = True | ||||||
|  |     for conf in config.get(CONF_ON_PROVISIONING, []): | ||||||
|  |         trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) | ||||||
|  |         await automation.build_automation(trigger, [], conf) | ||||||
|  |         use_state_callback = True | ||||||
|  |     for conf in config.get(CONF_ON_START, []): | ||||||
|  |         trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) | ||||||
|  |         await automation.build_automation(trigger, [], conf) | ||||||
|  |         use_state_callback = True | ||||||
|  |     for conf in config.get(CONF_ON_STATE, []): | ||||||
|  |         trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) | ||||||
|  |         await automation.build_automation( | ||||||
|  |             trigger, [(State, "state"), (Error, "error")], conf | ||||||
|  |         ) | ||||||
|  |         use_state_callback = True | ||||||
|  |     for conf in config.get(CONF_ON_STOP, []): | ||||||
|  |         trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) | ||||||
|  |         await automation.build_automation(trigger, [], conf) | ||||||
|  |         use_state_callback = True | ||||||
|  |     if use_state_callback: | ||||||
|  |         cg.add_define("USE_ESP32_IMPROV_STATE_CALLBACK") | ||||||
|   | |||||||
							
								
								
									
										72
									
								
								esphome/components/esp32_improv/automation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								esphome/components/esp32_improv/automation.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | #pragma once | ||||||
|  | #ifdef USE_ESP32 | ||||||
|  | #ifdef USE_ESP32_IMPROV_STATE_CALLBACK | ||||||
|  | #include "esp32_improv_component.h" | ||||||
|  |  | ||||||
|  | #include "esphome/core/automation.h" | ||||||
|  |  | ||||||
|  | #include <improv.h> | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace esp32_improv { | ||||||
|  |  | ||||||
|  | class ESP32ImprovProvisionedTrigger : public Trigger<> { | ||||||
|  |  public: | ||||||
|  |   explicit ESP32ImprovProvisionedTrigger(ESP32ImprovComponent *parent) { | ||||||
|  |     parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) { | ||||||
|  |       if (state == improv::STATE_PROVISIONED && !parent->is_failed()) { | ||||||
|  |         trigger(); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class ESP32ImprovProvisioningTrigger : public Trigger<> { | ||||||
|  |  public: | ||||||
|  |   explicit ESP32ImprovProvisioningTrigger(ESP32ImprovComponent *parent) { | ||||||
|  |     parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) { | ||||||
|  |       if (state == improv::STATE_PROVISIONING && !parent->is_failed()) { | ||||||
|  |         trigger(); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class ESP32ImprovStartTrigger : public Trigger<> { | ||||||
|  |  public: | ||||||
|  |   explicit ESP32ImprovStartTrigger(ESP32ImprovComponent *parent) { | ||||||
|  |     parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) { | ||||||
|  |       if ((state == improv::STATE_AUTHORIZED || state == improv::STATE_AWAITING_AUTHORIZATION) && | ||||||
|  |           !parent->is_failed()) { | ||||||
|  |         trigger(); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class ESP32ImprovStateTrigger : public Trigger<improv::State, improv::Error> { | ||||||
|  |  public: | ||||||
|  |   explicit ESP32ImprovStateTrigger(ESP32ImprovComponent *parent) { | ||||||
|  |     parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) { | ||||||
|  |       if (!parent->is_failed()) { | ||||||
|  |         trigger(state, error); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class ESP32ImprovStoppedTrigger : public Trigger<> { | ||||||
|  |  public: | ||||||
|  |   explicit ESP32ImprovStoppedTrigger(ESP32ImprovComponent *parent) { | ||||||
|  |     parent->add_on_state_callback([this, parent](improv::State state, improv::Error error) { | ||||||
|  |       if (state == improv::STATE_STOPPED && !parent->is_failed()) { | ||||||
|  |         trigger(); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace esp32_improv | ||||||
|  | }  // namespace esphome | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
| @@ -68,7 +68,12 @@ void ESP32ImprovComponent::setup_characteristics() { | |||||||
|  |  | ||||||
| void ESP32ImprovComponent::loop() { | void ESP32ImprovComponent::loop() { | ||||||
|   if (!global_ble_server->is_running()) { |   if (!global_ble_server->is_running()) { | ||||||
|  |     if (this->state_ != improv::STATE_STOPPED) { | ||||||
|       this->state_ = improv::STATE_STOPPED; |       this->state_ = improv::STATE_STOPPED; | ||||||
|  | #ifdef USE_ESP32_IMPROV_STATE_CALLBACK | ||||||
|  |       this->state_callback_.call(this->state_, this->error_state_); | ||||||
|  | #endif | ||||||
|  |     } | ||||||
|     this->incoming_data_.clear(); |     this->incoming_data_.clear(); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| @@ -217,6 +222,9 @@ void ESP32ImprovComponent::set_state_(improv::State state) { | |||||||
|   service_data[7] = 0x00;  // Reserved |   service_data[7] = 0x00;  // Reserved | ||||||
|  |  | ||||||
|   esp32_ble::global_ble->advertising_set_service_data(service_data); |   esp32_ble::global_ble->advertising_set_service_data(service_data); | ||||||
|  | #ifdef USE_ESP32_IMPROV_STATE_CALLBACK | ||||||
|  |   this->state_callback_.call(this->state_, this->error_state_); | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| void ESP32ImprovComponent::set_error_(improv::Error error) { | void ESP32ImprovComponent::set_error_(improv::Error error) { | ||||||
| @@ -270,7 +278,7 @@ void ESP32ImprovComponent::dump_config() { | |||||||
| void ESP32ImprovComponent::process_incoming_data_() { | void ESP32ImprovComponent::process_incoming_data_() { | ||||||
|   uint8_t length = this->incoming_data_[1]; |   uint8_t length = this->incoming_data_[1]; | ||||||
|  |  | ||||||
|   ESP_LOGD(TAG, "Processing bytes - %s", format_hex_pretty(this->incoming_data_).c_str()); |   ESP_LOGV(TAG, "Processing bytes - %s", format_hex_pretty(this->incoming_data_).c_str()); | ||||||
|   if (this->incoming_data_.size() - 3 == length) { |   if (this->incoming_data_.size() - 3 == length) { | ||||||
|     this->set_error_(improv::ERROR_NONE); |     this->set_error_(improv::ERROR_NONE); | ||||||
|     improv::ImprovCommand command = improv::parse_improv_data(this->incoming_data_); |     improv::ImprovCommand command = improv::parse_improv_data(this->incoming_data_); | ||||||
| @@ -295,7 +303,7 @@ void ESP32ImprovComponent::process_incoming_data_() { | |||||||
|         wifi::global_wifi_component->set_sta(sta); |         wifi::global_wifi_component->set_sta(sta); | ||||||
|         wifi::global_wifi_component->start_connecting(sta, false); |         wifi::global_wifi_component->start_connecting(sta, false); | ||||||
|         this->set_state_(improv::STATE_PROVISIONING); |         this->set_state_(improv::STATE_PROVISIONING); | ||||||
|         ESP_LOGD(TAG, "Received Improv wifi settings ssid=%s, password=" LOG_SECRET("%s"), command.ssid.c_str(), |         ESP_LOGD(TAG, "Received Improv Wi-Fi settings ssid=%s, password=" LOG_SECRET("%s"), command.ssid.c_str(), | ||||||
|                  command.password.c_str()); |                  command.password.c_str()); | ||||||
|  |  | ||||||
|         auto f = std::bind(&ESP32ImprovComponent::on_wifi_connect_timeout_, this); |         auto f = std::bind(&ESP32ImprovComponent::on_wifi_connect_timeout_, this); | ||||||
| @@ -313,7 +321,7 @@ void ESP32ImprovComponent::process_incoming_data_() { | |||||||
|         this->incoming_data_.clear(); |         this->incoming_data_.clear(); | ||||||
|     } |     } | ||||||
|   } else if (this->incoming_data_.size() - 2 > length) { |   } else if (this->incoming_data_.size() - 2 > length) { | ||||||
|     ESP_LOGV(TAG, "Too much data came in, or malformed resetting buffer..."); |     ESP_LOGV(TAG, "Too much data received or data malformed; resetting buffer..."); | ||||||
|     this->incoming_data_.clear(); |     this->incoming_data_.clear(); | ||||||
|   } else { |   } else { | ||||||
|     ESP_LOGV(TAG, "Waiting for split data packets..."); |     ESP_LOGV(TAG, "Waiting for split data packets..."); | ||||||
| @@ -327,7 +335,7 @@ void ESP32ImprovComponent::on_wifi_connect_timeout_() { | |||||||
|   if (this->authorizer_ != nullptr) |   if (this->authorizer_ != nullptr) | ||||||
|     this->authorized_start_ = millis(); |     this->authorized_start_ = millis(); | ||||||
| #endif | #endif | ||||||
|   ESP_LOGW(TAG, "Timed out trying to connect to given WiFi network"); |   ESP_LOGW(TAG, "Timed out while connecting to Wi-Fi network"); | ||||||
|   wifi::global_wifi_component->clear_sta(); |   wifi::global_wifi_component->clear_sta(); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,6 +9,10 @@ | |||||||
| #include "esphome/components/esp32_ble_server/ble_server.h" | #include "esphome/components/esp32_ble_server/ble_server.h" | ||||||
| #include "esphome/components/wifi/wifi_component.h" | #include "esphome/components/wifi/wifi_component.h" | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP32_IMPROV_STATE_CALLBACK | ||||||
|  | #include "esphome/core/automation.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #ifdef USE_BINARY_SENSOR | #ifdef USE_BINARY_SENSOR | ||||||
| #include "esphome/components/binary_sensor/binary_sensor.h" | #include "esphome/components/binary_sensor/binary_sensor.h" | ||||||
| #endif | #endif | ||||||
| @@ -42,6 +46,11 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { | |||||||
|   void stop() override; |   void stop() override; | ||||||
|   bool is_active() const { return this->state_ != improv::STATE_STOPPED; } |   bool is_active() const { return this->state_ != improv::STATE_STOPPED; } | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP32_IMPROV_STATE_CALLBACK | ||||||
|  |   void add_on_state_callback(std::function<void(improv::State, improv::Error)> &&callback) { | ||||||
|  |     this->state_callback_.add(std::move(callback)); | ||||||
|  |   } | ||||||
|  | #endif | ||||||
| #ifdef USE_BINARY_SENSOR | #ifdef USE_BINARY_SENSOR | ||||||
|   void set_authorizer(binary_sensor::BinarySensor *authorizer) { this->authorizer_ = authorizer; } |   void set_authorizer(binary_sensor::BinarySensor *authorizer) { this->authorizer_ = authorizer; } | ||||||
| #endif | #endif | ||||||
| @@ -54,6 +63,9 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { | |||||||
|   void set_wifi_timeout(uint32_t wifi_timeout) { this->wifi_timeout_ = wifi_timeout; } |   void set_wifi_timeout(uint32_t wifi_timeout) { this->wifi_timeout_ = wifi_timeout; } | ||||||
|   uint32_t get_wifi_timeout() const { return this->wifi_timeout_; } |   uint32_t get_wifi_timeout() const { return this->wifi_timeout_; } | ||||||
|  |  | ||||||
|  |   improv::State get_improv_state() const { return this->state_; } | ||||||
|  |   improv::Error get_improv_error_state() const { return this->error_state_; } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   bool should_start_{false}; |   bool should_start_{false}; | ||||||
|   bool setup_complete_{false}; |   bool setup_complete_{false}; | ||||||
| @@ -84,6 +96,9 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { | |||||||
|  |  | ||||||
|   improv::State state_{improv::STATE_STOPPED}; |   improv::State state_{improv::STATE_STOPPED}; | ||||||
|   improv::Error error_state_{improv::ERROR_NONE}; |   improv::Error error_state_{improv::ERROR_NONE}; | ||||||
|  | #ifdef USE_ESP32_IMPROV_STATE_CALLBACK | ||||||
|  |   CallbackManager<void(improv::State, improv::Error)> state_callback_{}; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|   bool status_indicator_state_{false}; |   bool status_indicator_state_{false}; | ||||||
|   void set_status_indicator_state_(bool state); |   void set_status_indicator_state_(bool state); | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ | |||||||
| #define USE_DATETIME_TIME | #define USE_DATETIME_TIME | ||||||
| #define USE_DEEP_SLEEP | #define USE_DEEP_SLEEP | ||||||
| #define USE_DISPLAY | #define USE_DISPLAY | ||||||
|  | #define USE_ESP32_IMPROV_STATE_CALLBACK | ||||||
| #define USE_EVENT | #define USE_EVENT | ||||||
| #define USE_FAN | #define USE_FAN | ||||||
| #define USE_GRAPH | #define USE_GRAPH | ||||||
| @@ -45,10 +46,10 @@ | |||||||
| #define USE_LVGL_BUTTONMATRIX | #define USE_LVGL_BUTTONMATRIX | ||||||
| #define USE_LVGL_FONT | #define USE_LVGL_FONT | ||||||
| #define USE_LVGL_IMAGE | #define USE_LVGL_IMAGE | ||||||
| #define USE_LVGL_KEYBOARD |  | ||||||
| #define USE_LVGL_KEY_LISTENER | #define USE_LVGL_KEY_LISTENER | ||||||
| #define USE_LVGL_TOUCHSCREEN | #define USE_LVGL_KEYBOARD | ||||||
| #define USE_LVGL_ROTARY_ENCODER | #define USE_LVGL_ROTARY_ENCODER | ||||||
|  | #define USE_LVGL_TOUCHSCREEN | ||||||
| #define USE_MDNS | #define USE_MDNS | ||||||
| #define USE_MEDIA_PLAYER | #define USE_MEDIA_PLAYER | ||||||
| #define USE_MQTT | #define USE_MQTT | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user