mirror of
https://github.com/esphome/esphome.git
synced 2024-11-25 00:18:11 +01: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:
parent
af612add24
commit
402a6a9edb
5 changed files with 185 additions and 8 deletions
|
@ -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()) {
|
||||
this->state_ = improv::STATE_STOPPED;
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue