mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +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 | ||||
| from esphome.components import binary_sensor, esp32_ble_server, output | ||||
| 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"] | ||||
| CODEOWNERS = ["@jesserockz"] | ||||
| @@ -11,13 +12,36 @@ CONF_AUTHORIZED_DURATION = "authorized_duration" | ||||
| CONF_AUTHORIZER = "authorizer" | ||||
| CONF_BLE_SERVER_ID = "ble_server_id" | ||||
| 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_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") | ||||
| ESP32ImprovComponent = esp32_improv_ns.class_( | ||||
|     "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( | ||||
| @@ -37,6 +61,37 @@ CONFIG_SCHEMA = cv.Schema( | ||||
|         cv.Optional( | ||||
|             CONF_WIFI_TIMEOUT, default="1min" | ||||
|         ): 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) | ||||
|  | ||||
| @@ -63,3 +118,29 @@ async def to_code(config): | ||||
|     if CONF_STATUS_INDICATOR in config: | ||||
|         status_indicator = await cg.get_variable(config[CONF_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() { | ||||
|   if (!global_ble_server->is_running()) { | ||||
|     if (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(); | ||||
|     return; | ||||
|   } | ||||
| @@ -217,6 +222,9 @@ void ESP32ImprovComponent::set_state_(improv::State state) { | ||||
|   service_data[7] = 0x00;  // Reserved | ||||
|  | ||||
|   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) { | ||||
| @@ -270,7 +278,7 @@ void ESP32ImprovComponent::dump_config() { | ||||
| void ESP32ImprovComponent::process_incoming_data_() { | ||||
|   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) { | ||||
|     this->set_error_(improv::ERROR_NONE); | ||||
|     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->start_connecting(sta, false); | ||||
|         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()); | ||||
|  | ||||
|         auto f = std::bind(&ESP32ImprovComponent::on_wifi_connect_timeout_, this); | ||||
| @@ -313,7 +321,7 @@ void ESP32ImprovComponent::process_incoming_data_() { | ||||
|         this->incoming_data_.clear(); | ||||
|     } | ||||
|   } 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(); | ||||
|   } else { | ||||
|     ESP_LOGV(TAG, "Waiting for split data packets..."); | ||||
| @@ -327,7 +335,7 @@ void ESP32ImprovComponent::on_wifi_connect_timeout_() { | ||||
|   if (this->authorizer_ != nullptr) | ||||
|     this->authorized_start_ = millis(); | ||||
| #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(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -9,6 +9,10 @@ | ||||
| #include "esphome/components/esp32_ble_server/ble_server.h" | ||||
| #include "esphome/components/wifi/wifi_component.h" | ||||
|  | ||||
| #ifdef USE_ESP32_IMPROV_STATE_CALLBACK | ||||
| #include "esphome/core/automation.h" | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_BINARY_SENSOR | ||||
| #include "esphome/components/binary_sensor/binary_sensor.h" | ||||
| #endif | ||||
| @@ -42,6 +46,11 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { | ||||
|   void stop() override; | ||||
|   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 | ||||
|   void set_authorizer(binary_sensor::BinarySensor *authorizer) { this->authorizer_ = authorizer; } | ||||
| #endif | ||||
| @@ -54,6 +63,9 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { | ||||
|   void set_wifi_timeout(uint32_t wifi_timeout) { this->wifi_timeout_ = 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: | ||||
|   bool should_start_{false}; | ||||
|   bool setup_complete_{false}; | ||||
| @@ -84,6 +96,9 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent { | ||||
|  | ||||
|   improv::State state_{improv::STATE_STOPPED}; | ||||
|   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}; | ||||
|   void set_status_indicator_state_(bool state); | ||||
|   | ||||
| @@ -29,6 +29,7 @@ | ||||
| #define USE_DATETIME_TIME | ||||
| #define USE_DEEP_SLEEP | ||||
| #define USE_DISPLAY | ||||
| #define USE_ESP32_IMPROV_STATE_CALLBACK | ||||
| #define USE_EVENT | ||||
| #define USE_FAN | ||||
| #define USE_GRAPH | ||||
| @@ -45,10 +46,10 @@ | ||||
| #define USE_LVGL_BUTTONMATRIX | ||||
| #define USE_LVGL_FONT | ||||
| #define USE_LVGL_IMAGE | ||||
| #define USE_LVGL_KEYBOARD | ||||
| #define USE_LVGL_KEY_LISTENER | ||||
| #define USE_LVGL_TOUCHSCREEN | ||||
| #define USE_LVGL_KEYBOARD | ||||
| #define USE_LVGL_ROTARY_ENCODER | ||||
| #define USE_LVGL_TOUCHSCREEN | ||||
| #define USE_MDNS | ||||
| #define USE_MEDIA_PLAYER | ||||
| #define USE_MQTT | ||||
|   | ||||
		Reference in New Issue
	
	Block a user