ESPHome  2024.4.1
api_server.cpp
Go to the documentation of this file.
1 #include "api_server.h"
2 #include <cerrno>
3 #include "api_connection.h"
6 #include "esphome/core/defines.h"
7 #include "esphome/core/hal.h"
8 #include "esphome/core/log.h"
9 #include "esphome/core/util.h"
10 #include "esphome/core/version.h"
11 
12 #ifdef USE_LOGGER
14 #endif
15 
16 #include <algorithm>
17 
18 namespace esphome {
19 namespace api {
20 
21 static const char *const TAG = "api";
22 
23 // APIServer
25  ESP_LOGCONFIG(TAG, "Setting up Home Assistant API server...");
26  this->setup_controller();
27  socket_ = socket::socket_ip(SOCK_STREAM, 0);
28  if (socket_ == nullptr) {
29  ESP_LOGW(TAG, "Could not create socket.");
30  this->mark_failed();
31  return;
32  }
33  int enable = 1;
34  int err = socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
35  if (err != 0) {
36  ESP_LOGW(TAG, "Socket unable to set reuseaddr: errno %d", err);
37  // we can still continue
38  }
39  err = socket_->setblocking(false);
40  if (err != 0) {
41  ESP_LOGW(TAG, "Socket unable to set nonblocking mode: errno %d", err);
42  this->mark_failed();
43  return;
44  }
45 
46  struct sockaddr_storage server;
47 
48  socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), this->port_);
49  if (sl == 0) {
50  ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno);
51  this->mark_failed();
52  return;
53  }
54 
55  err = socket_->bind((struct sockaddr *) &server, sl);
56  if (err != 0) {
57  ESP_LOGW(TAG, "Socket unable to bind: errno %d", errno);
58  this->mark_failed();
59  return;
60  }
61 
62  err = socket_->listen(4);
63  if (err != 0) {
64  ESP_LOGW(TAG, "Socket unable to listen: errno %d", errno);
65  this->mark_failed();
66  return;
67  }
68 
69 #ifdef USE_LOGGER
70  if (logger::global_logger != nullptr) {
71  logger::global_logger->add_on_log_callback([this](int level, const char *tag, const char *message) {
72  for (auto &c : this->clients_) {
73  if (!c->remove_)
74  c->send_log_message(level, tag, message);
75  }
76  });
77  }
78 #endif
79 
80  this->last_connected_ = millis();
81 
82 #ifdef USE_ESP32_CAMERA
83  if (esp32_camera::global_esp32_camera != nullptr && !esp32_camera::global_esp32_camera->is_internal()) {
85  [this](const std::shared_ptr<esp32_camera::CameraImage> &image) {
86  for (auto &c : this->clients_) {
87  if (!c->remove_)
88  c->send_camera_state(image);
89  }
90  });
91  }
92 #endif
93 }
95  // Accept new clients
96  while (true) {
97  struct sockaddr_storage source_addr;
98  socklen_t addr_len = sizeof(source_addr);
99  auto sock = socket_->accept((struct sockaddr *) &source_addr, &addr_len);
100  if (!sock)
101  break;
102  ESP_LOGD(TAG, "Accepted %s", sock->getpeername().c_str());
103 
104  auto *conn = new APIConnection(std::move(sock), this);
105  clients_.emplace_back(conn);
106  conn->start();
107  }
108 
109  // Partition clients into remove and active
110  auto new_end = std::partition(this->clients_.begin(), this->clients_.end(),
111  [](const std::unique_ptr<APIConnection> &conn) { return !conn->remove_; });
112  // print disconnection messages
113  for (auto it = new_end; it != this->clients_.end(); ++it) {
114  this->client_disconnected_trigger_->trigger((*it)->client_info_, (*it)->client_peername_);
115  ESP_LOGV(TAG, "Removing connection to %s", (*it)->client_info_.c_str());
116  }
117  // resize vector
118  this->clients_.erase(new_end, this->clients_.end());
119 
120  for (auto &client : this->clients_) {
121  client->loop();
122  }
123 
124  if (this->reboot_timeout_ != 0) {
125  const uint32_t now = millis();
126  if (!this->is_connected()) {
127  if (now - this->last_connected_ > this->reboot_timeout_) {
128  ESP_LOGE(TAG, "No client connected to API. Rebooting...");
129  App.reboot();
130  }
131  this->status_set_warning();
132  } else {
133  this->last_connected_ = now;
134  this->status_clear_warning();
135  }
136  }
137 }
139  ESP_LOGCONFIG(TAG, "API Server:");
140  ESP_LOGCONFIG(TAG, " Address: %s:%u", network::get_use_address().c_str(), this->port_);
141 #ifdef USE_API_NOISE
142  ESP_LOGCONFIG(TAG, " Using noise encryption: YES");
143 #else
144  ESP_LOGCONFIG(TAG, " Using noise encryption: NO");
145 #endif
146 }
147 bool APIServer::uses_password() const { return !this->password_.empty(); }
148 bool APIServer::check_password(const std::string &password) const {
149  // depend only on input password length
150  const char *a = this->password_.c_str();
151  uint32_t len_a = this->password_.length();
152  const char *b = password.c_str();
153  uint32_t len_b = password.length();
154 
155  // disable optimization with volatile
156  volatile uint32_t length = len_b;
157  volatile const char *left = nullptr;
158  volatile const char *right = b;
159  uint8_t result = 0;
160 
161  if (len_a == length) {
162  left = *((volatile const char **) &a);
163  result = 0;
164  }
165  if (len_a != length) {
166  left = b;
167  result = 1;
168  }
169 
170  for (size_t i = 0; i < length; i++) {
171  result |= *left++ ^ *right++; // NOLINT
172  }
173 
174  return result == 0;
175 }
177 #ifdef USE_BINARY_SENSOR
179  if (obj->is_internal())
180  return;
181  for (auto &c : this->clients_)
182  c->send_binary_sensor_state(obj, state);
183 }
184 #endif
185 
186 #ifdef USE_COVER
188  if (obj->is_internal())
189  return;
190  for (auto &c : this->clients_)
191  c->send_cover_state(obj);
192 }
193 #endif
194 
195 #ifdef USE_FAN
197  if (obj->is_internal())
198  return;
199  for (auto &c : this->clients_)
200  c->send_fan_state(obj);
201 }
202 #endif
203 
204 #ifdef USE_LIGHT
206  if (obj->is_internal())
207  return;
208  for (auto &c : this->clients_)
209  c->send_light_state(obj);
210 }
211 #endif
212 
213 #ifdef USE_SENSOR
215  if (obj->is_internal())
216  return;
217  for (auto &c : this->clients_)
218  c->send_sensor_state(obj, state);
219 }
220 #endif
221 
222 #ifdef USE_SWITCH
224  if (obj->is_internal())
225  return;
226  for (auto &c : this->clients_)
227  c->send_switch_state(obj, state);
228 }
229 #endif
230 
231 #ifdef USE_TEXT_SENSOR
233  if (obj->is_internal())
234  return;
235  for (auto &c : this->clients_)
236  c->send_text_sensor_state(obj, state);
237 }
238 #endif
239 
240 #ifdef USE_CLIMATE
242  if (obj->is_internal())
243  return;
244  for (auto &c : this->clients_)
245  c->send_climate_state(obj);
246 }
247 #endif
248 
249 #ifdef USE_NUMBER
251  if (obj->is_internal())
252  return;
253  for (auto &c : this->clients_)
254  c->send_number_state(obj, state);
255 }
256 #endif
257 
258 #ifdef USE_DATETIME_DATE
260  if (obj->is_internal())
261  return;
262  for (auto &c : this->clients_)
263  c->send_date_state(obj);
264 }
265 #endif
266 
267 #ifdef USE_DATETIME_TIME
269  if (obj->is_internal())
270  return;
271  for (auto &c : this->clients_)
272  c->send_time_state(obj);
273 }
274 #endif
275 
276 #ifdef USE_TEXT
277 void APIServer::on_text_update(text::Text *obj, const std::string &state) {
278  if (obj->is_internal())
279  return;
280  for (auto &c : this->clients_)
281  c->send_text_state(obj, state);
282 }
283 #endif
284 
285 #ifdef USE_SELECT
286 void APIServer::on_select_update(select::Select *obj, const std::string &state, size_t index) {
287  if (obj->is_internal())
288  return;
289  for (auto &c : this->clients_)
290  c->send_select_state(obj, state);
291 }
292 #endif
293 
294 #ifdef USE_LOCK
296  if (obj->is_internal())
297  return;
298  for (auto &c : this->clients_)
299  c->send_lock_state(obj, obj->state);
300 }
301 #endif
302 
303 #ifdef USE_MEDIA_PLAYER
305  if (obj->is_internal())
306  return;
307  for (auto &c : this->clients_)
308  c->send_media_player_state(obj);
309 }
310 #endif
311 
313 void APIServer::set_port(uint16_t port) { this->port_ = port; }
314 APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
315 
316 void APIServer::set_password(const std::string &password) { this->password_ = password; }
318  for (auto &client : this->clients_) {
319  client->send_homeassistant_service_call(call);
320  }
321 }
322 
323 APIServer::APIServer() { global_api_server = this; }
325  std::function<void(std::string)> f) {
327  .entity_id = std::move(entity_id),
328  .attribute = std::move(attribute),
329  .callback = std::move(f),
330  });
331 }
332 const std::vector<APIServer::HomeAssistantStateSubscription> &APIServer::get_state_subs() const {
333  return this->state_subs_;
334 }
335 uint16_t APIServer::get_port() const { return this->port_; }
336 void APIServer::set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
337 #ifdef USE_HOMEASSISTANT_TIME
339  for (auto &client : this->clients_) {
340  if (!client->remove_ && client->is_authenticated())
341  client->send_time_request();
342  }
343 }
344 #endif
345 bool APIServer::is_connected() const { return !this->clients_.empty(); }
347  for (auto &c : this->clients_) {
348  c->send_disconnect_request(DisconnectRequest());
349  }
350  delay(10);
351 }
352 
353 #ifdef USE_ALARM_CONTROL_PANEL
355  if (obj->is_internal())
356  return;
357  for (auto &c : this->clients_)
358  c->send_alarm_control_panel_state(obj);
359 }
360 #endif
361 
362 } // namespace api
363 } // namespace esphome
Base class for all switches.
Definition: switch.h:39
std::unique_ptr< Socket > socket_ip(int type, int protocol)
Create a socket in the newest available IP domain (IPv6 or IPv4) of the given type and protocol...
Definition: socket.cpp:12
void handle_disconnect(APIConnection *conn)
Definition: api_server.cpp:176
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Definition: light_state.h:34
bool is_connected() const
Definition: api_server.cpp:345
void add_on_log_callback(std::function< void(int, const char *, const char *)> &&callback)
Register a callback that will be called for every log message sent.
Definition: logger.cpp:159
Base class for all cover devices.
Definition: cover.h:111
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition: component.cpp:26
socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port)
Set a sockaddr to the any address and specified port for the IP version used by socket_ip().
Definition: socket.cpp:53
std::string get_use_address()
Get the active network hostname.
Definition: util.cpp:52
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:151
LockState state
The current reported state of the lock.
Definition: lock.h:122
void on_media_player_update(media_player::MediaPlayer *obj) override
Definition: api_server.cpp:304
void on_select_update(select::Select *obj, const std::string &state, size_t index) override
Definition: api_server.cpp:286
bool check_password(const std::string &password) const
Definition: api_server.cpp:148
std::vector< HomeAssistantStateSubscription > state_subs_
Definition: api_server.h:122
void on_light_update(light::LightState *obj) override
Definition: api_server.cpp:205
uint32_t socklen_t
Definition: headers.h:97
void on_lock_update(lock::Lock *obj) override
Definition: api_server.cpp:295
void send_homeassistant_service_call(const HomeassistantServiceResponse &call)
Definition: api_server.cpp:317
void add_image_callback(std::function< void(std::shared_ptr< CameraImage >)> &&callback)
void on_cover_update(cover::Cover *obj) override
Definition: api_server.cpp:187
void on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) override
Definition: api_server.cpp:178
Base-class for all text inputs.
Definition: text.h:24
void loop() override
Definition: api_server.cpp:94
Trigger< std::string, std::string > * client_disconnected_trigger_
Definition: api_server.h:125
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
void on_fan_update(fan::Fan *obj) override
Definition: api_server.cpp:196
void trigger(Ts... x)
Inform the parent automation that the event has triggered.
Definition: automation.h:95
void setup() override
Definition: api_server.cpp:24
void on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) override
Definition: api_server.cpp:354
Logger * global_logger
Definition: logger.cpp:179
void on_switch_update(switch_::Switch *obj, bool state) override
Definition: api_server.cpp:223
void dump_config() override
Definition: api_server.cpp:138
void on_date_update(datetime::DateEntity *obj) override
Definition: api_server.cpp:259
ESP32Camera * global_esp32_camera
void on_text_update(text::Text *obj, const std::string &state) override
Definition: api_server.cpp:277
void on_number_update(number::Number *obj, float state) override
Definition: api_server.cpp:250
Base-class for all numbers.
Definition: number.h:39
void status_clear_warning()
Definition: component.cpp:166
void set_reboot_timeout(uint32_t reboot_timeout)
Definition: api_server.cpp:336
void on_climate_update(climate::Climate *obj) override
Definition: api_server.cpp:241
bool is_internal() const
Definition: entity_base.cpp:22
void on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) override
Definition: api_server.cpp:232
Application App
Global storage of Application pointer - only one Application can exist.
void set_port(uint16_t port)
Definition: api_server.cpp:313
const std::vector< HomeAssistantStateSubscription > & get_state_subs() const
Definition: api_server.cpp:332
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
void on_sensor_update(sensor::Sensor *obj, float state) override
Definition: api_server.cpp:214
void setup_controller(bool include_internal=false)
Definition: controller.cpp:7
uint16_t length
Definition: tt21100.cpp:12
bool uses_password() const
Definition: api_server.cpp:147
Base-class for all selects.
Definition: select.h:31
std::vector< std::unique_ptr< APIConnection > > clients_
Definition: api_server.h:120
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
Base class for all binary_sensor-type classes.
Definition: binary_sensor.h:37
float get_setup_priority() const override
Definition: api_server.cpp:312
void subscribe_home_assistant_state(std::string entity_id, optional< std::string > attribute, std::function< void(std::string)> f)
Definition: api_server.cpp:324
void on_shutdown() override
Definition: api_server.cpp:346
Base-class for all sensors.
Definition: sensor.h:57
uint16_t get_port() const
Definition: api_server.cpp:335
void set_password(const std::string &password)
Definition: api_server.cpp:316
APIServer * global_api_server
Definition: api_server.cpp:314
std::unique_ptr< socket::Socket > socket_
Definition: api_server.h:116
Base class for all locks.
Definition: lock.h:103
ClimateDevice - This is the base class for all climate integrations.
Definition: climate.h:168
bool state
Definition: fan.h:34
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26
void on_time_update(datetime::TimeEntity *obj) override
Definition: api_server.cpp:268