18#ifdef USE_HOMEASSISTANT_TIME
21#ifdef USE_BLUETOOTH_PROXY
24#ifdef USE_VOICE_ASSISTANT
31static const char *
const TAG =
"api.connection";
32static const int ESP32_CAMERA_STOP_STREAM = 5000;
35 : parent_(parent), initial_state_iterator_(this), list_entities_iterator_(this) {
36#if defined(USE_API_PLAINTEXT) && defined(USE_API_NOISE)
38 if (noise_ctx->has_psk()) {
39 this->helper_ = std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), noise_ctx)};
43#elif defined(USE_API_PLAINTEXT)
44 this->helper_ = std::unique_ptr<APIFrameHelper>{
new APIPlaintextFrameHelper(std::move(sock))};
45#elif defined(USE_API_NOISE)
46 this->helper_ = std::unique_ptr<APIFrameHelper>{
new APINoiseFrameHelper(std::move(sock), parent->get_noise_ctx())};
48#error "No frame helper defined"
52uint32_t APIConnection::get_batch_delay_ms_()
const {
return this->parent_->get_batch_delay(); }
54void APIConnection::start() {
59 this->next_ping_retry_ = this->last_traffic_ + KEEPALIVE_TIMEOUT_MS;
61 APIError err = this->helper_->init();
62 if (err != APIError::OK) {
64 ESP_LOGW(TAG,
"%s: Helper init failed: %s errno=%d", this->client_combined_info_.c_str(),
api_error_to_str(err),
68 this->client_info_ = helper_->getpeername();
69 this->client_peername_ = this->client_info_;
70 this->helper_->set_log_info(this->client_info_);
73APIConnection::~APIConnection() {
74#ifdef USE_BLUETOOTH_PROXY
79#ifdef USE_VOICE_ASSISTANT
86void APIConnection::loop() {
93 this->on_fatal_error();
94 ESP_LOGW(TAG,
"%s: Network unavailable; disconnecting", this->client_combined_info_.c_str());
97 if (this->next_close_) {
99 this->helper_->close();
100 this->remove_ =
true;
104 APIError err = this->helper_->loop();
105 if (err != APIError::OK) {
107 ESP_LOGW(TAG,
"%s: Socket operation failed: %s errno=%d", this->client_combined_info_.c_str(),
113 if (this->helper_->is_socket_ready()) {
115 err = this->helper_->read_packet(&buffer);
116 if (err == APIError::WOULD_BLOCK) {
118 }
else if (err != APIError::OK) {
120 if (err == APIError::SOCKET_READ_FAILED && errno == ECONNRESET) {
121 ESP_LOGW(TAG,
"%s: Connection reset", this->client_combined_info_.c_str());
122 }
else if (err == APIError::CONNECTION_CLOSED) {
123 ESP_LOGW(TAG,
"%s: Connection closed", this->client_combined_info_.c_str());
125 ESP_LOGW(TAG,
"%s: Reading failed: %s errno=%d", this->client_combined_info_.c_str(),
api_error_to_str(err),
135 this->read_message(0, buffer.
type,
nullptr);
143 if (this->deferred_batch_.batch_scheduled &&
145 this->process_batch_();
148 if (!this->list_entities_iterator_.completed())
149 this->list_entities_iterator_.advance();
150 if (!this->initial_state_iterator_.completed() && this->list_entities_iterator_.completed())
151 this->initial_state_iterator_.advance();
153 static uint8_t max_ping_retries = 60;
154 static uint16_t ping_retry_interval = 1000;
156 if (this->sent_ping_) {
158 if (now - this->last_traffic_ > (KEEPALIVE_TIMEOUT_MS * 5) / 2) {
160 ESP_LOGW(TAG,
"%s is unresponsive; disconnecting", this->client_combined_info_.c_str());
162 }
else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && now > this->next_ping_retry_) {
163 ESP_LOGVV(TAG,
"Sending keepalive PING");
164 this->sent_ping_ = this->send_message(
PingRequest());
165 if (!this->sent_ping_) {
166 this->next_ping_retry_ = now + ping_retry_interval;
167 this->ping_retries_++;
168 std::string warn_str =
str_sprintf(
"%s: Sending keepalive failed %u time(s);",
169 this->client_combined_info_.c_str(), this->ping_retries_);
170 if (this->ping_retries_ >= max_ping_retries) {
172 ESP_LOGE(TAG,
"%s disconnecting", warn_str.c_str());
173 }
else if (this->ping_retries_ >= 10) {
174 ESP_LOGW(TAG,
"%s retrying in %u ms", warn_str.c_str(), ping_retry_interval);
176 ESP_LOGD(TAG,
"%s retrying in %u ms", warn_str.c_str(), ping_retry_interval);
181#ifdef USE_ESP32_CAMERA
182 if (this->image_reader_.available() && this->helper_->can_write_without_blocking()) {
183 uint32_t to_send = std::min((
size_t) MAX_PACKET_SIZE, this->image_reader_.available());
184 bool done = this->image_reader_.available() == to_send;
185 uint32_t msg_size = 0;
186 ProtoSize::add_fixed_field<4>(msg_size, 1,
true);
189 msg_size += 1 + ProtoSize::varint(to_send) + to_send;
190 ProtoSize::add_bool_field(msg_size, 1, done);
192 auto buffer = this->create_buffer(msg_size);
196 buffer.encode_bytes(2, this->image_reader_.peek_data_buffer(), to_send);
198 buffer.encode_bool(3, done);
200 bool success = this->send_buffer(buffer, 44);
203 this->image_reader_.consume_data(to_send);
205 if (success && done) {
206 this->image_reader_.return_image();
211 if (state_subs_at_ != -1) {
212 const auto &subs = this->parent_->get_state_subs();
213 if (state_subs_at_ >= (
int) subs.size()) {
216 auto &it = subs[state_subs_at_];
221 if (this->send_message(resp)) {
236 ESP_LOGD(TAG,
"%s disconnected", this->client_combined_info_.c_str());
237 this->next_close_ =
true;
242 this->helper_->close();
243 this->remove_ =
true;
249 uint32_t remaining_size,
bool is_single) {
251 uint32_t calculated_size = 0;
255 const uint8_t header_padding = conn->
helper_->frame_header_padding();
256 const uint8_t footer_size = conn->
helper_->frame_footer_size();
259 size_t total_calculated_size = calculated_size + header_padding + footer_size;
262 if (total_calculated_size > remaining_size) {
272 size_t size_before_encode = shared_buf.size();
278 size_t actual_payload_size = shared_buf.size() - size_before_encode;
281 size_t actual_total_size = header_padding + actual_payload_size + footer_size;
284 assert(calculated_size == actual_payload_size);
285 return static_cast<uint16_t
>(actual_total_size);
288#ifdef USE_BINARY_SENSOR
290 return this->schedule_message_(binary_sensor, &APIConnection::try_send_binary_sensor_state,
291 BinarySensorStateResponse::MESSAGE_TYPE);
294 this->schedule_message_(binary_sensor, &APIConnection::try_send_binary_sensor_info,
295 ListEntitiesBinarySensorResponse::MESSAGE_TYPE);
302 resp.
state = binary_sensor->state;
304 fill_entity_state_base(binary_sensor, resp);
305 return encode_message_to_buffer(resp, BinarySensorStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
315 fill_entity_info_base(binary_sensor, msg);
316 return encode_message_to_buffer(msg, ListEntitiesBinarySensorResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
322 return this->schedule_message_(cover, &APIConnection::try_send_cover_state, CoverStateResponse::MESSAGE_TYPE);
325 this->schedule_message_(cover, &APIConnection::try_send_cover_info, ListEntitiesCoverResponse::MESSAGE_TYPE);
331 auto traits = cover->get_traits();
333 (cover->position ==
cover::COVER_OPEN) ? enums::LEGACY_COVER_STATE_OPEN : enums::LEGACY_COVER_STATE_CLOSED;
335 if (traits.get_supports_tilt())
336 msg.
tilt = cover->tilt;
338 fill_entity_state_base(cover, msg);
339 return encode_message_to_buffer(msg, CoverStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
345 auto traits = cover->get_traits();
352 fill_entity_info_base(cover, msg);
353 return encode_message_to_buffer(msg, ListEntitiesCoverResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
357 if (cover ==
nullptr)
363 case enums::LEGACY_COVER_COMMAND_OPEN:
364 call.set_command_open();
366 case enums::LEGACY_COVER_COMMAND_CLOSE:
367 call.set_command_close();
369 case enums::LEGACY_COVER_COMMAND_STOP:
370 call.set_command_stop();
386 return this->schedule_message_(fan, &APIConnection::try_send_fan_state, FanStateResponse::MESSAGE_TYPE);
389 this->schedule_message_(fan, &APIConnection::try_send_fan_info, ListEntitiesFanResponse::MESSAGE_TYPE);
393 auto *fan =
static_cast<fan::Fan *
>(entity);
395 auto traits = fan->get_traits();
396 msg.
state = fan->state;
397 if (traits.supports_oscillation())
399 if (traits.supports_speed()) {
402 if (traits.supports_direction())
404 if (traits.supports_preset_modes())
406 fill_entity_state_base(fan, msg);
407 return encode_message_to_buffer(msg, FanStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
411 auto *fan =
static_cast<fan::Fan *
>(entity);
413 auto traits = fan->get_traits();
418 for (
auto const &
preset : traits.supported_preset_modes())
421 fill_entity_info_base(fan, msg);
422 return encode_message_to_buffer(msg, ListEntitiesFanResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
448 return this->schedule_message_(light, &APIConnection::try_send_light_state, LightStateResponse::MESSAGE_TYPE);
451 this->schedule_message_(light, &APIConnection::try_send_light_info, ListEntitiesLightResponse::MESSAGE_TYPE);
457 auto traits = light->get_traits();
458 auto values = light->remote_values;
459 auto color_mode = values.get_color_mode();
460 resp.
state = values.is_on();
464 resp.
red = values.get_red();
465 resp.
green = values.get_green();
466 resp.
blue = values.get_blue();
467 resp.
white = values.get_white();
471 if (light->supports_effects())
472 resp.
effect = light->get_effect_name();
473 fill_entity_state_base(light, resp);
474 return encode_message_to_buffer(resp, LightStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
480 auto traits = light->get_traits();
481 for (
auto mode : traits.get_supported_color_modes())
494 if (light->supports_effects()) {
495 msg.
effects.emplace_back(
"None");
496 for (
auto *effect : light->get_effects()) {
497 msg.
effects.push_back(effect->get_name());
501 fill_entity_info_base(light, msg);
502 return encode_message_to_buffer(msg, ListEntitiesLightResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
506 if (light ==
nullptr)
519 call.set_red(msg.
red);
520 call.set_green(msg.
green);
521 call.set_blue(msg.
blue);
543 return this->schedule_message_(sensor, &APIConnection::try_send_sensor_state, SensorStateResponse::MESSAGE_TYPE);
546 this->schedule_message_(sensor, &APIConnection::try_send_sensor_info, ListEntitiesSensorResponse::MESSAGE_TYPE);
553 resp.
state = sensor->state;
555 fill_entity_state_base(sensor, resp);
556 return encode_message_to_buffer(resp, SensorStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
571 fill_entity_info_base(sensor, msg);
572 return encode_message_to_buffer(msg, ListEntitiesSensorResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
578 return this->schedule_message_(a_switch, &APIConnection::try_send_switch_state, SwitchStateResponse::MESSAGE_TYPE);
581 this->schedule_message_(a_switch, &APIConnection::try_send_switch_info, ListEntitiesSwitchResponse::MESSAGE_TYPE);
588 resp.
state = a_switch->state;
589 fill_entity_state_base(a_switch, resp);
590 return encode_message_to_buffer(resp, SwitchStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
600 fill_entity_info_base(a_switch, msg);
601 return encode_message_to_buffer(msg, ListEntitiesSwitchResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
605 if (a_switch ==
nullptr)
616#ifdef USE_TEXT_SENSOR
618 return this->schedule_message_(text_sensor, &APIConnection::try_send_text_sensor_state,
619 TextSensorStateResponse::MESSAGE_TYPE);
622 this->schedule_message_(text_sensor, &APIConnection::try_send_text_sensor_info,
623 ListEntitiesTextSensorResponse::MESSAGE_TYPE);
630 resp.
state = text_sensor->state;
632 fill_entity_state_base(text_sensor, resp);
633 return encode_message_to_buffer(resp, TextSensorStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
640 msg.
unique_id = text_sensor->unique_id();
643 fill_entity_info_base(text_sensor, msg);
644 return encode_message_to_buffer(msg, ListEntitiesTextSensorResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
650 return this->schedule_message_(climate, &APIConnection::try_send_climate_state, ClimateStateResponse::MESSAGE_TYPE);
656 fill_entity_state_base(climate, resp);
657 auto traits = climate->get_traits();
660 if (traits.get_supports_current_temperature())
662 if (traits.get_supports_two_point_target_temperature()) {
668 if (traits.get_supports_fan_modes() && climate->fan_mode.has_value())
670 if (!traits.get_supported_custom_fan_modes().empty() && climate->custom_fan_mode.has_value())
672 if (traits.get_supports_presets() && climate->preset.has_value()) {
675 if (!traits.get_supported_custom_presets().empty() && climate->custom_preset.has_value())
677 if (traits.get_supports_swing_modes())
679 if (traits.get_supports_current_humidity())
681 if (traits.get_supports_target_humidity())
683 return encode_message_to_buffer(resp, ClimateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
686 this->schedule_message_(climate, &APIConnection::try_send_climate_info, ListEntitiesClimateResponse::MESSAGE_TYPE);
692 auto traits = climate->get_traits();
697 for (
auto mode : traits.get_supported_modes())
707 for (
auto fan_mode : traits.get_supported_fan_modes())
709 for (
auto const &
custom_fan_mode : traits.get_supported_custom_fan_modes())
711 for (
auto preset : traits.get_supported_presets())
713 for (
auto const &
custom_preset : traits.get_supported_custom_presets())
715 for (
auto swing_mode : traits.get_supported_swing_modes())
718 fill_entity_info_base(climate, msg);
719 return encode_message_to_buffer(msg, ListEntitiesClimateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
723 if (climate ==
nullptr)
753 return this->schedule_message_(number, &APIConnection::try_send_number_state, NumberStateResponse::MESSAGE_TYPE);
756 this->schedule_message_(number, &APIConnection::try_send_number_info, ListEntitiesNumberResponse::MESSAGE_TYPE);
763 resp.
state = number->state;
765 fill_entity_state_base(number, resp);
766 return encode_message_to_buffer(resp, NumberStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
776 msg.
min_value = number->traits.get_min_value();
777 msg.
max_value = number->traits.get_max_value();
778 msg.
step = number->traits.get_step();
780 fill_entity_info_base(number, msg);
781 return encode_message_to_buffer(msg, ListEntitiesNumberResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
785 if (number ==
nullptr)
794#ifdef USE_DATETIME_DATE
796 return this->schedule_message_(date, &APIConnection::try_send_date_state, DateStateResponse::MESSAGE_TYPE);
803 resp.
year = date->year;
804 resp.
month = date->month;
805 resp.
day = date->day;
806 fill_entity_state_base(date, resp);
807 return encode_message_to_buffer(resp, DateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
810 this->schedule_message_(date, &APIConnection::try_send_date_info, ListEntitiesDateResponse::MESSAGE_TYPE);
817 fill_entity_info_base(date, msg);
818 return encode_message_to_buffer(msg, ListEntitiesDateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
831#ifdef USE_DATETIME_TIME
833 return this->schedule_message_(time, &APIConnection::try_send_time_state, TimeStateResponse::MESSAGE_TYPE);
840 resp.
hour = time->hour;
841 resp.
minute = time->minute;
842 resp.
second = time->second;
843 fill_entity_state_base(time, resp);
844 return encode_message_to_buffer(resp, TimeStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
847 this->schedule_message_(time, &APIConnection::try_send_time_info, ListEntitiesTimeResponse::MESSAGE_TYPE);
854 fill_entity_info_base(time, msg);
855 return encode_message_to_buffer(msg, ListEntitiesTimeResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
868#ifdef USE_DATETIME_DATETIME
870 return this->schedule_message_(datetime, &APIConnection::try_send_datetime_state,
871 DateTimeStateResponse::MESSAGE_TYPE);
878 if (datetime->has_state()) {
882 fill_entity_state_base(datetime, resp);
883 return encode_message_to_buffer(resp, DateTimeStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
886 this->schedule_message_(datetime, &APIConnection::try_send_datetime_info, ListEntitiesDateTimeResponse::MESSAGE_TYPE);
893 fill_entity_info_base(datetime, msg);
894 return encode_message_to_buffer(msg, ListEntitiesDateTimeResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
898 if (datetime ==
nullptr)
909 return this->schedule_message_(text, &APIConnection::try_send_text_state, TextStateResponse::MESSAGE_TYPE);
912 this->schedule_message_(text, &APIConnection::try_send_text_info, ListEntitiesTextResponse::MESSAGE_TYPE);
917 auto *text =
static_cast<text::Text *
>(entity);
919 resp.
state = text->state;
921 fill_entity_state_base(text, resp);
922 return encode_message_to_buffer(resp, TextStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
927 auto *text =
static_cast<text::Text *
>(entity);
930 msg.
min_length = text->traits.get_min_length();
931 msg.
max_length = text->traits.get_max_length();
932 msg.
pattern = text->traits.get_pattern();
934 fill_entity_info_base(text, msg);
935 return encode_message_to_buffer(msg, ListEntitiesTextResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
950 return this->schedule_message_(select, &APIConnection::try_send_select_state, SelectStateResponse::MESSAGE_TYPE);
953 this->schedule_message_(select, &APIConnection::try_send_select_info, ListEntitiesSelectResponse::MESSAGE_TYPE);
960 resp.
state = select->state;
962 fill_entity_state_base(select, resp);
963 return encode_message_to_buffer(resp, SelectStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
970 for (
const auto &option : select->traits.get_options())
973 fill_entity_info_base(select, msg);
974 return encode_message_to_buffer(msg, ListEntitiesSelectResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
978 if (select ==
nullptr)
989 this->schedule_message_(button, &APIConnection::try_send_button_info, ListEntitiesButtonResponse::MESSAGE_TYPE);
997 fill_entity_info_base(button, msg);
998 return encode_message_to_buffer(msg, ListEntitiesButtonResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1002 if (button ==
nullptr)
1011 return this->schedule_message_(a_lock, &APIConnection::try_send_lock_state, LockStateResponse::MESSAGE_TYPE);
1014 this->schedule_message_(a_lock, &APIConnection::try_send_lock_info, ListEntitiesLockResponse::MESSAGE_TYPE);
1019 auto *a_lock =
static_cast<lock::Lock *
>(entity);
1022 fill_entity_state_base(a_lock, resp);
1023 return encode_message_to_buffer(resp, LockStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1028 auto *a_lock =
static_cast<lock::Lock *
>(entity);
1034 fill_entity_info_base(a_lock, msg);
1035 return encode_message_to_buffer(msg, ListEntitiesLockResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1039 if (a_lock ==
nullptr)
1043 case enums::LOCK_UNLOCK:
1046 case enums::LOCK_LOCK:
1049 case enums::LOCK_OPEN:
1058 return this->schedule_message_(valve, &APIConnection::try_send_valve_state, ValveStateResponse::MESSAGE_TYPE);
1066 fill_entity_state_base(valve, resp);
1067 return encode_message_to_buffer(resp, ValveStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1070 this->schedule_message_(valve, &APIConnection::try_send_valve_info, ListEntitiesValveResponse::MESSAGE_TYPE);
1076 auto traits = valve->get_traits();
1082 fill_entity_info_base(valve, msg);
1083 return encode_message_to_buffer(msg, ListEntitiesValveResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1087 if (valve ==
nullptr)
1099#ifdef USE_MEDIA_PLAYER
1101 return this->schedule_message_(media_player, &APIConnection::try_send_media_player_state,
1102 MediaPlayerStateResponse::MESSAGE_TYPE);
1110 : media_player->state;
1112 resp.
volume = media_player->volume;
1113 resp.
muted = media_player->is_muted();
1114 fill_entity_state_base(media_player, resp);
1115 return encode_message_to_buffer(resp, MediaPlayerStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1118 this->schedule_message_(media_player, &APIConnection::try_send_media_player_info,
1119 ListEntitiesMediaPlayerResponse::MESSAGE_TYPE);
1125 auto traits = media_player->get_traits();
1127 for (
auto &supported_format : traits.get_supported_formats()) {
1129 media_format.
format = supported_format.format;
1130 media_format.
sample_rate = supported_format.sample_rate;
1131 media_format.
num_channels = supported_format.num_channels;
1133 media_format.
sample_bytes = supported_format.sample_bytes;
1137 fill_entity_info_base(media_player, msg);
1138 return encode_message_to_buffer(msg, ListEntitiesMediaPlayerResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1142 if (media_player ==
nullptr)
1150 call.set_volume(msg.
volume);
1162#ifdef USE_ESP32_CAMERA
1163void APIConnection::set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) {
1164 if (!this->state_subscription_)
1166 if (this->image_reader_.available())
1170 this->image_reader_.set_image(std::move(image));
1173 this->schedule_message_(camera, &APIConnection::try_send_camera_info, ListEntitiesCameraResponse::MESSAGE_TYPE);
1180 fill_entity_info_base(camera, msg);
1181 return encode_message_to_buffer(msg, ListEntitiesCameraResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1199#ifdef USE_HOMEASSISTANT_TIME
1206#ifdef USE_BLUETOOTH_PROXY
1214 if (this->client_api_version_major_ < 1 || this->client_api_version_minor_ < 7) {
1217 service.legacy_data.assign(service.data.begin(), service.data.end());
1218 service.data.clear();
1221 manufacturer_data.legacy_data.assign(manufacturer_data.data.begin(), manufacturer_data.data.end());
1222 manufacturer_data.data.clear();
1224 return this->send_message(resp);
1226 return this->send_message(msg);
1261 msg.
mode == enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE);
1265#ifdef USE_VOICE_ASSISTANT
1281 if (msg.
port == 0) {
1287 this->helper_->getpeername((
struct sockaddr *) &storage, &
len);
1339 for (
auto &wake_word : config.available_wake_words) {
1341 resp_wake_word.
id = wake_word.id;
1342 resp_wake_word.
wake_word = wake_word.wake_word;
1343 for (
const auto &lang : wake_word.trained_languages) {
1348 for (
auto &wake_word_id : config.active_wake_words) {
1368#ifdef USE_ALARM_CONTROL_PANEL
1370 return this->schedule_message_(a_alarm_control_panel, &APIConnection::try_send_alarm_control_panel_state,
1371 AlarmControlPanelStateResponse::MESSAGE_TYPE);
1374 uint32_t remaining_size,
bool is_single) {
1378 fill_entity_state_base(a_alarm_control_panel, resp);
1379 return encode_message_to_buffer(resp, AlarmControlPanelStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1382 this->schedule_message_(a_alarm_control_panel, &APIConnection::try_send_alarm_control_panel_info,
1383 ListEntitiesAlarmControlPanelResponse::MESSAGE_TYPE);
1386 uint32_t remaining_size,
bool is_single) {
1390 msg.
requires_code = a_alarm_control_panel->get_requires_code();
1393 fill_entity_info_base(a_alarm_control_panel, msg);
1394 return encode_message_to_buffer(msg, ListEntitiesAlarmControlPanelResponse::MESSAGE_TYPE, conn, remaining_size,
1399 if (a_alarm_control_panel ==
nullptr)
1402 auto call = a_alarm_control_panel->
make_call();
1404 case enums::ALARM_CONTROL_PANEL_DISARM:
1407 case enums::ALARM_CONTROL_PANEL_ARM_AWAY:
1410 case enums::ALARM_CONTROL_PANEL_ARM_HOME:
1413 case enums::ALARM_CONTROL_PANEL_ARM_NIGHT:
1416 case enums::ALARM_CONTROL_PANEL_ARM_VACATION:
1417 call.arm_vacation();
1419 case enums::ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS:
1420 call.arm_custom_bypass();
1422 case enums::ALARM_CONTROL_PANEL_TRIGGER:
1432void APIConnection::send_event(
event::Event *event,
const std::string &event_type) {
1433 this->schedule_message_(event,
MessageCreator(event_type, EventResponse::MESSAGE_TYPE), EventResponse::MESSAGE_TYPE);
1436 this->schedule_message_(event, &APIConnection::try_send_event_info, ListEntitiesEventResponse::MESSAGE_TYPE);
1439 uint32_t remaining_size,
bool is_single) {
1442 fill_entity_state_base(event, resp);
1443 return encode_message_to_buffer(resp, EventResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1451 for (
const auto &event_type : event->get_event_types())
1454 fill_entity_info_base(event, msg);
1455 return encode_message_to_buffer(msg, ListEntitiesEventResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1461 return this->schedule_message_(update, &APIConnection::try_send_update_state, UpdateStateResponse::MESSAGE_TYPE);
1468 if (update->has_state()) {
1470 if (update->update_info.has_progress) {
1472 resp.
progress = update->update_info.progress;
1476 resp.
title = update->update_info.title;
1478 resp.
release_url = update->update_info.release_url;
1480 fill_entity_state_base(update, resp);
1481 return encode_message_to_buffer(resp, UpdateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1484 this->schedule_message_(update, &APIConnection::try_send_update_info, ListEntitiesUpdateResponse::MESSAGE_TYPE);
1492 fill_entity_info_base(update, msg);
1493 return encode_message_to_buffer(msg, ListEntitiesUpdateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1497 if (update ==
nullptr)
1501 case enums::UPDATE_COMMAND_UPDATE:
1504 case enums::UPDATE_COMMAND_CHECK:
1507 case enums::UPDATE_COMMAND_NONE:
1508 ESP_LOGE(TAG,
"UPDATE_COMMAND_NONE not handled; confirm command is correct");
1511 ESP_LOGW(TAG,
"Unknown update command: %" PRIu32, msg.
command);
1517bool APIConnection::try_send_log_message(
int level,
const char *tag,
const char *line) {
1518 if (this->log_subscription_ < level)
1522 const size_t line_length = strlen(line);
1523 uint32_t msg_size = 0;
1534 auto buffer = this->create_buffer(msg_size);
1537 buffer.encode_uint32(1,
static_cast<uint32_t
>(level));
1538 buffer.encode_string(3, line, line_length);
1541 return this->send_buffer(buffer, SubscribeLogsResponse::MESSAGE_TYPE);
1546 this->client_peername_ = this->helper_->getpeername();
1547 this->client_combined_info_ = this->client_info_ +
" (" + this->client_peername_ +
")";
1548 this->helper_->set_log_info(this->client_combined_info_);
1551 ESP_LOGV(TAG,
"Hello from client: '%s' | %s | API Version %" PRIu32
".%" PRIu32, this->client_info_.c_str(),
1552 this->client_peername_.c_str(), this->client_api_version_major_, this->client_api_version_minor_);
1560 this->connection_state_ = ConnectionState::CONNECTED;
1564 bool correct = this->parent_->check_password(msg.
password);
1570 ESP_LOGD(TAG,
"%s connected", this->client_combined_info_.c_str());
1571 this->connection_state_ = ConnectionState::AUTHENTICATED;
1572 this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->client_peername_);
1573#ifdef USE_HOMEASSISTANT_TIME
1575 this->send_time_request();
1588 resp.esphome_version = ESPHOME_VERSION;
1590#if defined(USE_ESP8266) || defined(USE_ESP32)
1591 resp.manufacturer =
"Espressif";
1592#elif defined(USE_RP2040)
1593 resp.manufacturer =
"Raspberry Pi";
1594#elif defined(USE_BK72XX)
1595 resp.manufacturer =
"Beken";
1596#elif defined(USE_RTL87XX)
1597 resp.manufacturer =
"Realtek";
1598#elif defined(USE_HOST)
1599 resp.manufacturer =
"Host";
1601 resp.model = ESPHOME_BOARD;
1602#ifdef USE_DEEP_SLEEP
1605#ifdef ESPHOME_PROJECT_NAME
1606 resp.project_name = ESPHOME_PROJECT_NAME;
1607 resp.project_version = ESPHOME_PROJECT_VERSION;
1610 resp.webserver_port = USE_WEBSERVER_PORT;
1612#ifdef USE_BLUETOOTH_PROXY
1617#ifdef USE_VOICE_ASSISTANT
1622 resp.api_encryption_supported =
true;
1627 for (
auto &it : this->parent_->get_state_subs()) {
1629 it.callback(msg.
state);
1635 for (
auto *service : this->parent_->get_user_services()) {
1636 if (service->execute_service(msg)) {
1641 ESP_LOGV(TAG,
"Could not find service");
1649 ESP_LOGW(TAG,
"Invalid encryption key length");
1654 if (!this->parent_->save_noise_psk(psk,
true)) {
1655 ESP_LOGW(TAG,
"Failed to save encryption key");
1667bool APIConnection::try_to_clear_buffer(
bool log_out_of_space) {
1670 if (this->helper_->can_write_without_blocking())
1673 APIError err = this->helper_->loop();
1674 if (err != APIError::OK) {
1676 ESP_LOGW(TAG,
"%s: Socket operation failed: %s errno=%d", this->client_combined_info_.c_str(),
1680 if (this->helper_->can_write_without_blocking())
1682 if (log_out_of_space) {
1683 ESP_LOGV(TAG,
"Cannot send message because of TCP buffer space");
1688 if (!this->try_to_clear_buffer(message_type != SubscribeLogsResponse::MESSAGE_TYPE)) {
1692 APIError err = this->helper_->write_protobuf_packet(message_type, buffer);
1693 if (err == APIError::WOULD_BLOCK)
1695 if (err != APIError::OK) {
1697 if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) {
1698 ESP_LOGW(TAG,
"%s: Connection reset", this->client_combined_info_.c_str());
1700 ESP_LOGW(TAG,
"%s: Packet write failed %s errno=%d", this->client_combined_info_.c_str(),
api_error_to_str(err),
1708void APIConnection::on_unauthenticated_access() {
1709 this->on_fatal_error();
1710 ESP_LOGD(TAG,
"%s requested access without authentication", this->client_combined_info_.c_str());
1712void APIConnection::on_no_setup_connection() {
1713 this->on_fatal_error();
1714 ESP_LOGD(TAG,
"%s requested access without full connection", this->client_combined_info_.c_str());
1716void APIConnection::on_fatal_error() {
1717 this->helper_->close();
1718 this->remove_ =
true;
1725 for (
auto &item : items) {
1726 if (item.entity == entity && item.message_type == message_type) {
1728 item.creator = std::move(creator);
1734 items.emplace_back(entity, std::move(creator), message_type);
1737bool APIConnection::schedule_batch_() {
1738 if (!this->deferred_batch_.batch_scheduled) {
1739 this->deferred_batch_.batch_scheduled =
true;
1745ProtoWriteBuffer APIConnection::allocate_single_message_buffer(uint16_t size) {
return this->create_buffer(size); }
1748 ProtoWriteBuffer result = this->prepare_message_buffer(size, this->batch_first_message_);
1749 this->batch_first_message_ =
false;
1753void APIConnection::process_batch_() {
1754 if (this->deferred_batch_.empty()) {
1755 this->deferred_batch_.batch_scheduled =
false;
1760 if (!this->try_to_clear_buffer(
true)) {
1765 size_t num_items = this->deferred_batch_.items.size();
1768 if (num_items == 1) {
1769 const auto &item = this->deferred_batch_.items[0];
1772 uint16_t
payload_size = item.creator(item.entity,
this, std::numeric_limits<uint16_t>::max(),
true);
1775 this->send_buffer(
ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, item.message_type)) {
1776 this->deferred_batch_.clear();
1779 ESP_LOGW(TAG,
"Message too large to send: type=%u", item.message_type);
1780 this->deferred_batch_.clear();
1786 std::vector<PacketInfo> packet_info;
1787 packet_info.reserve(num_items);
1790 const uint8_t header_padding = this->helper_->frame_header_padding();
1791 const uint8_t footer_size = this->helper_->frame_footer_size();
1794 this->parent_->get_shared_buffer_ref().clear();
1797 uint32_t total_estimated_size = 0;
1798 for (
const auto &item : this->deferred_batch_.items) {
1799 total_estimated_size += get_estimated_message_size(item.message_type);
1803 uint32_t total_overhead = (header_padding + footer_size) * num_items;
1806 this->parent_->get_shared_buffer_ref().reserve(total_estimated_size + total_overhead);
1807 this->batch_first_message_ =
true;
1809 size_t items_processed = 0;
1810 uint16_t remaining_size = std::numeric_limits<uint16_t>::max();
1816 uint32_t current_offset = 0;
1819 for (
const auto &item : this->deferred_batch_.items) {
1822 uint16_t
payload_size = item.creator(item.entity,
this, remaining_size,
false);
1831 uint16_t proto_payload_size =
payload_size - header_padding - footer_size;
1832 packet_info.emplace_back(item.message_type, current_offset, proto_payload_size);
1837 if (items_processed == 1) {
1838 remaining_size = MAX_PACKET_SIZE;
1843 current_offset = this->parent_->get_shared_buffer_ref().size() + footer_size;
1846 if (items_processed == 0) {
1847 this->deferred_batch_.clear();
1852 if (footer_size > 0) {
1853 auto &shared_buf = this->parent_->get_shared_buffer_ref();
1854 shared_buf.resize(shared_buf.size() + footer_size);
1859 this->helper_->write_protobuf_packets(
ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, packet_info);
1860 if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
1862 if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) {
1863 ESP_LOGW(TAG,
"%s: Connection reset during batch write", this->client_combined_info_.c_str());
1865 ESP_LOGW(TAG,
"%s: Batch write failed %s errno=%d", this->client_combined_info_.c_str(),
api_error_to_str(err),
1871 if (items_processed < this->deferred_batch_.items.size()) {
1873 this->deferred_batch_.items.erase(this->deferred_batch_.items.begin(),
1874 this->deferred_batch_.items.begin() + items_processed);
1877 this->schedule_batch_();
1880 this->deferred_batch_.clear();
1885 bool is_single)
const {
1886 switch (message_type_) {
1888 return data_.ptr(entity, conn, remaining_size, is_single);
1891 case EventResponse::MESSAGE_TYPE: {
1893 return APIConnection::try_send_event_response(e, *data_.string_ptr, conn, remaining_size, is_single);
1906 return encode_message_to_buffer(resp, ListEntitiesDoneResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
1912 return encode_message_to_buffer(req, DisconnectRequest::MESSAGE_TYPE, conn, remaining_size, is_single);
1915uint16_t APIConnection::get_estimated_message_size(uint16_t message_type) {
1917 switch (message_type) {
1918#ifdef USE_BINARY_SENSOR
1919 case BinarySensorStateResponse::MESSAGE_TYPE:
1920 return BinarySensorStateResponse::ESTIMATED_SIZE;
1921 case ListEntitiesBinarySensorResponse::MESSAGE_TYPE:
1922 return ListEntitiesBinarySensorResponse::ESTIMATED_SIZE;
1925 case SensorStateResponse::MESSAGE_TYPE:
1926 return SensorStateResponse::ESTIMATED_SIZE;
1927 case ListEntitiesSensorResponse::MESSAGE_TYPE:
1928 return ListEntitiesSensorResponse::ESTIMATED_SIZE;
1931 case SwitchStateResponse::MESSAGE_TYPE:
1932 return SwitchStateResponse::ESTIMATED_SIZE;
1933 case ListEntitiesSwitchResponse::MESSAGE_TYPE:
1934 return ListEntitiesSwitchResponse::ESTIMATED_SIZE;
1936#ifdef USE_TEXT_SENSOR
1937 case TextSensorStateResponse::MESSAGE_TYPE:
1938 return TextSensorStateResponse::ESTIMATED_SIZE;
1939 case ListEntitiesTextSensorResponse::MESSAGE_TYPE:
1940 return ListEntitiesTextSensorResponse::ESTIMATED_SIZE;
1943 case NumberStateResponse::MESSAGE_TYPE:
1944 return NumberStateResponse::ESTIMATED_SIZE;
1945 case ListEntitiesNumberResponse::MESSAGE_TYPE:
1946 return ListEntitiesNumberResponse::ESTIMATED_SIZE;
1949 case TextStateResponse::MESSAGE_TYPE:
1950 return TextStateResponse::ESTIMATED_SIZE;
1951 case ListEntitiesTextResponse::MESSAGE_TYPE:
1952 return ListEntitiesTextResponse::ESTIMATED_SIZE;
1955 case SelectStateResponse::MESSAGE_TYPE:
1956 return SelectStateResponse::ESTIMATED_SIZE;
1957 case ListEntitiesSelectResponse::MESSAGE_TYPE:
1958 return ListEntitiesSelectResponse::ESTIMATED_SIZE;
1961 case LockStateResponse::MESSAGE_TYPE:
1962 return LockStateResponse::ESTIMATED_SIZE;
1963 case ListEntitiesLockResponse::MESSAGE_TYPE:
1964 return ListEntitiesLockResponse::ESTIMATED_SIZE;
1967 case EventResponse::MESSAGE_TYPE:
1968 return EventResponse::ESTIMATED_SIZE;
1969 case ListEntitiesEventResponse::MESSAGE_TYPE:
1970 return ListEntitiesEventResponse::ESTIMATED_SIZE;
1973 case CoverStateResponse::MESSAGE_TYPE:
1974 return CoverStateResponse::ESTIMATED_SIZE;
1975 case ListEntitiesCoverResponse::MESSAGE_TYPE:
1976 return ListEntitiesCoverResponse::ESTIMATED_SIZE;
1979 case FanStateResponse::MESSAGE_TYPE:
1980 return FanStateResponse::ESTIMATED_SIZE;
1981 case ListEntitiesFanResponse::MESSAGE_TYPE:
1982 return ListEntitiesFanResponse::ESTIMATED_SIZE;
1985 case LightStateResponse::MESSAGE_TYPE:
1986 return LightStateResponse::ESTIMATED_SIZE;
1987 case ListEntitiesLightResponse::MESSAGE_TYPE:
1988 return ListEntitiesLightResponse::ESTIMATED_SIZE;
1991 case ClimateStateResponse::MESSAGE_TYPE:
1992 return ClimateStateResponse::ESTIMATED_SIZE;
1993 case ListEntitiesClimateResponse::MESSAGE_TYPE:
1994 return ListEntitiesClimateResponse::ESTIMATED_SIZE;
1996#ifdef USE_ESP32_CAMERA
1997 case ListEntitiesCameraResponse::MESSAGE_TYPE:
1998 return ListEntitiesCameraResponse::ESTIMATED_SIZE;
2001 case ListEntitiesButtonResponse::MESSAGE_TYPE:
2002 return ListEntitiesButtonResponse::ESTIMATED_SIZE;
2004#ifdef USE_MEDIA_PLAYER
2005 case MediaPlayerStateResponse::MESSAGE_TYPE:
2006 return MediaPlayerStateResponse::ESTIMATED_SIZE;
2007 case ListEntitiesMediaPlayerResponse::MESSAGE_TYPE:
2008 return ListEntitiesMediaPlayerResponse::ESTIMATED_SIZE;
2010#ifdef USE_ALARM_CONTROL_PANEL
2011 case AlarmControlPanelStateResponse::MESSAGE_TYPE:
2012 return AlarmControlPanelStateResponse::ESTIMATED_SIZE;
2013 case ListEntitiesAlarmControlPanelResponse::MESSAGE_TYPE:
2014 return ListEntitiesAlarmControlPanelResponse::ESTIMATED_SIZE;
2016#ifdef USE_DATETIME_DATE
2017 case DateStateResponse::MESSAGE_TYPE:
2018 return DateStateResponse::ESTIMATED_SIZE;
2019 case ListEntitiesDateResponse::MESSAGE_TYPE:
2020 return ListEntitiesDateResponse::ESTIMATED_SIZE;
2022#ifdef USE_DATETIME_TIME
2023 case TimeStateResponse::MESSAGE_TYPE:
2024 return TimeStateResponse::ESTIMATED_SIZE;
2025 case ListEntitiesTimeResponse::MESSAGE_TYPE:
2026 return ListEntitiesTimeResponse::ESTIMATED_SIZE;
2028#ifdef USE_DATETIME_DATETIME
2029 case DateTimeStateResponse::MESSAGE_TYPE:
2030 return DateTimeStateResponse::ESTIMATED_SIZE;
2031 case ListEntitiesDateTimeResponse::MESSAGE_TYPE:
2032 return ListEntitiesDateTimeResponse::ESTIMATED_SIZE;
2035 case ValveStateResponse::MESSAGE_TYPE:
2036 return ValveStateResponse::ESTIMATED_SIZE;
2037 case ListEntitiesValveResponse::MESSAGE_TYPE:
2038 return ListEntitiesValveResponse::ESTIMATED_SIZE;
2041 case UpdateStateResponse::MESSAGE_TYPE:
2042 return UpdateStateResponse::ESTIMATED_SIZE;
2043 case ListEntitiesUpdateResponse::MESSAGE_TYPE:
2044 return ListEntitiesUpdateResponse::ESTIMATED_SIZE;
2046 case ListEntitiesServicesResponse::MESSAGE_TYPE:
2047 return ListEntitiesServicesResponse::ESTIMATED_SIZE;
2048 case ListEntitiesDoneResponse::MESSAGE_TYPE:
2049 return ListEntitiesDoneResponse::ESTIMATED_SIZE;
2050 case DisconnectRequest::MESSAGE_TYPE:
2051 return DisconnectRequest::ESTIMATED_SIZE;
BedjetMode mode
BedJet operating mode.
datetime::DateEntity * get_date_by_key(uint32_t key, bool include_internal=false)
alarm_control_panel::AlarmControlPanel * get_alarm_control_panel_by_key(uint32_t key, bool include_internal=false)
const std::string & get_friendly_name() const
Get the friendly name of this Application set by pre_setup().
text::Text * get_text_by_key(uint32_t key, bool include_internal=false)
button::Button * get_button_by_key(uint32_t key, bool include_internal=false)
std::string get_area() const
Get the area of this Application set by pre_setup().
fan::Fan * get_fan_by_key(uint32_t key, bool include_internal=false)
std::string get_compilation_time() const
light::LightState * get_light_by_key(uint32_t key, bool include_internal=false)
media_player::MediaPlayer * get_media_player_by_key(uint32_t key, bool include_internal=false)
climate::Climate * get_climate_by_key(uint32_t key, bool include_internal=false)
const std::string & get_name() const
Get the name of this Application set by pre_setup().
lock::Lock * get_lock_by_key(uint32_t key, bool include_internal=false)
switch_::Switch * get_switch_by_key(uint32_t key, bool include_internal=false)
number::Number * get_number_by_key(uint32_t key, bool include_internal=false)
datetime::TimeEntity * get_time_by_key(uint32_t key, bool include_internal=false)
update::UpdateEntity * get_update_by_key(uint32_t key, bool include_internal=false)
datetime::DateTimeEntity * get_datetime_by_key(uint32_t key, bool include_internal=false)
valve::Valve * get_valve_by_key(uint32_t key, bool include_internal=false)
select::Select * get_select_by_key(uint32_t key, bool include_internal=false)
cover::Cover * get_cover_by_key(uint32_t key, bool include_internal=false)
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
std::string get_object_id() const
void set_timeout(Component *component, const std::string &name, uint32_t timeout, std::function< void()> func)
AlarmControlPanelCall & set_code(const std::string &code)
AlarmControlPanelCall make_call()
Make a AlarmControlPanelCall.
std::unique_ptr< APIFrameHelper > helper_
ProtoWriteBuffer allocate_batch_message_buffer(uint16_t size)
APIConnection(std::unique_ptr< socket::Socket > socket, APIServer *parent)
ProtoWriteBuffer allocate_single_message_buffer(uint16_t size)
void send_button_info(button::Button *button)
void button_command(const ButtonCommandRequest &msg) override
std::shared_ptr< APINoiseContext > get_noise_ctx()
std::vector< uint8_t > & get_shared_buffer_ref()
enums::AlarmControlPanelStateCommand command
enums::AlarmControlPanelState state
std::vector< BluetoothServiceData > service_data
std::vector< BluetoothServiceData > manufacturer_data
enums::BluetoothScannerMode mode
bool has_target_temperature_high
float target_temperature_low
bool has_target_temperature_low
float target_temperature_high
enums::ClimateSwingMode swing_mode
enums::ClimateFanMode fan_mode
bool has_target_temperature
std::string custom_fan_mode
enums::ClimatePreset preset
std::string custom_preset
enums::ClimateFanMode fan_mode
float target_temperature_low
enums::ClimateSwingMode swing_mode
std::string custom_fan_mode
enums::ClimateAction action
enums::ClimatePreset preset
std::string custom_preset
float current_temperature
float target_temperature_high
enums::LegacyCoverCommand legacy_command
enums::LegacyCoverState legacy_state
enums::CoverOperation current_operation
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
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
std::vector< enums::ClimatePreset > supported_presets
std::vector< enums::ClimateSwingMode > supported_swing_modes
float visual_max_humidity
std::vector< enums::ClimateFanMode > supported_fan_modes
bool supports_current_temperature
bool supports_current_humidity
std::vector< enums::ClimateMode > supported_modes
bool supports_target_humidity
float visual_min_humidity
float visual_max_temperature
float visual_target_temperature_step
bool supports_two_point_target_temperature
float visual_min_temperature
float visual_current_temperature_step
bool legacy_supports_away
std::vector< std::string > supported_custom_presets
std::vector< std::string > supported_custom_fan_modes
std::vector< std::string > event_types
std::vector< std::string > supported_preset_modes
int32_t supported_speed_count
bool supports_oscillation
bool legacy_supports_color_temperature
bool legacy_supports_white_value
bool legacy_supports_brightness
std::vector< std::string > effects
std::vector< enums::ColorMode > supported_color_modes
std::string unit_of_measurement
std::vector< std::string > options
int32_t accuracy_decimals
std::string unit_of_measurement
enums::SensorStateClass state_class
enums::LockCommand command
virtual void calculate_size(uint32_t &total_size) const =0
virtual void encode(ProtoWriteBuffer buffer) const =0
static uint32_t varint(uint32_t value)
ProtoSize class for Protocol Buffer serialization size calculation.
enums::UpdateCommand command
std::string latest_version
std::string current_version
std::string release_summary
enums::ValveOperation current_operation
std::vector< VoiceAssistantWakeWord > available_wake_words
uint32_t max_active_wake_words
std::vector< std::string > active_wake_words
std::vector< std::string > active_wake_words
std::vector< std::string > trained_languages
Base class for all binary_sensor-type classes.
void bluetooth_gatt_read(const api::BluetoothGATTReadRequest &msg)
int get_bluetooth_connections_limit()
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_legacy_version() const
uint32_t get_feature_flags() const
void unsubscribe_api_connection(api::APIConnection *api_connection)
int get_bluetooth_connections_free()
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)
std::string get_bluetooth_mac_address_pretty()
ClimateCall & set_target_temperature(float target_temperature)
Set the target temperature of the climate device.
ClimateCall & set_swing_mode(ClimateSwingMode swing_mode)
Set the swing mode of the climate device.
ClimateCall & set_target_temperature_low(float target_temperature_low)
Set the low point target temperature of the climate device.
ClimateCall & set_preset(ClimatePreset preset)
Set the preset of the climate device.
ClimateCall & set_fan_mode(ClimateFanMode fan_mode)
Set the fan mode of the climate device.
ClimateCall & set_target_humidity(float target_humidity)
Set the target humidity of the climate device.
ClimateCall & set_target_temperature_high(float target_temperature_high)
Set the high point target temperature of the climate device.
ClimateCall & set_mode(ClimateMode mode)
Set the mode of the climate device.
ClimateDevice - This is the base class for all climate integrations.
ClimateCall make_call()
Make a climate device control call, this is used to control the climate device, see the ClimateCall d...
void perform()
Perform the cover call.
CoverCall & set_position(float position)
Set the call to a certain target position.
CoverCall & set_command_stop()
Set the command to stop the cover.
CoverCall & set_tilt(float tilt)
Set the call to a certain target tilt.
Base class for all cover devices.
CoverCall make_call()
Construct a new cover call used to control the cover.
DateCall & set_date(uint16_t year, uint8_t month, uint8_t day)
DateTimeCall & set_datetime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second)
TimeCall & set_time(uint8_t hour, uint8_t minute, uint8_t second)
void request_image(CameraRequester requester)
void stop_stream(CameraRequester requester)
void start_stream(CameraRequester requester)
FanCall & set_oscillating(bool oscillating)
FanCall & set_direction(FanDirection direction)
FanCall & set_state(bool binary_state)
FanCall & set_preset_mode(const std::string &preset_mode)
void set_epoch_time(uint32_t epoch)
LightCall & set_color_temperature(optional< float > color_temperature)
Set the color temperature of the light in mireds for CWWW or RGBWW lights.
LightCall & set_color_brightness(optional< float > brightness)
Set the color brightness of the light from 0.0 (no color) to 1.0 (fully on)
LightCall & set_effect(optional< std::string > effect)
Set the effect of the light by its name.
LightCall & set_white(optional< float > white)
Set the white value value of the light from 0.0 to 1.0 for RGBW[W] lights.
LightCall & set_warm_white(optional< float > warm_white)
Set the warm white value of the light from 0.0 to 1.0.
LightCall & set_flash_length(optional< uint32_t > flash_length)
Start and set the flash length of this call in milliseconds.
LightCall & set_cold_white(optional< float > cold_white)
Set the cold white value of the light from 0.0 to 1.0.
LightCall & set_brightness(optional< float > brightness)
Set the target brightness of the light from 0.0 (fully off) to 1.0 (fully on)
LightCall & set_state(optional< bool > state)
Set the binary ON/OFF state of the light.
LightCall & set_color_mode(optional< ColorMode > color_mode)
Set the color mode of the light.
LightCall & set_transition_length(optional< uint32_t > transition_length)
Set the transition length of this call in milliseconds.
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
Base class for all locks.
void lock()
Turn this lock on.
void unlock()
Turn this lock off.
void open()
Open (unlatch) this lock.
NumberCall & set_value(float value)
Base-class for all numbers.
SelectCall & set_option(const std::string &option)
Base-class for all selects.
SelectCall make_call()
Instantiate a SelectCall object to modify this select component's state.
Base-class for all sensors.
Base class for all switches.
void turn_on()
Turn this switch on.
void turn_off()
Turn this switch off.
TextCall & set_value(const std::string &value)
Base-class for all text inputs.
TextCall make_call()
Instantiate a TextCall object to modify this text component's state.
ValveCall & set_position(float position)
Set the call to a certain target position.
ValveCall & set_command_stop()
Set the command to stop the valve.
void perform()
Perform the valve call.
Base class for all valve devices.
ValveCall make_call()
Construct a new valve call used to control the valve.
const Configuration & get_configuration()
uint32_t get_legacy_version() const
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)
uint32_t get_feature_flags() const
void on_set_configuration(const std::vector< std::string > &active_wake_words)
ClimateSwingMode swing_mode
std::string get_default_unique_id(const std::string &component_type, EntityBase *entity)
std::array< uint8_t, 32 > psk_t
const char * api_error_to_str(APIError err)
BluetoothProxy * global_bluetooth_proxy
ClimatePreset
Enum for all preset modes.
@ CLIMATE_PRESET_AWAY
Device is in away preset.
ClimateSwingMode
Enum for all modes a climate swing can be in.
ClimateMode
Enum for all modes a climate device can be in.
bool global_has_deep_sleep
ESP32Camera * global_esp32_camera
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.
@ BRIGHTNESS
Master brightness of the light can be controlled.
@ RGB
Color can be controlled using RGB format (includes a brightness control for the color).
@ COLOR_TEMPERATURE
Color temperature can be controlled.
@ WHITE
Brightness of white channel can be controlled separately from other channels.
@ COLD_WARM_WHITE
Brightness of cold and warm white output can be controlled.
bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
@ UPDATE_STATE_INSTALLING
VoiceAssistant * global_voice_assistant
Providing packet encoding functions for exchanging data with a remote host.
std::string get_mac_address_pretty()
Get the device MAC address as a string, in colon-separated uppercase hex notation.
std::string str_sprintf(const char *fmt,...)
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.
std::vector< uint8_t > container