mirror of
https://github.com/esphome/esphome.git
synced 2024-11-26 08:55:22 +01:00
commit
229ba18e6c
15 changed files with 181 additions and 93 deletions
|
@ -18,6 +18,8 @@ from esphome.const import (
|
||||||
CONF_TRIGGER_ID,
|
CONF_TRIGGER_ID,
|
||||||
CONF_EVENT,
|
CONF_EVENT,
|
||||||
CONF_TAG,
|
CONF_TAG,
|
||||||
|
CONF_ON_CLIENT_CONNECTED,
|
||||||
|
CONF_ON_CLIENT_DISCONNECTED,
|
||||||
)
|
)
|
||||||
from esphome.core import coroutine_with_priority
|
from esphome.core import coroutine_with_priority
|
||||||
|
|
||||||
|
@ -87,6 +89,12 @@ CONFIG_SCHEMA = cv.Schema(
|
||||||
cv.Required(CONF_KEY): validate_encryption_key,
|
cv.Required(CONF_KEY): validate_encryption_key,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation(
|
||||||
|
single=True
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_ON_CLIENT_DISCONNECTED): automation.validate_automation(
|
||||||
|
single=True
|
||||||
|
),
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA)
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
@ -116,6 +124,20 @@ async def to_code(config):
|
||||||
cg.add(var.register_user_service(trigger))
|
cg.add(var.register_user_service(trigger))
|
||||||
await automation.build_automation(trigger, func_args, conf)
|
await automation.build_automation(trigger, func_args, conf)
|
||||||
|
|
||||||
|
if CONF_ON_CLIENT_CONNECTED in config:
|
||||||
|
await automation.build_automation(
|
||||||
|
var.get_client_connected_trigger(),
|
||||||
|
[(cg.std_string, "client_info"), (cg.std_string, "client_address")],
|
||||||
|
config[CONF_ON_CLIENT_CONNECTED],
|
||||||
|
)
|
||||||
|
|
||||||
|
if CONF_ON_CLIENT_DISCONNECTED in config:
|
||||||
|
await automation.build_automation(
|
||||||
|
var.get_client_disconnected_trigger(),
|
||||||
|
[(cg.std_string, "client_info"), (cg.std_string, "client_address")],
|
||||||
|
config[CONF_ON_CLIENT_DISCONNECTED],
|
||||||
|
)
|
||||||
|
|
||||||
if encryption_config := config.get(CONF_ENCRYPTION):
|
if encryption_config := config.get(CONF_ENCRYPTION):
|
||||||
decoded = base64.b64decode(encryption_config[CONF_KEY])
|
decoded = base64.b64decode(encryption_config[CONF_KEY])
|
||||||
cg.add(var.set_noise_psk(list(decoded)))
|
cg.add(var.set_noise_psk(list(decoded)))
|
||||||
|
|
|
@ -31,9 +31,9 @@ APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *pa
|
||||||
this->proto_write_buffer_.reserve(64);
|
this->proto_write_buffer_.reserve(64);
|
||||||
|
|
||||||
#if defined(USE_API_PLAINTEXT)
|
#if defined(USE_API_PLAINTEXT)
|
||||||
helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock))};
|
this->helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock))};
|
||||||
#elif defined(USE_API_NOISE)
|
#elif defined(USE_API_NOISE)
|
||||||
helper_ = std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), parent->get_noise_ctx())};
|
this->helper_ = std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), parent->get_noise_ctx())};
|
||||||
#else
|
#else
|
||||||
#error "No frame helper defined"
|
#error "No frame helper defined"
|
||||||
#endif
|
#endif
|
||||||
|
@ -41,14 +41,16 @@ APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *pa
|
||||||
void APIConnection::start() {
|
void APIConnection::start() {
|
||||||
this->last_traffic_ = millis();
|
this->last_traffic_ = millis();
|
||||||
|
|
||||||
APIError err = helper_->init();
|
APIError err = this->helper_->init();
|
||||||
if (err != APIError::OK) {
|
if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Helper init failed: %s errno=%d", client_info_.c_str(), api_error_to_str(err), errno);
|
ESP_LOGW(TAG, "%s: Helper init failed: %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err),
|
||||||
|
errno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
client_info_ = helper_->getpeername();
|
this->client_info_ = helper_->getpeername();
|
||||||
helper_->set_log_info(client_info_);
|
this->client_peername_ = this->client_info_;
|
||||||
|
this->helper_->set_log_info(this->client_info_);
|
||||||
}
|
}
|
||||||
|
|
||||||
APIConnection::~APIConnection() {
|
APIConnection::~APIConnection() {
|
||||||
|
@ -57,6 +59,11 @@ APIConnection::~APIConnection() {
|
||||||
bluetooth_proxy::global_bluetooth_proxy->unsubscribe_api_connection(this);
|
bluetooth_proxy::global_bluetooth_proxy->unsubscribe_api_connection(this);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_VOICE_ASSISTANT
|
||||||
|
if (voice_assistant::global_voice_assistant->get_api_connection() == this) {
|
||||||
|
voice_assistant::global_voice_assistant->client_subscription(this, false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIConnection::loop() {
|
void APIConnection::loop() {
|
||||||
|
@ -67,7 +74,7 @@ void APIConnection::loop() {
|
||||||
// when network is disconnected force disconnect immediately
|
// when network is disconnected force disconnect immediately
|
||||||
// don't wait for timeout
|
// don't wait for timeout
|
||||||
this->on_fatal_error();
|
this->on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Network unavailable, disconnecting", client_info_.c_str());
|
ESP_LOGW(TAG, "%s: Network unavailable, disconnecting", this->client_combined_info_.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this->next_close_) {
|
if (this->next_close_) {
|
||||||
|
@ -77,24 +84,26 @@ void APIConnection::loop() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
APIError err = helper_->loop();
|
APIError err = this->helper_->loop();
|
||||||
if (err != APIError::OK) {
|
if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", client_info_.c_str(), api_error_to_str(err), errno);
|
ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->client_combined_info_.c_str(),
|
||||||
|
api_error_to_str(err), errno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ReadPacketBuffer buffer;
|
ReadPacketBuffer buffer;
|
||||||
err = helper_->read_packet(&buffer);
|
err = this->helper_->read_packet(&buffer);
|
||||||
if (err == APIError::WOULD_BLOCK) {
|
if (err == APIError::WOULD_BLOCK) {
|
||||||
// pass
|
// pass
|
||||||
} else if (err != APIError::OK) {
|
} else if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
if (err == APIError::SOCKET_READ_FAILED && errno == ECONNRESET) {
|
if (err == APIError::SOCKET_READ_FAILED && errno == ECONNRESET) {
|
||||||
ESP_LOGW(TAG, "%s: Connection reset", client_info_.c_str());
|
ESP_LOGW(TAG, "%s: Connection reset", this->client_combined_info_.c_str());
|
||||||
} else if (err == APIError::CONNECTION_CLOSED) {
|
} else if (err == APIError::CONNECTION_CLOSED) {
|
||||||
ESP_LOGW(TAG, "%s: Connection closed", client_info_.c_str());
|
ESP_LOGW(TAG, "%s: Connection closed", this->client_combined_info_.c_str());
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW(TAG, "%s: Reading failed: %s errno=%d", client_info_.c_str(), api_error_to_str(err), errno);
|
ESP_LOGW(TAG, "%s: Reading failed: %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err),
|
||||||
|
errno);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -114,7 +123,7 @@ void APIConnection::loop() {
|
||||||
// Disconnect if not responded within 2.5*keepalive
|
// Disconnect if not responded within 2.5*keepalive
|
||||||
if (now - this->last_traffic_ > (keepalive * 5) / 2) {
|
if (now - this->last_traffic_ > (keepalive * 5) / 2) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s didn't respond to ping request in time. Disconnecting...", this->client_info_.c_str());
|
ESP_LOGW(TAG, "%s didn't respond to ping request in time. Disconnecting...", this->client_combined_info_.c_str());
|
||||||
}
|
}
|
||||||
} else if (now - this->last_traffic_ > keepalive) {
|
} else if (now - this->last_traffic_ > keepalive) {
|
||||||
ESP_LOGVV(TAG, "Sending keepalive PING...");
|
ESP_LOGVV(TAG, "Sending keepalive PING...");
|
||||||
|
@ -168,7 +177,7 @@ DisconnectResponse APIConnection::disconnect(const DisconnectRequest &msg) {
|
||||||
// remote initiated disconnect_client
|
// remote initiated disconnect_client
|
||||||
// don't close yet, we still need to send the disconnect response
|
// don't close yet, we still need to send the disconnect response
|
||||||
// close will happen on next loop
|
// close will happen on next loop
|
||||||
ESP_LOGD(TAG, "%s requested disconnected", client_info_.c_str());
|
ESP_LOGD(TAG, "%s requested disconnected", this->client_combined_info_.c_str());
|
||||||
this->next_close_ = true;
|
this->next_close_ = true;
|
||||||
DisconnectResponse resp;
|
DisconnectResponse resp;
|
||||||
return resp;
|
return resp;
|
||||||
|
@ -907,14 +916,17 @@ BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_VOICE_ASSISTANT
|
#ifdef USE_VOICE_ASSISTANT
|
||||||
bool APIConnection::request_voice_assistant(const VoiceAssistantRequest &msg) {
|
void APIConnection::subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) {
|
||||||
if (!this->voice_assistant_subscription_)
|
if (voice_assistant::global_voice_assistant != nullptr) {
|
||||||
return false;
|
voice_assistant::global_voice_assistant->client_subscription(this, msg.subscribe);
|
||||||
|
}
|
||||||
return this->send_voice_assistant_request(msg);
|
|
||||||
}
|
}
|
||||||
void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) {
|
void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) {
|
||||||
if (voice_assistant::global_voice_assistant != nullptr) {
|
if (voice_assistant::global_voice_assistant != nullptr) {
|
||||||
|
if (voice_assistant::global_voice_assistant->get_api_connection() != this) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (msg.error) {
|
if (msg.error) {
|
||||||
voice_assistant::global_voice_assistant->failed_to_start();
|
voice_assistant::global_voice_assistant->failed_to_start();
|
||||||
return;
|
return;
|
||||||
|
@ -927,6 +939,10 @@ void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &ms
|
||||||
};
|
};
|
||||||
void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) {
|
void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) {
|
||||||
if (voice_assistant::global_voice_assistant != nullptr) {
|
if (voice_assistant::global_voice_assistant != nullptr) {
|
||||||
|
if (voice_assistant::global_voice_assistant->get_api_connection() != this) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
voice_assistant::global_voice_assistant->on_event(msg);
|
voice_assistant::global_voice_assistant->on_event(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1006,12 +1022,14 @@ bool APIConnection::send_log_message(int level, const char *tag, const char *lin
|
||||||
}
|
}
|
||||||
|
|
||||||
HelloResponse APIConnection::hello(const HelloRequest &msg) {
|
HelloResponse APIConnection::hello(const HelloRequest &msg) {
|
||||||
this->client_info_ = msg.client_info + " (" + this->helper_->getpeername() + ")";
|
this->client_info_ = msg.client_info;
|
||||||
this->helper_->set_log_info(client_info_);
|
this->client_peername_ = this->helper_->getpeername();
|
||||||
|
this->client_combined_info_ = this->client_info_ + " (" + this->client_peername_ + ")";
|
||||||
|
this->helper_->set_log_info(this->client_combined_info_);
|
||||||
this->client_api_version_major_ = msg.api_version_major;
|
this->client_api_version_major_ = msg.api_version_major;
|
||||||
this->client_api_version_minor_ = msg.api_version_minor;
|
this->client_api_version_minor_ = msg.api_version_minor;
|
||||||
ESP_LOGV(TAG, "Hello from client: '%s' | API Version %" PRIu32 ".%" PRIu32, this->client_info_.c_str(),
|
ESP_LOGV(TAG, "Hello from client: '%s' | %s | API Version %" PRIu32 ".%" PRIu32, this->client_info_.c_str(),
|
||||||
this->client_api_version_major_, this->client_api_version_minor_);
|
this->client_peername_.c_str(), this->client_api_version_major_, this->client_api_version_minor_);
|
||||||
|
|
||||||
HelloResponse resp;
|
HelloResponse resp;
|
||||||
resp.api_version_major = 1;
|
resp.api_version_major = 1;
|
||||||
|
@ -1029,9 +1047,9 @@ ConnectResponse APIConnection::connect(const ConnectRequest &msg) {
|
||||||
// bool invalid_password = 1;
|
// bool invalid_password = 1;
|
||||||
resp.invalid_password = !correct;
|
resp.invalid_password = !correct;
|
||||||
if (correct) {
|
if (correct) {
|
||||||
ESP_LOGD(TAG, "%s: Connected successfully", this->client_info_.c_str());
|
ESP_LOGD(TAG, "%s: Connected successfully", this->client_combined_info_.c_str());
|
||||||
this->connection_state_ = ConnectionState::AUTHENTICATED;
|
this->connection_state_ = ConnectionState::AUTHENTICATED;
|
||||||
|
this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->client_peername_);
|
||||||
#ifdef USE_HOMEASSISTANT_TIME
|
#ifdef USE_HOMEASSISTANT_TIME
|
||||||
if (homeassistant::global_homeassistant_time != nullptr) {
|
if (homeassistant::global_homeassistant_time != nullptr) {
|
||||||
this->send_time_request();
|
this->send_time_request();
|
||||||
|
@ -1105,10 +1123,11 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type)
|
||||||
return false;
|
return false;
|
||||||
if (!this->helper_->can_write_without_blocking()) {
|
if (!this->helper_->can_write_without_blocking()) {
|
||||||
delay(0);
|
delay(0);
|
||||||
APIError err = helper_->loop();
|
APIError err = this->helper_->loop();
|
||||||
if (err != APIError::OK) {
|
if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", client_info_.c_str(), api_error_to_str(err), errno);
|
ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->client_combined_info_.c_str(),
|
||||||
|
api_error_to_str(err), errno);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!this->helper_->can_write_without_blocking()) {
|
if (!this->helper_->can_write_without_blocking()) {
|
||||||
|
@ -1127,9 +1146,10 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type)
|
||||||
if (err != APIError::OK) {
|
if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) {
|
if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) {
|
||||||
ESP_LOGW(TAG, "%s: Connection reset", client_info_.c_str());
|
ESP_LOGW(TAG, "%s: Connection reset", this->client_combined_info_.c_str());
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW(TAG, "%s: Packet write failed %s errno=%d", client_info_.c_str(), api_error_to_str(err), errno);
|
ESP_LOGW(TAG, "%s: Packet write failed %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err),
|
||||||
|
errno);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1138,11 +1158,11 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type)
|
||||||
}
|
}
|
||||||
void APIConnection::on_unauthenticated_access() {
|
void APIConnection::on_unauthenticated_access() {
|
||||||
this->on_fatal_error();
|
this->on_fatal_error();
|
||||||
ESP_LOGD(TAG, "%s: tried to access without authentication.", this->client_info_.c_str());
|
ESP_LOGD(TAG, "%s: tried to access without authentication.", this->client_combined_info_.c_str());
|
||||||
}
|
}
|
||||||
void APIConnection::on_no_setup_connection() {
|
void APIConnection::on_no_setup_connection() {
|
||||||
this->on_fatal_error();
|
this->on_fatal_error();
|
||||||
ESP_LOGD(TAG, "%s: tried to access without full connection.", this->client_info_.c_str());
|
ESP_LOGD(TAG, "%s: tried to access without full connection.", this->client_combined_info_.c_str());
|
||||||
}
|
}
|
||||||
void APIConnection::on_fatal_error() {
|
void APIConnection::on_fatal_error() {
|
||||||
this->helper_->close();
|
this->helper_->close();
|
||||||
|
|
|
@ -121,10 +121,7 @@ class APIConnection : public APIServerConnection {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_VOICE_ASSISTANT
|
#ifdef USE_VOICE_ASSISTANT
|
||||||
void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override {
|
void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override;
|
||||||
this->voice_assistant_subscription_ = msg.subscribe;
|
|
||||||
}
|
|
||||||
bool request_voice_assistant(const VoiceAssistantRequest &msg);
|
|
||||||
void on_voice_assistant_response(const VoiceAssistantResponse &msg) override;
|
void on_voice_assistant_response(const VoiceAssistantResponse &msg) override;
|
||||||
void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override;
|
void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override;
|
||||||
#endif
|
#endif
|
||||||
|
@ -183,6 +180,8 @@ class APIConnection : public APIServerConnection {
|
||||||
}
|
}
|
||||||
bool send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) override;
|
bool send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) override;
|
||||||
|
|
||||||
|
std::string get_client_combined_info() const { return this->client_combined_info_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend APIServer;
|
friend APIServer;
|
||||||
|
|
||||||
|
@ -202,6 +201,8 @@ class APIConnection : public APIServerConnection {
|
||||||
std::unique_ptr<APIFrameHelper> helper_;
|
std::unique_ptr<APIFrameHelper> helper_;
|
||||||
|
|
||||||
std::string client_info_;
|
std::string client_info_;
|
||||||
|
std::string client_peername_;
|
||||||
|
std::string client_combined_info_;
|
||||||
uint32_t client_api_version_major_{0};
|
uint32_t client_api_version_major_{0};
|
||||||
uint32_t client_api_version_minor_{0};
|
uint32_t client_api_version_minor_{0};
|
||||||
#ifdef USE_ESP32_CAMERA
|
#ifdef USE_ESP32_CAMERA
|
||||||
|
@ -213,9 +214,6 @@ class APIConnection : public APIServerConnection {
|
||||||
uint32_t last_traffic_;
|
uint32_t last_traffic_;
|
||||||
bool sent_ping_{false};
|
bool sent_ping_{false};
|
||||||
bool service_call_subscription_{false};
|
bool service_call_subscription_{false};
|
||||||
#ifdef USE_VOICE_ASSISTANT
|
|
||||||
bool voice_assistant_subscription_{false};
|
|
||||||
#endif
|
|
||||||
bool next_close_ = false;
|
bool next_close_ = false;
|
||||||
APIServer *parent_;
|
APIServer *parent_;
|
||||||
InitialStateIterator initial_state_iterator_;
|
InitialStateIterator initial_state_iterator_;
|
||||||
|
|
|
@ -111,6 +111,7 @@ void APIServer::loop() {
|
||||||
[](const std::unique_ptr<APIConnection> &conn) { return !conn->remove_; });
|
[](const std::unique_ptr<APIConnection> &conn) { return !conn->remove_; });
|
||||||
// print disconnection messages
|
// print disconnection messages
|
||||||
for (auto it = new_end; it != this->clients_.end(); ++it) {
|
for (auto it = new_end; it != this->clients_.end(); ++it) {
|
||||||
|
this->client_disconnected_trigger_->trigger((*it)->client_info_, (*it)->client_peername_);
|
||||||
ESP_LOGV(TAG, "Removing connection to %s", (*it)->client_info_.c_str());
|
ESP_LOGV(TAG, "Removing connection to %s", (*it)->client_info_.c_str());
|
||||||
}
|
}
|
||||||
// resize vector
|
// resize vector
|
||||||
|
@ -322,30 +323,6 @@ void APIServer::on_shutdown() {
|
||||||
delay(10);
|
delay(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_VOICE_ASSISTANT
|
|
||||||
bool APIServer::start_voice_assistant(const std::string &conversation_id, uint32_t flags,
|
|
||||||
const api::VoiceAssistantAudioSettings &audio_settings) {
|
|
||||||
VoiceAssistantRequest msg;
|
|
||||||
msg.start = true;
|
|
||||||
msg.conversation_id = conversation_id;
|
|
||||||
msg.flags = flags;
|
|
||||||
msg.audio_settings = audio_settings;
|
|
||||||
for (auto &c : this->clients_) {
|
|
||||||
if (c->request_voice_assistant(msg))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void APIServer::stop_voice_assistant() {
|
|
||||||
VoiceAssistantRequest msg;
|
|
||||||
msg.start = false;
|
|
||||||
for (auto &c : this->clients_) {
|
|
||||||
if (c->request_voice_assistant(msg))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_ALARM_CONTROL_PANEL
|
#ifdef USE_ALARM_CONTROL_PANEL
|
||||||
void APIServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) {
|
void APIServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) {
|
||||||
if (obj->is_internal())
|
if (obj->is_internal())
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "api_pb2.h"
|
#include "api_pb2.h"
|
||||||
#include "api_pb2_service.h"
|
#include "api_pb2_service.h"
|
||||||
#include "esphome/components/socket/socket.h"
|
#include "esphome/components/socket/socket.h"
|
||||||
|
#include "esphome/core/automation.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/controller.h"
|
#include "esphome/core/controller.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
|
@ -80,12 +81,6 @@ class APIServer : public Component, public Controller {
|
||||||
void request_time();
|
void request_time();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_VOICE_ASSISTANT
|
|
||||||
bool start_voice_assistant(const std::string &conversation_id, uint32_t flags,
|
|
||||||
const api::VoiceAssistantAudioSettings &audio_settings);
|
|
||||||
void stop_voice_assistant();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_ALARM_CONTROL_PANEL
|
#ifdef USE_ALARM_CONTROL_PANEL
|
||||||
void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) override;
|
void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) override;
|
||||||
#endif
|
#endif
|
||||||
|
@ -103,6 +98,11 @@ class APIServer : public Component, public Controller {
|
||||||
const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
|
const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
|
||||||
const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; }
|
const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; }
|
||||||
|
|
||||||
|
Trigger<std::string, std::string> *get_client_connected_trigger() const { return this->client_connected_trigger_; }
|
||||||
|
Trigger<std::string, std::string> *get_client_disconnected_trigger() const {
|
||||||
|
return this->client_disconnected_trigger_;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<socket::Socket> socket_ = nullptr;
|
std::unique_ptr<socket::Socket> socket_ = nullptr;
|
||||||
uint16_t port_{6053};
|
uint16_t port_{6053};
|
||||||
|
@ -112,6 +112,8 @@ class APIServer : public Component, public Controller {
|
||||||
std::string password_;
|
std::string password_;
|
||||||
std::vector<HomeAssistantStateSubscription> state_subs_;
|
std::vector<HomeAssistantStateSubscription> state_subs_;
|
||||||
std::vector<UserServiceDescriptor *> user_services_;
|
std::vector<UserServiceDescriptor *> user_services_;
|
||||||
|
Trigger<std::string, std::string> *client_connected_trigger_ = new Trigger<std::string, std::string>();
|
||||||
|
Trigger<std::string, std::string> *client_disconnected_trigger_ = new Trigger<std::string, std::string>();
|
||||||
|
|
||||||
#ifdef USE_API_NOISE
|
#ifdef USE_API_NOISE
|
||||||
std::shared_ptr<APINoiseContext> noise_ctx_ = std::make_shared<APINoiseContext>();
|
std::shared_ptr<APINoiseContext> noise_ctx_ = std::make_shared<APINoiseContext>();
|
||||||
|
|
|
@ -48,7 +48,7 @@ void CaptivePortal::start() {
|
||||||
this->dns_server_ = make_unique<DNSServer>();
|
this->dns_server_ = make_unique<DNSServer>();
|
||||||
this->dns_server_->setErrorReplyCode(DNSReplyCode::NoError);
|
this->dns_server_->setErrorReplyCode(DNSReplyCode::NoError);
|
||||||
network::IPAddress ip = wifi::global_wifi_component->wifi_soft_ap_ip();
|
network::IPAddress ip = wifi::global_wifi_component->wifi_soft_ap_ip();
|
||||||
this->dns_server_->start(53, "*", IPAddress(ip));
|
this->dns_server_->start(53, "*", ip);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
this->base_->get_server()->onNotFound([this](AsyncWebServerRequest *req) {
|
this->base_->get_server()->onNotFound([this](AsyncWebServerRequest *req) {
|
||||||
|
|
|
@ -19,7 +19,7 @@ class MQTTBackendESP8266 final : public MQTTBackend {
|
||||||
void set_will(const char *topic, uint8_t qos, bool retain, const char *payload) final {
|
void set_will(const char *topic, uint8_t qos, bool retain, const char *payload) final {
|
||||||
mqtt_client_.setWill(topic, qos, retain, payload);
|
mqtt_client_.setWill(topic, qos, retain, payload);
|
||||||
}
|
}
|
||||||
void set_server(network::IPAddress ip, uint16_t port) final { mqtt_client_.setServer(IPAddress(ip), port); }
|
void set_server(network::IPAddress ip, uint16_t port) final { mqtt_client_.setServer(ip, port); }
|
||||||
void set_server(const char *host, uint16_t port) final { mqtt_client_.setServer(host, port); }
|
void set_server(const char *host, uint16_t port) final { mqtt_client_.setServer(host, port); }
|
||||||
#if ASYNC_TCP_SSL_ENABLED
|
#if ASYNC_TCP_SSL_ENABLED
|
||||||
void set_secure(bool secure) { mqtt_client.setSecure(secure); }
|
void set_secure(bool secure) { mqtt_client.setSecure(secure); }
|
||||||
|
|
|
@ -6,6 +6,8 @@ from esphome.const import (
|
||||||
CONF_MICROPHONE,
|
CONF_MICROPHONE,
|
||||||
CONF_SPEAKER,
|
CONF_SPEAKER,
|
||||||
CONF_MEDIA_PLAYER,
|
CONF_MEDIA_PLAYER,
|
||||||
|
CONF_ON_CLIENT_CONNECTED,
|
||||||
|
CONF_ON_CLIENT_DISCONNECTED,
|
||||||
)
|
)
|
||||||
from esphome import automation
|
from esphome import automation
|
||||||
from esphome.automation import register_action, register_condition
|
from esphome.automation import register_action, register_condition
|
||||||
|
@ -80,6 +82,12 @@ CONFIG_SCHEMA = cv.All(
|
||||||
cv.Optional(CONF_ON_TTS_END): automation.validate_automation(single=True),
|
cv.Optional(CONF_ON_TTS_END): automation.validate_automation(single=True),
|
||||||
cv.Optional(CONF_ON_END): automation.validate_automation(single=True),
|
cv.Optional(CONF_ON_END): automation.validate_automation(single=True),
|
||||||
cv.Optional(CONF_ON_ERROR): automation.validate_automation(single=True),
|
cv.Optional(CONF_ON_ERROR): automation.validate_automation(single=True),
|
||||||
|
cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation(
|
||||||
|
single=True
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_ON_CLIENT_DISCONNECTED): automation.validate_automation(
|
||||||
|
single=True
|
||||||
|
),
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA),
|
).extend(cv.COMPONENT_SCHEMA),
|
||||||
)
|
)
|
||||||
|
@ -155,6 +163,20 @@ async def to_code(config):
|
||||||
config[CONF_ON_ERROR],
|
config[CONF_ON_ERROR],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if CONF_ON_CLIENT_CONNECTED in config:
|
||||||
|
await automation.build_automation(
|
||||||
|
var.get_client_connected_trigger(),
|
||||||
|
[],
|
||||||
|
config[CONF_ON_CLIENT_CONNECTED],
|
||||||
|
)
|
||||||
|
|
||||||
|
if CONF_ON_CLIENT_DISCONNECTED in config:
|
||||||
|
await automation.build_automation(
|
||||||
|
var.get_client_disconnected_trigger(),
|
||||||
|
[],
|
||||||
|
config[CONF_ON_CLIENT_DISCONNECTED],
|
||||||
|
)
|
||||||
|
|
||||||
cg.add_define("USE_VOICE_ASSISTANT")
|
cg.add_define("USE_VOICE_ASSISTANT")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -127,8 +127,8 @@ int VoiceAssistant::read_microphone_() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoiceAssistant::loop() {
|
void VoiceAssistant::loop() {
|
||||||
if (this->state_ != State::IDLE && this->state_ != State::STOP_MICROPHONE &&
|
if (this->api_client_ == nullptr && this->state_ != State::IDLE && this->state_ != State::STOP_MICROPHONE &&
|
||||||
this->state_ != State::STOPPING_MICROPHONE && !api::global_api_server->is_connected()) {
|
this->state_ != State::STOPPING_MICROPHONE) {
|
||||||
if (this->mic_->is_running() || this->state_ == State::STARTING_MICROPHONE) {
|
if (this->mic_->is_running() || this->state_ == State::STARTING_MICROPHONE) {
|
||||||
this->set_state_(State::STOP_MICROPHONE, State::IDLE);
|
this->set_state_(State::STOP_MICROPHONE, State::IDLE);
|
||||||
} else {
|
} else {
|
||||||
|
@ -213,7 +213,14 @@ void VoiceAssistant::loop() {
|
||||||
audio_settings.noise_suppression_level = this->noise_suppression_level_;
|
audio_settings.noise_suppression_level = this->noise_suppression_level_;
|
||||||
audio_settings.auto_gain = this->auto_gain_;
|
audio_settings.auto_gain = this->auto_gain_;
|
||||||
audio_settings.volume_multiplier = this->volume_multiplier_;
|
audio_settings.volume_multiplier = this->volume_multiplier_;
|
||||||
if (!api::global_api_server->start_voice_assistant(this->conversation_id_, flags, audio_settings)) {
|
|
||||||
|
api::VoiceAssistantRequest msg;
|
||||||
|
msg.start = true;
|
||||||
|
msg.conversation_id = this->conversation_id_;
|
||||||
|
msg.flags = flags;
|
||||||
|
msg.audio_settings = audio_settings;
|
||||||
|
|
||||||
|
if (this->api_client_ == nullptr || !this->api_client_->send_voice_assistant_request(msg)) {
|
||||||
ESP_LOGW(TAG, "Could not request start.");
|
ESP_LOGW(TAG, "Could not request start.");
|
||||||
this->error_trigger_->trigger("not-connected", "Could not request start.");
|
this->error_trigger_->trigger("not-connected", "Could not request start.");
|
||||||
this->continuous_ = false;
|
this->continuous_ = false;
|
||||||
|
@ -326,6 +333,28 @@ void VoiceAssistant::loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VoiceAssistant::client_subscription(api::APIConnection *client, bool subscribe) {
|
||||||
|
if (!subscribe) {
|
||||||
|
if (this->api_client_ == nullptr || client != this->api_client_) {
|
||||||
|
ESP_LOGE(TAG, "Client attempting to unsubscribe that is not the current API Client");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->api_client_ = nullptr;
|
||||||
|
this->client_disconnected_trigger_->trigger();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->api_client_ != nullptr) {
|
||||||
|
ESP_LOGE(TAG, "Multiple API Clients attempting to connect to Voice Assistant");
|
||||||
|
ESP_LOGE(TAG, "Current client: %s", this->api_client_->get_client_combined_info().c_str());
|
||||||
|
ESP_LOGE(TAG, "New client: %s", client->get_client_combined_info().c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->api_client_ = client;
|
||||||
|
this->client_connected_trigger_->trigger();
|
||||||
|
}
|
||||||
|
|
||||||
static const LogString *voice_assistant_state_to_string(State state) {
|
static const LogString *voice_assistant_state_to_string(State state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case State::IDLE:
|
case State::IDLE:
|
||||||
|
@ -408,7 +437,7 @@ void VoiceAssistant::start_streaming(struct sockaddr_storage *addr, uint16_t por
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoiceAssistant::request_start(bool continuous, bool silence_detection) {
|
void VoiceAssistant::request_start(bool continuous, bool silence_detection) {
|
||||||
if (!api::global_api_server->is_connected()) {
|
if (this->api_client_ == nullptr) {
|
||||||
ESP_LOGE(TAG, "No API client connected");
|
ESP_LOGE(TAG, "No API client connected");
|
||||||
this->set_state_(State::IDLE, State::IDLE);
|
this->set_state_(State::IDLE, State::IDLE);
|
||||||
this->continuous_ = false;
|
this->continuous_ = false;
|
||||||
|
@ -459,9 +488,14 @@ void VoiceAssistant::request_stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoiceAssistant::signal_stop_() {
|
void VoiceAssistant::signal_stop_() {
|
||||||
ESP_LOGD(TAG, "Signaling stop...");
|
|
||||||
api::global_api_server->stop_voice_assistant();
|
|
||||||
memset(&this->dest_addr_, 0, sizeof(this->dest_addr_));
|
memset(&this->dest_addr_, 0, sizeof(this->dest_addr_));
|
||||||
|
if (this->api_client_ == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "Signaling stop...");
|
||||||
|
api::VoiceAssistantRequest msg;
|
||||||
|
msg.start = false;
|
||||||
|
this->api_client_->send_voice_assistant_request(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
|
#include "esphome/components/api/api_connection.h"
|
||||||
#include "esphome/components/api/api_pb2.h"
|
#include "esphome/components/api/api_pb2.h"
|
||||||
#include "esphome/components/api/api_server.h"
|
|
||||||
#include "esphome/components/microphone/microphone.h"
|
#include "esphome/components/microphone/microphone.h"
|
||||||
#ifdef USE_SPEAKER
|
#ifdef USE_SPEAKER
|
||||||
#include "esphome/components/speaker/speaker.h"
|
#include "esphome/components/speaker/speaker.h"
|
||||||
|
@ -109,6 +109,12 @@ class VoiceAssistant : public Component {
|
||||||
Trigger<> *get_end_trigger() const { return this->end_trigger_; }
|
Trigger<> *get_end_trigger() const { return this->end_trigger_; }
|
||||||
Trigger<std::string, std::string> *get_error_trigger() const { return this->error_trigger_; }
|
Trigger<std::string, std::string> *get_error_trigger() const { return this->error_trigger_; }
|
||||||
|
|
||||||
|
Trigger<> *get_client_connected_trigger() const { return this->client_connected_trigger_; }
|
||||||
|
Trigger<> *get_client_disconnected_trigger() const { return this->client_disconnected_trigger_; }
|
||||||
|
|
||||||
|
void client_subscription(api::APIConnection *client, bool subscribe);
|
||||||
|
api::APIConnection *get_api_connection() const { return this->api_client_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int read_microphone_();
|
int read_microphone_();
|
||||||
void set_state_(State state);
|
void set_state_(State state);
|
||||||
|
@ -127,6 +133,11 @@ class VoiceAssistant : public Component {
|
||||||
Trigger<> *end_trigger_ = new Trigger<>();
|
Trigger<> *end_trigger_ = new Trigger<>();
|
||||||
Trigger<std::string, std::string> *error_trigger_ = new Trigger<std::string, std::string>();
|
Trigger<std::string, std::string> *error_trigger_ = new Trigger<std::string, std::string>();
|
||||||
|
|
||||||
|
Trigger<> *client_connected_trigger_ = new Trigger<>();
|
||||||
|
Trigger<> *client_disconnected_trigger_ = new Trigger<>();
|
||||||
|
|
||||||
|
api::APIConnection *api_client_{nullptr};
|
||||||
|
|
||||||
microphone::Microphone *mic_{nullptr};
|
microphone::Microphone *mic_{nullptr};
|
||||||
#ifdef USE_SPEAKER
|
#ifdef USE_SPEAKER
|
||||||
speaker::Speaker *speaker_{nullptr};
|
speaker::Speaker *speaker_{nullptr};
|
||||||
|
|
|
@ -261,8 +261,8 @@ void WiFiComponent::set_sta(const WiFiAP &ap) {
|
||||||
void WiFiComponent::clear_sta() { this->sta_.clear(); }
|
void WiFiComponent::clear_sta() { this->sta_.clear(); }
|
||||||
void WiFiComponent::save_wifi_sta(const std::string &ssid, const std::string &password) {
|
void WiFiComponent::save_wifi_sta(const std::string &ssid, const std::string &password) {
|
||||||
SavedWifiSettings save{};
|
SavedWifiSettings save{};
|
||||||
strncpy(save.ssid, ssid.c_str(), sizeof(save.ssid));
|
strncpy(save.ssid, ssid.c_str(), sizeof(save.ssid) - 1);
|
||||||
strncpy(save.password, password.c_str(), sizeof(save.password));
|
strncpy(save.password, password.c_str(), sizeof(save.password) - 1);
|
||||||
this->pref_.save(&save);
|
this->pref_.save(&save);
|
||||||
// ensure it's written immediately
|
// ensure it's written immediately
|
||||||
global_preferences->sync();
|
global_preferences->sync();
|
||||||
|
|
|
@ -164,8 +164,8 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
|
||||||
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv417wifi_sta_config_t
|
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv417wifi_sta_config_t
|
||||||
wifi_config_t conf;
|
wifi_config_t conf;
|
||||||
memset(&conf, 0, sizeof(conf));
|
memset(&conf, 0, sizeof(conf));
|
||||||
strncpy(reinterpret_cast<char *>(conf.sta.ssid), ap.get_ssid().c_str(), sizeof(conf.sta.ssid));
|
strncpy(reinterpret_cast<char *>(conf.sta.ssid), ap.get_ssid().c_str(), sizeof(conf.sta.ssid) - 1);
|
||||||
strncpy(reinterpret_cast<char *>(conf.sta.password), ap.get_password().c_str(), sizeof(conf.sta.password));
|
strncpy(reinterpret_cast<char *>(conf.sta.password), ap.get_password().c_str(), sizeof(conf.sta.password) - 1);
|
||||||
|
|
||||||
// The weakest authmode to accept in the fast scan mode
|
// The weakest authmode to accept in the fast scan mode
|
||||||
if (ap.get_password().empty()) {
|
if (ap.get_password().empty()) {
|
||||||
|
@ -661,7 +661,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
|
||||||
|
|
||||||
wifi_config_t conf;
|
wifi_config_t conf;
|
||||||
memset(&conf, 0, sizeof(conf));
|
memset(&conf, 0, sizeof(conf));
|
||||||
strncpy(reinterpret_cast<char *>(conf.ap.ssid), ap.get_ssid().c_str(), sizeof(conf.ap.ssid));
|
strncpy(reinterpret_cast<char *>(conf.ap.ssid), ap.get_ssid().c_str(), sizeof(conf.ap.ssid) - 1);
|
||||||
conf.ap.channel = ap.get_channel().value_or(1);
|
conf.ap.channel = ap.get_channel().value_or(1);
|
||||||
conf.ap.ssid_hidden = ap.get_ssid().size();
|
conf.ap.ssid_hidden = ap.get_ssid().size();
|
||||||
conf.ap.max_connection = 5;
|
conf.ap.max_connection = 5;
|
||||||
|
@ -672,7 +672,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
|
||||||
*conf.ap.password = 0;
|
*conf.ap.password = 0;
|
||||||
} else {
|
} else {
|
||||||
conf.ap.authmode = WIFI_AUTH_WPA2_PSK;
|
conf.ap.authmode = WIFI_AUTH_WPA2_PSK;
|
||||||
strncpy(reinterpret_cast<char *>(conf.ap.password), ap.get_password().c_str(), sizeof(conf.ap.ssid));
|
strncpy(reinterpret_cast<char *>(conf.ap.password), ap.get_password().c_str(), sizeof(conf.ap.ssid) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
conf.ap.pairwise_cipher = WIFI_CIPHER_TYPE_CCMP;
|
conf.ap.pairwise_cipher = WIFI_CIPHER_TYPE_CCMP;
|
||||||
|
|
|
@ -230,8 +230,8 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
|
||||||
|
|
||||||
struct station_config conf {};
|
struct station_config conf {};
|
||||||
memset(&conf, 0, sizeof(conf));
|
memset(&conf, 0, sizeof(conf));
|
||||||
strncpy(reinterpret_cast<char *>(conf.ssid), ap.get_ssid().c_str(), sizeof(conf.ssid));
|
strncpy(reinterpret_cast<char *>(conf.ssid), ap.get_ssid().c_str(), sizeof(conf.ssid) - 1);
|
||||||
strncpy(reinterpret_cast<char *>(conf.password), ap.get_password().c_str(), sizeof(conf.password));
|
strncpy(reinterpret_cast<char *>(conf.password), ap.get_password().c_str(), sizeof(conf.password) - 1);
|
||||||
|
|
||||||
if (ap.get_bssid().has_value()) {
|
if (ap.get_bssid().has_value()) {
|
||||||
conf.bssid_set = 1;
|
conf.bssid_set = 1;
|
||||||
|
@ -759,7 +759,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
struct softap_config conf {};
|
struct softap_config conf {};
|
||||||
strncpy(reinterpret_cast<char *>(conf.ssid), ap.get_ssid().c_str(), sizeof(conf.ssid));
|
strncpy(reinterpret_cast<char *>(conf.ssid), ap.get_ssid().c_str(), sizeof(conf.ssid) - 1);
|
||||||
conf.ssid_len = static_cast<uint8>(ap.get_ssid().size());
|
conf.ssid_len = static_cast<uint8>(ap.get_ssid().size());
|
||||||
conf.channel = ap.get_channel().value_or(1);
|
conf.channel = ap.get_channel().value_or(1);
|
||||||
conf.ssid_hidden = ap.get_hidden();
|
conf.ssid_hidden = ap.get_hidden();
|
||||||
|
@ -771,7 +771,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
|
||||||
*conf.password = 0;
|
*conf.password = 0;
|
||||||
} else {
|
} else {
|
||||||
conf.authmode = AUTH_WPA2_PSK;
|
conf.authmode = AUTH_WPA2_PSK;
|
||||||
strncpy(reinterpret_cast<char *>(conf.password), ap.get_password().c_str(), sizeof(conf.password));
|
strncpy(reinterpret_cast<char *>(conf.password), ap.get_password().c_str(), sizeof(conf.password) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ETS_UART_INTR_DISABLE();
|
ETS_UART_INTR_DISABLE();
|
||||||
|
|
|
@ -275,8 +275,8 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
|
||||||
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv417wifi_sta_config_t
|
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv417wifi_sta_config_t
|
||||||
wifi_config_t conf;
|
wifi_config_t conf;
|
||||||
memset(&conf, 0, sizeof(conf));
|
memset(&conf, 0, sizeof(conf));
|
||||||
strncpy(reinterpret_cast<char *>(conf.sta.ssid), ap.get_ssid().c_str(), sizeof(conf.sta.ssid));
|
strncpy(reinterpret_cast<char *>(conf.sta.ssid), ap.get_ssid().c_str(), sizeof(conf.sta.ssid) - 1);
|
||||||
strncpy(reinterpret_cast<char *>(conf.sta.password), ap.get_password().c_str(), sizeof(conf.sta.password));
|
strncpy(reinterpret_cast<char *>(conf.sta.password), ap.get_password().c_str(), sizeof(conf.sta.password) - 1);
|
||||||
|
|
||||||
// The weakest authmode to accept in the fast scan mode
|
// The weakest authmode to accept in the fast scan mode
|
||||||
if (ap.get_password().empty()) {
|
if (ap.get_password().empty()) {
|
||||||
|
@ -823,7 +823,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
|
||||||
|
|
||||||
wifi_config_t conf;
|
wifi_config_t conf;
|
||||||
memset(&conf, 0, sizeof(conf));
|
memset(&conf, 0, sizeof(conf));
|
||||||
strncpy(reinterpret_cast<char *>(conf.ap.ssid), ap.get_ssid().c_str(), sizeof(conf.ap.ssid));
|
strncpy(reinterpret_cast<char *>(conf.ap.ssid), ap.get_ssid().c_str(), sizeof(conf.ap.ssid) - 1);
|
||||||
conf.ap.channel = ap.get_channel().value_or(1);
|
conf.ap.channel = ap.get_channel().value_or(1);
|
||||||
conf.ap.ssid_hidden = ap.get_ssid().size();
|
conf.ap.ssid_hidden = ap.get_ssid().size();
|
||||||
conf.ap.max_connection = 5;
|
conf.ap.max_connection = 5;
|
||||||
|
@ -834,7 +834,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
|
||||||
*conf.ap.password = 0;
|
*conf.ap.password = 0;
|
||||||
} else {
|
} else {
|
||||||
conf.ap.authmode = WIFI_AUTH_WPA2_PSK;
|
conf.ap.authmode = WIFI_AUTH_WPA2_PSK;
|
||||||
strncpy(reinterpret_cast<char *>(conf.ap.password), ap.get_password().c_str(), sizeof(conf.ap.password));
|
strncpy(reinterpret_cast<char *>(conf.ap.password), ap.get_password().c_str(), sizeof(conf.ap.password) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pairwise cipher of SoftAP, group cipher will be derived using this.
|
// pairwise cipher of SoftAP, group cipher will be derived using this.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Constants used by esphome."""
|
"""Constants used by esphome."""
|
||||||
|
|
||||||
__version__ = "2023.10.4"
|
__version__ = "2023.10.5"
|
||||||
|
|
||||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||||
|
@ -481,6 +481,8 @@ CONF_ON_BLE_MANUFACTURER_DATA_ADVERTISE = "on_ble_manufacturer_data_advertise"
|
||||||
CONF_ON_BLE_SERVICE_DATA_ADVERTISE = "on_ble_service_data_advertise"
|
CONF_ON_BLE_SERVICE_DATA_ADVERTISE = "on_ble_service_data_advertise"
|
||||||
CONF_ON_BOOT = "on_boot"
|
CONF_ON_BOOT = "on_boot"
|
||||||
CONF_ON_CLICK = "on_click"
|
CONF_ON_CLICK = "on_click"
|
||||||
|
CONF_ON_CLIENT_CONNECTED = "on_client_connected"
|
||||||
|
CONF_ON_CLIENT_DISCONNECTED = "on_client_disconnected"
|
||||||
CONF_ON_CONNECT = "on_connect"
|
CONF_ON_CONNECT = "on_connect"
|
||||||
CONF_ON_CONTROL = "on_control"
|
CONF_ON_CONTROL = "on_control"
|
||||||
CONF_ON_DISCONNECT = "on_disconnect"
|
CONF_ON_DISCONNECT = "on_disconnect"
|
||||||
|
|
Loading…
Reference in a new issue