6#ifdef USE_API_PLAINTEXT
9#ifdef USE_API_USER_DEFINED_ACTIONS
31#ifdef USE_HOMEASSISTANT_TIME
34#ifdef USE_BLUETOOTH_PROXY
40#ifdef USE_VOICE_ASSISTANT
46#ifdef USE_WATER_HEATER
59static constexpr uint8_t MAX_MESSAGES_PER_LOOP = 5;
60static constexpr uint8_t MAX_PING_RETRIES = 60;
61static constexpr uint16_t PING_RETRY_INTERVAL = 1000;
62static constexpr uint32_t KEEPALIVE_DISCONNECT_TIMEOUT = (KEEPALIVE_TIMEOUT_MS * 5) / 2;
66static const char *
const TAG =
"api.connection";
68static const int CAMERA_STOP_STREAM = 5000;
74#define ENTITY_COMMAND_MAKE_CALL(entity_type, entity_var, getter_name) \
75 entity_type *entity_var = App.get_##getter_name##_by_key(msg.key, msg.device_id); \
76 if ((entity_var) == nullptr) \
78 auto call = (entity_var)->make_call();
82#define ENTITY_COMMAND_GET(entity_type, entity_var, getter_name) \
83 entity_type *entity_var = App.get_##getter_name##_by_key(msg.key, msg.device_id); \
84 if ((entity_var) == nullptr) \
89#define ENTITY_COMMAND_MAKE_CALL(entity_type, entity_var, getter_name) \
90 entity_type *entity_var = App.get_##getter_name##_by_key(msg.key); \
91 if ((entity_var) == nullptr) \
93 auto call = (entity_var)->make_call();
97#define ENTITY_COMMAND_GET(entity_type, entity_var, getter_name) \
98 entity_type *entity_var = App.get_##getter_name##_by_key(msg.key); \
99 if ((entity_var) == nullptr) \
104#if defined(USE_API_PLAINTEXT) && defined(USE_API_NOISE)
106 if (noise_ctx.has_psk()) {
107 this->helper_ = std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), noise_ctx)};
111#elif defined(USE_API_PLAINTEXT)
112 this->helper_ = std::unique_ptr<APIFrameHelper>{
new APIPlaintextFrameHelper(std::move(sock))};
113#elif defined(USE_API_NOISE)
114 this->helper_ = std::unique_ptr<APIFrameHelper>{
new APINoiseFrameHelper(std::move(sock), parent->get_noise_ctx())};
116#error "No frame helper defined"
125uint32_t APIConnection::get_batch_delay_ms_()
const {
return this->parent_->get_batch_delay(); }
127void APIConnection::start() {
130 APIError err = this->helper_->init();
131 if (err != APIError::OK) {
132 this->fatal_error_with_log_(LOG_STR(
"Helper init failed"), err);
136 char peername[socket::SOCKADDR_STR_LEN];
137 this->helper_->set_client_name(this->helper_->get_peername_to(peername), strlen(peername));
140APIConnection::~APIConnection() {
141 this->destroy_active_iterator_();
142#ifdef USE_BLUETOOTH_PROXY
147#ifdef USE_VOICE_ASSISTANT
154void APIConnection::destroy_active_iterator_() {
155 switch (this->active_iterator_) {
156 case ActiveIterator::LIST_ENTITIES:
157 this->iterator_storage_.list_entities.~ListEntitiesIterator();
159 case ActiveIterator::INITIAL_STATE:
160 this->iterator_storage_.initial_state.~InitialStateIterator();
162 case ActiveIterator::NONE:
165 this->active_iterator_ = ActiveIterator::NONE;
169 this->destroy_active_iterator_();
170 this->active_iterator_ =
type;
171 if (
type == ActiveIterator::LIST_ENTITIES) {
173 this->iterator_storage_.list_entities.
begin();
176 this->iterator_storage_.initial_state.
begin();
180void APIConnection::loop() {
181 if (this->flags_.next_close) {
184 this->flags_.remove =
true;
188 APIError err = this->helper_->loop();
189 if (err != APIError::OK) {
190 this->fatal_error_with_log_(LOG_STR(
"Socket operation failed"), err);
196 if (this->helper_->is_socket_ready()) {
198 for (uint8_t message_count = 0; message_count < MAX_MESSAGES_PER_LOOP; message_count++) {
200 err = this->helper_->read_packet(&buffer);
201 if (err == APIError::WOULD_BLOCK) {
204 }
else if (err != APIError::OK) {
205 this->fatal_error_with_log_(LOG_STR(
"Reading failed"), err);
208 this->last_traffic_ = now;
211 if (this->flags_.remove)
218 if (this->flags_.batch_scheduled && now - this->deferred_batch_.batch_start_time >= this->get_batch_delay_ms_()) {
219 this->process_batch_();
222 if (this->active_iterator_ != ActiveIterator::NONE) {
223 this->process_active_iterator_();
226 if (this->flags_.sent_ping) {
228 if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) {
230 this->log_client_(ESPHOME_LOG_LEVEL_WARN, LOG_STR(
"is unresponsive; disconnecting"));
232 }
else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && !this->flags_.remove) {
234 ESP_LOGVV(TAG,
"Sending keepalive PING");
236 this->flags_.sent_ping = this->send_message(req, PingRequest::MESSAGE_TYPE);
237 if (!this->flags_.sent_ping) {
240 ESP_LOGW(TAG,
"Buffer full, ping queued");
241 this->schedule_message_front_(
nullptr, PingRequest::MESSAGE_TYPE, PingRequest::ESTIMATED_SIZE);
242 this->flags_.sent_ping =
true;
246#ifdef USE_API_HOMEASSISTANT_STATES
247 if (state_subs_at_ >= 0) {
248 this->process_state_subscriptions_();
255 this->try_send_camera_image_();
259void APIConnection::process_active_iterator_() {
261 if (this->active_iterator_ == ActiveIterator::LIST_ENTITIES) {
262 if (this->iterator_storage_.list_entities.completed()) {
263 this->destroy_active_iterator_();
264 if (this->flags_.state_subscription) {
265 this->begin_iterator_(ActiveIterator::INITIAL_STATE);
268 this->process_iterator_batch_(this->iterator_storage_.list_entities);
271 if (this->iterator_storage_.initial_state.completed()) {
272 this->destroy_active_iterator_();
274 if (!this->deferred_batch_.empty()) {
275 this->process_batch_();
278 this->flags_.should_try_send_immediately =
true;
280 this->deferred_batch_.release_buffer();
281 this->helper_->release_buffers();
283 this->process_iterator_batch_(this->iterator_storage_.initial_state);
289 size_t initial_size = this->deferred_batch_.size();
290 size_t max_batch = this->get_max_batch_size_();
291 while (!iterator.
completed() && (this->deferred_batch_.size() - initial_size) < max_batch) {
297 if (this->deferred_batch_.size() >= max_batch) {
298 this->process_batch_();
302bool APIConnection::send_disconnect_response_() {
306 this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR(
"disconnected"));
307 this->flags_.next_close =
true;
309 return this->send_message(resp, DisconnectResponse::MESSAGE_TYPE);
311void APIConnection::on_disconnect_response() {
314 this->flags_.remove =
true;
320 uint32_t remaining_size) {
321#ifdef HAS_PROTO_MESSAGE_DUMP
333 uint32_t calculated_size = size_calc.
get_size();
336 const uint8_t header_padding = conn->
helper_->frame_header_padding();
337 const uint8_t footer_size = conn->
helper_->frame_footer_size();
340 size_t total_calculated_size = calculated_size + header_padding + footer_size;
343 if (total_calculated_size > remaining_size) {
356 size_t current_size = shared_buf.size();
357 shared_buf.reserve(current_size + total_calculated_size);
358 shared_buf.resize(current_size + footer_size + header_padding);
362 size_t size_before_encode = shared_buf.size();
363 msg.
encode({&shared_buf});
366 size_t actual_payload_size = shared_buf.size() - size_before_encode;
369 size_t actual_total_size = header_padding + actual_payload_size + footer_size;
372 assert(calculated_size == actual_payload_size);
373 return static_cast<uint16_t
>(actual_total_size);
376#ifdef USE_BINARY_SENSOR
378 return this->send_message_smart_(binary_sensor, BinarySensorStateResponse::MESSAGE_TYPE,
379 BinarySensorStateResponse::ESTIMATED_SIZE);
385 resp.
state = binary_sensor->state;
387 return fill_and_encode_entity_state(binary_sensor, resp, BinarySensorStateResponse::MESSAGE_TYPE, conn,
394 msg.
device_class = binary_sensor->get_device_class_ref();
396 return fill_and_encode_entity_info(binary_sensor, msg, ListEntitiesBinarySensorResponse::MESSAGE_TYPE, conn,
403 return this->send_message_smart_(cover, CoverStateResponse::MESSAGE_TYPE, CoverStateResponse::ESTIMATED_SIZE);
408 auto traits = cover->get_traits();
410 if (traits.get_supports_tilt())
411 msg.
tilt = cover->tilt;
413 return fill_and_encode_entity_state(cover, msg, CoverStateResponse::MESSAGE_TYPE, conn, remaining_size);
418 auto traits = cover->get_traits();
424 return fill_and_encode_entity_info(cover, msg, ListEntitiesCoverResponse::MESSAGE_TYPE, conn, remaining_size);
431 call.set_tilt(msg.
tilt);
433 call.set_command_stop();
440 return this->send_message_smart_(fan, FanStateResponse::MESSAGE_TYPE, FanStateResponse::ESTIMATED_SIZE);
443 auto *fan =
static_cast<fan::Fan *
>(entity);
445 auto traits = fan->get_traits();
446 msg.
state = fan->state;
447 if (traits.supports_oscillation())
449 if (traits.supports_speed()) {
452 if (traits.supports_direction())
454 if (traits.supports_preset_modes() && fan->has_preset_mode())
456 return fill_and_encode_entity_state(fan, msg, FanStateResponse::MESSAGE_TYPE, conn, remaining_size);
459 auto *fan =
static_cast<fan::Fan *
>(entity);
461 auto traits = fan->get_traits();
467 return fill_and_encode_entity_info(fan, msg, ListEntitiesFanResponse::MESSAGE_TYPE, conn, remaining_size);
470 ENTITY_COMMAND_MAKE_CALL(
fan::Fan, fan, fan)
472 call.set_state(msg.
state);
489 return this->send_message_smart_(light, LightStateResponse::MESSAGE_TYPE, LightStateResponse::ESTIMATED_SIZE);
494 auto values = light->remote_values;
495 auto color_mode = values.get_color_mode();
496 resp.
state = values.is_on();
500 resp.
red = values.get_red();
501 resp.
green = values.get_green();
502 resp.
blue = values.get_blue();
503 resp.
white = values.get_white();
507 if (light->supports_effects()) {
508 resp.
effect = light->get_effect_name();
510 return fill_and_encode_entity_state(light, resp, LightStateResponse::MESSAGE_TYPE, conn, remaining_size);
515 auto traits = light->get_traits();
516 auto supported_modes = traits.get_supported_color_modes();
525 if (light->supports_effects()) {
526 auto &light_effects = light->get_effects();
527 effects_list.
init(light_effects.size() + 1);
529 for (
auto *effect : light_effects) {
531 effects_list.
push_back(effect->get_name().c_str());
535 return fill_and_encode_entity_info(light, msg, ListEntitiesLightResponse::MESSAGE_TYPE, conn, remaining_size);
540 call.set_state(msg.
state);
548 call.set_red(msg.
red);
549 call.set_green(msg.
green);
550 call.set_blue(msg.
blue);
553 call.set_white(msg.
white);
572 return this->send_message_smart_(sensor, SensorStateResponse::MESSAGE_TYPE, SensorStateResponse::ESTIMATED_SIZE);
578 resp.
state = sensor->state;
580 return fill_and_encode_entity_state(sensor, resp, SensorStateResponse::MESSAGE_TYPE, conn, remaining_size);
591 return fill_and_encode_entity_info(sensor, msg, ListEntitiesSensorResponse::MESSAGE_TYPE, conn, remaining_size);
597 return this->send_message_smart_(a_switch, SwitchStateResponse::MESSAGE_TYPE, SwitchStateResponse::ESTIMATED_SIZE);
603 resp.
state = a_switch->state;
604 return fill_and_encode_entity_state(a_switch, resp, SwitchStateResponse::MESSAGE_TYPE, conn, remaining_size);
612 return fill_and_encode_entity_info(a_switch, msg, ListEntitiesSwitchResponse::MESSAGE_TYPE, conn, remaining_size);
620 a_switch->turn_off();
625#ifdef USE_TEXT_SENSOR
627 return this->send_message_smart_(text_sensor, TextSensorStateResponse::MESSAGE_TYPE,
628 TextSensorStateResponse::ESTIMATED_SIZE);
636 return fill_and_encode_entity_state(text_sensor, resp, TextSensorStateResponse::MESSAGE_TYPE, conn, remaining_size);
642 return fill_and_encode_entity_info(text_sensor, msg, ListEntitiesTextSensorResponse::MESSAGE_TYPE, conn,
649 return this->send_message_smart_(climate, ClimateStateResponse::MESSAGE_TYPE, ClimateStateResponse::ESTIMATED_SIZE);
654 auto traits = climate->get_traits();
666 if (traits.get_supports_fan_modes() && climate->fan_mode.has_value())
668 if (!traits.get_supported_custom_fan_modes().empty() && climate->has_custom_fan_mode()) {
671 if (traits.get_supports_presets() && climate->preset.has_value()) {
674 if (!traits.get_supported_custom_presets().empty() && climate->has_custom_preset()) {
677 if (traits.get_supports_swing_modes())
683 return fill_and_encode_entity_state(climate, resp, ClimateStateResponse::MESSAGE_TYPE, conn, remaining_size);
688 auto traits = climate->get_traits();
710 return fill_and_encode_entity_info(climate, msg, ListEntitiesClimateResponse::MESSAGE_TYPE, conn, remaining_size);
740 return this->send_message_smart_(number, NumberStateResponse::MESSAGE_TYPE, NumberStateResponse::ESTIMATED_SIZE);
746 resp.
state = number->state;
748 return fill_and_encode_entity_state(number, resp, NumberStateResponse::MESSAGE_TYPE, conn, remaining_size);
756 msg.
device_class = number->traits.get_device_class_ref();
757 msg.
min_value = number->traits.get_min_value();
758 msg.
max_value = number->traits.get_max_value();
759 msg.
step = number->traits.get_step();
760 return fill_and_encode_entity_info(number, msg, ListEntitiesNumberResponse::MESSAGE_TYPE, conn, remaining_size);
764 call.set_value(msg.
state);
769#ifdef USE_DATETIME_DATE
771 return this->send_message_smart_(date, DateStateResponse::MESSAGE_TYPE, DateStateResponse::ESTIMATED_SIZE);
777 resp.
year = date->year;
778 resp.
month = date->month;
779 resp.
day = date->day;
780 return fill_and_encode_entity_state(date, resp, DateStateResponse::MESSAGE_TYPE, conn, remaining_size);
785 return fill_and_encode_entity_info(date, msg, ListEntitiesDateResponse::MESSAGE_TYPE, conn, remaining_size);
794#ifdef USE_DATETIME_TIME
796 return this->send_message_smart_(time, TimeStateResponse::MESSAGE_TYPE, TimeStateResponse::ESTIMATED_SIZE);
802 resp.
hour = time->hour;
803 resp.
minute = time->minute;
804 resp.
second = time->second;
805 return fill_and_encode_entity_state(time, resp, TimeStateResponse::MESSAGE_TYPE, conn, remaining_size);
810 return fill_and_encode_entity_info(time, msg, ListEntitiesTimeResponse::MESSAGE_TYPE, conn, remaining_size);
819#ifdef USE_DATETIME_DATETIME
821 return this->send_message_smart_(datetime, DateTimeStateResponse::MESSAGE_TYPE,
822 DateTimeStateResponse::ESTIMATED_SIZE);
828 if (datetime->has_state()) {
832 return fill_and_encode_entity_state(datetime, resp, DateTimeStateResponse::MESSAGE_TYPE, conn, remaining_size);
837 return fill_and_encode_entity_info(datetime, msg, ListEntitiesDateTimeResponse::MESSAGE_TYPE, conn, remaining_size);
848 return this->send_message_smart_(text, TextStateResponse::MESSAGE_TYPE, TextStateResponse::ESTIMATED_SIZE);
852 auto *text =
static_cast<text::Text *
>(entity);
856 return fill_and_encode_entity_state(text, resp, TextStateResponse::MESSAGE_TYPE, conn, remaining_size);
860 auto *text =
static_cast<text::Text *
>(entity);
863 msg.
min_length = text->traits.get_min_length();
864 msg.
max_length = text->traits.get_max_length();
865 msg.
pattern = text->traits.get_pattern_ref();
866 return fill_and_encode_entity_info(text, msg, ListEntitiesTextResponse::MESSAGE_TYPE, conn, remaining_size);
869 ENTITY_COMMAND_MAKE_CALL(
text::Text, text, text)
870 call.set_value(msg.
state);
877 return this->send_message_smart_(select, SelectStateResponse::MESSAGE_TYPE, SelectStateResponse::ESTIMATED_SIZE);
883 resp.
state = select->current_option();
885 return fill_and_encode_entity_state(select, resp, SelectStateResponse::MESSAGE_TYPE, conn, remaining_size);
891 msg.
options = &select->traits.get_options();
892 return fill_and_encode_entity_info(select, msg, ListEntitiesSelectResponse::MESSAGE_TYPE, conn, remaining_size);
906 return fill_and_encode_entity_info(button, msg, ListEntitiesButtonResponse::MESSAGE_TYPE, conn, remaining_size);
916 return this->send_message_smart_(a_lock, LockStateResponse::MESSAGE_TYPE, LockStateResponse::ESTIMATED_SIZE);
920 auto *a_lock =
static_cast<lock::Lock *
>(entity);
923 return fill_and_encode_entity_state(a_lock, resp, LockStateResponse::MESSAGE_TYPE, conn, remaining_size);
927 auto *a_lock =
static_cast<lock::Lock *
>(entity);
932 return fill_and_encode_entity_info(a_lock, msg, ListEntitiesLockResponse::MESSAGE_TYPE, conn, remaining_size);
938 case enums::LOCK_UNLOCK:
941 case enums::LOCK_LOCK:
944 case enums::LOCK_OPEN:
953 return this->send_message_smart_(valve, ValveStateResponse::MESSAGE_TYPE, ValveStateResponse::ESTIMATED_SIZE);
960 return fill_and_encode_entity_state(valve, resp, ValveStateResponse::MESSAGE_TYPE, conn, remaining_size);
965 auto traits = valve->get_traits();
970 return fill_and_encode_entity_info(valve, msg, ListEntitiesValveResponse::MESSAGE_TYPE, conn, remaining_size);
977 call.set_command_stop();
982#ifdef USE_MEDIA_PLAYER
984 return this->send_message_smart_(media_player, MediaPlayerStateResponse::MESSAGE_TYPE,
985 MediaPlayerStateResponse::ESTIMATED_SIZE);
992 : media_player->state;
994 resp.
volume = media_player->volume;
995 resp.
muted = media_player->is_muted();
996 return fill_and_encode_entity_state(media_player, resp, MediaPlayerStateResponse::MESSAGE_TYPE, conn, remaining_size);
1001 auto traits = media_player->get_traits();
1004 for (
auto &supported_format : traits.get_supported_formats()) {
1007 media_format.format =
StringRef(supported_format.format);
1008 media_format.sample_rate = supported_format.sample_rate;
1009 media_format.num_channels = supported_format.num_channels;
1011 media_format.sample_bytes = supported_format.sample_bytes;
1013 return fill_and_encode_entity_info(media_player, msg, ListEntitiesMediaPlayerResponse::MESSAGE_TYPE, conn,
1022 call.set_volume(msg.
volume);
1035void APIConnection::try_send_camera_image_() {
1036 if (!this->image_reader_)
1040 while (this->image_reader_->available()) {
1041 if (!this->helper_->can_write_without_blocking())
1044 uint32_t to_send = std::min((
size_t) MAX_BATCH_PACKET_SIZE, this->image_reader_->available());
1045 bool done = this->image_reader_->available() == to_send;
1049 msg.
set_data(this->image_reader_->peek_data_buffer(), to_send);
1055 if (!this->send_message_impl(msg, CameraImageResponse::MESSAGE_TYPE)) {
1058 this->image_reader_->consume_data(to_send);
1060 this->image_reader_->return_image();
1065void APIConnection::set_camera_state(std::shared_ptr<camera::CameraImage> image) {
1066 if (!this->flags_.state_subscription)
1068 if (!this->image_reader_)
1070 if (this->image_reader_->available())
1073 this->image_reader_->set_image(std::move(image));
1075 this->try_send_camera_image_();
1081 return fill_and_encode_entity_info(camera, msg, ListEntitiesCameraResponse::MESSAGE_TYPE, conn, remaining_size);
1092 App.scheduler.set_timeout(this->parent_,
"api_camera_stop_stream", CAMERA_STOP_STREAM,
1098#ifdef USE_HOMEASSISTANT_TIME
1102#ifdef USE_TIME_TIMEZONE
1111#ifdef USE_BLUETOOTH_PROXY
1112void APIConnection::on_subscribe_bluetooth_le_advertisements_request(
1116void APIConnection::on_unsubscribe_bluetooth_le_advertisements_request() {
1142bool APIConnection::send_subscribe_bluetooth_connections_free_response_() {
1146void APIConnection::on_subscribe_bluetooth_connections_free_request() {
1147 if (!this->send_subscribe_bluetooth_connections_free_response_()) {
1148 this->on_fatal_error();
1154 msg.
mode == enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE);
1158#ifdef USE_VOICE_ASSISTANT
1159bool APIConnection::check_voice_assistant_api_connection_()
const {
1170 if (!this->check_voice_assistant_api_connection_()) {
1178 if (msg.
port == 0) {
1184 this->helper_->getpeername((
struct sockaddr *) &storage, &
len);
1189 if (this->check_voice_assistant_api_connection_()) {
1194 if (this->check_voice_assistant_api_connection_()) {
1199 if (this->check_voice_assistant_api_connection_()) {
1205 if (this->check_voice_assistant_api_connection_()) {
1212 if (!this->check_voice_assistant_api_connection_()) {
1213 return this->send_message(resp, VoiceAssistantConfigurationResponse::MESSAGE_TYPE);
1217 for (
auto &wake_word : config.available_wake_words) {
1220 resp_wake_word.id =
StringRef(wake_word.id);
1221 resp_wake_word.wake_word =
StringRef(wake_word.wake_word);
1222 for (
const auto &lang : wake_word.trained_languages) {
1223 resp_wake_word.trained_languages.push_back(lang);
1229 if (wake_word.model_type !=
"micro") {
1236 resp_wake_word.id =
StringRef(wake_word.id);
1237 resp_wake_word.wake_word =
StringRef(wake_word.wake_word);
1238 for (
const auto &lang : wake_word.trained_languages) {
1239 resp_wake_word.trained_languages.push_back(lang);
1245 return this->send_message(resp, VoiceAssistantConfigurationResponse::MESSAGE_TYPE);
1248 if (!this->send_voice_assistant_get_configuration_response_(msg)) {
1249 this->on_fatal_error();
1254 if (this->check_voice_assistant_api_connection_()) {
1260#ifdef USE_ZWAVE_PROXY
1270#ifdef USE_ALARM_CONTROL_PANEL
1272 return this->send_message_smart_(a_alarm_control_panel, AlarmControlPanelStateResponse::MESSAGE_TYPE,
1273 AlarmControlPanelStateResponse::ESTIMATED_SIZE);
1276 uint32_t remaining_size) {
1280 return fill_and_encode_entity_state(a_alarm_control_panel, resp, AlarmControlPanelStateResponse::MESSAGE_TYPE, conn,
1284 uint32_t remaining_size) {
1288 msg.
requires_code = a_alarm_control_panel->get_requires_code();
1290 return fill_and_encode_entity_info(a_alarm_control_panel, msg, ListEntitiesAlarmControlPanelResponse::MESSAGE_TYPE,
1291 conn, remaining_size);
1296 case enums::ALARM_CONTROL_PANEL_DISARM:
1299 case enums::ALARM_CONTROL_PANEL_ARM_AWAY:
1302 case enums::ALARM_CONTROL_PANEL_ARM_HOME:
1305 case enums::ALARM_CONTROL_PANEL_ARM_NIGHT:
1308 case enums::ALARM_CONTROL_PANEL_ARM_VACATION:
1309 call.arm_vacation();
1311 case enums::ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS:
1312 call.arm_custom_bypass();
1314 case enums::ALARM_CONTROL_PANEL_TRIGGER:
1318 call.set_code(msg.
code);
1323#ifdef USE_WATER_HEATER
1325 return this->send_message_smart_(water_heater, WaterHeaterStateResponse::MESSAGE_TYPE,
1326 WaterHeaterStateResponse::ESTIMATED_SIZE);
1336 resp.
state = wh->get_state();
1338 return fill_and_encode_entity_state(wh, resp, WaterHeaterStateResponse::MESSAGE_TYPE, conn, remaining_size);
1343 auto traits = wh->get_traits();
1349 return fill_and_encode_entity_info(wh, msg, ListEntitiesWaterHeaterResponse::MESSAGE_TYPE, conn, remaining_size);
1354 if (msg.
has_fields & enums::WATER_HEATER_COMMAND_HAS_MODE)
1356 if (msg.
has_fields & enums::WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE)
1358 if (msg.
has_fields & enums::WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE_LOW)
1360 if (msg.
has_fields & enums::WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE_HIGH)
1362 if ((msg.
has_fields & enums::WATER_HEATER_COMMAND_HAS_AWAY_STATE) ||
1363 (msg.
has_fields & enums::WATER_HEATER_COMMAND_HAS_STATE)) {
1366 if ((msg.
has_fields & enums::WATER_HEATER_COMMAND_HAS_ON_STATE) ||
1367 (msg.
has_fields & enums::WATER_HEATER_COMMAND_HAS_STATE)) {
1378 this->send_message_smart_(event, EventResponse::MESSAGE_TYPE, EventResponse::ESTIMATED_SIZE,
1382 uint32_t remaining_size) {
1385 return fill_and_encode_entity_state(event, resp, EventResponse::MESSAGE_TYPE, conn, remaining_size);
1393 return fill_and_encode_entity_info(event, msg, ListEntitiesEventResponse::MESSAGE_TYPE, conn, remaining_size);
1411 this->send_message(msg, InfraredRFReceiveEvent::MESSAGE_TYPE);
1420 return fill_and_encode_entity_info(infrared, msg, ListEntitiesInfraredResponse::MESSAGE_TYPE, conn, remaining_size);
1426 return this->send_message_smart_(update, UpdateStateResponse::MESSAGE_TYPE, UpdateStateResponse::ESTIMATED_SIZE);
1432 if (update->has_state()) {
1434 if (update->update_info.has_progress) {
1436 resp.
progress = update->update_info.progress;
1444 return fill_and_encode_entity_state(update, resp, UpdateStateResponse::MESSAGE_TYPE, conn, remaining_size);
1450 return fill_and_encode_entity_info(update, msg, ListEntitiesUpdateResponse::MESSAGE_TYPE, conn, remaining_size);
1456 case enums::UPDATE_COMMAND_UPDATE:
1459 case enums::UPDATE_COMMAND_CHECK:
1462 case enums::UPDATE_COMMAND_NONE:
1463 ESP_LOGE(TAG,
"UPDATE_COMMAND_NONE not handled; confirm command is correct");
1466 ESP_LOGW(TAG,
"Unknown update command: %" PRIu32, msg.
command);
1472bool APIConnection::try_send_log_message(
int level,
const char *tag,
const char *line,
size_t message_len) {
1475 msg.
set_message(
reinterpret_cast<const uint8_t *
>(line), message_len);
1476 return this->send_message_impl(msg, SubscribeLogsResponse::MESSAGE_TYPE);
1479void APIConnection::complete_authentication_() {
1481 if (this->flags_.connection_state ==
static_cast<uint8_t
>(ConnectionState::AUTHENTICATED)) {
1485 this->flags_.connection_state =
static_cast<uint8_t
>(ConnectionState::AUTHENTICATED);
1486 this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR(
"connected"));
1487#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
1489 char peername[socket::SOCKADDR_STR_LEN];
1490 this->parent_->get_client_connected_trigger()->trigger(std::string(this->helper_->get_client_name()),
1491 std::string(this->helper_->get_peername_to(peername)));
1494#ifdef USE_HOMEASSISTANT_TIME
1496 this->send_time_request();
1499#ifdef USE_ZWAVE_PROXY
1511 char peername[socket::SOCKADDR_STR_LEN];
1512 ESP_LOGV(TAG,
"Hello from client: '%s' | %s | API Version %" PRIu16
".%" PRIu16, this->helper_->get_client_name(),
1513 this->helper_->get_peername_to(peername), this->client_api_version_major_, this->client_api_version_minor_);
1523 this->complete_authentication_();
1525 return this->send_message(resp, HelloResponse::MESSAGE_TYPE);
1528bool APIConnection::send_ping_response_() {
1530 return this->send_message(resp, PingResponse::MESSAGE_TYPE);
1533bool APIConnection::send_device_info_response_() {
1541 char mac_address[18];
1545 resp.mac_address =
StringRef(mac_address);
1547 resp.esphome_version = ESPHOME_VERSION_REF;
1552 resp.compilation_time =
StringRef(build_time_str);
1555#if defined(USE_ESP8266) || defined(USE_ESP32)
1556#define ESPHOME_MANUFACTURER "Espressif"
1557#elif defined(USE_RP2040)
1558#define ESPHOME_MANUFACTURER "Raspberry Pi"
1559#elif defined(USE_BK72XX)
1560#define ESPHOME_MANUFACTURER "Beken"
1561#elif defined(USE_LN882X)
1562#define ESPHOME_MANUFACTURER "Lightning"
1563#elif defined(USE_NRF52)
1564#define ESPHOME_MANUFACTURER "Nordic Semiconductor"
1565#elif defined(USE_RTL87XX)
1566#define ESPHOME_MANUFACTURER "Realtek"
1567#elif defined(USE_HOST)
1568#define ESPHOME_MANUFACTURER "Host"
1573 static const char MANUFACTURER_PROGMEM[]
PROGMEM = ESPHOME_MANUFACTURER;
1574 char manufacturer_buf[
sizeof(MANUFACTURER_PROGMEM)];
1575 memcpy_P(manufacturer_buf, MANUFACTURER_PROGMEM,
sizeof(MANUFACTURER_PROGMEM));
1576 resp.manufacturer =
StringRef(manufacturer_buf,
sizeof(MANUFACTURER_PROGMEM) - 1);
1579 resp.manufacturer = MANUFACTURER;
1581#undef ESPHOME_MANUFACTURER
1584 static const char MODEL_PROGMEM[]
PROGMEM = ESPHOME_BOARD;
1585 char model_buf[
sizeof(MODEL_PROGMEM)];
1586 memcpy_P(model_buf, MODEL_PROGMEM,
sizeof(MODEL_PROGMEM));
1587 resp.model =
StringRef(model_buf,
sizeof(MODEL_PROGMEM) - 1);
1592#ifdef USE_DEEP_SLEEP
1595#ifdef ESPHOME_PROJECT_NAME
1597 static const char PROJECT_NAME_PROGMEM[]
PROGMEM = ESPHOME_PROJECT_NAME;
1598 static const char PROJECT_VERSION_PROGMEM[]
PROGMEM = ESPHOME_PROJECT_VERSION;
1599 char project_name_buf[
sizeof(PROJECT_NAME_PROGMEM)];
1600 char project_version_buf[
sizeof(PROJECT_VERSION_PROGMEM)];
1601 memcpy_P(project_name_buf, PROJECT_NAME_PROGMEM,
sizeof(PROJECT_NAME_PROGMEM));
1602 memcpy_P(project_version_buf, PROJECT_VERSION_PROGMEM,
sizeof(PROJECT_VERSION_PROGMEM));
1603 resp.project_name =
StringRef(project_name_buf,
sizeof(PROJECT_NAME_PROGMEM) - 1);
1604 resp.project_version =
StringRef(project_version_buf,
sizeof(PROJECT_VERSION_PROGMEM) - 1);
1608 resp.project_name = PROJECT_NAME;
1609 resp.project_version = PROJECT_VERSION;
1613 resp.webserver_port = USE_WEBSERVER_PORT;
1615#ifdef USE_BLUETOOTH_PROXY
1618 char bluetooth_mac[18];
1620 resp.bluetooth_mac_address =
StringRef(bluetooth_mac);
1622#ifdef USE_VOICE_ASSISTANT
1625#ifdef USE_ZWAVE_PROXY
1630 resp.api_encryption_supported =
true;
1633 size_t device_index = 0;
1635 if (device_index >= ESPHOME_DEVICE_COUNT)
1637 auto &device_info = resp.devices[device_index++];
1638 device_info.device_id = device->get_device_id();
1639 device_info.name =
StringRef(device->get_name());
1640 device_info.area_id = device->get_area_id();
1644 size_t area_index = 0;
1646 if (area_index >= ESPHOME_AREA_COUNT)
1648 auto &area_info = resp.areas[area_index++];
1649 area_info.area_id = area->get_area_id();
1650 area_info.name =
StringRef(area->get_name());
1654 return this->send_message(resp, DeviceInfoResponse::MESSAGE_TYPE);
1657 if (!this->send_hello_response_(msg)) {
1658 this->on_fatal_error();
1661void APIConnection::on_disconnect_request() {
1662 if (!this->send_disconnect_response_()) {
1663 this->on_fatal_error();
1666void APIConnection::on_ping_request() {
1667 if (!this->send_ping_response_()) {
1668 this->on_fatal_error();
1671void APIConnection::on_device_info_request() {
1672 if (!this->send_device_info_response_()) {
1673 this->on_fatal_error();
1677#ifdef USE_API_HOMEASSISTANT_STATES
1684 for (
auto &it : this->parent_->get_state_subs()) {
1686 size_t entity_id_len = strlen(it.entity_id);
1693 size_t sub_attr_len = it.attribute !=
nullptr ? strlen(it.attribute) : 0;
1695 (sub_attr_len > 0 && memcmp(it.attribute, msg.
attribute.
c_str(), sub_attr_len) != 0)) {
1704 char *state_buf =
reinterpret_cast<char *
>(state_buf_alloc.
get());
1705 if (state_len > 0) {
1706 memcpy(state_buf, msg.
state.
c_str(), state_len);
1708 state_buf[state_len] =
'\0';
1709 it.callback(
StringRef(state_buf, state_len));
1713#ifdef USE_API_USER_DEFINED_ACTIONS
1716#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
1719 uint32_t action_call_id = 0;
1721 action_call_id = this->parent_->register_active_action_call(msg.
call_id,
this);
1724 for (
auto *service : this->parent_->get_user_services()) {
1725 if (service->execute_service(msg, action_call_id)) {
1730 for (
auto *service : this->parent_->get_user_services()) {
1731 if (service->execute_service(msg)) {
1737 ESP_LOGV(TAG,
"Could not find service");
1743#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
1744void APIConnection::send_execute_service_response(uint32_t call_id,
bool success,
StringRef error_message) {
1749 this->send_message(resp, ExecuteServiceResponse::MESSAGE_TYPE);
1751#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
1752void APIConnection::send_execute_service_response(uint32_t call_id,
bool success,
StringRef error_message,
1753 const uint8_t *response_data,
size_t response_data_len) {
1760 this->send_message(resp, ExecuteServiceResponse::MESSAGE_TYPE);
1766#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
1768#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
1786 if (this->parent_->clear_noise_psk(
true)) {
1789 ESP_LOGW(TAG,
"Failed to clear encryption key");
1792 ESP_LOGW(TAG,
"Invalid encryption key length");
1793 }
else if (!this->parent_->save_noise_psk(psk,
true)) {
1794 ESP_LOGW(TAG,
"Failed to save encryption key");
1799 return this->send_message(resp, NoiseEncryptionSetKeyResponse::MESSAGE_TYPE);
1802 if (!this->send_noise_encryption_set_key_response_(msg)) {
1803 this->on_fatal_error();
1807#ifdef USE_API_HOMEASSISTANT_STATES
1808void APIConnection::on_subscribe_home_assistant_states_request() { state_subs_at_ = 0; }
1810bool APIConnection::try_to_clear_buffer(
bool log_out_of_space) {
1811 if (this->flags_.remove)
1813 if (this->helper_->can_write_without_blocking())
1816 APIError err = this->helper_->loop();
1817 if (err != APIError::OK) {
1818 this->fatal_error_with_log_(LOG_STR(
"Socket operation failed"), err);
1821 if (this->helper_->can_write_without_blocking())
1823 if (log_out_of_space) {
1824 ESP_LOGV(TAG,
"Cannot send message because of TCP buffer space");
1828bool APIConnection::send_message_impl(
const ProtoMessage &msg, uint8_t message_type) {
1831 std::vector<uint8_t> &shared_buf = this->parent_->get_shared_buffer_ref();
1832 this->prepare_first_message_buffer(shared_buf,
size.get_size());
1833 msg.
encode({&shared_buf});
1834 return this->send_buffer({&shared_buf}, message_type);
1837 const bool is_log_message = (message_type == SubscribeLogsResponse::MESSAGE_TYPE);
1839 if (!this->try_to_clear_buffer(!is_log_message)) {
1844 this->helper_->set_nodelay_for_message(is_log_message);
1846 APIError err = this->helper_->write_protobuf_packet(message_type, buffer);
1847 if (err == APIError::WOULD_BLOCK)
1849 if (err != APIError::OK) {
1850 this->fatal_error_with_log_(LOG_STR(
"Packet write failed"), err);
1856void APIConnection::on_no_setup_connection() {
1857 this->on_fatal_error();
1858 this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR(
"no connection setup"));
1860void APIConnection::on_fatal_error() {
1863 this->flags_.remove =
true;
1866void APIConnection::DeferredBatch::add_item(
EntityBase *entity, uint8_t message_type, uint8_t estimated_size,
1867 uint8_t aux_data_index) {
1873 if (message_type != EventResponse::MESSAGE_TYPE)
1876 for (
const auto &item : items) {
1877 if (item.entity == entity && item.message_type == message_type)
1882 items.push_back({entity, message_type, estimated_size, aux_data_index});
1885void APIConnection::DeferredBatch::add_item_front(
EntityBase *entity, uint8_t message_type, uint8_t estimated_size) {
1890 items.push_back({entity, message_type, estimated_size, AUX_DATA_UNUSED});
1891 if (items.size() > 1) {
1893 std::swap(items.front(), items.back());
1897bool APIConnection::send_message_smart_(
EntityBase *entity, uint8_t message_type, uint8_t estimated_size,
1898 uint8_t aux_data_index) {
1899 if (this->should_send_immediately_(message_type) && this->helper_->can_write_without_blocking()) {
1900 auto &shared_buf = this->parent_->get_shared_buffer_ref();
1901 this->prepare_first_message_buffer(shared_buf, estimated_size);
1903 if (this->dispatch_message_(item, MAX_BATCH_PACKET_SIZE,
true) &&
1905#ifdef HAS_PROTO_MESSAGE_DUMP
1906 this->log_batch_item_(item);
1911 return this->schedule_message_(entity, message_type, estimated_size, aux_data_index);
1914bool APIConnection::schedule_batch_() {
1915 if (!this->flags_.batch_scheduled) {
1916 this->flags_.batch_scheduled =
true;
1922void APIConnection::process_batch_() {
1923 if (this->deferred_batch_.empty()) {
1924 this->flags_.batch_scheduled =
false;
1929 if (!this->try_to_clear_buffer(
true)) {
1935 auto &shared_buf = this->parent_->get_shared_buffer_ref();
1936 size_t num_items = this->deferred_batch_.size();
1939 const uint8_t header_padding = this->helper_->frame_header_padding();
1940 const uint8_t footer_size = this->helper_->frame_footer_size();
1943 uint32_t total_estimated_size = num_items * (header_padding + footer_size);
1944 for (
size_t i = 0; i < num_items; i++) {
1945 total_estimated_size += this->deferred_batch_[i].estimated_size;
1948 if (total_estimated_size > MAX_BATCH_PACKET_SIZE) {
1949 total_estimated_size = MAX_BATCH_PACKET_SIZE;
1952 this->prepare_first_message_buffer(shared_buf, header_padding, total_estimated_size);
1955 if (num_items == 1) {
1956 const auto &item = this->deferred_batch_[0];
1958 uint16_t
payload_size = this->dispatch_message_(item, std::numeric_limits<uint16_t>::max(),
true);
1961#ifdef HAS_PROTO_MESSAGE_DUMP
1963 this->log_batch_item_(item);
1965 this->clear_batch_();
1968 ESP_LOGW(TAG,
"Message too large to send: type=%u", item.message_type);
1969 this->clear_batch_();
1975 this->process_batch_multi_(shared_buf, num_items, header_padding, footer_size);
1980void APIConnection::process_batch_multi_(std::vector<uint8_t> &shared_buf,
size_t num_items, uint8_t header_padding,
1981 uint8_t footer_size) {
1983 static_assert(std::is_trivially_destructible<MessageInfo>::value,
1984 "MessageInfo must remain trivially destructible with this placement-new approach");
1986 const size_t messages_to_process = std::min(num_items, MAX_MESSAGES_PER_BATCH);
1987 const uint8_t frame_overhead = header_padding + footer_size;
1992 size_t items_processed = 0;
1993 uint16_t remaining_size = std::numeric_limits<uint16_t>::max();
1998 uint32_t current_offset = 0;
2001 for (
size_t i = 0; i < messages_to_process; i++) {
2002 const auto &item = this->deferred_batch_[i];
2005 uint16_t
payload_size = this->dispatch_message_(item, remaining_size, i == 0);
2014 uint16_t proto_payload_size =
payload_size - frame_overhead;
2019 new (&message_info[items_processed++])
MessageInfo(item.message_type, current_offset, proto_payload_size);
2021 if (items_processed == 1) {
2022 remaining_size = MAX_BATCH_PACKET_SIZE;
2027 current_offset = shared_buf.size() + footer_size;
2030 if (items_processed > 0) {
2032 if (footer_size > 0) {
2033 shared_buf.resize(shared_buf.size() + footer_size);
2038 std::span<const MessageInfo>(message_info, items_processed));
2039 if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
2040 this->fatal_error_with_log_(LOG_STR(
"Batch write failed"), err);
2043#ifdef HAS_PROTO_MESSAGE_DUMP
2046 for (
size_t i = 0; i < items_processed; i++) {
2047 const auto &item = this->deferred_batch_[i];
2048 this->log_batch_item_(item);
2053 if (items_processed < this->deferred_batch_.size()) {
2054 this->deferred_batch_.remove_front(items_processed);
2055 this->schedule_batch_();
2061 this->clear_batch_();
2068 this->flags_.batch_first_message = batch_first;
2071 if (item.
message_type == EventResponse::MESSAGE_TYPE) {
2077 this, remaining_size);
2085#define CASE_STATE_INFO(entity_name, StateResp, InfoResp) \
2086 case StateResp::MESSAGE_TYPE: \
2087 func = &try_send_##entity_name##_state; \
2089 case InfoResp::MESSAGE_TYPE: \
2090 func = &try_send_##entity_name##_info; \
2092#define CASE_INFO_ONLY(entity_name, InfoResp) \
2093 case InfoResp::MESSAGE_TYPE: \
2094 func = &try_send_##entity_name##_info; \
2098#ifdef USE_BINARY_SENSOR
2119#ifdef USE_TEXT_SENSOR
2128#ifdef USE_DATETIME_DATE
2131#ifdef USE_DATETIME_TIME
2134#ifdef USE_DATETIME_DATETIME
2149#ifdef USE_MEDIA_PLAYER
2152#ifdef USE_ALARM_CONTROL_PANEL
2155#ifdef USE_WATER_HEATER
2171 case ListEntitiesDoneResponse::MESSAGE_TYPE:
2172 func = &try_send_list_info_done;
2174 case DisconnectRequest::MESSAGE_TYPE:
2175 func = &try_send_disconnect_request;
2177 case PingRequest::MESSAGE_TYPE:
2178 func = &try_send_ping_request;
2184#undef CASE_STATE_INFO
2185#undef CASE_INFO_ONLY
2187 return func(item.
entity,
this, remaining_size);
2192 return encode_message_to_buffer(resp, ListEntitiesDoneResponse::MESSAGE_TYPE, conn, remaining_size);
2197 return encode_message_to_buffer(req, DisconnectRequest::MESSAGE_TYPE, conn, remaining_size);
2202 return encode_message_to_buffer(req, PingRequest::MESSAGE_TYPE, conn, remaining_size);
2205#ifdef USE_API_HOMEASSISTANT_STATES
2206void APIConnection::process_state_subscriptions_() {
2207 const auto &subs = this->parent_->get_state_subs();
2208 if (this->state_subs_at_ >=
static_cast<int>(subs.size())) {
2209 this->state_subs_at_ = -1;
2213 const auto &it = subs[this->state_subs_at_];
2220 resp.
once = it.once;
2221 if (this->send_message(resp, SubscribeHomeAssistantStateResponse::MESSAGE_TYPE)) {
2222 this->state_subs_at_++;
2227void APIConnection::log_client_(
int level,
const LogString *
message) {
2228 char peername[socket::SOCKADDR_STR_LEN];
2229 esp_log_printf_(level, TAG, __LINE__, ESPHOME_LOG_FORMAT(
"%s (%s): %s"), this->helper_->get_client_name(),
2230 this->helper_->get_peername_to(peername), LOG_STR_ARG(
message));
2234 char peername[socket::SOCKADDR_STR_LEN];
2235 ESP_LOGW(TAG,
"%s (%s): %s %s errno=%d", this->helper_->get_client_name(), this->helper_->get_peername_to(peername),
const std::string & get_friendly_name() const
Get the friendly name of this Application set by pre_setup().
static constexpr size_t BUILD_TIME_STR_SIZE
Size of buffer required for build time string (including null terminator)
void get_build_time_string(std::span< char, BUILD_TIME_STR_SIZE > buffer)
Copy the build time string into the provided buffer Buffer must be BUILD_TIME_STR_SIZE bytes (compile...
const char * get_area() const
Get the area of this Application set by pre_setup().
const auto & get_devices()
const std::string & get_name() const
Get the name of this Application set by pre_setup().
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.
void begin(bool include_internal=false)
ESPDEPRECATED("object_id mangles names and all object_id methods are planned for removal " "(see https://github.com/esphome/backlog/issues/76). " "Now is the time to stop using object_id. If still needed, use get_object_id_to() " "which will remain available longer. get_object_id() will be removed in 2026.7.0", "2025.12.0") std uint32_t get_object_id_hash()
uint32_t get_device_id() const
Fixed-capacity vector - allocates once at runtime, never reallocates This avoids std::vector template...
void push_back(const T &value)
Add element without bounds checking Caller must ensure sufficient capacity was allocated via init() S...
Helper class for efficient buffer allocation - uses stack for small sizes, heap for large This is use...
StringRef is a reference to a string owned by something else.
constexpr const char * c_str() const
constexpr bool empty() const
constexpr size_type size() const
static constexpr StringRef from_lit(const CharT(&s)[N])
static StringRef from_maybe_nullptr(const char *s)
struct esphome::api::APIConnection::APIFlags flags_
std::unique_ptr< APIFrameHelper > helper_
APIConnection(std::unique_ptr< socket::Socket > socket, APIServer *parent)
uint16_t(*)(EntityBase *, APIConnection *, uint32_t remaining_size) MessageCreatorPtr
void on_button_command_request(const ButtonCommandRequest &msg) override
void log_send_message_(const char *name, const char *dump)
APINoiseContext & get_noise_ctx()
std::vector< uint8_t > & get_shared_buffer_ref()
enums::AlarmControlPanelStateCommand command
enums::AlarmControlPanelState state
enums::BluetoothScannerMode mode
void set_data(const uint8_t *data, size_t len)
bool has_target_temperature_high
float target_temperature_low
bool has_target_temperature_low
StringRef custom_fan_mode
float target_temperature_high
enums::ClimateSwingMode swing_mode
enums::ClimateFanMode fan_mode
bool has_target_temperature
enums::ClimatePreset preset
enums::ClimateFanMode fan_mode
float target_temperature_low
enums::ClimateSwingMode swing_mode
enums::ClimateAction action
enums::ClimatePreset preset
StringRef custom_fan_mode
float current_temperature
float target_temperature_high
enums::CoverOperation current_operation
Fixed-size buffer for message dumps - avoids heap allocation.
uint16_t response_data_len
const uint8_t * response_data
enums::FanDirection direction
enums::FanDirection direction
uint32_t api_version_major
uint32_t api_version_minor
uint32_t api_version_minor
uint32_t api_version_major
const uint8_t * response_data
uint16_t response_data_len
const uint8_t * timings_data_
uint32_t carrier_frequency
bool has_color_temperature
enums::ColorMode color_mode
bool has_transition_length
uint32_t transition_length
bool has_color_brightness
enums::ColorMode color_mode
bool requires_code_to_arm
uint32_t supported_features
bool is_status_binary_sensor
const std::vector< const char * > * supported_custom_presets
const climate::ClimateSwingModeMask * supported_swing_modes
float visual_max_humidity
const std::vector< const char * > * supported_custom_fan_modes
bool supports_current_temperature
bool supports_current_humidity
bool supports_target_humidity
float visual_min_humidity
float visual_max_temperature
float visual_target_temperature_step
bool supports_two_point_target_temperature
const climate::ClimatePresetMask * supported_presets
const climate::ClimateFanModeMask * supported_fan_modes
const climate::ClimateModeMask * supported_modes
float visual_min_temperature
float visual_current_temperature_step
const FixedVector< const char * > * event_types
const std::vector< const char * > * supported_preset_modes
int32_t supported_speed_count
bool supports_oscillation
const FixedVector< const char * > * effects
const light::ColorModeMask * supported_color_modes
StringRef unit_of_measurement
const FixedVector< const char * > * options
int32_t accuracy_decimals
StringRef unit_of_measurement
enums::SensorStateClass state_class
float target_temperature_step
const water_heater::WaterHeaterModeMask * supported_modes
uint32_t supported_features
enums::LockCommand command
virtual void encode(ProtoWriteBuffer buffer) const
virtual const char * message_name() const
virtual void calculate_size(ProtoSize &size) const
virtual const char * dump_to(DumpBuffer &out) const =0
uint32_t get_size() const
void set_message(const uint8_t *data, size_t len)
enums::UpdateCommand command
StringRef current_version
StringRef release_summary
enums::ValveOperation current_operation
std::vector< VoiceAssistantExternalWakeWord > external_wake_words
std::vector< VoiceAssistantWakeWord > available_wake_words
uint32_t max_active_wake_words
const std::vector< std::string > * active_wake_words
std::vector< std::string > active_wake_words
float target_temperature_low
enums::WaterHeaterMode mode
float target_temperature_high
float current_temperature
float target_temperature_low
float target_temperature_high
enums::WaterHeaterMode mode
enums::ZWaveProxyRequestType type
Base class for all binary_sensor-type classes.
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 bluetooth_scanner_set_mode(bool active)
void subscribe_api_connection(api::APIConnection *api_connection, uint32_t flags)
uint32_t get_feature_flags() const
void send_connections_free()
void unsubscribe_api_connection(api::APIConnection *api_connection)
void get_bluetooth_mac_address_pretty(std::span< char, 18 > output)
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)
Abstract camera base class.
virtual CameraImageReader * create_image_reader()=0
Returns a new camera image reader that keeps track of the JPEG data in the camera image.
virtual void start_stream(CameraRequester requester)=0
virtual void stop_stream(CameraRequester requester)=0
virtual void request_image(CameraRequester requester)=0
static Camera * instance()
The singleton instance of the camera implementation.
ClimateDevice - This is the base class for all climate integrations.
Base class for all cover devices.
uint8_t get_last_event_type_index() const
Return index of last triggered event type, or max uint8_t if no event triggered yet.
void set_epoch_time(uint32_t epoch)
Infrared - Base class for infrared remote control implementations.
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Base class for all locks.
Base-class for all numbers.
Base-class for all selects.
Base-class for all sensors.
Base class for all switches.
Base-class for all text inputs.
void set_timezone(const std::string &tz)
Set the time zone.
Base class for all valve devices.
const Configuration & get_configuration()
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)
api::APIConnection * get_api_connection() const
uint32_t get_feature_flags() const
void on_set_configuration(const std::vector< std::string > &active_wake_words)
void zwave_proxy_request(api::APIConnection *api_connection, api::enums::ZWaveProxyRequestType type)
void send_frame(const uint8_t *data, size_t length)
uint32_t get_feature_flags() const
void api_connection_authenticated(api::APIConnection *conn)
const LogString * api_error_to_logstr(APIError err)
std::array< uint8_t, 32 > psk_t
BluetoothProxy * global_bluetooth_proxy
@ CLIMATE_SUPPORTS_CURRENT_HUMIDITY
@ CLIMATE_SUPPORTS_TARGET_HUMIDITY
@ CLIMATE_SUPPORTS_TWO_POINT_TARGET_TEMPERATURE
@ CLIMATE_SUPPORTS_CURRENT_TEMPERATURE
@ CLIMATE_SUPPORTS_ACTION
@ CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE
ClimatePreset
Enum for all preset modes NOTE: If adding values, update ClimatePresetMask in climate_traits....
ClimateSwingMode
Enum for all modes a climate swing can be in NOTE: If adding values, update ClimateSwingModeMask in c...
ClimateMode
Enum for all modes a climate device can be in.
ClimateFanMode
NOTE: If adding values, update ClimateFanModeMask in climate_traits.h to use the new last value.
bool global_has_deep_sleep
FanDirection
Simple enum to represent the direction of a fan.
HomeassistantTime * global_homeassistant_time
ColorMode
Color modes are a combination of color capabilities that can be used at the same time.
@ COLOR_TEMPERATURE
Color temperature can be controlled.
@ COLD_WARM_WHITE
Brightness of cold and warm white output can be controlled.
@ UPDATE_STATE_INSTALLING
VoiceAssistant * global_voice_assistant
@ WATER_HEATER_STATE_ON
Water heater is on (not in standby)
@ WATER_HEATER_STATE_AWAY
Away/vacation mode is currently active.
ZWaveProxy * global_zwave_proxy
void HOT esp_log_printf_(int level, const char *tag, int line, const char *format,...)
void get_mac_address_raw(uint8_t *mac)
Get the device MAC address as raw bytes, written into the provided byte array (6 bytes).
void IRAM_ATTR HOT delay(uint32_t ms)
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)
char * format_mac_addr_upper(const uint8_t *mac, char *output)
Format MAC address as XX:XX:XX:XX:XX:XX (uppercase, colon separators)
A more user-friendly version of struct tm from time.h.
uint8_t batch_first_message
const uint8_t ESPHOME_WEBSERVER_INDEX_HTML[] PROGMEM