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