ESPHome 2025.5.0
Loading...
Searching...
No Matches
api_connection.cpp
Go to the documentation of this file.
1#include "api_connection.h"
2#ifdef USE_API
3#include <cerrno>
4#include <cinttypes>
5#include <utility>
8#include "esphome/core/hal.h"
9#include "esphome/core/log.h"
12
13#ifdef USE_DEEP_SLEEP
15#endif
16#ifdef USE_HOMEASSISTANT_TIME
18#endif
19#ifdef USE_BLUETOOTH_PROXY
21#endif
22#ifdef USE_VOICE_ASSISTANT
24#endif
25
26namespace esphome {
27namespace api {
28
29static const char *const TAG = "api.connection";
30static const int ESP32_CAMERA_STOP_STREAM = 5000;
31
32// helper for allowing only unique entries in the queue
34 DeferredMessage item(source, send_message);
35
36 auto iter = std::find_if(this->deferred_queue_.begin(), this->deferred_queue_.end(),
37 [&item](const DeferredMessage &test) -> bool { return test == item; });
38
39 if (iter != this->deferred_queue_.end()) {
40 (*iter) = item;
41 } else {
42 this->deferred_queue_.push_back(item);
43 }
44}
45
47 while (!deferred_queue_.empty()) {
48 DeferredMessage &de = deferred_queue_.front();
49 if ((this->api_connection_->*(de.send_message_))(de.source_)) {
50 // O(n) but memory efficiency is more important than speed here which is why std::vector was chosen
51 deferred_queue_.erase(deferred_queue_.begin());
52 } else {
53 break;
54 }
55 }
56}
57
58void DeferredMessageQueue::defer(void *source, send_message_t send_message) {
59 this->dmq_push_back_with_dedup_(source, send_message);
60}
61
62APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *parent)
63 : parent_(parent), deferred_message_queue_(this), initial_state_iterator_(this), list_entities_iterator_(this) {
64 this->proto_write_buffer_.reserve(64);
65
66#if defined(USE_API_PLAINTEXT) && defined(USE_API_NOISE)
67 auto noise_ctx = parent->get_noise_ctx();
68 if (noise_ctx->has_psk()) {
69 this->helper_ = std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), noise_ctx)};
70 } else {
71 this->helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock))};
72 }
73#elif defined(USE_API_PLAINTEXT)
74 this->helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock))};
75#elif defined(USE_API_NOISE)
76 this->helper_ = std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), parent->get_noise_ctx())};
77#else
78#error "No frame helper defined"
79#endif
80}
81void APIConnection::start() {
82 this->last_traffic_ = App.get_loop_component_start_time();
83
84 // Set next_ping_retry_ to prevent immediate ping
85 // This ensures the first ping happens after the keepalive period
86 this->next_ping_retry_ = this->last_traffic_ + KEEPALIVE_TIMEOUT_MS;
87
88 APIError err = this->helper_->init();
89 if (err != APIError::OK) {
90 on_fatal_error();
91 ESP_LOGW(TAG, "%s: Helper init failed: %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err),
92 errno);
93 return;
94 }
95 this->client_info_ = helper_->getpeername();
96 this->client_peername_ = this->client_info_;
97 this->helper_->set_log_info(this->client_info_);
98}
99
100APIConnection::~APIConnection() {
101#ifdef USE_BLUETOOTH_PROXY
102 if (bluetooth_proxy::global_bluetooth_proxy->get_api_connection() == this) {
104 }
105#endif
106#ifdef USE_VOICE_ASSISTANT
107 if (voice_assistant::global_voice_assistant->get_api_connection() == this) {
109 }
110#endif
111}
112
113void APIConnection::loop() {
114 if (this->remove_)
115 return;
116
117 if (!network::is_connected()) {
118 // when network is disconnected force disconnect immediately
119 // don't wait for timeout
120 this->on_fatal_error();
121 ESP_LOGW(TAG, "%s: Network unavailable, disconnecting", this->client_combined_info_.c_str());
122 return;
123 }
124 if (this->next_close_) {
125 // requested a disconnect
126 this->helper_->close();
127 this->remove_ = true;
128 return;
129 }
130
131 APIError err = this->helper_->loop();
132 if (err != APIError::OK) {
133 on_fatal_error();
134 ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->client_combined_info_.c_str(),
135 api_error_to_str(err), errno);
136 return;
137 }
138 ReadPacketBuffer buffer;
139 err = this->helper_->read_packet(&buffer);
140 if (err == APIError::WOULD_BLOCK) {
141 // pass
142 } else if (err != APIError::OK) {
143 on_fatal_error();
144 if (err == APIError::SOCKET_READ_FAILED && errno == ECONNRESET) {
145 ESP_LOGW(TAG, "%s: Connection reset", this->client_combined_info_.c_str());
146 } else if (err == APIError::CONNECTION_CLOSED) {
147 ESP_LOGW(TAG, "%s: Connection closed", this->client_combined_info_.c_str());
148 } else {
149 ESP_LOGW(TAG, "%s: Reading failed: %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err),
150 errno);
151 }
152 return;
153 } else {
154 this->last_traffic_ = App.get_loop_component_start_time();
155 // read a packet
156 this->read_message(buffer.data_len, buffer.type, &buffer.container[buffer.data_offset]);
157 if (this->remove_)
158 return;
159 }
160
161 if (!this->deferred_message_queue_.empty() && this->helper_->can_write_without_blocking()) {
162 this->deferred_message_queue_.process_queue();
163 }
164
165 if (!this->list_entities_iterator_.completed())
166 this->list_entities_iterator_.advance();
167 if (!this->initial_state_iterator_.completed() && this->list_entities_iterator_.completed())
168 this->initial_state_iterator_.advance();
169
170 static uint8_t max_ping_retries = 60;
171 static uint16_t ping_retry_interval = 1000;
172 const uint32_t now = App.get_loop_component_start_time();
173 if (this->sent_ping_) {
174 // Disconnect if not responded within 2.5*keepalive
175 if (now - this->last_traffic_ > (KEEPALIVE_TIMEOUT_MS * 5) / 2) {
176 on_fatal_error();
177 ESP_LOGW(TAG, "%s didn't respond to ping request in time. Disconnecting...", this->client_combined_info_.c_str());
178 }
179 } else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && now > this->next_ping_retry_) {
180 ESP_LOGVV(TAG, "Sending keepalive PING...");
181 this->sent_ping_ = this->send_ping_request(PingRequest());
182 if (!this->sent_ping_) {
183 this->next_ping_retry_ = now + ping_retry_interval;
184 this->ping_retries_++;
185 if (this->ping_retries_ >= max_ping_retries) {
186 on_fatal_error();
187 ESP_LOGE(TAG, "%s: Sending keepalive failed %d time(s). Disconnecting...", this->client_combined_info_.c_str(),
188 this->ping_retries_);
189 } else if (this->ping_retries_ >= 10) {
190 ESP_LOGW(TAG, "%s: Sending keepalive failed %d time(s), will retry in %d ms",
191 this->client_combined_info_.c_str(), this->ping_retries_, ping_retry_interval);
192 } else {
193 ESP_LOGD(TAG, "%s: Sending keepalive failed %d time(s), will retry in %d ms",
194 this->client_combined_info_.c_str(), this->ping_retries_, ping_retry_interval);
195 }
196 }
197 }
198
199#ifdef USE_ESP32_CAMERA
200 if (this->image_reader_.available() && this->helper_->can_write_without_blocking()) {
201 // Message will use 8 more bytes than the minimum size, and typical
202 // MTU is 1500. Sometimes users will see as low as 1460 MTU.
203 // If its IPv6 the header is 40 bytes, and if its IPv4
204 // the header is 20 bytes. So we have 1460 - 40 = 1420 bytes
205 // available for the payload. But we also need to add the size of
206 // the protobuf overhead, which is 8 bytes.
207 //
208 // To be safe we pick 1390 bytes as the maximum size
209 // to send in one go. This is the maximum size of a single packet
210 // that can be sent over the network.
211 // This is to avoid fragmentation of the packet.
212 uint32_t to_send = std::min((size_t) 1390, this->image_reader_.available());
213 bool done = this->image_reader_.available() == to_send;
214 uint32_t msg_size = 0;
215 ProtoSize::add_fixed_field<4>(msg_size, 1, true);
216 // partial message size calculated manually since its a special case
217 // 1 for the data field, varint for the data size, and the data itself
218 msg_size += 1 + ProtoSize::varint(to_send) + to_send;
219 ProtoSize::add_bool_field(msg_size, 1, done);
220
221 auto buffer = this->create_buffer(msg_size);
222 // fixed32 key = 1;
223 buffer.encode_fixed32(1, esp32_camera::global_esp32_camera->get_object_id_hash());
224 // bytes data = 2;
225 buffer.encode_bytes(2, this->image_reader_.peek_data_buffer(), to_send);
226 // bool done = 3;
227 buffer.encode_bool(3, done);
228
229 bool success = this->send_buffer(buffer, 44);
230
231 if (success) {
232 this->image_reader_.consume_data(to_send);
233 }
234 if (success && done) {
235 this->image_reader_.return_image();
236 }
237 }
238#endif
239
240 if (state_subs_at_ != -1) {
241 const auto &subs = this->parent_->get_state_subs();
242 if (state_subs_at_ >= (int) subs.size()) {
243 state_subs_at_ = -1;
244 } else {
245 auto &it = subs[state_subs_at_];
247 resp.entity_id = it.entity_id;
248 resp.attribute = it.attribute.value();
249 resp.once = it.once;
250 if (this->send_subscribe_home_assistant_state_response(resp)) {
251 state_subs_at_++;
252 }
253 }
254 }
255}
256
257std::string get_default_unique_id(const std::string &component_type, EntityBase *entity) {
258 return App.get_name() + component_type + entity->get_object_id();
259}
260
261DisconnectResponse APIConnection::disconnect(const DisconnectRequest &msg) {
262 // remote initiated disconnect_client
263 // don't close yet, we still need to send the disconnect response
264 // close will happen on next loop
265 ESP_LOGD(TAG, "%s requested disconnected", this->client_combined_info_.c_str());
266 this->next_close_ = true;
268 return resp;
269}
270void APIConnection::on_disconnect_response(const DisconnectResponse &value) {
271 // pass
272}
273
274#ifdef USE_BINARY_SENSOR
275bool APIConnection::send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor, bool state) {
276 return this->send_state_with_value_(binary_sensor, &APIConnection::try_send_binary_sensor_state_,
277 &APIConnection::try_send_binary_sensor_state_, state);
278}
279void APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor) {
280 this->send_info_(static_cast<EntityBase *>(binary_sensor),
281 reinterpret_cast<send_message_t>(&APIConnection::try_send_binary_sensor_info_));
282}
283bool APIConnection::try_send_binary_sensor_state_(binary_sensor::BinarySensor *binary_sensor) {
284 return this->try_send_binary_sensor_state_(binary_sensor, binary_sensor->state);
285}
286bool APIConnection::try_send_binary_sensor_state_(binary_sensor::BinarySensor *binary_sensor, bool state) {
288 msg.state = state;
289 msg.missing_state = !binary_sensor->has_state();
290 msg.key = binary_sensor->get_object_id_hash();
291 return this->send_binary_sensor_state_response(msg);
292}
293bool APIConnection::try_send_binary_sensor_info_(binary_sensor::BinarySensor *binary_sensor) {
295 msg.device_class = binary_sensor->get_device_class();
297 msg.unique_id = get_default_unique_id("binary_sensor", binary_sensor);
298 return this->try_send_entity_info_(static_cast<EntityBase *>(binary_sensor), msg,
299 &APIConnection::send_list_entities_binary_sensor_response);
300}
301#endif
302
303#ifdef USE_COVER
304bool APIConnection::send_cover_state(cover::Cover *cover) {
305 return this->send_state_(static_cast<EntityBase *>(cover),
306 reinterpret_cast<send_message_t>(&APIConnection::try_send_cover_state_));
307}
308void APIConnection::send_cover_info(cover::Cover *cover) {
309 this->send_info_(static_cast<EntityBase *>(cover),
310 reinterpret_cast<send_message_t>(&APIConnection::try_send_cover_info_));
311}
312bool APIConnection::try_send_cover_state_(cover::Cover *cover) {
314 auto traits = cover->get_traits();
315 msg.legacy_state =
316 (cover->position == cover::COVER_OPEN) ? enums::LEGACY_COVER_STATE_OPEN : enums::LEGACY_COVER_STATE_CLOSED;
317 msg.position = cover->position;
318 if (traits.get_supports_tilt())
319 msg.tilt = cover->tilt;
321 msg.key = cover->get_object_id_hash();
322 return this->send_cover_state_response(msg);
323}
324bool APIConnection::try_send_cover_info_(cover::Cover *cover) {
326 auto traits = cover->get_traits();
327 msg.assumed_state = traits.get_is_assumed_state();
328 msg.supports_position = traits.get_supports_position();
329 msg.supports_tilt = traits.get_supports_tilt();
330 msg.supports_stop = traits.get_supports_stop();
331 msg.device_class = cover->get_device_class();
332 msg.unique_id = get_default_unique_id("cover", cover);
333 return this->try_send_entity_info_(static_cast<EntityBase *>(cover), msg,
334 &APIConnection::send_list_entities_cover_response);
335}
336void APIConnection::cover_command(const CoverCommandRequest &msg) {
337 cover::Cover *cover = App.get_cover_by_key(msg.key);
338 if (cover == nullptr)
339 return;
340
341 auto call = cover->make_call();
342 if (msg.has_legacy_command) {
343 switch (msg.legacy_command) {
344 case enums::LEGACY_COVER_COMMAND_OPEN:
345 call.set_command_open();
346 break;
347 case enums::LEGACY_COVER_COMMAND_CLOSE:
348 call.set_command_close();
349 break;
350 case enums::LEGACY_COVER_COMMAND_STOP:
351 call.set_command_stop();
352 break;
353 }
354 }
355 if (msg.has_position)
356 call.set_position(msg.position);
357 if (msg.has_tilt)
358 call.set_tilt(msg.tilt);
359 if (msg.stop)
360 call.set_command_stop();
361 call.perform();
362}
363#endif
364
365#ifdef USE_FAN
366bool APIConnection::send_fan_state(fan::Fan *fan) {
367 return this->send_state_(static_cast<EntityBase *>(fan),
368 reinterpret_cast<send_message_t>(&APIConnection::try_send_fan_state_));
369}
370void APIConnection::send_fan_info(fan::Fan *fan) {
371 this->send_info_(static_cast<EntityBase *>(fan),
372 reinterpret_cast<send_message_t>(&APIConnection::try_send_fan_info_));
373}
374bool APIConnection::try_send_fan_state_(fan::Fan *fan) {
376 auto traits = fan->get_traits();
377 msg.state = fan->state;
378 if (traits.supports_oscillation())
379 msg.oscillating = fan->oscillating;
380 if (traits.supports_speed()) {
381 msg.speed_level = fan->speed;
382 }
383 if (traits.supports_direction())
384 msg.direction = static_cast<enums::FanDirection>(fan->direction);
385 if (traits.supports_preset_modes())
386 msg.preset_mode = fan->preset_mode;
387 msg.key = fan->get_object_id_hash();
388 return this->send_fan_state_response(msg);
389}
390bool APIConnection::try_send_fan_info_(fan::Fan *fan) {
392 auto traits = fan->get_traits();
393 msg.supports_oscillation = traits.supports_oscillation();
394 msg.supports_speed = traits.supports_speed();
395 msg.supports_direction = traits.supports_direction();
396 msg.supported_speed_count = traits.supported_speed_count();
397 for (auto const &preset : traits.supported_preset_modes())
398 msg.supported_preset_modes.push_back(preset);
399 msg.unique_id = get_default_unique_id("fan", fan);
400 return this->try_send_entity_info_(static_cast<EntityBase *>(fan), msg,
401 &APIConnection::send_list_entities_fan_response);
402}
403void APIConnection::fan_command(const FanCommandRequest &msg) {
404 fan::Fan *fan = App.get_fan_by_key(msg.key);
405 if (fan == nullptr)
406 return;
407
408 auto call = fan->make_call();
409 if (msg.has_state)
410 call.set_state(msg.state);
411 if (msg.has_oscillating)
413 if (msg.has_speed_level) {
414 // Prefer level
415 call.set_speed(msg.speed_level);
416 }
417 if (msg.has_direction)
418 call.set_direction(static_cast<fan::FanDirection>(msg.direction));
419 if (msg.has_preset_mode)
421 call.perform();
422}
423#endif
424
425#ifdef USE_LIGHT
426bool APIConnection::send_light_state(light::LightState *light) {
427 return this->send_state_(static_cast<EntityBase *>(light),
428 reinterpret_cast<send_message_t>(&APIConnection::try_send_light_state_));
429}
430void APIConnection::send_light_info(light::LightState *light) {
431 this->send_info_(static_cast<EntityBase *>(light),
432 reinterpret_cast<send_message_t>(&APIConnection::try_send_light_info_));
433}
434bool APIConnection::try_send_light_state_(light::LightState *light) {
436 auto traits = light->get_traits();
437 auto values = light->remote_values;
438 auto color_mode = values.get_color_mode();
439 resp.state = values.is_on();
440 resp.color_mode = static_cast<enums::ColorMode>(color_mode);
441 resp.brightness = values.get_brightness();
442 resp.color_brightness = values.get_color_brightness();
443 resp.red = values.get_red();
444 resp.green = values.get_green();
445 resp.blue = values.get_blue();
446 resp.white = values.get_white();
447 resp.color_temperature = values.get_color_temperature();
448 resp.cold_white = values.get_cold_white();
449 resp.warm_white = values.get_warm_white();
450 if (light->supports_effects())
451 resp.effect = light->get_effect_name();
452 resp.key = light->get_object_id_hash();
453 return this->send_light_state_response(resp);
454}
455bool APIConnection::try_send_light_info_(light::LightState *light) {
457 auto traits = light->get_traits();
458 for (auto mode : traits.get_supported_color_modes())
459 msg.supported_color_modes.push_back(static_cast<enums::ColorMode>(mode));
460 msg.legacy_supports_brightness = traits.supports_color_capability(light::ColorCapability::BRIGHTNESS);
461 msg.legacy_supports_rgb = traits.supports_color_capability(light::ColorCapability::RGB);
463 msg.legacy_supports_rgb && (traits.supports_color_capability(light::ColorCapability::WHITE) ||
464 traits.supports_color_capability(light::ColorCapability::COLD_WARM_WHITE));
466 traits.supports_color_capability(light::ColorCapability::COLD_WARM_WHITE);
468 msg.min_mireds = traits.get_min_mireds();
469 msg.max_mireds = traits.get_max_mireds();
470 }
471 if (light->supports_effects()) {
472 msg.effects.emplace_back("None");
473 for (auto *effect : light->get_effects()) {
474 msg.effects.push_back(effect->get_name());
475 }
476 }
477 msg.unique_id = get_default_unique_id("light", light);
478 return this->try_send_entity_info_(static_cast<EntityBase *>(light), msg,
479 &APIConnection::send_list_entities_light_response);
480}
481void APIConnection::light_command(const LightCommandRequest &msg) {
483 if (light == nullptr)
484 return;
485
486 auto call = light->make_call();
487 if (msg.has_state)
488 call.set_state(msg.state);
489 if (msg.has_brightness)
490 call.set_brightness(msg.brightness);
491 if (msg.has_color_mode)
492 call.set_color_mode(static_cast<light::ColorMode>(msg.color_mode));
493 if (msg.has_color_brightness)
495 if (msg.has_rgb) {
496 call.set_red(msg.red);
497 call.set_green(msg.green);
498 call.set_blue(msg.blue);
499 }
500 if (msg.has_white)
501 call.set_white(msg.white);
502 if (msg.has_color_temperature)
504 if (msg.has_cold_white)
505 call.set_cold_white(msg.cold_white);
506 if (msg.has_warm_white)
507 call.set_warm_white(msg.warm_white);
508 if (msg.has_transition_length)
510 if (msg.has_flash_length)
512 if (msg.has_effect)
513 call.set_effect(msg.effect);
514 call.perform();
515}
516#endif
517
518#ifdef USE_SENSOR
519bool APIConnection::send_sensor_state(sensor::Sensor *sensor, float state) {
520 return this->send_state_with_value_(sensor, &APIConnection::try_send_sensor_state_,
521 &APIConnection::try_send_sensor_state_, state);
522}
523void APIConnection::send_sensor_info(sensor::Sensor *sensor) {
524 this->send_info_(static_cast<EntityBase *>(sensor),
525 reinterpret_cast<send_message_t>(&APIConnection::try_send_sensor_info_));
526}
527bool APIConnection::try_send_sensor_state_(sensor::Sensor *sensor) {
528 return this->try_send_sensor_state_(sensor, sensor->state);
529}
530bool APIConnection::try_send_sensor_state_(sensor::Sensor *sensor, float state) {
532 resp.state = state;
533 resp.missing_state = !sensor->has_state();
534
535 resp.key = sensor->get_object_id_hash();
536 return this->send_sensor_state_response(resp);
537}
538bool APIConnection::try_send_sensor_info_(sensor::Sensor *sensor) {
542 msg.force_update = sensor->get_force_update();
543 msg.device_class = sensor->get_device_class();
544 msg.state_class = static_cast<enums::SensorStateClass>(sensor->get_state_class());
545 msg.unique_id = sensor->unique_id();
546 if (msg.unique_id.empty())
547 msg.unique_id = get_default_unique_id("sensor", sensor);
548 return this->try_send_entity_info_(static_cast<EntityBase *>(sensor), msg,
549 &APIConnection::send_list_entities_sensor_response);
550}
551#endif
552
553#ifdef USE_SWITCH
554bool APIConnection::send_switch_state(switch_::Switch *a_switch, bool state) {
555 return this->send_state_with_value_(a_switch, &APIConnection::try_send_switch_state_,
556 &APIConnection::try_send_switch_state_, state);
557}
558void APIConnection::send_switch_info(switch_::Switch *a_switch) {
559 this->send_info_(static_cast<EntityBase *>(a_switch),
560 reinterpret_cast<send_message_t>(&APIConnection::try_send_switch_info_));
561}
562bool APIConnection::try_send_switch_state_(switch_::Switch *a_switch) {
563 return this->try_send_switch_state_(a_switch, a_switch->state);
564}
565bool APIConnection::try_send_switch_state_(switch_::Switch *a_switch, bool state) {
567 resp.state = state;
568
569 resp.key = a_switch->get_object_id_hash();
570 return this->send_switch_state_response(resp);
571}
572bool APIConnection::try_send_switch_info_(switch_::Switch *a_switch) {
574 msg.assumed_state = a_switch->assumed_state();
575 msg.device_class = a_switch->get_device_class();
576 msg.unique_id = get_default_unique_id("switch", a_switch);
577 return this->try_send_entity_info_(static_cast<EntityBase *>(a_switch), msg,
578 &APIConnection::send_list_entities_switch_response);
579}
580void APIConnection::switch_command(const SwitchCommandRequest &msg) {
581 switch_::Switch *a_switch = App.get_switch_by_key(msg.key);
582 if (a_switch == nullptr)
583 return;
584
585 if (msg.state) {
586 a_switch->turn_on();
587 } else {
588 a_switch->turn_off();
589 }
590}
591#endif
592
593#ifdef USE_TEXT_SENSOR
594bool APIConnection::send_text_sensor_state(text_sensor::TextSensor *text_sensor, std::string state) {
595 return this->send_state_with_value_(text_sensor, &APIConnection::try_send_text_sensor_state_,
596 &APIConnection::try_send_text_sensor_state_, std::move(state));
597}
598void APIConnection::send_text_sensor_info(text_sensor::TextSensor *text_sensor) {
599 this->send_info_(static_cast<EntityBase *>(text_sensor),
600 reinterpret_cast<send_message_t>(&APIConnection::try_send_text_sensor_info_));
601}
602bool APIConnection::try_send_text_sensor_state_(text_sensor::TextSensor *text_sensor) {
603 return this->try_send_text_sensor_state_(text_sensor, text_sensor->state);
604}
605bool APIConnection::try_send_text_sensor_state_(text_sensor::TextSensor *text_sensor, std::string state) {
607 resp.state = std::move(state);
608 resp.missing_state = !text_sensor->has_state();
609
610 resp.key = text_sensor->get_object_id_hash();
611 return this->send_text_sensor_state_response(resp);
612}
613bool APIConnection::try_send_text_sensor_info_(text_sensor::TextSensor *text_sensor) {
615 msg.device_class = text_sensor->get_device_class();
616 msg.unique_id = text_sensor->unique_id();
617 if (msg.unique_id.empty())
618 msg.unique_id = get_default_unique_id("text_sensor", text_sensor);
619 return this->try_send_entity_info_(static_cast<EntityBase *>(text_sensor), msg,
620 &APIConnection::send_list_entities_text_sensor_response);
621}
622#endif
623
624#ifdef USE_CLIMATE
625bool APIConnection::send_climate_state(climate::Climate *climate) {
626 return this->send_state_(static_cast<EntityBase *>(climate),
627 reinterpret_cast<send_message_t>(&APIConnection::try_send_climate_state_));
628}
629void APIConnection::send_climate_info(climate::Climate *climate) {
630 this->send_info_(static_cast<EntityBase *>(climate),
631 reinterpret_cast<send_message_t>(&APIConnection::try_send_climate_info_));
632}
633bool APIConnection::try_send_climate_state_(climate::Climate *climate) {
635 resp.key = climate->get_object_id_hash();
636 auto traits = climate->get_traits();
637 resp.mode = static_cast<enums::ClimateMode>(climate->mode);
638 resp.action = static_cast<enums::ClimateAction>(climate->action);
639 if (traits.get_supports_current_temperature())
641 if (traits.get_supports_two_point_target_temperature()) {
644 } else {
646 }
647 if (traits.get_supports_fan_modes() && climate->fan_mode.has_value())
648 resp.fan_mode = static_cast<enums::ClimateFanMode>(climate->fan_mode.value());
649 if (!traits.get_supported_custom_fan_modes().empty() && climate->custom_fan_mode.has_value())
650 resp.custom_fan_mode = climate->custom_fan_mode.value();
651 if (traits.get_supports_presets() && climate->preset.has_value()) {
652 resp.preset = static_cast<enums::ClimatePreset>(climate->preset.value());
653 }
654 if (!traits.get_supported_custom_presets().empty() && climate->custom_preset.has_value())
655 resp.custom_preset = climate->custom_preset.value();
656 if (traits.get_supports_swing_modes())
657 resp.swing_mode = static_cast<enums::ClimateSwingMode>(climate->swing_mode);
658 if (traits.get_supports_current_humidity())
659 resp.current_humidity = climate->current_humidity;
660 if (traits.get_supports_target_humidity())
661 resp.target_humidity = climate->target_humidity;
662 return this->send_climate_state_response(resp);
663}
664bool APIConnection::try_send_climate_info_(climate::Climate *climate) {
666 auto traits = climate->get_traits();
667 msg.supports_current_temperature = traits.get_supports_current_temperature();
668 msg.supports_current_humidity = traits.get_supports_current_humidity();
669 msg.supports_two_point_target_temperature = traits.get_supports_two_point_target_temperature();
670 msg.supports_target_humidity = traits.get_supports_target_humidity();
671 for (auto mode : traits.get_supported_modes())
672 msg.supported_modes.push_back(static_cast<enums::ClimateMode>(mode));
673 msg.visual_min_temperature = traits.get_visual_min_temperature();
674 msg.visual_max_temperature = traits.get_visual_max_temperature();
675 msg.visual_target_temperature_step = traits.get_visual_target_temperature_step();
676 msg.visual_current_temperature_step = traits.get_visual_current_temperature_step();
677 msg.visual_min_humidity = traits.get_visual_min_humidity();
678 msg.visual_max_humidity = traits.get_visual_max_humidity();
679 msg.legacy_supports_away = traits.supports_preset(climate::CLIMATE_PRESET_AWAY);
680 msg.supports_action = traits.get_supports_action();
681 for (auto fan_mode : traits.get_supported_fan_modes())
682 msg.supported_fan_modes.push_back(static_cast<enums::ClimateFanMode>(fan_mode));
683 for (auto const &custom_fan_mode : traits.get_supported_custom_fan_modes())
685 for (auto preset : traits.get_supported_presets())
686 msg.supported_presets.push_back(static_cast<enums::ClimatePreset>(preset));
687 for (auto const &custom_preset : traits.get_supported_custom_presets())
689 for (auto swing_mode : traits.get_supported_swing_modes())
690 msg.supported_swing_modes.push_back(static_cast<enums::ClimateSwingMode>(swing_mode));
691 msg.unique_id = get_default_unique_id("climate", climate);
692 return this->try_send_entity_info_(static_cast<EntityBase *>(climate), msg,
693 &APIConnection::send_list_entities_climate_response);
694}
695void APIConnection::climate_command(const ClimateCommandRequest &msg) {
697 if (climate == nullptr)
698 return;
699
700 auto call = climate->make_call();
701 if (msg.has_mode)
702 call.set_mode(static_cast<climate::ClimateMode>(msg.mode));
709 if (msg.has_target_humidity)
711 if (msg.has_fan_mode)
712 call.set_fan_mode(static_cast<climate::ClimateFanMode>(msg.fan_mode));
713 if (msg.has_custom_fan_mode)
715 if (msg.has_preset)
716 call.set_preset(static_cast<climate::ClimatePreset>(msg.preset));
717 if (msg.has_custom_preset)
718 call.set_preset(msg.custom_preset);
719 if (msg.has_swing_mode)
721 call.perform();
722}
723#endif
724
725#ifdef USE_NUMBER
726bool APIConnection::send_number_state(number::Number *number, float state) {
727 return this->send_state_with_value_(number, &APIConnection::try_send_number_state_,
728 &APIConnection::try_send_number_state_, state);
729}
730void APIConnection::send_number_info(number::Number *number) {
731 this->send_info_(static_cast<EntityBase *>(number),
732 reinterpret_cast<send_message_t>(&APIConnection::try_send_number_info_));
733}
734bool APIConnection::try_send_number_state_(number::Number *number) {
735 return this->try_send_number_state_(number, number->state);
736}
737bool APIConnection::try_send_number_state_(number::Number *number, float state) {
739 resp.state = state;
740 resp.missing_state = !number->has_state();
741
742 resp.key = number->get_object_id_hash();
743 return this->send_number_state_response(resp);
744}
745bool APIConnection::try_send_number_info_(number::Number *number) {
748 msg.mode = static_cast<enums::NumberMode>(number->traits.get_mode());
749 msg.device_class = number->traits.get_device_class();
750 msg.min_value = number->traits.get_min_value();
751 msg.max_value = number->traits.get_max_value();
752 msg.step = number->traits.get_step();
753 msg.unique_id = get_default_unique_id("number", number);
754 return this->try_send_entity_info_(static_cast<EntityBase *>(number), msg,
755 &APIConnection::send_list_entities_number_response);
756}
757void APIConnection::number_command(const NumberCommandRequest &msg) {
759 if (number == nullptr)
760 return;
761
762 auto call = number->make_call();
763 call.set_value(msg.state);
764 call.perform();
765}
766#endif
767
768#ifdef USE_DATETIME_DATE
769bool APIConnection::send_date_state(datetime::DateEntity *date) {
770 return this->send_state_(static_cast<EntityBase *>(date),
771 reinterpret_cast<send_message_t>(&APIConnection::try_send_date_state_));
772}
773void APIConnection::send_date_info(datetime::DateEntity *date) {
774 this->send_info_(static_cast<EntityBase *>(date),
775 reinterpret_cast<send_message_t>(&APIConnection::try_send_date_info_));
776}
777bool APIConnection::try_send_date_state_(datetime::DateEntity *date) {
779 resp.missing_state = !date->has_state();
780 resp.year = date->year;
781 resp.month = date->month;
782 resp.day = date->day;
783
784 resp.key = date->get_object_id_hash();
785 return this->send_date_state_response(resp);
786}
787bool APIConnection::try_send_date_info_(datetime::DateEntity *date) {
789 msg.unique_id = get_default_unique_id("date", date);
790 return this->try_send_entity_info_(static_cast<EntityBase *>(date), msg,
791 &APIConnection::send_list_entities_date_response);
792}
793void APIConnection::date_command(const DateCommandRequest &msg) {
795 if (date == nullptr)
796 return;
797
798 auto call = date->make_call();
799 call.set_date(msg.year, msg.month, msg.day);
800 call.perform();
801}
802#endif
803
804#ifdef USE_DATETIME_TIME
805bool APIConnection::send_time_state(datetime::TimeEntity *time) {
806 return this->send_state_(static_cast<EntityBase *>(time),
807 reinterpret_cast<send_message_t>(&APIConnection::try_send_time_state_));
808}
809void APIConnection::send_time_info(datetime::TimeEntity *time) {
810 this->send_info_(static_cast<EntityBase *>(time),
811 reinterpret_cast<send_message_t>(&APIConnection::try_send_time_info_));
812}
813bool APIConnection::try_send_time_state_(datetime::TimeEntity *time) {
815 resp.missing_state = !time->has_state();
816 resp.hour = time->hour;
817 resp.minute = time->minute;
818 resp.second = time->second;
819
820 resp.key = time->get_object_id_hash();
821 return this->send_time_state_response(resp);
822}
823bool APIConnection::try_send_time_info_(datetime::TimeEntity *time) {
825 msg.unique_id = get_default_unique_id("time", time);
826 return this->try_send_entity_info_(static_cast<EntityBase *>(time), msg,
827 &APIConnection::send_list_entities_time_response);
828}
829void APIConnection::time_command(const TimeCommandRequest &msg) {
831 if (time == nullptr)
832 return;
833
834 auto call = time->make_call();
835 call.set_time(msg.hour, msg.minute, msg.second);
836 call.perform();
837}
838#endif
839
840#ifdef USE_DATETIME_DATETIME
841bool APIConnection::send_datetime_state(datetime::DateTimeEntity *datetime) {
842 return this->send_state_(static_cast<EntityBase *>(datetime),
843 reinterpret_cast<send_message_t>(&APIConnection::try_send_datetime_state_));
844}
845void APIConnection::send_datetime_info(datetime::DateTimeEntity *datetime) {
846 this->send_info_(static_cast<EntityBase *>(datetime),
847 reinterpret_cast<send_message_t>(&APIConnection::try_send_datetime_info_));
848}
849bool APIConnection::try_send_datetime_state_(datetime::DateTimeEntity *datetime) {
851 resp.missing_state = !datetime->has_state();
852 if (datetime->has_state()) {
853 ESPTime state = datetime->state_as_esptime();
854 resp.epoch_seconds = state.timestamp;
855 }
856
857 resp.key = datetime->get_object_id_hash();
858 return this->send_date_time_state_response(resp);
859}
860bool APIConnection::try_send_datetime_info_(datetime::DateTimeEntity *datetime) {
862 msg.unique_id = get_default_unique_id("datetime", datetime);
863 return this->try_send_entity_info_(static_cast<EntityBase *>(datetime), msg,
864 &APIConnection::send_list_entities_date_time_response);
865}
866void APIConnection::datetime_command(const DateTimeCommandRequest &msg) {
868 if (datetime == nullptr)
869 return;
870
871 auto call = datetime->make_call();
872 call.set_datetime(msg.epoch_seconds);
873 call.perform();
874}
875#endif
876
877#ifdef USE_TEXT
878bool APIConnection::send_text_state(text::Text *text, std::string state) {
879 return this->send_state_with_value_(text, &APIConnection::try_send_text_state_, &APIConnection::try_send_text_state_,
880 std::move(state));
881}
882void APIConnection::send_text_info(text::Text *text) {
883 this->send_info_(static_cast<EntityBase *>(text),
884 reinterpret_cast<send_message_t>(&APIConnection::try_send_text_info_));
885}
886bool APIConnection::try_send_text_state_(text::Text *text) { return this->try_send_text_state_(text, text->state); }
887bool APIConnection::try_send_text_state_(text::Text *text, std::string state) {
889 resp.state = std::move(state);
890 resp.missing_state = !text->has_state();
891
892 resp.key = text->get_object_id_hash();
893 return this->send_text_state_response(resp);
894}
895bool APIConnection::try_send_text_info_(text::Text *text) {
897 msg.mode = static_cast<enums::TextMode>(text->traits.get_mode());
898 msg.min_length = text->traits.get_min_length();
899 msg.max_length = text->traits.get_max_length();
900 msg.pattern = text->traits.get_pattern();
901 msg.unique_id = get_default_unique_id("text", text);
902 return this->try_send_entity_info_(static_cast<EntityBase *>(text), msg,
903 &APIConnection::send_list_entities_text_response);
904}
905void APIConnection::text_command(const TextCommandRequest &msg) {
906 text::Text *text = App.get_text_by_key(msg.key);
907 if (text == nullptr)
908 return;
909
910 auto call = text->make_call();
911 call.set_value(msg.state);
912 call.perform();
913}
914#endif
915
916#ifdef USE_SELECT
917bool APIConnection::send_select_state(select::Select *select, std::string state) {
918 return this->send_state_with_value_(select, &APIConnection::try_send_select_state_,
919 &APIConnection::try_send_select_state_, std::move(state));
920}
921void APIConnection::send_select_info(select::Select *select) {
922 this->send_info_(static_cast<EntityBase *>(select),
923 reinterpret_cast<send_message_t>(&APIConnection::try_send_select_info_));
924}
925bool APIConnection::try_send_select_state_(select::Select *select) {
926 return this->try_send_select_state_(select, select->state);
927}
928bool APIConnection::try_send_select_state_(select::Select *select, std::string state) {
930 resp.state = std::move(state);
931 resp.missing_state = !select->has_state();
932
933 resp.key = select->get_object_id_hash();
934 return this->send_select_state_response(resp);
935}
936bool APIConnection::try_send_select_info_(select::Select *select) {
938 for (const auto &option : select->traits.get_options())
939 msg.options.push_back(option);
940 msg.unique_id = get_default_unique_id("select", select);
941 return this->try_send_entity_info_(static_cast<EntityBase *>(select), msg,
942 &APIConnection::send_list_entities_select_response);
943}
944void APIConnection::select_command(const SelectCommandRequest &msg) {
946 if (select == nullptr)
947 return;
948
949 auto call = select->make_call();
950 call.set_option(msg.state);
951 call.perform();
952}
953#endif
954
955#ifdef USE_BUTTON
957 this->send_info_(static_cast<EntityBase *>(button),
958 reinterpret_cast<send_message_t>(&APIConnection::try_send_button_info_));
959}
962 msg.device_class = button->get_device_class();
963 msg.unique_id = get_default_unique_id("button", button);
964 return this->try_send_entity_info_(static_cast<EntityBase *>(button), msg,
965 &APIConnection::send_list_entities_button_response);
966}
969 if (button == nullptr)
970 return;
971
972 button->press();
973}
974#endif
975
976#ifdef USE_LOCK
977bool APIConnection::send_lock_state(lock::Lock *a_lock, lock::LockState state) {
978 return this->send_state_with_value_(a_lock, &APIConnection::try_send_lock_state_,
979 &APIConnection::try_send_lock_state_, state);
980}
981void APIConnection::send_lock_info(lock::Lock *a_lock) {
982 this->send_info_(static_cast<EntityBase *>(a_lock),
983 reinterpret_cast<send_message_t>(&APIConnection::try_send_lock_info_));
984}
985bool APIConnection::try_send_lock_state_(lock::Lock *a_lock) {
986 return this->try_send_lock_state_(a_lock, a_lock->state);
987}
988bool APIConnection::try_send_lock_state_(lock::Lock *a_lock, lock::LockState state) {
990 resp.state = static_cast<enums::LockState>(state);
991
992 resp.key = a_lock->get_object_id_hash();
993 return this->send_lock_state_response(resp);
994}
995bool APIConnection::try_send_lock_info_(lock::Lock *a_lock) {
997 msg.assumed_state = a_lock->traits.get_assumed_state();
998 msg.supports_open = a_lock->traits.get_supports_open();
999 msg.requires_code = a_lock->traits.get_requires_code();
1000 msg.unique_id = get_default_unique_id("lock", a_lock);
1001 return this->try_send_entity_info_(static_cast<EntityBase *>(a_lock), msg,
1002 &APIConnection::send_list_entities_lock_response);
1003}
1004void APIConnection::lock_command(const LockCommandRequest &msg) {
1005 lock::Lock *a_lock = App.get_lock_by_key(msg.key);
1006 if (a_lock == nullptr)
1007 return;
1008
1009 switch (msg.command) {
1010 case enums::LOCK_UNLOCK:
1011 a_lock->unlock();
1012 break;
1013 case enums::LOCK_LOCK:
1014 a_lock->lock();
1015 break;
1016 case enums::LOCK_OPEN:
1017 a_lock->open();
1018 break;
1019 }
1020}
1021#endif
1022
1023#ifdef USE_VALVE
1024bool APIConnection::send_valve_state(valve::Valve *valve) {
1025 return this->send_state_(static_cast<EntityBase *>(valve),
1026 reinterpret_cast<send_message_t>(&APIConnection::try_send_valve_state_));
1027}
1028void APIConnection::send_valve_info(valve::Valve *valve) {
1029 this->send_info_(static_cast<EntityBase *>(valve),
1030 reinterpret_cast<send_message_t>(&APIConnection::try_send_valve_info_));
1031}
1032bool APIConnection::try_send_valve_state_(valve::Valve *valve) {
1033 ValveStateResponse resp;
1034 resp.position = valve->position;
1035 resp.current_operation = static_cast<enums::ValveOperation>(valve->current_operation);
1036
1037 resp.key = valve->get_object_id_hash();
1038 return this->send_valve_state_response(resp);
1039}
1040bool APIConnection::try_send_valve_info_(valve::Valve *valve) {
1042 auto traits = valve->get_traits();
1043 msg.device_class = valve->get_device_class();
1044 msg.assumed_state = traits.get_is_assumed_state();
1045 msg.supports_position = traits.get_supports_position();
1046 msg.supports_stop = traits.get_supports_stop();
1047 msg.unique_id = get_default_unique_id("valve", valve);
1048 return this->try_send_entity_info_(static_cast<EntityBase *>(valve), msg,
1049 &APIConnection::send_list_entities_valve_response);
1050}
1051void APIConnection::valve_command(const ValveCommandRequest &msg) {
1052 valve::Valve *valve = App.get_valve_by_key(msg.key);
1053 if (valve == nullptr)
1054 return;
1055
1056 auto call = valve->make_call();
1057 if (msg.has_position)
1058 call.set_position(msg.position);
1059 if (msg.stop)
1060 call.set_command_stop();
1061 call.perform();
1062}
1063#endif
1064
1065#ifdef USE_MEDIA_PLAYER
1066bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_player) {
1067 return this->send_state_(static_cast<EntityBase *>(media_player),
1068 reinterpret_cast<send_message_t>(&APIConnection::try_send_media_player_state_));
1069}
1070void APIConnection::send_media_player_info(media_player::MediaPlayer *media_player) {
1071 this->send_info_(static_cast<EntityBase *>(media_player),
1072 reinterpret_cast<send_message_t>(&APIConnection::try_send_media_player_info_));
1073}
1074bool APIConnection::try_send_media_player_state_(media_player::MediaPlayer *media_player) {
1078 : media_player->state;
1079 resp.state = static_cast<enums::MediaPlayerState>(report_state);
1080 resp.volume = media_player->volume;
1081 resp.muted = media_player->is_muted();
1082
1083 resp.key = media_player->get_object_id_hash();
1084 return this->send_media_player_state_response(resp);
1085}
1086bool APIConnection::try_send_media_player_info_(media_player::MediaPlayer *media_player) {
1088 auto traits = media_player->get_traits();
1089 msg.supports_pause = traits.get_supports_pause();
1090 for (auto &supported_format : traits.get_supported_formats()) {
1091 MediaPlayerSupportedFormat media_format;
1092 media_format.format = supported_format.format;
1093 media_format.sample_rate = supported_format.sample_rate;
1094 media_format.num_channels = supported_format.num_channels;
1095 media_format.purpose = static_cast<enums::MediaPlayerFormatPurpose>(supported_format.purpose);
1096 media_format.sample_bytes = supported_format.sample_bytes;
1097 msg.supported_formats.push_back(media_format);
1098 }
1099 msg.unique_id = get_default_unique_id("media_player", media_player);
1100 return this->try_send_entity_info_(static_cast<EntityBase *>(media_player), msg,
1101 &APIConnection::send_list_entities_media_player_response);
1102}
1103void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
1105 if (media_player == nullptr)
1106 return;
1107
1108 auto call = media_player->make_call();
1109 if (msg.has_command) {
1110 call.set_command(static_cast<media_player::MediaPlayerCommand>(msg.command));
1111 }
1112 if (msg.has_volume) {
1113 call.set_volume(msg.volume);
1114 }
1115 if (msg.has_media_url) {
1116 call.set_media_url(msg.media_url);
1117 }
1118 if (msg.has_announcement) {
1119 call.set_announcement(msg.announcement);
1120 }
1121 call.perform();
1122}
1123#endif
1124
1125#ifdef USE_ESP32_CAMERA
1126void APIConnection::set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) {
1127 if (!this->state_subscription_)
1128 return;
1129 if (this->image_reader_.available())
1130 return;
1131 if (image->was_requested_by(esphome::esp32_camera::API_REQUESTER) ||
1132 image->was_requested_by(esphome::esp32_camera::IDLE))
1133 this->image_reader_.set_image(std::move(image));
1134}
1135void APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
1136 this->send_info_(static_cast<EntityBase *>(camera),
1137 reinterpret_cast<send_message_t>(&APIConnection::try_send_camera_info_));
1138}
1139bool APIConnection::try_send_camera_info_(esp32_camera::ESP32Camera *camera) {
1141 msg.unique_id = get_default_unique_id("camera", camera);
1142 return this->try_send_entity_info_(static_cast<EntityBase *>(camera), msg,
1143 &APIConnection::send_list_entities_camera_response);
1144}
1145void APIConnection::camera_image(const CameraImageRequest &msg) {
1146 if (esp32_camera::global_esp32_camera == nullptr)
1147 return;
1148
1149 if (msg.single)
1151 if (msg.stream) {
1153
1154 App.scheduler.set_timeout(this->parent_, "api_esp32_camera_stop_stream", ESP32_CAMERA_STOP_STREAM, []() {
1156 });
1157 }
1158}
1159#endif
1160
1161#ifdef USE_HOMEASSISTANT_TIME
1162void APIConnection::on_get_time_response(const GetTimeResponse &value) {
1165}
1166#endif
1167
1168#ifdef USE_BLUETOOTH_PROXY
1169void APIConnection::subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) {
1171}
1172void APIConnection::unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) {
1174}
1175bool APIConnection::send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg) {
1176 if (this->client_api_version_major_ < 1 || this->client_api_version_minor_ < 7) {
1178 for (auto &service : resp.service_data) {
1179 service.legacy_data.assign(service.data.begin(), service.data.end());
1180 service.data.clear();
1181 }
1182 for (auto &manufacturer_data : resp.manufacturer_data) {
1183 manufacturer_data.legacy_data.assign(manufacturer_data.data.begin(), manufacturer_data.data.end());
1184 manufacturer_data.data.clear();
1185 }
1186 return this->send_bluetooth_le_advertisement_response(resp);
1187 }
1188 return this->send_bluetooth_le_advertisement_response(msg);
1189}
1190void APIConnection::bluetooth_device_request(const BluetoothDeviceRequest &msg) {
1192}
1193void APIConnection::bluetooth_gatt_read(const BluetoothGATTReadRequest &msg) {
1195}
1196void APIConnection::bluetooth_gatt_write(const BluetoothGATTWriteRequest &msg) {
1198}
1199void APIConnection::bluetooth_gatt_read_descriptor(const BluetoothGATTReadDescriptorRequest &msg) {
1201}
1202void APIConnection::bluetooth_gatt_write_descriptor(const BluetoothGATTWriteDescriptorRequest &msg) {
1204}
1205void APIConnection::bluetooth_gatt_get_services(const BluetoothGATTGetServicesRequest &msg) {
1207}
1208
1209void APIConnection::bluetooth_gatt_notify(const BluetoothGATTNotifyRequest &msg) {
1211}
1212
1220
1221void APIConnection::bluetooth_scanner_set_mode(const BluetoothScannerSetModeRequest &msg) {
1223 msg.mode == enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE);
1224}
1225#endif
1226
1227#ifdef USE_VOICE_ASSISTANT
1228void APIConnection::subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) {
1231 }
1232}
1233void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) {
1235 if (voice_assistant::global_voice_assistant->get_api_connection() != this) {
1236 return;
1237 }
1238
1239 if (msg.error) {
1241 return;
1242 }
1243 if (msg.port == 0) {
1244 // Use API Audio
1246 } else {
1247 struct sockaddr_storage storage;
1248 socklen_t len = sizeof(storage);
1249 this->helper_->getpeername((struct sockaddr *) &storage, &len);
1251 }
1252 }
1253};
1254void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) {
1256 if (voice_assistant::global_voice_assistant->get_api_connection() != this) {
1257 return;
1258 }
1259
1261 }
1262}
1263void APIConnection::on_voice_assistant_audio(const VoiceAssistantAudio &msg) {
1265 if (voice_assistant::global_voice_assistant->get_api_connection() != this) {
1266 return;
1267 }
1268
1270 }
1271};
1272void APIConnection::on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg) {
1274 if (voice_assistant::global_voice_assistant->get_api_connection() != this) {
1275 return;
1276 }
1277
1279 }
1280};
1281
1282void APIConnection::on_voice_assistant_announce_request(const VoiceAssistantAnnounceRequest &msg) {
1284 if (voice_assistant::global_voice_assistant->get_api_connection() != this) {
1285 return;
1286 }
1287
1289 }
1290}
1291
1292VoiceAssistantConfigurationResponse APIConnection::voice_assistant_get_configuration(
1296 if (voice_assistant::global_voice_assistant->get_api_connection() != this) {
1297 return resp;
1298 }
1299
1301 for (auto &wake_word : config.available_wake_words) {
1302 VoiceAssistantWakeWord resp_wake_word;
1303 resp_wake_word.id = wake_word.id;
1304 resp_wake_word.wake_word = wake_word.wake_word;
1305 for (const auto &lang : wake_word.trained_languages) {
1306 resp_wake_word.trained_languages.push_back(lang);
1307 }
1308 resp.available_wake_words.push_back(std::move(resp_wake_word));
1309 }
1310 for (auto &wake_word_id : config.active_wake_words) {
1311 resp.active_wake_words.push_back(wake_word_id);
1312 }
1313 resp.max_active_wake_words = config.max_active_wake_words;
1314 }
1315 return resp;
1316}
1317
1318void APIConnection::voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) {
1320 if (voice_assistant::global_voice_assistant->get_api_connection() != this) {
1321 return;
1322 }
1323
1325 }
1326}
1327
1328#endif
1329
1330#ifdef USE_ALARM_CONTROL_PANEL
1331bool APIConnection::send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
1332 return this->send_state_(static_cast<EntityBase *>(a_alarm_control_panel),
1333 reinterpret_cast<send_message_t>(&APIConnection::try_send_alarm_control_panel_state_));
1334}
1335void APIConnection::send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
1336 this->send_info_(static_cast<EntityBase *>(a_alarm_control_panel),
1337 reinterpret_cast<send_message_t>(&APIConnection::try_send_alarm_control_panel_info_));
1338}
1339bool APIConnection::try_send_alarm_control_panel_state_(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
1341 resp.state = static_cast<enums::AlarmControlPanelState>(a_alarm_control_panel->get_state());
1342
1343 resp.key = a_alarm_control_panel->get_object_id_hash();
1344 return this->send_alarm_control_panel_state_response(resp);
1345}
1346bool APIConnection::try_send_alarm_control_panel_info_(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
1348 msg.supported_features = a_alarm_control_panel->get_supported_features();
1349 msg.requires_code = a_alarm_control_panel->get_requires_code();
1350 msg.requires_code_to_arm = a_alarm_control_panel->get_requires_code_to_arm();
1351 msg.unique_id = get_default_unique_id("alarm_control_panel", a_alarm_control_panel);
1352 return this->try_send_entity_info_(static_cast<EntityBase *>(a_alarm_control_panel), msg,
1353 &APIConnection::send_list_entities_alarm_control_panel_response);
1354}
1355void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) {
1357 if (a_alarm_control_panel == nullptr)
1358 return;
1359
1360 auto call = a_alarm_control_panel->make_call();
1361 switch (msg.command) {
1362 case enums::ALARM_CONTROL_PANEL_DISARM:
1363 call.disarm();
1364 break;
1365 case enums::ALARM_CONTROL_PANEL_ARM_AWAY:
1366 call.arm_away();
1367 break;
1368 case enums::ALARM_CONTROL_PANEL_ARM_HOME:
1369 call.arm_home();
1370 break;
1371 case enums::ALARM_CONTROL_PANEL_ARM_NIGHT:
1372 call.arm_night();
1373 break;
1374 case enums::ALARM_CONTROL_PANEL_ARM_VACATION:
1375 call.arm_vacation();
1376 break;
1377 case enums::ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS:
1378 call.arm_custom_bypass();
1379 break;
1380 case enums::ALARM_CONTROL_PANEL_TRIGGER:
1381 call.pending();
1382 break;
1383 }
1384 call.set_code(msg.code);
1385 call.perform();
1386}
1387#endif
1388
1389#ifdef USE_EVENT
1390void APIConnection::send_event(event::Event *event, std::string event_type) {
1391 this->send_state_with_value_(event, &APIConnection::try_send_event_, &APIConnection::try_send_event_,
1392 std::move(event_type));
1393}
1394void APIConnection::send_event_info(event::Event *event) {
1395 this->send_info_(static_cast<EntityBase *>(event),
1396 reinterpret_cast<send_message_t>(&APIConnection::try_send_event_info_));
1397}
1398bool APIConnection::try_send_event_(event::Event *event) {
1399 return this->try_send_event_(event, *(event->last_event_type));
1400}
1401bool APIConnection::try_send_event_(event::Event *event, std::string event_type) {
1402 EventResponse resp;
1403 resp.event_type = std::move(event_type);
1404
1405 resp.key = event->get_object_id_hash();
1406 return this->send_event_response(resp);
1407}
1408bool APIConnection::try_send_event_info_(event::Event *event) {
1410 msg.device_class = event->get_device_class();
1411 for (const auto &event_type : event->get_event_types())
1412 msg.event_types.push_back(event_type);
1413 msg.unique_id = get_default_unique_id("event", event);
1414 return this->try_send_entity_info_(static_cast<EntityBase *>(event), msg,
1415 &APIConnection::send_list_entities_event_response);
1416}
1417#endif
1418
1419#ifdef USE_UPDATE
1420bool APIConnection::send_update_state(update::UpdateEntity *update) {
1421 return this->send_state_(static_cast<EntityBase *>(update),
1422 reinterpret_cast<send_message_t>(&APIConnection::try_send_update_state_));
1423}
1424void APIConnection::send_update_info(update::UpdateEntity *update) {
1425 this->send_info_(static_cast<EntityBase *>(update),
1426 reinterpret_cast<send_message_t>(&APIConnection::try_send_update_info_));
1427}
1428bool APIConnection::try_send_update_state_(update::UpdateEntity *update) {
1430 resp.missing_state = !update->has_state();
1431 if (update->has_state()) {
1433 if (update->update_info.has_progress) {
1434 resp.has_progress = true;
1435 resp.progress = update->update_info.progress;
1436 }
1439 resp.title = update->update_info.title;
1440 resp.release_summary = update->update_info.summary;
1441 resp.release_url = update->update_info.release_url;
1442 }
1443
1444 resp.key = update->get_object_id_hash();
1445 return this->send_update_state_response(resp);
1446}
1447bool APIConnection::try_send_update_info_(update::UpdateEntity *update) {
1449 msg.device_class = update->get_device_class();
1450 msg.unique_id = get_default_unique_id("update", update);
1451 return this->try_send_entity_info_(static_cast<EntityBase *>(update), msg,
1452 &APIConnection::send_list_entities_update_response);
1453}
1454void APIConnection::update_command(const UpdateCommandRequest &msg) {
1456 if (update == nullptr)
1457 return;
1458
1459 switch (msg.command) {
1460 case enums::UPDATE_COMMAND_UPDATE:
1461 update->perform();
1462 break;
1463 case enums::UPDATE_COMMAND_CHECK:
1464 update->check();
1465 break;
1466 case enums::UPDATE_COMMAND_NONE:
1467 ESP_LOGE(TAG, "UPDATE_COMMAND_NONE not handled. Check client is sending the correct command");
1468 break;
1469 default:
1470 ESP_LOGW(TAG, "Unknown update command: %" PRIu32, msg.command);
1471 break;
1472 }
1473}
1474#endif
1475
1476bool APIConnection::try_send_log_message(int level, const char *tag, const char *line) {
1477 if (this->log_subscription_ < level)
1478 return false;
1479
1480 // Pre-calculate message size to avoid reallocations
1481 const size_t line_length = strlen(line);
1482 uint32_t msg_size = 0;
1483
1484 // Add size for level field (field ID 1, varint type)
1485 // 1 byte for field tag + size of the level varint
1486 msg_size += 1 + api::ProtoSize::varint(static_cast<uint32_t>(level));
1487
1488 // Add size for string field (field ID 3, string type)
1489 // 1 byte for field tag + size of length varint + string length
1490 msg_size += 1 + api::ProtoSize::varint(static_cast<uint32_t>(line_length)) + line_length;
1491
1492 // Create a pre-sized buffer
1493 auto buffer = this->create_buffer(msg_size);
1494
1495 // Encode the message (SubscribeLogsResponse)
1496 buffer.encode_uint32(1, static_cast<uint32_t>(level)); // LogLevel level = 1
1497 buffer.encode_string(3, line, line_length); // string message = 3
1498
1499 // SubscribeLogsResponse - 29
1500 return this->send_buffer(buffer, 29);
1501}
1502
1503HelloResponse APIConnection::hello(const HelloRequest &msg) {
1504 this->client_info_ = msg.client_info;
1505 this->client_peername_ = this->helper_->getpeername();
1506 this->client_combined_info_ = this->client_info_ + " (" + this->client_peername_ + ")";
1507 this->helper_->set_log_info(this->client_combined_info_);
1508 this->client_api_version_major_ = msg.api_version_major;
1509 this->client_api_version_minor_ = msg.api_version_minor;
1510 ESP_LOGV(TAG, "Hello from client: '%s' | %s | API Version %" PRIu32 ".%" PRIu32, this->client_info_.c_str(),
1511 this->client_peername_.c_str(), this->client_api_version_major_, this->client_api_version_minor_);
1512
1513 HelloResponse resp;
1514 resp.api_version_major = 1;
1515 resp.api_version_minor = 10;
1516 resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
1517 resp.name = App.get_name();
1518
1519 this->connection_state_ = ConnectionState::CONNECTED;
1520 return resp;
1521}
1522ConnectResponse APIConnection::connect(const ConnectRequest &msg) {
1523 bool correct = this->parent_->check_password(msg.password);
1524
1525 ConnectResponse resp;
1526 // bool invalid_password = 1;
1527 resp.invalid_password = !correct;
1528 if (correct) {
1529 ESP_LOGD(TAG, "%s: Connected successfully", this->client_combined_info_.c_str());
1530 this->connection_state_ = ConnectionState::AUTHENTICATED;
1531 this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->client_peername_);
1532#ifdef USE_HOMEASSISTANT_TIME
1534 this->send_time_request();
1535 }
1536#endif
1537 }
1538 return resp;
1539}
1540DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
1541 DeviceInfoResponse resp{};
1542 resp.uses_password = this->parent_->uses_password();
1543 resp.name = App.get_name();
1544 resp.friendly_name = App.get_friendly_name();
1545 resp.suggested_area = App.get_area();
1546 resp.mac_address = get_mac_address_pretty();
1547 resp.esphome_version = ESPHOME_VERSION;
1548 resp.compilation_time = App.get_compilation_time();
1549#if defined(USE_ESP8266) || defined(USE_ESP32)
1550 resp.manufacturer = "Espressif";
1551#elif defined(USE_RP2040)
1552 resp.manufacturer = "Raspberry Pi";
1553#elif defined(USE_BK72XX)
1554 resp.manufacturer = "Beken";
1555#elif defined(USE_RTL87XX)
1556 resp.manufacturer = "Realtek";
1557#elif defined(USE_HOST)
1558 resp.manufacturer = "Host";
1559#endif
1560 resp.model = ESPHOME_BOARD;
1561#ifdef USE_DEEP_SLEEP
1562 resp.has_deep_sleep = deep_sleep::global_has_deep_sleep;
1563#endif
1564#ifdef ESPHOME_PROJECT_NAME
1565 resp.project_name = ESPHOME_PROJECT_NAME;
1566 resp.project_version = ESPHOME_PROJECT_VERSION;
1567#endif
1568#ifdef USE_WEBSERVER
1569 resp.webserver_port = USE_WEBSERVER_PORT;
1570#endif
1571#ifdef USE_BLUETOOTH_PROXY
1572 resp.legacy_bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->get_legacy_version();
1573 resp.bluetooth_proxy_feature_flags = bluetooth_proxy::global_bluetooth_proxy->get_feature_flags();
1575#endif
1576#ifdef USE_VOICE_ASSISTANT
1577 resp.legacy_voice_assistant_version = voice_assistant::global_voice_assistant->get_legacy_version();
1578 resp.voice_assistant_feature_flags = voice_assistant::global_voice_assistant->get_feature_flags();
1579#endif
1580#ifdef USE_API_NOISE
1581 resp.api_encryption_supported = true;
1582#endif
1583 return resp;
1584}
1585void APIConnection::on_home_assistant_state_response(const HomeAssistantStateResponse &msg) {
1586 for (auto &it : this->parent_->get_state_subs()) {
1587 if (it.entity_id == msg.entity_id && it.attribute.value() == msg.attribute) {
1588 it.callback(msg.state);
1589 }
1590 }
1591}
1592void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
1593 bool found = false;
1594 for (auto *service : this->parent_->get_user_services()) {
1595 if (service->execute_service(msg)) {
1596 found = true;
1597 }
1598 }
1599 if (!found) {
1600 ESP_LOGV(TAG, "Could not find matching service!");
1601 }
1602}
1603#ifdef USE_API_NOISE
1604NoiseEncryptionSetKeyResponse APIConnection::noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) {
1605 psk_t psk{};
1607 if (base64_decode(msg.key, psk.data(), msg.key.size()) != psk.size()) {
1608 ESP_LOGW(TAG, "Invalid encryption key length");
1609 resp.success = false;
1610 return resp;
1611 }
1612
1613 if (!this->parent_->save_noise_psk(psk, true)) {
1614 ESP_LOGW(TAG, "Failed to save encryption key");
1615 resp.success = false;
1616 return resp;
1617 }
1618
1619 resp.success = true;
1620 return resp;
1621}
1622#endif
1623void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) {
1624 state_subs_at_ = 0;
1625}
1626bool APIConnection::try_to_clear_buffer(bool log_out_of_space) {
1627 if (this->remove_)
1628 return false;
1629 if (this->helper_->can_write_without_blocking())
1630 return true;
1631 delay(0);
1632 APIError err = this->helper_->loop();
1633 if (err != APIError::OK) {
1634 on_fatal_error();
1635 ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->client_combined_info_.c_str(),
1636 api_error_to_str(err), errno);
1637 return false;
1638 }
1639 if (this->helper_->can_write_without_blocking())
1640 return true;
1641 if (log_out_of_space) {
1642 ESP_LOGV(TAG, "Cannot send message because of TCP buffer space");
1643 }
1644 return false;
1645}
1646bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) {
1647 if (!this->try_to_clear_buffer(message_type != 29)) { // SubscribeLogsResponse
1648 return false;
1649 }
1650
1651 APIError err = this->helper_->write_protobuf_packet(message_type, buffer);
1652 if (err == APIError::WOULD_BLOCK)
1653 return false;
1654 if (err != APIError::OK) {
1655 on_fatal_error();
1656 if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) {
1657 ESP_LOGW(TAG, "%s: Connection reset", this->client_combined_info_.c_str());
1658 } else {
1659 ESP_LOGW(TAG, "%s: Packet write failed %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err),
1660 errno);
1661 }
1662 return false;
1663 }
1664 // Do not set last_traffic_ on send
1665 return true;
1666}
1667void APIConnection::on_unauthenticated_access() {
1668 this->on_fatal_error();
1669 ESP_LOGD(TAG, "%s: tried to access without authentication.", this->client_combined_info_.c_str());
1670}
1671void APIConnection::on_no_setup_connection() {
1672 this->on_fatal_error();
1673 ESP_LOGD(TAG, "%s: tried to access without full connection.", this->client_combined_info_.c_str());
1674}
1675void APIConnection::on_fatal_error() {
1676 this->helper_->close();
1677 this->remove_ = true;
1678}
1679
1680} // namespace api
1681} // namespace esphome
1682#endif
BedjetMode mode
BedJet operating mode.
datetime::DateEntity * get_date_by_key(uint32_t key, bool include_internal=false)
alarm_control_panel::AlarmControlPanel * get_alarm_control_panel_by_key(uint32_t key, bool include_internal=false)
const std::string & get_area() const
Get the area of this Application set by pre_setup().
const std::string & get_friendly_name() const
Get the friendly name of this Application set by pre_setup().
text::Text * get_text_by_key(uint32_t key, bool include_internal=false)
button::Button * get_button_by_key(uint32_t key, bool include_internal=false)
fan::Fan * get_fan_by_key(uint32_t key, bool include_internal=false)
std::string get_compilation_time() const
light::LightState * get_light_by_key(uint32_t key, bool include_internal=false)
media_player::MediaPlayer * get_media_player_by_key(uint32_t key, bool include_internal=false)
climate::Climate * get_climate_by_key(uint32_t key, bool include_internal=false)
const std::string & get_name() const
Get the name of this Application set by pre_setup().
lock::Lock * get_lock_by_key(uint32_t key, bool include_internal=false)
switch_::Switch * get_switch_by_key(uint32_t key, bool include_internal=false)
number::Number * get_number_by_key(uint32_t key, bool include_internal=false)
datetime::TimeEntity * get_time_by_key(uint32_t key, bool include_internal=false)
update::UpdateEntity * get_update_by_key(uint32_t key, bool include_internal=false)
datetime::DateTimeEntity * get_datetime_by_key(uint32_t key, bool include_internal=false)
valve::Valve * get_valve_by_key(uint32_t key, bool include_internal=false)
select::Select * get_select_by_key(uint32_t key, bool include_internal=false)
cover::Cover * get_cover_by_key(uint32_t key, bool include_internal=false)
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
std::string get_device_class()
Get the device class, using the manual override if set.
std::string get_unit_of_measurement()
Get the unit of measurement, using the manual override if set.
uint32_t get_object_id_hash()
std::string get_object_id() const
void set_timeout(Component *component, const std::string &name, uint32_t timeout, std::function< void()> func)
Definition scheduler.cpp:25
AlarmControlPanelCall & set_code(const std::string &code)
virtual uint32_t get_supported_features() const =0
A numeric representation of the supported features as per HomeAssistant.
AlarmControlPanelState get_state() const
Get the state.
virtual bool get_requires_code_to_arm() const =0
Returns if the alarm_control_panel requires a code to arm.
virtual bool get_requires_code() const =0
Returns if the alarm_control_panel has a code.
AlarmControlPanelCall make_call()
Make a AlarmControlPanelCall.
bool try_send_button_info_(button::Button *button)
APIConnection(std::unique_ptr< socket::Socket > socket, APIServer *parent)
std::vector< uint8_t > proto_write_buffer_
void send_button_info(button::Button *button)
void button_command(const ButtonCommandRequest &msg) override
std::shared_ptr< APINoiseContext > get_noise_ctx()
Definition api_server.h:46
enums::AlarmControlPanelStateCommand command
Definition api_pb2.h:2175
enums::AlarmControlPanelState state
Definition api_pb2.h:2161
std::vector< BluetoothServiceData > service_data
Definition api_pb2.h:1544
std::vector< BluetoothServiceData > manufacturer_data
Definition api_pb2.h:1545
enums::BluetoothScannerMode mode
Definition api_pb2.h:1929
enums::ClimateSwingMode swing_mode
Definition api_pb2.h:1162
enums::ClimateFanMode fan_mode
Definition api_pb2.h:1160
enums::ClimatePreset preset
Definition api_pb2.h:1166
enums::ClimateFanMode fan_mode
Definition api_pb2.h:1128
enums::ClimateSwingMode swing_mode
Definition api_pb2.h:1129
enums::ClimateAction action
Definition api_pb2.h:1127
enums::ClimatePreset preset
Definition api_pb2.h:1131
enums::LegacyCoverCommand legacy_command
Definition api_pb2.h:504
enums::LegacyCoverState legacy_state
Definition api_pb2.h:486
enums::CoverOperation current_operation
Definition api_pb2.h:489
std::vector< DeferredMessage > deferred_queue_
void dmq_push_back_with_dedup_(void *source, send_message_t send_message)
void defer(void *source, send_message_t send_message)
enums::FanDirection direction
Definition api_pb2.h:575
enums::FanDirection direction
Definition api_pb2.h:551
enums::ColorMode color_mode
Definition api_pb2.h:624
std::vector< enums::ClimatePreset > supported_presets
Definition api_pb2.h:1097
std::vector< enums::ClimateSwingMode > supported_swing_modes
Definition api_pb2.h:1095
std::vector< enums::ClimateFanMode > supported_fan_modes
Definition api_pb2.h:1094
std::vector< enums::ClimateMode > supported_modes
Definition api_pb2.h:1088
std::vector< std::string > supported_custom_presets
Definition api_pb2.h:1098
std::vector< std::string > supported_custom_fan_modes
Definition api_pb2.h:1096
std::vector< std::string > event_types
Definition api_pb2.h:2358
std::vector< std::string > supported_preset_modes
Definition api_pb2.h:533
std::vector< std::string > effects
Definition api_pb2.h:604
std::vector< enums::ColorMode > supported_color_modes
Definition api_pb2.h:597
std::vector< MediaPlayerSupportedFormat > supported_formats
Definition api_pb2.h:1461
std::vector< std::string > options
Definition api_pb2.h:1243
enums::SensorStateClass state_class
Definition api_pb2.h:696
enums::LockCommand command
Definition api_pb2.h:1387
enums::MediaPlayerCommand command
Definition api_pb2.h:1493
enums::MediaPlayerState state
Definition api_pb2.h:1476
enums::MediaPlayerFormatPurpose purpose
Definition api_pb2.h:1439
static uint32_t varint(uint32_t value)
ProtoSize class for Protocol Buffer serialization size calculation.
enums::UpdateCommand command
Definition api_pb2.h:2534
enums::ValveOperation current_operation
Definition api_pb2.h:2412
std::vector< VoiceAssistantWakeWord > available_wake_words
Definition api_pb2.h:2110
std::vector< std::string > active_wake_words
Definition api_pb2.h:2111
std::vector< std::string > active_wake_words
Definition api_pb2.h:2125
std::vector< std::string > trained_languages
Definition api_pb2.h:2088
Base class for all binary_sensor-type classes.
virtual bool has_state() const
Return whether this binary sensor has outputted a state.
bool state
The current reported state of the binary sensor.
virtual bool is_status_binary_sensor() const
void bluetooth_gatt_read(const api::BluetoothGATTReadRequest &msg)
void bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg)
void bluetooth_device_request(const api::BluetoothDeviceRequest &msg)
void bluetooth_gatt_write_descriptor(const api::BluetoothGATTWriteDescriptorRequest &msg)
void subscribe_api_connection(api::APIConnection *api_connection, uint32_t flags)
void unsubscribe_api_connection(api::APIConnection *api_connection)
void bluetooth_gatt_read_descriptor(const api::BluetoothGATTReadDescriptorRequest &msg)
void bluetooth_gatt_write(const api::BluetoothGATTWriteRequest &msg)
void bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg)
Base class for all buttons.
Definition button.h:29
void press()
Press this button.
Definition button.cpp:9
ClimateCall & set_target_temperature(float target_temperature)
Set the target temperature of the climate device.
Definition climate.cpp:256
ClimateCall & set_swing_mode(ClimateSwingMode swing_mode)
Set the swing mode of the climate device.
Definition climate.cpp:237
ClimateCall & set_target_temperature_low(float target_temperature_low)
Set the low point target temperature of the climate device.
Definition climate.cpp:260
ClimateCall & set_preset(ClimatePreset preset)
Set the preset of the climate device.
Definition climate.cpp:199
ClimateCall & set_fan_mode(ClimateFanMode fan_mode)
Set the fan mode of the climate device.
Definition climate.cpp:157
ClimateCall & set_target_humidity(float target_humidity)
Set the target humidity of the climate device.
Definition climate.cpp:268
ClimateCall & set_target_temperature_high(float target_temperature_high)
Set the high point target temperature of the climate device.
Definition climate.cpp:264
ClimateCall & set_mode(ClimateMode mode)
Set the mode of the climate device.
Definition climate.cpp:133
ClimateDevice - This is the base class for all climate integrations.
Definition climate.h:168
ClimateMode mode
The active mode of the climate device.
Definition climate.h:173
optional< ClimateFanMode > fan_mode
The active fan mode of the climate device.
Definition climate.h:199
ClimateTraits get_traits()
Get the traits of this climate device with all overrides applied.
Definition climate.cpp:440
float target_temperature
The target temperature of the climate device.
Definition climate.h:186
float current_humidity
The current humidity of the climate device, as reported from the integration.
Definition climate.h:182
optional< std::string > custom_fan_mode
The active custom fan mode of the climate device.
Definition climate.h:205
ClimateSwingMode swing_mode
The active swing mode of the climate device.
Definition climate.h:202
float target_temperature_low
The minimum target temperature of the climate device, for climate devices with split target temperatu...
Definition climate.h:189
optional< std::string > custom_preset
The active custom preset mode of the climate device.
Definition climate.h:211
float current_temperature
The current temperature of the climate device, as reported from the integration.
Definition climate.h:179
ClimateAction action
The active state of the climate device.
Definition climate.h:176
ClimateCall make_call()
Make a climate device control call, this is used to control the climate device, see the ClimateCall d...
Definition climate.cpp:479
optional< ClimatePreset > preset
The active preset of the climate device.
Definition climate.h:208
float target_humidity
The target humidity of the climate device.
Definition climate.h:196
float target_temperature_high
The maximum target temperature of the climate device, for climate devices with split target temperatu...
Definition climate.h:191
void perform()
Perform the cover call.
Definition cover.cpp:75
CoverCall & set_position(float position)
Set the call to a certain target position.
Definition cover.cpp:67
CoverCall & set_command_stop()
Set the command to stop the cover.
Definition cover.cpp:59
CoverCall & set_tilt(float tilt)
Set the call to a certain target tilt.
Definition cover.cpp:71
Base class for all cover devices.
Definition cover.h:111
CoverOperation current_operation
The current operation of the cover (idle, opening, closing).
Definition cover.h:116
CoverCall make_call()
Construct a new cover call used to control the cover.
Definition cover.cpp:149
float tilt
The current tilt value of the cover from 0.0 to 1.0.
Definition cover.h:124
float position
The position of the cover from 0.0 (fully closed) to 1.0 (fully open).
Definition cover.h:122
virtual CoverTraits get_traits()=0
DateCall & set_date(uint16_t year, uint8_t month, uint8_t day)
bool has_state() const
Return whether this Datetime has gotten a full state yet.
DateTimeCall & set_datetime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second)
ESPTime state_as_esptime() const override
TimeCall & set_time(uint8_t hour, uint8_t minute, uint8_t second)
void request_image(CameraRequester requester)
void stop_stream(CameraRequester requester)
void start_stream(CameraRequester requester)
std::set< std::string > get_event_types() const
Definition event.h:30
const std::string * last_event_type
Definition event.h:26
FanCall & set_oscillating(bool oscillating)
Definition fan.h:50
FanCall & set_direction(FanDirection direction)
Definition fan.h:66
FanCall & set_state(bool binary_state)
Definition fan.h:41
FanCall & set_preset_mode(const std::string &preset_mode)
Definition fan.h:75
FanCall make_call()
Definition fan.cpp:114
virtual FanTraits get_traits()=0
FanDirection direction
The current direction of the fan.
Definition fan.h:116
std::string preset_mode
Definition fan.h:118
bool oscillating
The current oscillation state of the fan.
Definition fan.h:112
bool state
The current on/off state of the fan.
Definition fan.h:110
int speed
The current fan speed level.
Definition fan.h:114
LightCall & set_color_temperature(optional< float > color_temperature)
Set the color temperature of the light in mireds for CWWW or RGBWW lights.
LightCall & set_color_brightness(optional< float > brightness)
Set the color brightness of the light from 0.0 (no color) to 1.0 (fully on)
LightCall & set_effect(optional< std::string > effect)
Set the effect of the light by its name.
LightCall & set_white(optional< float > white)
Set the white value value of the light from 0.0 to 1.0 for RGBW[W] lights.
LightCall & set_warm_white(optional< float > warm_white)
Set the warm white value of the light from 0.0 to 1.0.
LightCall & set_flash_length(optional< uint32_t > flash_length)
Start and set the flash length of this call in milliseconds.
LightCall & set_cold_white(optional< float > cold_white)
Set the cold white value of the light from 0.0 to 1.0.
LightCall & set_brightness(optional< float > brightness)
Set the target brightness of the light from 0.0 (fully off) to 1.0 (fully on)
LightCall & set_state(optional< bool > state)
Set the binary ON/OFF state of the light.
LightCall & set_color_mode(optional< ColorMode > color_mode)
Set the color mode of the light.
LightCall & set_transition_length(optional< uint32_t > transition_length)
Set the transition length of this call in milliseconds.
ColorMode get_color_mode() const
Get the color mode of these light color values.
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Definition light_state.h:63
const std::vector< LightEffect * > & get_effects() const
Get all effects for this light state.
LightColorValues remote_values
The remote color values reported to the frontend.
std::string get_effect_name()
Return the name of the current effect, or if no effect is active "None".
bool supports_effects()
Return whether the light has any effects that meet the trait requirements.
Base class for all locks.
Definition lock.h:103
void lock()
Turn this lock on.
Definition lock.cpp:30
LockTraits traits
Definition lock.h:124
LockState state
The current reported state of the lock.
Definition lock.h:122
void unlock()
Turn this lock off.
Definition lock.cpp:35
void open()
Open (unlatch) this lock.
Definition lock.cpp:40
bool get_requires_code() const
Definition lock.h:42
bool get_assumed_state() const
Definition lock.h:44
bool get_supports_open() const
Definition lock.h:40
virtual MediaPlayerTraits get_traits()=0
NumberCall & set_value(float value)
Base-class for all numbers.
Definition number.h:39
NumberCall make_call()
Definition number.h:45
NumberTraits traits
Definition number.h:49
bool has_state() const
Return whether this number has gotten a full state yet.
Definition number.h:52
NumberMode get_mode() const
bool has_value() const
Definition optional.h:87
value_type const & value() const
Definition optional.h:89
SelectCall & set_option(const std::string &option)
Base-class for all selects.
Definition select.h:31
SelectCall make_call()
Instantiate a SelectCall object to modify this select component's state.
Definition select.h:42
std::string state
Definition select.h:33
SelectTraits traits
Definition select.h:34
bool has_state() const
Return whether this select component has gotten a full state yet.
Definition select.h:39
std::vector< std::string > get_options() const
Base-class for all sensors.
Definition sensor.h:57
bool has_state() const
Return whether this sensor has gotten a full state (that passed through all filters) yet.
Definition sensor.cpp:97
float state
This member variable stores the last state that has passed through all filters.
Definition sensor.h:131
StateClass get_state_class()
Get the state class, using the manual override if set.
Definition sensor.cpp:33
virtual std::string unique_id()
Override this method to set the unique ID of this sensor.
Definition sensor.cpp:88
int8_t get_accuracy_decimals()
Get the accuracy in decimals, using the manual override if set.
Definition sensor.cpp:25
bool get_force_update() const
Get whether force update mode is enabled.
Definition sensor.h:78
Base class for all switches.
Definition switch.h:39
void turn_on()
Turn this switch on.
Definition switch.cpp:11
void turn_off()
Turn this switch off.
Definition switch.cpp:15
bool state
The current reported state of the binary sensor.
Definition switch.h:53
virtual bool assumed_state()
Return whether this switch uses an assumed state - i.e.
Definition switch.cpp:58
TextCall & set_value(const std::string &value)
Definition text_call.cpp:10
Base-class for all text inputs.
Definition text.h:24
TextCall make_call()
Instantiate a TextCall object to modify this text component's state.
Definition text.h:35
bool has_state() const
Return whether this text input has gotten a full state yet.
Definition text.h:32
std::string state
Definition text.h:26
TextTraits traits
Definition text.h:27
TextMode get_mode() const
Definition text_traits.h:29
std::string get_pattern() const
Definition text_traits.h:25
virtual std::string unique_id()
Override this method to set the unique ID of this sensor.
const UpdateState & state
const UpdateInfo & update_info
ValveCall & set_position(float position)
Set the call to a certain target position.
Definition valve.cpp:67
ValveCall & set_command_stop()
Set the command to stop the valve.
Definition valve.cpp:59
void perform()
Perform the valve call.
Definition valve.cpp:71
Base class for all valve devices.
Definition valve.h:105
float position
The position of the valve from 0.0 (fully closed) to 1.0 (fully open).
Definition valve.h:116
ValveCall make_call()
Construct a new valve call used to control the valve.
Definition valve.cpp:127
ValveOperation current_operation
The current operation of the valve (idle, opening, closing).
Definition valve.h:110
virtual ValveTraits get_traits()=0
void on_timer_event(const api::VoiceAssistantTimerEventResponse &msg)
void on_audio(const api::VoiceAssistantAudio &msg)
void client_subscription(api::APIConnection *client, bool subscribe)
void on_event(const api::VoiceAssistantEventResponse &msg)
void on_announce(const api::VoiceAssistantAnnounceRequest &msg)
void on_set_configuration(const std::vector< std::string > &active_wake_words)
ClimateSwingMode swing_mode
Definition climate.h:11
uint8_t custom_preset
Definition climate.h:9
ClimateFanMode fan_mode
Definition climate.h:3
ClimatePreset preset
Definition climate.h:8
uint8_t custom_fan_mode
Definition climate.h:4
bool state
Definition fan.h:0
uint32_t socklen_t
Definition headers.h:97
bool(APIConnection::*)(void *) send_message_t
std::string get_default_unique_id(const std::string &component_type, EntityBase *entity)
std::array< uint8_t, 32 > psk_t
const char * api_error_to_str(APIError err)
BluetoothProxy * global_bluetooth_proxy
ClimatePreset
Enum for all preset modes.
@ CLIMATE_PRESET_AWAY
Device is in away preset.
ClimateSwingMode
Enum for all modes a climate swing can be in.
ClimateMode
Enum for all modes a climate device can be in.
const float COVER_OPEN
Definition cover.cpp:9
ESP32Camera * global_esp32_camera
FanDirection
Simple enum to represent the direction of a fan.
Definition fan.h:20
HomeassistantTime * global_homeassistant_time
ColorMode
Color modes are a combination of color capabilities that can be used at the same time.
Definition color_mode.h:49
@ BRIGHTNESS
Master brightness of the light can be controlled.
@ RGB
Color can be controlled using RGB format (includes a brightness control for the color).
@ COLOR_TEMPERATURE
Color temperature can be controlled.
@ WHITE
Brightness of white channel can be controlled separately from other channels.
@ COLD_WARM_WHITE
Brightness of cold and warm white output can be controlled.
LockState
Enum for all states a lock can be in.
Definition lock.h:26
bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
Definition util.cpp:15
VoiceAssistant * global_voice_assistant
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:301
std::string get_mac_address_pretty()
Get the device MAC address as a string, in colon-separated uppercase hex notation.
Definition helpers.cpp:732
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:28
Application App
Global storage of Application pointer - only one Application can exist.
size_t base64_decode(const std::string &encoded_string, uint8_t *buf, size_t buf_len)
Definition helpers.cpp:507
A more user-friendly version of struct tm from time.h.
Definition time.h:15
std::vector< uint8_t > container