mirror of
https://github.com/esphome/esphome.git
synced 2024-11-28 01:34:18 +01:00
Store API key in preferences
This commit is contained in:
parent
a0c54504cd
commit
656bb6be0b
2 changed files with 122 additions and 61 deletions
|
@ -21,22 +21,40 @@ namespace api {
|
||||||
static const char *const TAG = "api";
|
static const char *const TAG = "api";
|
||||||
|
|
||||||
// APIServer
|
// APIServer
|
||||||
|
APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
|
APIServer::APIServer() { global_api_server = this; }
|
||||||
|
|
||||||
void APIServer::setup() {
|
void APIServer::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up Home Assistant API server...");
|
ESP_LOGCONFIG(TAG, "Setting up Home Assistant API server...");
|
||||||
this->setup_controller();
|
this->setup_controller();
|
||||||
socket_ = socket::socket_ip(SOCK_STREAM, 0);
|
|
||||||
if (socket_ == nullptr) {
|
#ifdef USE_API_NOISE
|
||||||
ESP_LOGW(TAG, "Could not create socket.");
|
uint32_t hash = 88491486UL;
|
||||||
|
|
||||||
|
this->noise_pref_ = global_preferences->make_preference<SavedNoisePsk>(hash, true);
|
||||||
|
|
||||||
|
SavedNoisePsk noise_pref_saved{};
|
||||||
|
if (this->noise_pref_.load(&noise_pref_saved)) {
|
||||||
|
ESP_LOGD(TAG, "Loaded saved Noise PSK");
|
||||||
|
|
||||||
|
this->set_noise_psk(noise_pref_saved.psk);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
this->socket_ = socket::socket_ip(SOCK_STREAM, 0);
|
||||||
|
if (this->socket_ == nullptr) {
|
||||||
|
ESP_LOGW(TAG, "Could not create socket");
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int enable = 1;
|
int enable = 1;
|
||||||
int err = socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
|
int err = this->socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
ESP_LOGW(TAG, "Socket unable to set reuseaddr: errno %d", err);
|
ESP_LOGW(TAG, "Socket unable to set reuseaddr: errno %d", err);
|
||||||
// we can still continue
|
// we can still continue
|
||||||
}
|
}
|
||||||
err = socket_->setblocking(false);
|
err = this->socket_->setblocking(false);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
ESP_LOGW(TAG, "Socket unable to set nonblocking mode: errno %d", err);
|
ESP_LOGW(TAG, "Socket unable to set nonblocking mode: errno %d", err);
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
|
@ -52,14 +70,14 @@ void APIServer::setup() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = socket_->bind((struct sockaddr *) &server, sl);
|
err = this->socket_->bind((struct sockaddr *) &server, sl);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
ESP_LOGW(TAG, "Socket unable to bind: errno %d", errno);
|
ESP_LOGW(TAG, "Socket unable to bind: errno %d", errno);
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = socket_->listen(4);
|
err = this->socket_->listen(4);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
ESP_LOGW(TAG, "Socket unable to listen: errno %d", errno);
|
ESP_LOGW(TAG, "Socket unable to listen: errno %d", errno);
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
|
@ -91,18 +109,19 @@ void APIServer::setup() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIServer::loop() {
|
void APIServer::loop() {
|
||||||
// Accept new clients
|
// Accept new clients
|
||||||
while (true) {
|
while (true) {
|
||||||
struct sockaddr_storage source_addr;
|
struct sockaddr_storage source_addr;
|
||||||
socklen_t addr_len = sizeof(source_addr);
|
socklen_t addr_len = sizeof(source_addr);
|
||||||
auto sock = socket_->accept((struct sockaddr *) &source_addr, &addr_len);
|
auto sock = this->socket_->accept((struct sockaddr *) &source_addr, &addr_len);
|
||||||
if (!sock)
|
if (!sock)
|
||||||
break;
|
break;
|
||||||
ESP_LOGD(TAG, "Accepted %s", sock->getpeername().c_str());
|
ESP_LOGD(TAG, "Accepted %s", sock->getpeername().c_str());
|
||||||
|
|
||||||
auto *conn = new APIConnection(std::move(sock), this);
|
auto *conn = new APIConnection(std::move(sock), this);
|
||||||
clients_.emplace_back(conn);
|
this->clients_.emplace_back(conn);
|
||||||
conn->start();
|
conn->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +154,7 @@ void APIServer::loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIServer::dump_config() {
|
void APIServer::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "API Server:");
|
ESP_LOGCONFIG(TAG, "API Server:");
|
||||||
ESP_LOGCONFIG(TAG, " Address: %s: %u", network::get_use_address().c_str(), this->port_);
|
ESP_LOGCONFIG(TAG, " Address: %s: %u", network::get_use_address().c_str(), this->port_);
|
||||||
|
@ -144,7 +164,9 @@ void APIServer::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, " Using noise encryption: NO");
|
ESP_LOGCONFIG(TAG, " Using noise encryption: NO");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool APIServer::uses_password() const { return !this->password_.empty(); }
|
bool APIServer::uses_password() const { return !this->password_.empty(); }
|
||||||
|
|
||||||
bool APIServer::check_password(const std::string &password) const {
|
bool APIServer::check_password(const std::string &password) const {
|
||||||
// depend only on input password length
|
// depend only on input password length
|
||||||
const char *a = this->password_.c_str();
|
const char *a = this->password_.c_str();
|
||||||
|
@ -173,7 +195,9 @@ bool APIServer::check_password(const std::string &password) const {
|
||||||
|
|
||||||
return result == 0;
|
return result == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIServer::handle_disconnect(APIConnection *conn) {}
|
void APIServer::handle_disconnect(APIConnection *conn) {}
|
||||||
|
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
void APIServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) {
|
void APIServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) {
|
||||||
if (obj->is_internal())
|
if (obj->is_internal())
|
||||||
|
@ -341,57 +365,6 @@ void APIServer::on_update(update::UpdateEntity *obj) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
|
|
||||||
void APIServer::set_port(uint16_t port) { this->port_ = port; }
|
|
||||||
APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
|
||||||
|
|
||||||
void APIServer::set_password(const std::string &password) { this->password_ = password; }
|
|
||||||
void APIServer::send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
|
|
||||||
for (auto &client : this->clients_) {
|
|
||||||
client->send_homeassistant_service_call(call);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
APIServer::APIServer() { global_api_server = this; }
|
|
||||||
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
|
||||||
std::function<void(std::string)> f) {
|
|
||||||
this->state_subs_.push_back(HomeAssistantStateSubscription{
|
|
||||||
.entity_id = std::move(entity_id),
|
|
||||||
.attribute = std::move(attribute),
|
|
||||||
.callback = std::move(f),
|
|
||||||
.once = false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
void APIServer::get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
|
||||||
std::function<void(std::string)> f) {
|
|
||||||
this->state_subs_.push_back(HomeAssistantStateSubscription{
|
|
||||||
.entity_id = std::move(entity_id),
|
|
||||||
.attribute = std::move(attribute),
|
|
||||||
.callback = std::move(f),
|
|
||||||
.once = true,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const std::vector<APIServer::HomeAssistantStateSubscription> &APIServer::get_state_subs() const {
|
|
||||||
return this->state_subs_;
|
|
||||||
}
|
|
||||||
uint16_t APIServer::get_port() const { return this->port_; }
|
|
||||||
void APIServer::set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
|
|
||||||
#ifdef USE_HOMEASSISTANT_TIME
|
|
||||||
void APIServer::request_time() {
|
|
||||||
for (auto &client : this->clients_) {
|
|
||||||
if (!client->remove_ && client->is_authenticated())
|
|
||||||
client->send_time_request();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
bool APIServer::is_connected() const { return !this->clients_.empty(); }
|
|
||||||
void APIServer::on_shutdown() {
|
|
||||||
for (auto &c : this->clients_) {
|
|
||||||
c->send_disconnect_request(DisconnectRequest());
|
|
||||||
}
|
|
||||||
delay(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
#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())
|
||||||
|
@ -401,5 +374,85 @@ void APIServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlP
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
|
||||||
|
|
||||||
|
void APIServer::set_port(uint16_t port) { this->port_ = port; }
|
||||||
|
|
||||||
|
void APIServer::set_password(const std::string &password) { this->password_ = password; }
|
||||||
|
|
||||||
|
void APIServer::send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
|
||||||
|
for (auto &client : this->clients_) {
|
||||||
|
client->send_homeassistant_service_call(call);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||||
|
std::function<void(std::string)> f) {
|
||||||
|
this->state_subs_.push_back(HomeAssistantStateSubscription{
|
||||||
|
.entity_id = std::move(entity_id),
|
||||||
|
.attribute = std::move(attribute),
|
||||||
|
.callback = std::move(f),
|
||||||
|
.once = false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void APIServer::get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
|
||||||
|
std::function<void(std::string)> f) {
|
||||||
|
this->state_subs_.push_back(HomeAssistantStateSubscription{
|
||||||
|
.entity_id = std::move(entity_id),
|
||||||
|
.attribute = std::move(attribute),
|
||||||
|
.callback = std::move(f),
|
||||||
|
.once = true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::vector<APIServer::HomeAssistantStateSubscription> &APIServer::get_state_subs() const {
|
||||||
|
return this->state_subs_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t APIServer::get_port() const { return this->port_; }
|
||||||
|
|
||||||
|
void APIServer::set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
|
||||||
|
|
||||||
|
#ifdef USE_API_NOISE
|
||||||
|
void APIServer::save_noise_psk(psk_t psk, bool make_active) {
|
||||||
|
if (psk == this->noise_ctx_->get_psk()) {
|
||||||
|
ESP_LOGW(TAG, "New PSK matches old; doing nothing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SavedNoisePsk new_saved_psk{psk};
|
||||||
|
this->noise_pref_.save(&new_saved_psk);
|
||||||
|
// ensure it's written immediately
|
||||||
|
global_preferences->sync();
|
||||||
|
ESP_LOGD(TAG, "Noise PSK updated");
|
||||||
|
if (make_active) {
|
||||||
|
ESP_LOGW(TAG, "Disconnecting all clients to reset connections");
|
||||||
|
this->set_noise_psk(psk);
|
||||||
|
for (auto &c : this->clients_) {
|
||||||
|
c->send_disconnect_request(DisconnectRequest());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_HOMEASSISTANT_TIME
|
||||||
|
void APIServer::request_time() {
|
||||||
|
for (auto &client : this->clients_) {
|
||||||
|
if (!client->remove_ && client->is_authenticated())
|
||||||
|
client->send_time_request();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool APIServer::is_connected() const { return !this->clients_.empty(); }
|
||||||
|
|
||||||
|
void APIServer::on_shutdown() {
|
||||||
|
for (auto &c : this->clients_) {
|
||||||
|
c->send_disconnect_request(DisconnectRequest());
|
||||||
|
}
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
|
@ -18,6 +18,12 @@
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
|
#ifdef USE_API_NOISE
|
||||||
|
struct SavedNoisePsk {
|
||||||
|
psk_t psk;
|
||||||
|
} PACKED; // NOLINT
|
||||||
|
#endif
|
||||||
|
|
||||||
class APIServer : public Component, public Controller {
|
class APIServer : public Component, public Controller {
|
||||||
public:
|
public:
|
||||||
APIServer();
|
APIServer();
|
||||||
|
@ -34,6 +40,7 @@ class APIServer : public Component, public Controller {
|
||||||
void set_reboot_timeout(uint32_t reboot_timeout);
|
void set_reboot_timeout(uint32_t reboot_timeout);
|
||||||
|
|
||||||
#ifdef USE_API_NOISE
|
#ifdef USE_API_NOISE
|
||||||
|
void save_noise_psk(psk_t psk, bool make_active = true);
|
||||||
void set_noise_psk(psk_t psk) { noise_ctx_->set_psk(psk); }
|
void set_noise_psk(psk_t psk) { noise_ctx_->set_psk(psk); }
|
||||||
std::shared_ptr<APINoiseContext> get_noise_ctx() { return noise_ctx_; }
|
std::shared_ptr<APINoiseContext> get_noise_ctx() { return noise_ctx_; }
|
||||||
#endif // USE_API_NOISE
|
#endif // USE_API_NOISE
|
||||||
|
@ -141,6 +148,7 @@ class APIServer : public Component, public Controller {
|
||||||
|
|
||||||
#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>();
|
||||||
|
ESPPreferenceObject noise_pref_;
|
||||||
#endif // USE_API_NOISE
|
#endif // USE_API_NOISE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue