ESPHome  2022.9.1
api_server.cpp
Go to the documentation of this file.
1 #include "api_server.h"
2 #include "api_connection.h"
4 #include "esphome/core/defines.h"
5 #include "esphome/core/log.h"
6 #include "esphome/core/util.h"
7 #include "esphome/core/version.h"
8 #include "esphome/core/hal.h"
10 #include <cerrno>
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), htons(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  ESP_LOGV(TAG, "Removing connection to %s", (*it)->client_info_.c_str());
115  }
116  // resize vector
117  this->clients_.erase(new_end, this->clients_.end());
118 
119  for (auto &client : this->clients_) {
120  client->loop();
121  }
122 
123  if (this->reboot_timeout_ != 0) {
124  const uint32_t now = millis();
125  if (!this->is_connected()) {
126  if (now - this->last_connected_ > this->reboot_timeout_) {
127  ESP_LOGE(TAG, "No client connected to API. Rebooting...");
128  App.reboot();
129  }
130  this->status_set_warning();
131  } else {
132  this->last_connected_ = now;
133  this->status_clear_warning();
134  }
135  }
136 }
138  ESP_LOGCONFIG(TAG, "API Server:");
139  ESP_LOGCONFIG(TAG, " Address: %s:%u", network::get_use_address().c_str(), this->port_);
140 #ifdef USE_API_NOISE
141  ESP_LOGCONFIG(TAG, " Using noise encryption: YES");
142 #else
143  ESP_LOGCONFIG(TAG, " Using noise encryption: NO");
144 #endif
145 }
146 bool APIServer::uses_password() const { return !this->password_.empty(); }
147 bool APIServer::check_password(const std::string &password) const {
148  // depend only on input password length
149  const char *a = this->password_.c_str();
150  uint32_t len_a = this->password_.length();
151  const char *b = password.c_str();
152  uint32_t len_b = password.length();
153 
154  // disable optimization with volatile
155  volatile uint32_t length = len_b;
156  volatile const char *left = nullptr;
157  volatile const char *right = b;
158  uint8_t result = 0;
159 
160  if (len_a == length) {
161  left = *((volatile const char **) &a);
162  result = 0;
163  }
164  if (len_a != length) {
165  left = b;
166  result = 1;
167  }
168 
169  for (size_t i = 0; i < length; i++) {
170  result |= *left++ ^ *right++; // NOLINT
171  }
172 
173  return result == 0;
174 }
176 #ifdef USE_BINARY_SENSOR
178  if (obj->is_internal())
179  return;
180  for (auto &c : this->clients_)
181  c->send_binary_sensor_state(obj, state);
182 }
183 #endif
184 
185 #ifdef USE_COVER
187  if (obj->is_internal())
188  return;
189  for (auto &c : this->clients_)
190  c->send_cover_state(obj);
191 }
192 #endif
193 
194 #ifdef USE_FAN
196  if (obj->is_internal())
197  return;
198  for (auto &c : this->clients_)
199  c->send_fan_state(obj);
200 }
201 #endif
202 
203 #ifdef USE_LIGHT
205  if (obj->is_internal())
206  return;
207  for (auto &c : this->clients_)
208  c->send_light_state(obj);
209 }
210 #endif
211 
212 #ifdef USE_SENSOR
214  if (obj->is_internal())
215  return;
216  for (auto &c : this->clients_)
217  c->send_sensor_state(obj, state);
218 }
219 #endif
220 
221 #ifdef USE_SWITCH
223  if (obj->is_internal())
224  return;
225  for (auto &c : this->clients_)
226  c->send_switch_state(obj, state);
227 }
228 #endif
229 
230 #ifdef USE_TEXT_SENSOR
232  if (obj->is_internal())
233  return;
234  for (auto &c : this->clients_)
235  c->send_text_sensor_state(obj, state);
236 }
237 #endif
238 
239 #ifdef USE_CLIMATE
241  if (obj->is_internal())
242  return;
243  for (auto &c : this->clients_)
244  c->send_climate_state(obj);
245 }
246 #endif
247 
248 #ifdef USE_NUMBER
250  if (obj->is_internal())
251  return;
252  for (auto &c : this->clients_)
253  c->send_number_state(obj, state);
254 }
255 #endif
256 
257 #ifdef USE_SELECT
258 void APIServer::on_select_update(select::Select *obj, const std::string &state, size_t index) {
259  if (obj->is_internal())
260  return;
261  for (auto &c : this->clients_)
262  c->send_select_state(obj, state);
263 }
264 #endif
265 
266 #ifdef USE_LOCK
268  if (obj->is_internal())
269  return;
270  for (auto &c : this->clients_)
271  c->send_lock_state(obj, obj->state);
272 }
273 #endif
274 
275 #ifdef USE_MEDIA_PLAYER
277  if (obj->is_internal())
278  return;
279  for (auto &c : this->clients_)
280  c->send_media_player_state(obj);
281 }
282 #endif
283 
285 void APIServer::set_port(uint16_t port) { this->port_ = port; }
286 APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
287 
288 void APIServer::set_password(const std::string &password) { this->password_ = password; }
290  for (auto &client : this->clients_) {
291  client->send_homeassistant_service_call(call);
292  }
293 }
294 #ifdef USE_BLUETOOTH_PROXY
296  for (auto &client : this->clients_) {
297  client->send_bluetooth_le_advertisement(call);
298  }
299 }
300 #endif
301 APIServer::APIServer() { global_api_server = this; }
303  std::function<void(std::string)> f) {
305  .entity_id = std::move(entity_id),
306  .attribute = std::move(attribute),
307  .callback = std::move(f),
308  });
309 }
310 const std::vector<APIServer::HomeAssistantStateSubscription> &APIServer::get_state_subs() const {
311  return this->state_subs_;
312 }
313 uint16_t APIServer::get_port() const { return this->port_; }
314 void APIServer::set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
315 #ifdef USE_HOMEASSISTANT_TIME
317  for (auto &client : this->clients_) {
318  if (!client->remove_ && client->connection_state_ == APIConnection::ConnectionState::CONNECTED)
319  client->send_time_request();
320  }
321 }
322 #endif
323 bool APIServer::is_connected() const { return !this->clients_.empty(); }
325  for (auto &c : this->clients_) {
326  c->send_disconnect_request(DisconnectRequest());
327  }
328  delay(10);
329 }
330 
331 } // namespace api
332 } // namespace esphome
Base class for all switches.
Definition: switch.h:33
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:9
void handle_disconnect(APIConnection *conn)
Definition: api_server.cpp:175
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Definition: light_state.h:32
bool is_connected() const
Definition: api_server.cpp:323
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:250
Base class for all cover devices.
Definition: cover.h:111
void send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &call)
Definition: api_server.cpp:295
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition: component.cpp:24
socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port)
Set a sockaddr to the any address for the IP version used by socket_ip().
Definition: socket.cpp:17
std::string get_use_address()
Get the active network hostname.
Definition: util.cpp:41
LockState state
The current reported state of the lock.
Definition: lock.h:123
void on_media_player_update(media_player::MediaPlayer *obj) override
Definition: api_server.cpp:276
void on_select_update(select::Select *obj, const std::string &state, size_t index) override
Definition: api_server.cpp:258
bool check_password(const std::string &password) const
Definition: api_server.cpp:147
std::vector< HomeAssistantStateSubscription > state_subs_
Definition: api_server.h:104
void on_light_update(light::LightState *obj) override
Definition: api_server.cpp:204
uint32_t socklen_t
Definition: headers.h:86
void on_lock_update(lock::Lock *obj) override
Definition: api_server.cpp:267
void send_homeassistant_service_call(const HomeassistantServiceResponse &call)
Definition: api_server.cpp:289
void add_image_callback(std::function< void(std::shared_ptr< CameraImage >)> &&f)
void on_cover_update(cover::Cover *obj) override
Definition: api_server.cpp:186
void on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) override
Definition: api_server.cpp:177
void loop() override
Definition: api_server.cpp:94
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:26
void on_fan_update(fan::Fan *obj) override
Definition: api_server.cpp:195
void setup() override
Definition: api_server.cpp:24
Logger * global_logger
Definition: logger.cpp:285
void on_switch_update(switch_::Switch *obj, bool state) override
Definition: api_server.cpp:222
void dump_config() override
Definition: api_server.cpp:137
ESP32Camera * global_esp32_camera
void on_number_update(number::Number *obj, float state) override
Definition: api_server.cpp:249
Base-class for all numbers.
Definition: number.h:29
void status_clear_warning()
Definition: component.cpp:148
void set_reboot_timeout(uint32_t reboot_timeout)
Definition: api_server.cpp:314
void on_climate_update(climate::Climate *obj) override
Definition: api_server.cpp:240
bool is_internal() const
Definition: entity_base.cpp:18
void on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) override
Definition: api_server.cpp:231
Application App
Global storage of Application pointer - only one Application can exist.
void status_set_warning()
Definition: component.cpp:140
void set_port(uint16_t port)
Definition: api_server.cpp:285
const std::vector< HomeAssistantStateSubscription > & get_state_subs() const
Definition: api_server.cpp:310
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:111
void on_sensor_update(sensor::Sensor *obj, float state) override
Definition: api_server.cpp:213
void setup_controller(bool include_internal=false)
Definition: controller.cpp:7
bool uses_password() const
Definition: api_server.cpp:146
Base-class for all selects.
Definition: select.h:24
std::vector< std::unique_ptr< APIConnection > > clients_
Definition: api_server.h:102
Definition: a4988.cpp:4
Base class for all binary_sensor-type classes.
Definition: binary_sensor.h:26
float get_setup_priority() const override
Definition: api_server.cpp:284
void subscribe_home_assistant_state(std::string entity_id, optional< std::string > attribute, std::function< void(std::string)> f)
Definition: api_server.cpp:302
void on_shutdown() override
Definition: api_server.cpp:324
Base-class for all sensors.
Definition: sensor.h:48
uint16_t get_port() const
Definition: api_server.cpp:313
void set_password(const std::string &password)
Definition: api_server.cpp:288
APIServer * global_api_server
Definition: api_server.cpp:286
std::unique_ptr< socket::Socket > socket_
Definition: api_server.h:98
Base class for all locks.
Definition: lock.h:103
ClimateDevice - This is the base class for all climate integrations.
Definition: climate.h:167
bool state
Definition: fan.h:34
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:27