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
56static constexpr uint8_t MAX_MESSAGES_PER_LOOP = 5;
57static constexpr uint8_t MAX_PING_RETRIES = 60;
58static constexpr uint16_t PING_RETRY_INTERVAL = 1000;
59static constexpr uint32_t KEEPALIVE_DISCONNECT_TIMEOUT = (KEEPALIVE_TIMEOUT_MS * 5) / 2;
63static const char *
const TAG =
"api.connection";
65static const int CAMERA_STOP_STREAM = 5000;
71#define ENTITY_COMMAND_MAKE_CALL(entity_type, entity_var, getter_name) \
72 entity_type *entity_var = App.get_##getter_name##_by_key(msg.key, msg.device_id); \
73 if ((entity_var) == nullptr) \
75 auto call = (entity_var)->make_call();
79#define ENTITY_COMMAND_GET(entity_type, entity_var, getter_name) \
80 entity_type *entity_var = App.get_##getter_name##_by_key(msg.key, msg.device_id); \
81 if ((entity_var) == nullptr) \
86#define ENTITY_COMMAND_MAKE_CALL(entity_type, entity_var, getter_name) \
87 entity_type *entity_var = App.get_##getter_name##_by_key(msg.key); \
88 if ((entity_var) == nullptr) \
90 auto call = (entity_var)->make_call();
94#define ENTITY_COMMAND_GET(entity_type, entity_var, getter_name) \
95 entity_type *entity_var = App.get_##getter_name##_by_key(msg.key); \
96 if ((entity_var) == nullptr) \
101#if defined(USE_API_PLAINTEXT) && defined(USE_API_NOISE)
103 if (noise_ctx.has_psk()) {
105 std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), noise_ctx, &this->client_info_)};
107 this->helper_ = std::unique_ptr<APIFrameHelper>{
new APIPlaintextFrameHelper(std::move(sock), &this->client_info_)};
109#elif defined(USE_API_PLAINTEXT)
110 this->helper_ = std::unique_ptr<APIFrameHelper>{
new APIPlaintextFrameHelper(std::move(sock), &this->client_info_)};
111#elif defined(USE_API_NOISE)
112 this->helper_ = std::unique_ptr<APIFrameHelper>{
113 new APINoiseFrameHelper(std::move(sock), parent->get_noise_ctx(), &this->client_info_)};
115#error "No frame helper defined"
124uint32_t APIConnection::get_batch_delay_ms_()
const {
return this->parent_->get_batch_delay(); }
126void APIConnection::start() {
129 APIError err = this->helper_->init();
130 if (err != APIError::OK) {
131 this->fatal_error_with_log_(LOG_STR(
"Helper init failed"), err);
134 this->client_info_.peername = helper_->getpeername();
135 this->client_info_.name = this->client_info_.peername;
138APIConnection::~APIConnection() {
139 this->destroy_active_iterator_();
140#ifdef USE_BLUETOOTH_PROXY
145#ifdef USE_VOICE_ASSISTANT
152void APIConnection::destroy_active_iterator_() {
153 switch (this->active_iterator_) {
154 case ActiveIterator::LIST_ENTITIES:
155 this->iterator_storage_.list_entities.~ListEntitiesIterator();
157 case ActiveIterator::INITIAL_STATE:
158 this->iterator_storage_.initial_state.~InitialStateIterator();
160 case ActiveIterator::NONE:
163 this->active_iterator_ = ActiveIterator::NONE;
167 this->destroy_active_iterator_();
168 this->active_iterator_ =
type;
169 if (
type == ActiveIterator::LIST_ENTITIES) {
171 this->iterator_storage_.list_entities.
begin();
174 this->iterator_storage_.initial_state.
begin();
178void APIConnection::loop() {
179 if (this->flags_.next_close) {
181 this->helper_->close();
182 this->flags_.remove =
true;
186 APIError err = this->helper_->loop();
187 if (err != APIError::OK) {
188 this->fatal_error_with_log_(LOG_STR(
"Socket operation failed"), err);
194 if (this->helper_->is_socket_ready()) {
196 for (uint8_t message_count = 0; message_count < MAX_MESSAGES_PER_LOOP; message_count++) {
198 err = this->helper_->read_packet(&buffer);
199 if (err == APIError::WOULD_BLOCK) {
202 }
else if (err != APIError::OK) {
203 this->fatal_error_with_log_(LOG_STR(
"Reading failed"), err);
206 this->last_traffic_ = now;
209 if (this->flags_.remove)
216 if (this->flags_.batch_scheduled && now - this->deferred_batch_.batch_start_time >= this->get_batch_delay_ms_()) {
217 this->process_batch_();
220 switch (this->active_iterator_) {
221 case ActiveIterator::LIST_ENTITIES:
222 if (this->iterator_storage_.list_entities.completed()) {
223 this->destroy_active_iterator_();
224 if (this->flags_.state_subscription) {
225 this->begin_iterator_(ActiveIterator::INITIAL_STATE);
228 this->process_iterator_batch_(this->iterator_storage_.list_entities);
231 case ActiveIterator::INITIAL_STATE:
232 if (this->iterator_storage_.initial_state.completed()) {
233 this->destroy_active_iterator_();
235 if (!this->deferred_batch_.empty()) {
236 this->process_batch_();
239 this->flags_.should_try_send_immediately =
true;
241 this->deferred_batch_.release_buffer();
242 this->helper_->release_buffers();
244 this->process_iterator_batch_(this->iterator_storage_.initial_state);
247 case ActiveIterator::NONE:
251 if (this->flags_.sent_ping) {
253 if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) {
255 ESP_LOGW(TAG,
"%s (%s) is unresponsive; disconnecting", this->client_info_.name.c_str(),
256 this->client_info_.peername.c_str());
258 }
else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && !this->flags_.remove) {
260 ESP_LOGVV(TAG,
"Sending keepalive PING");
262 this->flags_.sent_ping = this->send_message(req, PingRequest::MESSAGE_TYPE);
263 if (!this->flags_.sent_ping) {
266 ESP_LOGW(TAG,
"Buffer full, ping queued");
267 this->schedule_message_front_(
nullptr, &APIConnection::try_send_ping_request, PingRequest::MESSAGE_TYPE,
268 PingRequest::ESTIMATED_SIZE);
269 this->flags_.sent_ping =
true;
273#ifdef USE_API_HOMEASSISTANT_STATES
274 if (state_subs_at_ >= 0) {
275 this->process_state_subscriptions_();
282 this->try_send_camera_image_();
290 ESP_LOGD(TAG,
"%s (%s) disconnected", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
291 this->flags_.next_close =
true;
293 return this->send_message(resp, DisconnectResponse::MESSAGE_TYPE);
296 this->helper_->close();
297 this->flags_.remove =
true;
303 uint32_t remaining_size,
bool is_single) {
304#ifdef HAS_PROTO_MESSAGE_DUMP
315 uint32_t calculated_size = size_calc.
get_size();
318 const uint8_t header_padding = conn->
helper_->frame_header_padding();
319 const uint8_t footer_size = conn->
helper_->frame_footer_size();
322 size_t total_calculated_size = calculated_size + header_padding + footer_size;
325 if (total_calculated_size > remaining_size) {
341 size_t current_size = shared_buf.size();
342 shared_buf.reserve(current_size + total_calculated_size);
343 shared_buf.resize(current_size + footer_size + header_padding);
347 size_t size_before_encode = shared_buf.size();
348 msg.
encode({&shared_buf});
351 size_t actual_payload_size = shared_buf.size() - size_before_encode;
354 size_t actual_total_size = header_padding + actual_payload_size + footer_size;
357 assert(calculated_size == actual_payload_size);
358 return static_cast<uint16_t
>(actual_total_size);
361#ifdef USE_BINARY_SENSOR
363 return this->send_message_smart_(binary_sensor, &APIConnection::try_send_binary_sensor_state,
364 BinarySensorStateResponse::MESSAGE_TYPE, BinarySensorStateResponse::ESTIMATED_SIZE);
371 resp.
state = binary_sensor->state;
373 return fill_and_encode_entity_state(binary_sensor, resp, BinarySensorStateResponse::MESSAGE_TYPE, conn,
374 remaining_size, is_single);
383 return fill_and_encode_entity_info(binary_sensor, msg, ListEntitiesBinarySensorResponse::MESSAGE_TYPE, conn,
384 remaining_size, is_single);
390 return this->send_message_smart_(cover, &APIConnection::try_send_cover_state, CoverStateResponse::MESSAGE_TYPE,
391 CoverStateResponse::ESTIMATED_SIZE);
397 auto traits = cover->get_traits();
399 if (traits.get_supports_tilt())
400 msg.
tilt = cover->tilt;
402 return fill_and_encode_entity_state(cover, msg, CoverStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
408 auto traits = cover->get_traits();
414 return fill_and_encode_entity_info(cover, msg, ListEntitiesCoverResponse::MESSAGE_TYPE, conn, remaining_size,
422 call.set_tilt(msg.
tilt);
424 call.set_command_stop();
431 return this->send_message_smart_(fan, &APIConnection::try_send_fan_state, FanStateResponse::MESSAGE_TYPE,
432 FanStateResponse::ESTIMATED_SIZE);
436 auto *fan =
static_cast<fan::Fan *
>(entity);
438 auto traits = fan->get_traits();
439 msg.
state = fan->state;
440 if (traits.supports_oscillation())
442 if (traits.supports_speed()) {
445 if (traits.supports_direction())
447 if (traits.supports_preset_modes() && fan->has_preset_mode())
449 return fill_and_encode_entity_state(fan, msg, FanStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
453 auto *fan =
static_cast<fan::Fan *
>(entity);
455 auto traits = fan->get_traits();
461 return fill_and_encode_entity_info(fan, msg, ListEntitiesFanResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
464 ENTITY_COMMAND_MAKE_CALL(
fan::Fan, fan, fan)
466 call.set_state(msg.
state);
483 return this->send_message_smart_(light, &APIConnection::try_send_light_state, LightStateResponse::MESSAGE_TYPE,
484 LightStateResponse::ESTIMATED_SIZE);
490 auto values = light->remote_values;
491 auto color_mode = values.get_color_mode();
492 resp.
state = values.is_on();
496 resp.
red = values.get_red();
497 resp.
green = values.get_green();
498 resp.
blue = values.get_blue();
499 resp.
white = values.get_white();
503 if (light->supports_effects()) {
504 resp.
set_effect(light->get_effect_name_ref());
506 return fill_and_encode_entity_state(light, resp, LightStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
512 auto traits = light->get_traits();
513 auto supported_modes = traits.get_supported_color_modes();
522 if (light->supports_effects()) {
523 auto &light_effects = light->get_effects();
524 effects_list.
init(light_effects.size() + 1);
526 for (
auto *effect : light_effects) {
527 effects_list.
push_back(effect->get_name());
531 return fill_and_encode_entity_info(light, msg, ListEntitiesLightResponse::MESSAGE_TYPE, conn, remaining_size,
537 call.set_state(msg.
state);
545 call.set_red(msg.
red);
546 call.set_green(msg.
green);
547 call.set_blue(msg.
blue);
550 call.set_white(msg.
white);
562 call.set_effect(
reinterpret_cast<const char *
>(msg.
effect), msg.
effect_len);
569 return this->send_message_smart_(sensor, &APIConnection::try_send_sensor_state, SensorStateResponse::MESSAGE_TYPE,
570 SensorStateResponse::ESTIMATED_SIZE);
577 resp.
state = sensor->state;
579 return fill_and_encode_entity_state(sensor, resp, SensorStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
591 return fill_and_encode_entity_info(sensor, msg, ListEntitiesSensorResponse::MESSAGE_TYPE, conn, remaining_size,
598 return this->send_message_smart_(a_switch, &APIConnection::try_send_switch_state, SwitchStateResponse::MESSAGE_TYPE,
599 SwitchStateResponse::ESTIMATED_SIZE);
606 resp.
state = a_switch->state;
607 return fill_and_encode_entity_state(a_switch, resp, SwitchStateResponse::MESSAGE_TYPE, conn, remaining_size,
617 return fill_and_encode_entity_info(a_switch, msg, ListEntitiesSwitchResponse::MESSAGE_TYPE, conn, remaining_size,
626 a_switch->turn_off();
631#ifdef USE_TEXT_SENSOR
633 return this->send_message_smart_(text_sensor, &APIConnection::try_send_text_sensor_state,
634 TextSensorStateResponse::MESSAGE_TYPE, TextSensorStateResponse::ESTIMATED_SIZE);
643 return fill_and_encode_entity_state(text_sensor, resp, TextSensorStateResponse::MESSAGE_TYPE, conn, remaining_size,
651 return fill_and_encode_entity_info(text_sensor, msg, ListEntitiesTextSensorResponse::MESSAGE_TYPE, conn,
652 remaining_size, is_single);
658 return this->send_message_smart_(climate, &APIConnection::try_send_climate_state, ClimateStateResponse::MESSAGE_TYPE,
659 ClimateStateResponse::ESTIMATED_SIZE);
665 auto traits = climate->get_traits();
677 if (traits.get_supports_fan_modes() && climate->fan_mode.has_value())
679 if (!traits.get_supported_custom_fan_modes().empty() && climate->has_custom_fan_mode()) {
682 if (traits.get_supports_presets() && climate->preset.has_value()) {
685 if (!traits.get_supported_custom_presets().empty() && climate->has_custom_preset()) {
688 if (traits.get_supports_swing_modes())
694 return fill_and_encode_entity_state(climate, resp, ClimateStateResponse::MESSAGE_TYPE, conn, remaining_size,
701 auto traits = climate->get_traits();
723 return fill_and_encode_entity_info(climate, msg, ListEntitiesClimateResponse::MESSAGE_TYPE, conn, remaining_size,
754 return this->send_message_smart_(number, &APIConnection::try_send_number_state, NumberStateResponse::MESSAGE_TYPE,
755 NumberStateResponse::ESTIMATED_SIZE);
762 resp.
state = number->state;
764 return fill_and_encode_entity_state(number, resp, NumberStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
774 msg.
min_value = number->traits.get_min_value();
775 msg.
max_value = number->traits.get_max_value();
776 msg.
step = number->traits.get_step();
777 return fill_and_encode_entity_info(number, msg, ListEntitiesNumberResponse::MESSAGE_TYPE, conn, remaining_size,
782 call.set_value(msg.
state);
787#ifdef USE_DATETIME_DATE
789 return this->send_message_smart_(date, &APIConnection::try_send_date_state, DateStateResponse::MESSAGE_TYPE,
790 DateStateResponse::ESTIMATED_SIZE);
797 resp.
year = date->year;
798 resp.
month = date->month;
799 resp.
day = date->day;
800 return fill_and_encode_entity_state(date, resp, DateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
806 return fill_and_encode_entity_info(date, msg, ListEntitiesDateResponse::MESSAGE_TYPE, conn, remaining_size,
816#ifdef USE_DATETIME_TIME
818 return this->send_message_smart_(time, &APIConnection::try_send_time_state, TimeStateResponse::MESSAGE_TYPE,
819 TimeStateResponse::ESTIMATED_SIZE);
826 resp.
hour = time->hour;
827 resp.
minute = time->minute;
828 resp.
second = time->second;
829 return fill_and_encode_entity_state(time, resp, TimeStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
835 return fill_and_encode_entity_info(time, msg, ListEntitiesTimeResponse::MESSAGE_TYPE, conn, remaining_size,
845#ifdef USE_DATETIME_DATETIME
847 return this->send_message_smart_(datetime, &APIConnection::try_send_datetime_state,
848 DateTimeStateResponse::MESSAGE_TYPE, DateTimeStateResponse::ESTIMATED_SIZE);
855 if (datetime->has_state()) {
859 return fill_and_encode_entity_state(datetime, resp, DateTimeStateResponse::MESSAGE_TYPE, conn, remaining_size,
866 return fill_and_encode_entity_info(datetime, msg, ListEntitiesDateTimeResponse::MESSAGE_TYPE, conn, remaining_size,
878 return this->send_message_smart_(text, &APIConnection::try_send_text_state, TextStateResponse::MESSAGE_TYPE,
879 TextStateResponse::ESTIMATED_SIZE);
884 auto *text =
static_cast<text::Text *
>(entity);
888 return fill_and_encode_entity_state(text, resp, TextStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
893 auto *text =
static_cast<text::Text *
>(entity);
896 msg.
min_length = text->traits.get_min_length();
897 msg.
max_length = text->traits.get_max_length();
899 return fill_and_encode_entity_info(text, msg, ListEntitiesTextResponse::MESSAGE_TYPE, conn, remaining_size,
903 ENTITY_COMMAND_MAKE_CALL(
text::Text, text, text)
904 call.set_value(msg.
state);
911 return this->send_message_smart_(select, &APIConnection::try_send_select_state, SelectStateResponse::MESSAGE_TYPE,
912 SelectStateResponse::ESTIMATED_SIZE);
921 return fill_and_encode_entity_state(select, resp, SelectStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
928 msg.
options = &select->traits.get_options();
929 return fill_and_encode_entity_info(select, msg, ListEntitiesSelectResponse::MESSAGE_TYPE, conn, remaining_size,
934 call.set_option(
reinterpret_cast<const char *
>(msg.
state), msg.
state_len);
945 return fill_and_encode_entity_info(button, msg, ListEntitiesButtonResponse::MESSAGE_TYPE, conn, remaining_size,
956 return this->send_message_smart_(a_lock, &APIConnection::try_send_lock_state, LockStateResponse::MESSAGE_TYPE,
957 LockStateResponse::ESTIMATED_SIZE);
962 auto *a_lock =
static_cast<lock::Lock *
>(entity);
965 return fill_and_encode_entity_state(a_lock, resp, LockStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
970 auto *a_lock =
static_cast<lock::Lock *
>(entity);
975 return fill_and_encode_entity_info(a_lock, msg, ListEntitiesLockResponse::MESSAGE_TYPE, conn, remaining_size,
982 case enums::LOCK_UNLOCK:
985 case enums::LOCK_LOCK:
988 case enums::LOCK_OPEN:
997 return this->send_message_smart_(valve, &APIConnection::try_send_valve_state, ValveStateResponse::MESSAGE_TYPE,
998 ValveStateResponse::ESTIMATED_SIZE);
1006 return fill_and_encode_entity_state(valve, resp, ValveStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1012 auto traits = valve->get_traits();
1017 return fill_and_encode_entity_info(valve, msg, ListEntitiesValveResponse::MESSAGE_TYPE, conn, remaining_size,
1025 call.set_command_stop();
1030#ifdef USE_MEDIA_PLAYER
1032 return this->send_message_smart_(media_player, &APIConnection::try_send_media_player_state,
1033 MediaPlayerStateResponse::MESSAGE_TYPE, MediaPlayerStateResponse::ESTIMATED_SIZE);
1041 : media_player->state;
1043 resp.
volume = media_player->volume;
1044 resp.
muted = media_player->is_muted();
1045 return fill_and_encode_entity_state(media_player, resp, MediaPlayerStateResponse::MESSAGE_TYPE, conn, remaining_size,
1052 auto traits = media_player->get_traits();
1055 for (
auto &supported_format : traits.get_supported_formats()) {
1058 media_format.set_format(
StringRef(supported_format.format));
1059 media_format.sample_rate = supported_format.sample_rate;
1060 media_format.num_channels = supported_format.num_channels;
1062 media_format.sample_bytes = supported_format.sample_bytes;
1064 return fill_and_encode_entity_info(media_player, msg, ListEntitiesMediaPlayerResponse::MESSAGE_TYPE, conn,
1065 remaining_size, is_single);
1073 call.set_volume(msg.
volume);
1086void APIConnection::try_send_camera_image_() {
1087 if (!this->image_reader_)
1091 while (this->image_reader_->available()) {
1092 if (!this->helper_->can_write_without_blocking())
1095 uint32_t to_send = std::min((
size_t) MAX_BATCH_PACKET_SIZE, this->image_reader_->available());
1096 bool done = this->image_reader_->available() == to_send;
1100 msg.
set_data(this->image_reader_->peek_data_buffer(), to_send);
1106 if (!this->send_message_(msg, CameraImageResponse::MESSAGE_TYPE)) {
1109 this->image_reader_->consume_data(to_send);
1111 this->image_reader_->return_image();
1116void APIConnection::set_camera_state(std::shared_ptr<camera::CameraImage> image) {
1117 if (!this->flags_.state_subscription)
1119 if (!this->image_reader_)
1121 if (this->image_reader_->available())
1124 this->image_reader_->set_image(std::move(image));
1126 this->try_send_camera_image_();
1133 return fill_and_encode_entity_info(camera, msg, ListEntitiesCameraResponse::MESSAGE_TYPE, conn, remaining_size,
1145 App.scheduler.set_timeout(this->parent_,
"api_camera_stop_stream", CAMERA_STOP_STREAM,
1151#ifdef USE_HOMEASSISTANT_TIME
1155#ifdef USE_TIME_TIMEZONE
1165#ifdef USE_BLUETOOTH_PROXY
1195bool APIConnection::send_subscribe_bluetooth_connections_free_response(
1203 msg.
mode == enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE);
1207#ifdef USE_VOICE_ASSISTANT
1208bool APIConnection::check_voice_assistant_api_connection_()
const {
1219 if (!this->check_voice_assistant_api_connection_()) {
1227 if (msg.
port == 0) {
1233 this->helper_->getpeername((
struct sockaddr *) &storage, &
len);
1238 if (this->check_voice_assistant_api_connection_()) {
1243 if (this->check_voice_assistant_api_connection_()) {
1248 if (this->check_voice_assistant_api_connection_()) {
1254 if (this->check_voice_assistant_api_connection_()) {
1261 if (!this->check_voice_assistant_api_connection_()) {
1262 return this->send_message(resp, VoiceAssistantConfigurationResponse::MESSAGE_TYPE);
1266 for (
auto &wake_word : config.available_wake_words) {
1269 resp_wake_word.set_id(
StringRef(wake_word.id));
1270 resp_wake_word.set_wake_word(
StringRef(wake_word.wake_word));
1271 for (
const auto &lang : wake_word.trained_languages) {
1272 resp_wake_word.trained_languages.push_back(lang);
1278 if (wake_word.model_type !=
"micro") {
1285 resp_wake_word.set_id(
StringRef(wake_word.id));
1286 resp_wake_word.set_wake_word(
StringRef(wake_word.wake_word));
1287 for (
const auto &lang : wake_word.trained_languages) {
1288 resp_wake_word.trained_languages.push_back(lang);
1294 return this->send_message(resp, VoiceAssistantConfigurationResponse::MESSAGE_TYPE);
1298 if (this->check_voice_assistant_api_connection_()) {
1304#ifdef USE_ZWAVE_PROXY
1314#ifdef USE_ALARM_CONTROL_PANEL
1316 return this->send_message_smart_(a_alarm_control_panel, &APIConnection::try_send_alarm_control_panel_state,
1317 AlarmControlPanelStateResponse::MESSAGE_TYPE,
1318 AlarmControlPanelStateResponse::ESTIMATED_SIZE);
1321 uint32_t remaining_size,
bool is_single) {
1325 return fill_and_encode_entity_state(a_alarm_control_panel, resp, AlarmControlPanelStateResponse::MESSAGE_TYPE, conn,
1326 remaining_size, is_single);
1329 uint32_t remaining_size,
bool is_single) {
1333 msg.
requires_code = a_alarm_control_panel->get_requires_code();
1335 return fill_and_encode_entity_info(a_alarm_control_panel, msg, ListEntitiesAlarmControlPanelResponse::MESSAGE_TYPE,
1336 conn, remaining_size, is_single);
1341 case enums::ALARM_CONTROL_PANEL_DISARM:
1344 case enums::ALARM_CONTROL_PANEL_ARM_AWAY:
1347 case enums::ALARM_CONTROL_PANEL_ARM_HOME:
1350 case enums::ALARM_CONTROL_PANEL_ARM_NIGHT:
1353 case enums::ALARM_CONTROL_PANEL_ARM_VACATION:
1354 call.arm_vacation();
1356 case enums::ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS:
1357 call.arm_custom_bypass();
1359 case enums::ALARM_CONTROL_PANEL_TRIGGER:
1363 call.set_code(msg.
code);
1368#ifdef USE_WATER_HEATER
1370 return this->send_message_smart_(water_heater, &APIConnection::try_send_water_heater_state,
1371 WaterHeaterStateResponse::MESSAGE_TYPE, WaterHeaterStateResponse::ESTIMATED_SIZE);
1382 resp.
state = wh->get_state();
1383 resp.
key = wh->get_object_id_hash();
1385 return encode_message_to_buffer(resp, WaterHeaterStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1391 auto traits = wh->get_traits();
1397 return fill_and_encode_entity_info(wh, msg, ListEntitiesWaterHeaterResponse::MESSAGE_TYPE, conn, remaining_size,
1403 if (msg.
has_fields & enums::WATER_HEATER_COMMAND_HAS_MODE)
1405 if (msg.
has_fields & enums::WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE)
1407 if (msg.
has_fields & enums::WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE_LOW)
1409 if (msg.
has_fields & enums::WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE_HIGH)
1411 if (msg.
has_fields & enums::WATER_HEATER_COMMAND_HAS_STATE) {
1420void APIConnection::send_event(
event::Event *event,
const char *event_type) {
1421 this->send_message_smart_(event,
MessageCreator(event_type), EventResponse::MESSAGE_TYPE,
1422 EventResponse::ESTIMATED_SIZE);
1425 uint32_t remaining_size,
bool is_single) {
1428 return fill_and_encode_entity_state(event, resp, EventResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1437 return fill_and_encode_entity_info(event, msg, ListEntitiesEventResponse::MESSAGE_TYPE, conn, remaining_size,
1444 return this->send_message_smart_(update, &APIConnection::try_send_update_state, UpdateStateResponse::MESSAGE_TYPE,
1445 UpdateStateResponse::ESTIMATED_SIZE);
1452 if (update->has_state()) {
1454 if (update->update_info.has_progress) {
1456 resp.
progress = update->update_info.progress;
1464 return fill_and_encode_entity_state(update, resp, UpdateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1471 return fill_and_encode_entity_info(update, msg, ListEntitiesUpdateResponse::MESSAGE_TYPE, conn, remaining_size,
1478 case enums::UPDATE_COMMAND_UPDATE:
1481 case enums::UPDATE_COMMAND_CHECK:
1484 case enums::UPDATE_COMMAND_NONE:
1485 ESP_LOGE(TAG,
"UPDATE_COMMAND_NONE not handled; confirm command is correct");
1488 ESP_LOGW(TAG,
"Unknown update command: %" PRIu32, msg.
command);
1494bool APIConnection::try_send_log_message(
int level,
const char *tag,
const char *line,
size_t message_len) {
1497 msg.
set_message(
reinterpret_cast<const uint8_t *
>(line), message_len);
1498 return this->send_message_(msg, SubscribeLogsResponse::MESSAGE_TYPE);
1501void APIConnection::complete_authentication_() {
1503 if (this->flags_.connection_state ==
static_cast<uint8_t
>(ConnectionState::AUTHENTICATED)) {
1507 this->flags_.connection_state =
static_cast<uint8_t
>(ConnectionState::AUTHENTICATED);
1508 ESP_LOGD(TAG,
"%s (%s) connected", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
1509#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
1510 this->parent_->get_client_connected_trigger()->trigger(this->client_info_.name, this->client_info_.peername);
1512#ifdef USE_HOMEASSISTANT_TIME
1514 this->send_time_request();
1517#ifdef USE_ZWAVE_PROXY
1526 this->client_info_.peername = this->helper_->getpeername();
1529 ESP_LOGV(TAG,
"Hello from client: '%s' | %s | API Version %" PRIu32
".%" PRIu32, this->client_info_.name.c_str(),
1530 this->client_info_.peername.c_str(), this->client_api_version_major_, this->client_api_version_minor_);
1539#ifdef USE_API_PASSWORD
1541 this->flags_.connection_state =
static_cast<uint8_t
>(ConnectionState::CONNECTED);
1544 this->complete_authentication_();
1547 return this->send_message(resp, HelloResponse::MESSAGE_TYPE);
1549#ifdef USE_API_PASSWORD
1555 this->complete_authentication_();
1557 return this->send_message(resp, AuthenticationResponse::MESSAGE_TYPE);
1563 return this->send_message(resp, PingResponse::MESSAGE_TYPE);
1568#ifdef USE_API_PASSWORD
1577 char mac_address[18];
1581 resp.set_mac_address(
StringRef(mac_address));
1583 resp.set_esphome_version(ESPHOME_VERSION_REF);
1588 resp.set_compilation_time(
StringRef(build_time_str));
1591#if defined(USE_ESP8266) || defined(USE_ESP32)
1592#define ESPHOME_MANUFACTURER "Espressif"
1593#elif defined(USE_RP2040)
1594#define ESPHOME_MANUFACTURER "Raspberry Pi"
1595#elif defined(USE_BK72XX)
1596#define ESPHOME_MANUFACTURER "Beken"
1597#elif defined(USE_LN882X)
1598#define ESPHOME_MANUFACTURER "Lightning"
1599#elif defined(USE_NRF52)
1600#define ESPHOME_MANUFACTURER "Nordic Semiconductor"
1601#elif defined(USE_RTL87XX)
1602#define ESPHOME_MANUFACTURER "Realtek"
1603#elif defined(USE_HOST)
1604#define ESPHOME_MANUFACTURER "Host"
1609 static const char MANUFACTURER_PROGMEM[]
PROGMEM = ESPHOME_MANUFACTURER;
1610 char manufacturer_buf[
sizeof(MANUFACTURER_PROGMEM)];
1611 memcpy_P(manufacturer_buf, MANUFACTURER_PROGMEM,
sizeof(MANUFACTURER_PROGMEM));
1612 resp.set_manufacturer(
StringRef(manufacturer_buf,
sizeof(MANUFACTURER_PROGMEM) - 1));
1615 resp.set_manufacturer(MANUFACTURER);
1617#undef ESPHOME_MANUFACTURER
1620 static const char MODEL_PROGMEM[]
PROGMEM = ESPHOME_BOARD;
1621 char model_buf[
sizeof(MODEL_PROGMEM)];
1622 memcpy_P(model_buf, MODEL_PROGMEM,
sizeof(MODEL_PROGMEM));
1623 resp.set_model(
StringRef(model_buf,
sizeof(MODEL_PROGMEM) - 1));
1626 resp.set_model(MODEL);
1628#ifdef USE_DEEP_SLEEP
1631#ifdef ESPHOME_PROJECT_NAME
1633 static const char PROJECT_NAME_PROGMEM[]
PROGMEM = ESPHOME_PROJECT_NAME;
1634 static const char PROJECT_VERSION_PROGMEM[]
PROGMEM = ESPHOME_PROJECT_VERSION;
1635 char project_name_buf[
sizeof(PROJECT_NAME_PROGMEM)];
1636 char project_version_buf[
sizeof(PROJECT_VERSION_PROGMEM)];
1637 memcpy_P(project_name_buf, PROJECT_NAME_PROGMEM,
sizeof(PROJECT_NAME_PROGMEM));
1638 memcpy_P(project_version_buf, PROJECT_VERSION_PROGMEM,
sizeof(PROJECT_VERSION_PROGMEM));
1639 resp.set_project_name(
StringRef(project_name_buf,
sizeof(PROJECT_NAME_PROGMEM) - 1));
1640 resp.set_project_version(
StringRef(project_version_buf,
sizeof(PROJECT_VERSION_PROGMEM) - 1));
1644 resp.set_project_name(PROJECT_NAME);
1645 resp.set_project_version(PROJECT_VERSION);
1649 resp.webserver_port = USE_WEBSERVER_PORT;
1651#ifdef USE_BLUETOOTH_PROXY
1654 char bluetooth_mac[18];
1656 resp.set_bluetooth_mac_address(
StringRef(bluetooth_mac));
1658#ifdef USE_VOICE_ASSISTANT
1661#ifdef USE_ZWAVE_PROXY
1666 resp.api_encryption_supported =
true;
1669 size_t device_index = 0;
1671 if (device_index >= ESPHOME_DEVICE_COUNT)
1673 auto &device_info = resp.devices[device_index++];
1674 device_info.device_id = device->get_device_id();
1675 device_info.set_name(
StringRef(device->get_name()));
1676 device_info.area_id = device->get_area_id();
1680 size_t area_index = 0;
1682 if (area_index >= ESPHOME_AREA_COUNT)
1684 auto &area_info = resp.areas[area_index++];
1685 area_info.area_id = area->get_area_id();
1686 area_info.set_name(
StringRef(area->get_name()));
1690 return this->send_message(resp, DeviceInfoResponse::MESSAGE_TYPE);
1693#ifdef USE_API_HOMEASSISTANT_STATES
1700 for (
auto &it : this->parent_->get_state_subs()) {
1702 size_t entity_id_len = strlen(it.entity_id);
1708 size_t sub_attr_len = it.attribute !=
nullptr ? strlen(it.attribute) : 0;
1710 (sub_attr_len > 0 && memcmp(it.attribute, msg.
attribute, sub_attr_len) != 0)) {
1721#ifdef USE_API_USER_DEFINED_ACTIONS
1724#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
1727 uint32_t action_call_id = 0;
1729 action_call_id = this->parent_->register_active_action_call(msg.
call_id,
this);
1732 for (
auto *service : this->parent_->get_user_services()) {
1733 if (service->execute_service(msg, action_call_id)) {
1738 for (
auto *service : this->parent_->get_user_services()) {
1739 if (service->execute_service(msg)) {
1745 ESP_LOGV(TAG,
"Could not find service");
1751#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
1752void APIConnection::send_execute_service_response(uint32_t call_id,
bool success,
const std::string &error_message) {
1757 this->send_message(resp, ExecuteServiceResponse::MESSAGE_TYPE);
1759#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
1760void APIConnection::send_execute_service_response(uint32_t call_id,
bool success,
const std::string &error_message,
1761 const uint8_t *response_data,
size_t response_data_len) {
1768 this->send_message(resp, ExecuteServiceResponse::MESSAGE_TYPE);
1774#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
1776#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
1794 if (this->parent_->clear_noise_psk(
true)) {
1797 ESP_LOGW(TAG,
"Failed to clear encryption key");
1800 ESP_LOGW(TAG,
"Invalid encryption key length");
1801 }
else if (!this->parent_->save_noise_psk(psk,
true)) {
1802 ESP_LOGW(TAG,
"Failed to save encryption key");
1807 return this->send_message(resp, NoiseEncryptionSetKeyResponse::MESSAGE_TYPE);
1810#ifdef USE_API_HOMEASSISTANT_STATES
1815bool APIConnection::try_to_clear_buffer(
bool log_out_of_space) {
1816 if (this->flags_.remove)
1818 if (this->helper_->can_write_without_blocking())
1821 APIError err = this->helper_->loop();
1822 if (err != APIError::OK) {
1823 this->fatal_error_with_log_(LOG_STR(
"Socket operation failed"), err);
1826 if (this->helper_->can_write_without_blocking())
1828 if (log_out_of_space) {
1829 ESP_LOGV(TAG,
"Cannot send message because of TCP buffer space");
1834 if (!this->try_to_clear_buffer(message_type != SubscribeLogsResponse::MESSAGE_TYPE)) {
1838 APIError err = this->helper_->write_protobuf_packet(message_type, buffer);
1839 if (err == APIError::WOULD_BLOCK)
1841 if (err != APIError::OK) {
1842 this->fatal_error_with_log_(LOG_STR(
"Packet write failed"), err);
1848#ifdef USE_API_PASSWORD
1849void APIConnection::on_unauthenticated_access() {
1850 this->on_fatal_error();
1851 ESP_LOGD(TAG,
"%s (%s) no authentication", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
1854void APIConnection::on_no_setup_connection() {
1855 this->on_fatal_error();
1856 ESP_LOGD(TAG,
"%s (%s) no connection setup", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
1858void APIConnection::on_fatal_error() {
1859 this->helper_->close();
1860 this->flags_.remove =
true;
1864 uint8_t estimated_size) {
1868 for (
auto &item : items) {
1869 if (item.entity == entity && item.message_type == message_type) {
1871 item.creator = creator;
1877 items.emplace_back(entity, creator, message_type, estimated_size);
1881 uint8_t estimated_size) {
1886 items.emplace_back(entity, creator, message_type, estimated_size);
1887 if (items.size() > 1) {
1889 std::swap(items.front(), items.back());
1893bool APIConnection::schedule_batch_() {
1894 if (!this->flags_.batch_scheduled) {
1895 this->flags_.batch_scheduled =
true;
1901void APIConnection::process_batch_() {
1903 static_assert(std::is_trivially_destructible<PacketInfo>::value,
1904 "PacketInfo must remain trivially destructible with this placement-new approach");
1906 if (this->deferred_batch_.empty()) {
1907 this->flags_.batch_scheduled =
false;
1912 if (!this->try_to_clear_buffer(
true)) {
1918 auto &shared_buf = this->parent_->get_shared_buffer_ref();
1919 size_t num_items = this->deferred_batch_.size();
1922 if (num_items == 1) {
1923 const auto &item = this->deferred_batch_[0];
1927 item.creator(item.entity,
this, std::numeric_limits<uint16_t>::max(),
true, item.message_type);
1930#ifdef HAS_PROTO_MESSAGE_DUMP
1933 this->log_batch_item_(item);
1935 this->clear_batch_();
1938 ESP_LOGW(TAG,
"Message too large to send: type=%u", item.message_type);
1939 this->clear_batch_();
1944 size_t packets_to_process = std::min(num_items, MAX_PACKETS_PER_BATCH);
1949 size_t packet_count = 0;
1952 const uint8_t header_padding = this->helper_->frame_header_padding();
1953 const uint8_t footer_size = this->helper_->frame_footer_size();
1959 uint32_t total_estimated_size = num_items * (header_padding + footer_size);
1960 for (
size_t i = 0; i < this->deferred_batch_.size(); i++) {
1961 const auto &item = this->deferred_batch_[i];
1962 total_estimated_size += item.estimated_size;
1967 shared_buf.reserve(total_estimated_size);
1968 this->flags_.batch_first_message =
true;
1970 size_t items_processed = 0;
1971 uint16_t remaining_size = std::numeric_limits<uint16_t>::max();
1977 uint32_t current_offset = 0;
1980 for (
size_t i = 0; i < packets_to_process; i++) {
1981 const auto &item = this->deferred_batch_[i];
1984 uint16_t
payload_size = item.creator(item.entity,
this, remaining_size,
false, item.message_type);
1993 uint16_t proto_payload_size =
payload_size - header_padding - footer_size;
1998 new (&packet_info[packet_count++])
PacketInfo(item.message_type, current_offset, proto_payload_size);
2003 if (items_processed == 1) {
2004 remaining_size = MAX_BATCH_PACKET_SIZE;
2009 current_offset = shared_buf.size() + footer_size;
2012 if (items_processed == 0) {
2013 this->deferred_batch_.clear();
2018 if (footer_size > 0) {
2019 shared_buf.resize(shared_buf.size() + footer_size);
2024 std::span<const PacketInfo>(packet_info, packet_count));
2025 if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
2026 this->fatal_error_with_log_(LOG_STR(
"Batch write failed"), err);
2029#ifdef HAS_PROTO_MESSAGE_DUMP
2032 for (
size_t i = 0; i < items_processed; i++) {
2033 const auto &item = this->deferred_batch_[i];
2034 this->log_batch_item_(item);
2039 if (items_processed < this->deferred_batch_.size()) {
2041 this->deferred_batch_.remove_front(items_processed);
2043 this->schedule_batch_();
2046 this->clear_batch_();
2051 bool is_single, uint8_t message_type)
const {
2054 if (message_type == EventResponse::MESSAGE_TYPE) {
2056 return APIConnection::try_send_event_response(e, data_.const_char_ptr, conn, remaining_size, is_single);
2061 return data_.function_ptr(entity, conn, remaining_size, is_single);
2067 return encode_message_to_buffer(resp, ListEntitiesDoneResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
2073 return encode_message_to_buffer(req, DisconnectRequest::MESSAGE_TYPE, conn, remaining_size, is_single);
2079 return encode_message_to_buffer(req, PingRequest::MESSAGE_TYPE, conn, remaining_size, is_single);
2082#ifdef USE_API_HOMEASSISTANT_STATES
2083void APIConnection::process_state_subscriptions_() {
2084 const auto &subs = this->parent_->get_state_subs();
2085 if (this->state_subs_at_ >=
static_cast<int>(subs.size())) {
2086 this->state_subs_at_ = -1;
2090 const auto &it = subs[this->state_subs_at_];
2097 resp.
once = it.once;
2098 if (this->send_message(resp, SubscribeHomeAssistantStateResponse::MESSAGE_TYPE)) {
2099 this->state_subs_at_++;
2105 ESP_LOGW(TAG,
"%s (%s): %s %s errno=%d", this->client_info_.name.c_str(), this->client_info_.peername.c_str(),
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)
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...
StringRef is a reference to a string owned by something else.
static constexpr StringRef from_lit(const CharT(&s)[N])
struct esphome::api::APIConnection::APIFlags flags_
void prepare_first_message_buffer(std::vector< uint8_t > &shared_buf, size_t header_padding, size_t total_size)
std::unique_ptr< APIFrameHelper > helper_
APIConnection(std::unique_ptr< socket::Socket > socket, APIServer *parent)
void button_command(const ButtonCommandRequest &msg) override
void log_send_message_(const char *name, const std::string &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
uint16_t custom_fan_mode_len
float target_temperature_high
const uint8_t * custom_preset
const uint8_t * custom_fan_mode
enums::ClimateSwingMode swing_mode
uint16_t custom_preset_len
enums::ClimateFanMode fan_mode
bool has_target_temperature
enums::ClimatePreset preset
enums::ClimateFanMode fan_mode
float target_temperature_low
enums::ClimateSwingMode swing_mode
void set_custom_fan_mode(const StringRef &ref)
void set_custom_preset(const StringRef &ref)
enums::ClimateAction action
enums::ClimatePreset preset
float current_temperature
float target_temperature_high
enums::CoverOperation current_operation
void set_event_type(const StringRef &ref)
uint16_t response_data_len
const uint8_t * response_data
void set_error_message(const StringRef &ref)
const uint8_t * preset_mode
enums::FanDirection direction
enums::FanDirection direction
void set_preset_mode(const StringRef &ref)
const uint8_t * client_info
uint32_t api_version_major
uint32_t api_version_minor
uint32_t api_version_minor
void set_name(const StringRef &ref)
void set_server_info(const StringRef &ref)
uint32_t api_version_major
const uint8_t * attribute
const uint8_t * entity_id
const uint8_t * response_data
std::string error_message
uint16_t response_data_len
bool has_color_temperature
enums::ColorMode color_mode
bool has_transition_length
uint32_t transition_length
bool has_color_brightness
void set_effect(const StringRef &ref)
enums::ColorMode color_mode
bool requires_code_to_arm
uint32_t supported_features
bool is_status_binary_sensor
void set_device_class(const StringRef &ref)
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
void set_device_class(const StringRef &ref)
const FixedVector< const char * > * event_types
void set_device_class(const StringRef &ref)
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
void set_unit_of_measurement(const StringRef &ref)
void set_device_class(const StringRef &ref)
const FixedVector< const char * > * options
int32_t accuracy_decimals
void set_unit_of_measurement(const StringRef &ref)
void set_device_class(const StringRef &ref)
enums::SensorStateClass state_class
void set_device_class(const StringRef &ref)
void set_pattern(const StringRef &ref)
void set_device_class(const StringRef &ref)
void set_device_class(const StringRef &ref)
void set_device_class(const StringRef &ref)
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
uint32_t get_size() const
void set_state(const StringRef &ref)
void set_entity_id(const StringRef &ref)
void set_attribute(const StringRef &ref)
void set_message(const uint8_t *data, size_t len)
void set_state(const StringRef &ref)
void set_state(const StringRef &ref)
enums::UpdateCommand command
void set_current_version(const StringRef &ref)
void set_latest_version(const StringRef &ref)
void set_release_summary(const StringRef &ref)
void set_title(const StringRef &ref)
void set_release_url(const StringRef &ref)
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.
void set_epoch_time(uint32_t epoch)
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 format_mac_addr_upper(const uint8_t *mac, char *output)
Format MAC address as XX:XX:XX:XX:XX:XX (uppercase, colon separators)
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)
A more user-friendly version of struct tm from time.h.
uint8_t batch_first_message
const uint8_t ESPHOME_WEBSERVER_INDEX_HTML[] PROGMEM