This commit is contained in:
vinhpn96 2024-05-02 15:46:55 +12:00 committed by GitHub
commit 35cf2fa1fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 304 additions and 1 deletions

View File

@ -323,6 +323,7 @@ esphome/components/sm10bit_base/* @Cossid
esphome/components/sm2135/* @BoukeHaarsma23 @dd32 @matika77
esphome/components/sm2235/* @Cossid
esphome/components/sm2335/* @Cossid
esphome/components/smartconfig/* @vinhpn96
esphome/components/sml/* @alengwenus
esphome/components/smt100/* @piechade
esphome/components/sn74hc165/* @jesserockz

View File

@ -0,0 +1,36 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
from esphome.const import CONF_ID, CONF_TRIGGER_ID
CODEOWNERS = ["@vinhpn96"]
DEPENDENCIES = ["wifi"]
CONF_ON_READY = "on_ready"
smartconfig_ns = cg.esphome_ns.namespace("smartconfig")
SmartConfigComponent = smartconfig_ns.class_("SmartConfigComponent", cg.Component)
SmartConfigReadyTrigger = smartconfig_ns.class_(
"SmartConfigReadyTrigger", automation.Trigger.template()
)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(SmartConfigComponent),
cv.Optional(CONF_ON_READY): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SmartConfigReadyTrigger),
}
),
}
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
cg.add_define("USE_SMARTCONFIG")
for conf in config.get(CONF_ON_READY, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf)

View File

@ -0,0 +1,183 @@
#include "smartconfig_component.h"
#ifdef USE_ESP32
#include "freertos/FreeRTOS.h"
#include "esp_event.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_smartconfig.h"
#endif
#ifdef USE_ESP8266
#include "smartconfig.h"
#endif
#include "esphome/core/application.h"
#include "esphome/core/log.h"
#if defined(USE_ESP32) || defined(USE_ESP8266)
namespace esphome {
namespace smartconfig {
#ifdef USE_ESP32
#define SC_START_BIT BIT0
#define SC_READY_BIT BIT1
#define SC_DONE_BIT BIT2
#endif
static const char *const TAG = "smartconfig";
static wifi::WiFiAP connecting_sta_; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
#ifdef USE_ESP32
static EventGroupHandle_t sce_group = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
static void smartconfig_event_handler(void *arg, esp_event_base_t event_base, int32_t event, void *event_data);
#endif
#ifdef USE_ESP8266
static bool is_sc_ready{false}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
static void smartconfig_done(sc_status status, void *pdata);
#endif
static void smartconfig_got_ssid_pwd(void *data);
SmartConfigComponent::SmartConfigComponent() { global_smartconfig_component = this; }
float SmartConfigComponent::get_setup_priority() const { return setup_priority::WIFI; }
void SmartConfigComponent::config() {
ESP_LOGD(TAG, "config SmartConfig");
#if defined(USE_ESP32)
sce_group = xEventGroupCreate();
esp_err_t err;
esp_event_handler_instance_t instance_sc_id;
err = esp_event_handler_instance_register(SC_EVENT, ESP_EVENT_ANY_ID, &smartconfig_event_handler, nullptr,
&instance_sc_id);
ESP_ERROR_CHECK(err);
#elif defined(USE_ESP8266)
smartconfig_set_type(SC_TYPE_ESPTOUCH);
smartconfig_start(smartconfig_done);
this->state_ = SmartConfigState::SC_START;
#endif
}
void SmartConfigComponent::loop() {
#if defined(USE_ESP32)
if (sce_group == nullptr) {
return;
}
EventBits_t xbits;
xbits = xEventGroupWaitBits(sce_group, SC_START_BIT | SC_READY_BIT | SC_DONE_BIT, true, false, 0);
if (xbits & SC_START_BIT) {
ESP_LOGD(TAG, "Starting SmartConfig");
smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
esp_smartconfig_set_type(SC_TYPE_ESPTOUCH);
esp_smartconfig_start(&cfg);
this->state_ = SmartConfigState::SC_START;
}
if (xbits & SC_READY_BIT) {
ESP_LOGD(TAG, "Smartconfig ready");
this->state_ = SmartConfigState::SC_READY;
on_smartconfig_ready_.call();
}
if (xbits & SC_DONE_BIT) {
ESP_LOGD(TAG, "Smartconfig over");
esp_smartconfig_stop();
this->state_ = SmartConfigState::SC_DONE;
this->set_timeout("save-wifi", 1000, [] {
wifi::global_wifi_component->save_wifi_sta(connecting_sta_.get_ssid(), connecting_sta_.get_password());
});
}
#elif defined(USE_ESP8266)
if (is_sc_ready && (this->state_ != SmartConfigState::SC_READY)) {
this->state_ = SmartConfigState::SC_READY;
on_smartconfig_ready_.call();
} else if (!is_sc_ready && (this->state_ == SmartConfigState::SC_READY) &&
wifi::global_wifi_component->is_connected()) {
this->state_ = SmartConfigState::SC_DONE;
this->set_timeout("save-wifi", 1000, [] {
wifi::global_wifi_component->save_wifi_sta(connecting_sta_.get_ssid(), connecting_sta_.get_password());
});
}
#endif
}
#ifdef USE_ESP32
void SmartConfigComponent::start() {
if (this->state_ == SmartConfigState::SC_IDLE) {
xEventGroupSetBits(sce_group, SC_START_BIT);
}
}
void smartconfig_event_handler(void *arg, esp_event_base_t event_base, int32_t event, void *event_data) {
if (event_base == SC_EVENT && event == SC_EVENT_SCAN_DONE) {
ESP_LOGD(TAG, "SC_EVENT_SCAN_DONE");
xEventGroupSetBits(sce_group, SC_READY_BIT);
} else if (event_base == SC_EVENT && event == SC_EVENT_FOUND_CHANNEL) {
ESP_LOGD(TAG, "Found channel");
} else if (event_base == SC_EVENT && event == SC_EVENT_GOT_SSID_PSWD) {
smartconfig_got_ssid_pwd(event_data);
} else if (event_base == SC_EVENT && event == SC_EVENT_SEND_ACK_DONE) {
xEventGroupSetBits(sce_group, SC_DONE_BIT);
}
}
#endif
static void smartconfig_got_ssid_pwd(void *data) {
#if defined(USE_ESP32)
smartconfig_event_got_ssid_pswd_t *sta_conf = (smartconfig_event_got_ssid_pswd_t *) data;
#elif defined(USE_ESP8266)
struct station_config *sta_conf = (struct station_config *) data;
#endif
std::string ssid((char *) sta_conf->ssid);
std::string password((char *) sta_conf->password);
connecting_sta_.set_ssid(ssid);
connecting_sta_.set_password(password);
wifi::global_wifi_component->set_sta(connecting_sta_);
wifi::global_wifi_component->start_scanning();
ESP_LOGD(TAG, "Received smartconfig wifi settings ssid=%s, password=" LOG_SECRET("%s"), ssid.c_str(),
password.c_str());
}
#ifdef USE_ESP8266
void smartconfig_done(sc_status status, void *pdata) {
switch (status) {
case SC_STATUS_WAIT:
ESP_LOGD(TAG, "SC_STATUS_WAIT");
break;
case SC_STATUS_FIND_CHANNEL:
ESP_LOGD(TAG, "SC_STATUS_FIND_CHANNEL");
is_sc_ready = true;
break;
case SC_STATUS_GETTING_SSID_PSWD:
ESP_LOGD(TAG, "SC_STATUS_GETTING_SSID_PSWD");
break;
case SC_STATUS_LINK:
ESP_LOGD(TAG, "SC_STATUS_LINK");
smartconfig_got_ssid_pwd(pdata);
break;
case SC_STATUS_LINK_OVER:
ESP_LOGD(TAG, "SC_STATUS_LINK_OVER");
smartconfig_stop();
is_sc_ready = false;
break;
}
}
#endif
SmartConfigComponent *global_smartconfig_component = // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
nullptr;
SmartConfigReadyTrigger::SmartConfigReadyTrigger(SmartConfigComponent *&sc_component) {
sc_component->add_on_ready([this]() {
ESP_LOGD(TAG, "Smartconfig is ready");
this->trigger();
});
}
} // namespace smartconfig
} // namespace esphome
#endif

View File

@ -0,0 +1,49 @@
#pragma once
#include "esphome/components/wifi/wifi_component.h"
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#if defined(USE_ESP32) || defined(USE_ESP8266)
namespace esphome {
namespace smartconfig {
using on_smartconfig_ready_cb_t = std::function<void()>;
class SmartConfigComponent : public Component {
public:
enum class SmartConfigState {
SC_IDLE,
SC_START,
SC_READY,
SC_DONE,
};
SmartConfigComponent();
void loop() override;
#ifdef USE_ESP32
void start();
#endif
float get_setup_priority() const override;
void config();
void add_on_ready(on_smartconfig_ready_cb_t callback) { on_smartconfig_ready_.add(std::move(callback)); }
protected:
CallbackManager<void()> on_smartconfig_ready_;
SmartConfigState state_{SmartConfigState::SC_IDLE};
};
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
extern SmartConfigComponent *global_smartconfig_component;
class SmartConfigReadyTrigger : public Trigger<> {
public:
explicit SmartConfigReadyTrigger(SmartConfigComponent *&sc_component);
};
} // namespace smartconfig
} // namespace esphome
#endif

View File

@ -164,7 +164,8 @@ def final_validate(config):
has_ap = CONF_AP in config
has_improv = "esp32_improv" in fv.full_config.get()
has_improv_serial = "improv_serial" in fv.full_config.get()
if not (has_sta or has_ap or has_improv or has_improv_serial):
has_smartconfig = "smartconfig" in fv.full_config.get()
if not (has_sta or has_ap or has_improv or has_improv_serial or has_smartconfig):
raise cv.Invalid(
"Please specify at least an SSID or an Access Point to create."
)

View File

@ -27,6 +27,10 @@
#include "esphome/components/esp32_improv/esp32_improv_component.h"
#endif
#ifdef USE_SMARTCONFIG
#include "esphome/components/smartconfig/smartconfig_component.h"
#endif
namespace esphome {
namespace wifi {
@ -106,6 +110,12 @@ void WiFiComponent::start() {
if (this->wifi_mode_(true, {}))
esp32_improv::global_improv_component->start();
}
#endif
#ifdef USE_SMARTCONFIG
if (!this->has_sta() && smartconfig::global_smartconfig_component != nullptr) {
if (this->wifi_mode_(true, {}))
smartconfig::global_smartconfig_component->config();
}
#endif
this->wifi_apply_hostname_();
}
@ -187,6 +197,11 @@ void WiFiComponent::loop() {
}
}
#endif
#ifdef USE_SMARTCONFIG
if ((smartconfig::global_smartconfig_component != nullptr) && (!this->is_connected())) {
this->wifi_mode_(true, {});
}
#endif
if (!this->has_ap() && this->reboot_timeout_ != 0) {

View File

@ -19,6 +19,10 @@
#include "esphome/core/log.h"
#include "esphome/core/util.h"
#ifdef USE_SMARTCONFIG
#include "esphome/components/smartconfig/smartconfig_component.h"
#endif
namespace esphome {
namespace wifi {
@ -451,6 +455,10 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
case ESPHOME_EVENT_ID_WIFI_STA_START: {
ESP_LOGV(TAG, "Event: WiFi STA start");
tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, App.get_name().c_str());
#ifdef USE_SMARTCONFIG
if (!this->has_sta())
smartconfig::global_smartconfig_component->start();
#endif
break;
}
case ESPHOME_EVENT_ID_WIFI_STA_STOP: {

View File

@ -31,6 +31,10 @@
#include "esphome/core/application.h"
#include "esphome/core/util.h"
#ifdef USE_SMARTCONFIG
#include "esphome/components/smartconfig/smartconfig_component.h"
#endif
namespace esphome {
namespace wifi {
@ -623,6 +627,10 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
s_sta_started = true;
// re-apply power save mode
wifi_apply_power_save_();
#ifdef USE_SMARTCONFIG
if (!this->has_sta())
smartconfig::global_smartconfig_component->start();
#endif
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_STA_STOP) {
ESP_LOGV(TAG, "Event: WiFi STA stop");

View File

@ -22,6 +22,8 @@ wifi:
gateway: 192.168.1.1
subnet: 255.255.255.0
smartconfig:
network:
enable_ipv6: true