mirror of
https://github.com/esphome/esphome.git
synced 2025-08-07 10:57:46 +00:00
Merge branch 'device_id_state' into integration
This commit is contained in:
commit
96352f047d
@ -124,6 +124,7 @@ esphome/components/dht/* @OttoWinter
|
|||||||
esphome/components/display_menu_base/* @numo68
|
esphome/components/display_menu_base/* @numo68
|
||||||
esphome/components/dps310/* @kbx81
|
esphome/components/dps310/* @kbx81
|
||||||
esphome/components/ds1307/* @badbadc0ffee
|
esphome/components/ds1307/* @badbadc0ffee
|
||||||
|
esphome/components/ds2484/* @mrk-its
|
||||||
esphome/components/dsmr/* @glmnet @zuidwijk
|
esphome/components/dsmr/* @glmnet @zuidwijk
|
||||||
esphome/components/duty_time/* @dudanov
|
esphome/components/duty_time/* @dudanov
|
||||||
esphome/components/ee895/* @Stock-M
|
esphome/components/ee895/* @Stock-M
|
||||||
|
@ -311,6 +311,7 @@ message BinarySensorStateResponse {
|
|||||||
// If the binary sensor does not have a valid state yet.
|
// If the binary sensor does not have a valid state yet.
|
||||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||||
bool missing_state = 3;
|
bool missing_state = 3;
|
||||||
|
uint32 device_id = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== COVER ====================
|
// ==================== COVER ====================
|
||||||
@ -360,6 +361,7 @@ message CoverStateResponse {
|
|||||||
float position = 3;
|
float position = 3;
|
||||||
float tilt = 4;
|
float tilt = 4;
|
||||||
CoverOperation current_operation = 5;
|
CoverOperation current_operation = 5;
|
||||||
|
uint32 device_id = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum LegacyCoverCommand {
|
enum LegacyCoverCommand {
|
||||||
@ -432,6 +434,7 @@ message FanStateResponse {
|
|||||||
FanDirection direction = 5;
|
FanDirection direction = 5;
|
||||||
int32 speed_level = 6;
|
int32 speed_level = 6;
|
||||||
string preset_mode = 7;
|
string preset_mode = 7;
|
||||||
|
uint32 device_id = 8;
|
||||||
}
|
}
|
||||||
message FanCommandRequest {
|
message FanCommandRequest {
|
||||||
option (id) = 31;
|
option (id) = 31;
|
||||||
@ -513,6 +516,7 @@ message LightStateResponse {
|
|||||||
float cold_white = 12;
|
float cold_white = 12;
|
||||||
float warm_white = 13;
|
float warm_white = 13;
|
||||||
string effect = 9;
|
string effect = 9;
|
||||||
|
uint32 device_id = 14;
|
||||||
}
|
}
|
||||||
message LightCommandRequest {
|
message LightCommandRequest {
|
||||||
option (id) = 32;
|
option (id) = 32;
|
||||||
@ -598,6 +602,7 @@ message SensorStateResponse {
|
|||||||
// If the sensor does not have a valid state yet.
|
// If the sensor does not have a valid state yet.
|
||||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||||
bool missing_state = 3;
|
bool missing_state = 3;
|
||||||
|
uint32 device_id = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== SWITCH ====================
|
// ==================== SWITCH ====================
|
||||||
@ -628,6 +633,7 @@ message SwitchStateResponse {
|
|||||||
|
|
||||||
fixed32 key = 1;
|
fixed32 key = 1;
|
||||||
bool state = 2;
|
bool state = 2;
|
||||||
|
uint32 device_id = 3;
|
||||||
}
|
}
|
||||||
message SwitchCommandRequest {
|
message SwitchCommandRequest {
|
||||||
option (id) = 33;
|
option (id) = 33;
|
||||||
@ -669,6 +675,7 @@ message TextSensorStateResponse {
|
|||||||
// If the text sensor does not have a valid state yet.
|
// If the text sensor does not have a valid state yet.
|
||||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||||
bool missing_state = 3;
|
bool missing_state = 3;
|
||||||
|
uint32 device_id = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== SUBSCRIBE LOGS ====================
|
// ==================== SUBSCRIBE LOGS ====================
|
||||||
@ -966,6 +973,7 @@ message ClimateStateResponse {
|
|||||||
string custom_preset = 13;
|
string custom_preset = 13;
|
||||||
float current_humidity = 14;
|
float current_humidity = 14;
|
||||||
float target_humidity = 15;
|
float target_humidity = 15;
|
||||||
|
uint32 device_id = 16;
|
||||||
}
|
}
|
||||||
message ClimateCommandRequest {
|
message ClimateCommandRequest {
|
||||||
option (id) = 48;
|
option (id) = 48;
|
||||||
@ -1039,6 +1047,7 @@ message NumberStateResponse {
|
|||||||
// If the number does not have a valid state yet.
|
// If the number does not have a valid state yet.
|
||||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||||
bool missing_state = 3;
|
bool missing_state = 3;
|
||||||
|
uint32 device_id = 4;
|
||||||
}
|
}
|
||||||
message NumberCommandRequest {
|
message NumberCommandRequest {
|
||||||
option (id) = 51;
|
option (id) = 51;
|
||||||
@ -1080,6 +1089,7 @@ message SelectStateResponse {
|
|||||||
// If the select does not have a valid state yet.
|
// If the select does not have a valid state yet.
|
||||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||||
bool missing_state = 3;
|
bool missing_state = 3;
|
||||||
|
uint32 device_id = 4;
|
||||||
}
|
}
|
||||||
message SelectCommandRequest {
|
message SelectCommandRequest {
|
||||||
option (id) = 54;
|
option (id) = 54;
|
||||||
@ -1120,6 +1130,7 @@ message SirenStateResponse {
|
|||||||
|
|
||||||
fixed32 key = 1;
|
fixed32 key = 1;
|
||||||
bool state = 2;
|
bool state = 2;
|
||||||
|
uint32 device_id = 3;
|
||||||
}
|
}
|
||||||
message SirenCommandRequest {
|
message SirenCommandRequest {
|
||||||
option (id) = 57;
|
option (id) = 57;
|
||||||
@ -1183,6 +1194,7 @@ message LockStateResponse {
|
|||||||
option (no_delay) = true;
|
option (no_delay) = true;
|
||||||
fixed32 key = 1;
|
fixed32 key = 1;
|
||||||
LockState state = 2;
|
LockState state = 2;
|
||||||
|
uint32 device_id = 3;
|
||||||
}
|
}
|
||||||
message LockCommandRequest {
|
message LockCommandRequest {
|
||||||
option (id) = 60;
|
option (id) = 60;
|
||||||
@ -1282,6 +1294,7 @@ message MediaPlayerStateResponse {
|
|||||||
MediaPlayerState state = 2;
|
MediaPlayerState state = 2;
|
||||||
float volume = 3;
|
float volume = 3;
|
||||||
bool muted = 4;
|
bool muted = 4;
|
||||||
|
uint32 device_id = 5;
|
||||||
}
|
}
|
||||||
message MediaPlayerCommandRequest {
|
message MediaPlayerCommandRequest {
|
||||||
option (id) = 65;
|
option (id) = 65;
|
||||||
@ -1822,6 +1835,7 @@ message AlarmControlPanelStateResponse {
|
|||||||
option (no_delay) = true;
|
option (no_delay) = true;
|
||||||
fixed32 key = 1;
|
fixed32 key = 1;
|
||||||
AlarmControlPanelState state = 2;
|
AlarmControlPanelState state = 2;
|
||||||
|
uint32 device_id = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AlarmControlPanelCommandRequest {
|
message AlarmControlPanelCommandRequest {
|
||||||
@ -1871,6 +1885,7 @@ message TextStateResponse {
|
|||||||
// If the Text does not have a valid state yet.
|
// If the Text does not have a valid state yet.
|
||||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||||
bool missing_state = 3;
|
bool missing_state = 3;
|
||||||
|
uint32 device_id = 4;
|
||||||
}
|
}
|
||||||
message TextCommandRequest {
|
message TextCommandRequest {
|
||||||
option (id) = 99;
|
option (id) = 99;
|
||||||
@ -1914,6 +1929,7 @@ message DateStateResponse {
|
|||||||
uint32 year = 3;
|
uint32 year = 3;
|
||||||
uint32 month = 4;
|
uint32 month = 4;
|
||||||
uint32 day = 5;
|
uint32 day = 5;
|
||||||
|
uint32 device_id = 6;
|
||||||
}
|
}
|
||||||
message DateCommandRequest {
|
message DateCommandRequest {
|
||||||
option (id) = 102;
|
option (id) = 102;
|
||||||
@ -1958,6 +1974,7 @@ message TimeStateResponse {
|
|||||||
uint32 hour = 3;
|
uint32 hour = 3;
|
||||||
uint32 minute = 4;
|
uint32 minute = 4;
|
||||||
uint32 second = 5;
|
uint32 second = 5;
|
||||||
|
uint32 device_id = 6;
|
||||||
}
|
}
|
||||||
message TimeCommandRequest {
|
message TimeCommandRequest {
|
||||||
option (id) = 105;
|
option (id) = 105;
|
||||||
@ -1999,6 +2016,7 @@ message EventResponse {
|
|||||||
|
|
||||||
fixed32 key = 1;
|
fixed32 key = 1;
|
||||||
string event_type = 2;
|
string event_type = 2;
|
||||||
|
uint32 device_id = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== VALVE ====================
|
// ==================== VALVE ====================
|
||||||
@ -2039,6 +2057,7 @@ message ValveStateResponse {
|
|||||||
fixed32 key = 1;
|
fixed32 key = 1;
|
||||||
float position = 2;
|
float position = 2;
|
||||||
ValveOperation current_operation = 3;
|
ValveOperation current_operation = 3;
|
||||||
|
uint32 device_id = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ValveCommandRequest {
|
message ValveCommandRequest {
|
||||||
@ -2082,6 +2101,7 @@ message DateTimeStateResponse {
|
|||||||
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
|
||||||
bool missing_state = 2;
|
bool missing_state = 2;
|
||||||
fixed32 epoch_seconds = 3;
|
fixed32 epoch_seconds = 3;
|
||||||
|
uint32 device_id = 4;
|
||||||
}
|
}
|
||||||
message DateTimeCommandRequest {
|
message DateTimeCommandRequest {
|
||||||
option (id) = 114;
|
option (id) = 114;
|
||||||
@ -2128,6 +2148,7 @@ message UpdateStateResponse {
|
|||||||
string title = 8;
|
string title = 8;
|
||||||
string release_summary = 9;
|
string release_summary = 9;
|
||||||
string release_url = 10;
|
string release_url = 10;
|
||||||
|
uint32 device_id = 11;
|
||||||
}
|
}
|
||||||
enum UpdateCommand {
|
enum UpdateCommand {
|
||||||
UPDATE_COMMAND_NONE = 0;
|
UPDATE_COMMAND_NONE = 0;
|
||||||
|
@ -90,19 +90,6 @@ APIConnection::~APIConnection() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
|
||||||
void APIConnection::log_batch_item_(const DeferredBatch::BatchItem &item) {
|
|
||||||
// Set log-only mode
|
|
||||||
this->flags_.log_only_mode = true;
|
|
||||||
|
|
||||||
// Call the creator - it will create the message and log it via encode_message_to_buffer
|
|
||||||
item.creator(item.entity, this, std::numeric_limits<uint16_t>::max(), true, item.message_type);
|
|
||||||
|
|
||||||
// Clear log-only mode
|
|
||||||
this->flags_.log_only_mode = false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void APIConnection::loop() {
|
void APIConnection::loop() {
|
||||||
if (this->flags_.next_close) {
|
if (this->flags_.next_close) {
|
||||||
// requested a disconnect
|
// requested a disconnect
|
||||||
@ -154,15 +141,25 @@ void APIConnection::loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process deferred batch if scheduled
|
// Process deferred batch if scheduled and timer has expired
|
||||||
if (this->flags_.batch_scheduled && now - this->deferred_batch_.batch_start_time >= this->get_batch_delay_ms_()) {
|
if (this->flags_.batch_scheduled && now - this->deferred_batch_.batch_start_time >= this->get_batch_delay_ms_()) {
|
||||||
this->process_batch_();
|
this->process_batch_();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->list_entities_iterator_.completed()) {
|
if (!this->list_entities_iterator_.completed()) {
|
||||||
this->list_entities_iterator_.advance();
|
this->process_iterator_batch_(this->list_entities_iterator_);
|
||||||
} else if (!this->initial_state_iterator_.completed()) {
|
} else if (!this->initial_state_iterator_.completed()) {
|
||||||
this->initial_state_iterator_.advance();
|
this->process_iterator_batch_(this->initial_state_iterator_);
|
||||||
|
|
||||||
|
// If we've completed initial states, process any remaining and clear the flag
|
||||||
|
if (this->initial_state_iterator_.completed()) {
|
||||||
|
// Process any remaining batched messages immediately
|
||||||
|
if (!this->deferred_batch_.empty()) {
|
||||||
|
this->process_batch_();
|
||||||
|
}
|
||||||
|
// Now that everything is sent, enable immediate sending for future state changes
|
||||||
|
this->flags_.should_try_send_immediately = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->flags_.sent_ping) {
|
if (this->flags_.sent_ping) {
|
||||||
@ -300,8 +297,8 @@ uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint16_t mes
|
|||||||
|
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
bool APIConnection::send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor) {
|
bool APIConnection::send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor) {
|
||||||
return this->schedule_message_(binary_sensor, &APIConnection::try_send_binary_sensor_state,
|
return this->send_message_smart_(binary_sensor, &APIConnection::try_send_binary_sensor_state,
|
||||||
BinarySensorStateResponse::MESSAGE_TYPE);
|
BinarySensorStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t APIConnection::try_send_binary_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_binary_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
@ -328,7 +325,7 @@ uint16_t APIConnection::try_send_binary_sensor_info(EntityBase *entity, APIConne
|
|||||||
|
|
||||||
#ifdef USE_COVER
|
#ifdef USE_COVER
|
||||||
bool APIConnection::send_cover_state(cover::Cover *cover) {
|
bool APIConnection::send_cover_state(cover::Cover *cover) {
|
||||||
return this->schedule_message_(cover, &APIConnection::try_send_cover_state, CoverStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(cover, &APIConnection::try_send_cover_state, CoverStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
uint16_t APIConnection::try_send_cover_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_cover_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
bool is_single) {
|
bool is_single) {
|
||||||
@ -389,7 +386,7 @@ void APIConnection::cover_command(const CoverCommandRequest &msg) {
|
|||||||
|
|
||||||
#ifdef USE_FAN
|
#ifdef USE_FAN
|
||||||
bool APIConnection::send_fan_state(fan::Fan *fan) {
|
bool APIConnection::send_fan_state(fan::Fan *fan) {
|
||||||
return this->schedule_message_(fan, &APIConnection::try_send_fan_state, FanStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(fan, &APIConnection::try_send_fan_state, FanStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
uint16_t APIConnection::try_send_fan_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_fan_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
bool is_single) {
|
bool is_single) {
|
||||||
@ -448,7 +445,7 @@ void APIConnection::fan_command(const FanCommandRequest &msg) {
|
|||||||
|
|
||||||
#ifdef USE_LIGHT
|
#ifdef USE_LIGHT
|
||||||
bool APIConnection::send_light_state(light::LightState *light) {
|
bool APIConnection::send_light_state(light::LightState *light) {
|
||||||
return this->schedule_message_(light, &APIConnection::try_send_light_state, LightStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(light, &APIConnection::try_send_light_state, LightStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
uint16_t APIConnection::try_send_light_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_light_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
bool is_single) {
|
bool is_single) {
|
||||||
@ -540,7 +537,7 @@ void APIConnection::light_command(const LightCommandRequest &msg) {
|
|||||||
|
|
||||||
#ifdef USE_SENSOR
|
#ifdef USE_SENSOR
|
||||||
bool APIConnection::send_sensor_state(sensor::Sensor *sensor) {
|
bool APIConnection::send_sensor_state(sensor::Sensor *sensor) {
|
||||||
return this->schedule_message_(sensor, &APIConnection::try_send_sensor_state, SensorStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(sensor, &APIConnection::try_send_sensor_state, SensorStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t APIConnection::try_send_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
@ -572,7 +569,7 @@ uint16_t APIConnection::try_send_sensor_info(EntityBase *entity, APIConnection *
|
|||||||
|
|
||||||
#ifdef USE_SWITCH
|
#ifdef USE_SWITCH
|
||||||
bool APIConnection::send_switch_state(switch_::Switch *a_switch) {
|
bool APIConnection::send_switch_state(switch_::Switch *a_switch) {
|
||||||
return this->schedule_message_(a_switch, &APIConnection::try_send_switch_state, SwitchStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(a_switch, &APIConnection::try_send_switch_state, SwitchStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t APIConnection::try_send_switch_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_switch_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
@ -609,8 +606,8 @@ void APIConnection::switch_command(const SwitchCommandRequest &msg) {
|
|||||||
|
|
||||||
#ifdef USE_TEXT_SENSOR
|
#ifdef USE_TEXT_SENSOR
|
||||||
bool APIConnection::send_text_sensor_state(text_sensor::TextSensor *text_sensor) {
|
bool APIConnection::send_text_sensor_state(text_sensor::TextSensor *text_sensor) {
|
||||||
return this->schedule_message_(text_sensor, &APIConnection::try_send_text_sensor_state,
|
return this->send_message_smart_(text_sensor, &APIConnection::try_send_text_sensor_state,
|
||||||
TextSensorStateResponse::MESSAGE_TYPE);
|
TextSensorStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t APIConnection::try_send_text_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_text_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
@ -637,7 +634,7 @@ uint16_t APIConnection::try_send_text_sensor_info(EntityBase *entity, APIConnect
|
|||||||
|
|
||||||
#ifdef USE_CLIMATE
|
#ifdef USE_CLIMATE
|
||||||
bool APIConnection::send_climate_state(climate::Climate *climate) {
|
bool APIConnection::send_climate_state(climate::Climate *climate) {
|
||||||
return this->schedule_message_(climate, &APIConnection::try_send_climate_state, ClimateStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(climate, &APIConnection::try_send_climate_state, ClimateStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
uint16_t APIConnection::try_send_climate_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_climate_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
bool is_single) {
|
bool is_single) {
|
||||||
@ -737,7 +734,7 @@ void APIConnection::climate_command(const ClimateCommandRequest &msg) {
|
|||||||
|
|
||||||
#ifdef USE_NUMBER
|
#ifdef USE_NUMBER
|
||||||
bool APIConnection::send_number_state(number::Number *number) {
|
bool APIConnection::send_number_state(number::Number *number) {
|
||||||
return this->schedule_message_(number, &APIConnection::try_send_number_state, NumberStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(number, &APIConnection::try_send_number_state, NumberStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t APIConnection::try_send_number_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_number_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
@ -777,7 +774,7 @@ void APIConnection::number_command(const NumberCommandRequest &msg) {
|
|||||||
|
|
||||||
#ifdef USE_DATETIME_DATE
|
#ifdef USE_DATETIME_DATE
|
||||||
bool APIConnection::send_date_state(datetime::DateEntity *date) {
|
bool APIConnection::send_date_state(datetime::DateEntity *date) {
|
||||||
return this->schedule_message_(date, &APIConnection::try_send_date_state, DateStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(date, &APIConnection::try_send_date_state, DateStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
uint16_t APIConnection::try_send_date_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_date_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
bool is_single) {
|
bool is_single) {
|
||||||
@ -811,7 +808,7 @@ void APIConnection::date_command(const DateCommandRequest &msg) {
|
|||||||
|
|
||||||
#ifdef USE_DATETIME_TIME
|
#ifdef USE_DATETIME_TIME
|
||||||
bool APIConnection::send_time_state(datetime::TimeEntity *time) {
|
bool APIConnection::send_time_state(datetime::TimeEntity *time) {
|
||||||
return this->schedule_message_(time, &APIConnection::try_send_time_state, TimeStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(time, &APIConnection::try_send_time_state, TimeStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
uint16_t APIConnection::try_send_time_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_time_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
bool is_single) {
|
bool is_single) {
|
||||||
@ -845,8 +842,8 @@ void APIConnection::time_command(const TimeCommandRequest &msg) {
|
|||||||
|
|
||||||
#ifdef USE_DATETIME_DATETIME
|
#ifdef USE_DATETIME_DATETIME
|
||||||
bool APIConnection::send_datetime_state(datetime::DateTimeEntity *datetime) {
|
bool APIConnection::send_datetime_state(datetime::DateTimeEntity *datetime) {
|
||||||
return this->schedule_message_(datetime, &APIConnection::try_send_datetime_state,
|
return this->send_message_smart_(datetime, &APIConnection::try_send_datetime_state,
|
||||||
DateTimeStateResponse::MESSAGE_TYPE);
|
DateTimeStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
uint16_t APIConnection::try_send_datetime_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_datetime_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
bool is_single) {
|
bool is_single) {
|
||||||
@ -881,7 +878,7 @@ void APIConnection::datetime_command(const DateTimeCommandRequest &msg) {
|
|||||||
|
|
||||||
#ifdef USE_TEXT
|
#ifdef USE_TEXT
|
||||||
bool APIConnection::send_text_state(text::Text *text) {
|
bool APIConnection::send_text_state(text::Text *text) {
|
||||||
return this->schedule_message_(text, &APIConnection::try_send_text_state, TextStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(text, &APIConnection::try_send_text_state, TextStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t APIConnection::try_send_text_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_text_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
@ -919,7 +916,7 @@ void APIConnection::text_command(const TextCommandRequest &msg) {
|
|||||||
|
|
||||||
#ifdef USE_SELECT
|
#ifdef USE_SELECT
|
||||||
bool APIConnection::send_select_state(select::Select *select) {
|
bool APIConnection::send_select_state(select::Select *select) {
|
||||||
return this->schedule_message_(select, &APIConnection::try_send_select_state, SelectStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(select, &APIConnection::try_send_select_state, SelectStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t APIConnection::try_send_select_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_select_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
@ -974,7 +971,7 @@ void esphome::api::APIConnection::button_command(const ButtonCommandRequest &msg
|
|||||||
|
|
||||||
#ifdef USE_LOCK
|
#ifdef USE_LOCK
|
||||||
bool APIConnection::send_lock_state(lock::Lock *a_lock) {
|
bool APIConnection::send_lock_state(lock::Lock *a_lock) {
|
||||||
return this->schedule_message_(a_lock, &APIConnection::try_send_lock_state, LockStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(a_lock, &APIConnection::try_send_lock_state, LockStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t APIConnection::try_send_lock_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_lock_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
@ -1018,7 +1015,7 @@ void APIConnection::lock_command(const LockCommandRequest &msg) {
|
|||||||
|
|
||||||
#ifdef USE_VALVE
|
#ifdef USE_VALVE
|
||||||
bool APIConnection::send_valve_state(valve::Valve *valve) {
|
bool APIConnection::send_valve_state(valve::Valve *valve) {
|
||||||
return this->schedule_message_(valve, &APIConnection::try_send_valve_state, ValveStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(valve, &APIConnection::try_send_valve_state, ValveStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
uint16_t APIConnection::try_send_valve_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_valve_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
bool is_single) {
|
bool is_single) {
|
||||||
@ -1058,8 +1055,8 @@ void APIConnection::valve_command(const ValveCommandRequest &msg) {
|
|||||||
|
|
||||||
#ifdef USE_MEDIA_PLAYER
|
#ifdef USE_MEDIA_PLAYER
|
||||||
bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_player) {
|
bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_player) {
|
||||||
return this->schedule_message_(media_player, &APIConnection::try_send_media_player_state,
|
return this->send_message_smart_(media_player, &APIConnection::try_send_media_player_state,
|
||||||
MediaPlayerStateResponse::MESSAGE_TYPE);
|
MediaPlayerStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
uint16_t APIConnection::try_send_media_player_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_media_player_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
bool is_single) {
|
bool is_single) {
|
||||||
@ -1320,8 +1317,8 @@ void APIConnection::voice_assistant_set_configuration(const VoiceAssistantSetCon
|
|||||||
|
|
||||||
#ifdef USE_ALARM_CONTROL_PANEL
|
#ifdef USE_ALARM_CONTROL_PANEL
|
||||||
bool APIConnection::send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
|
bool APIConnection::send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
|
||||||
return this->schedule_message_(a_alarm_control_panel, &APIConnection::try_send_alarm_control_panel_state,
|
return this->send_message_smart_(a_alarm_control_panel, &APIConnection::try_send_alarm_control_panel_state,
|
||||||
AlarmControlPanelStateResponse::MESSAGE_TYPE);
|
AlarmControlPanelStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
uint16_t APIConnection::try_send_alarm_control_panel_state(EntityBase *entity, APIConnection *conn,
|
uint16_t APIConnection::try_send_alarm_control_panel_state(EntityBase *entity, APIConnection *conn,
|
||||||
uint32_t remaining_size, bool is_single) {
|
uint32_t remaining_size, bool is_single) {
|
||||||
@ -1404,7 +1401,7 @@ uint16_t APIConnection::try_send_event_info(EntityBase *entity, APIConnection *c
|
|||||||
|
|
||||||
#ifdef USE_UPDATE
|
#ifdef USE_UPDATE
|
||||||
bool APIConnection::send_update_state(update::UpdateEntity *update) {
|
bool APIConnection::send_update_state(update::UpdateEntity *update) {
|
||||||
return this->schedule_message_(update, &APIConnection::try_send_update_state, UpdateStateResponse::MESSAGE_TYPE);
|
return this->send_message_smart_(update, &APIConnection::try_send_update_state, UpdateStateResponse::MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
uint16_t APIConnection::try_send_update_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::try_send_update_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
bool is_single) {
|
bool is_single) {
|
||||||
@ -1751,11 +1748,16 @@ void APIConnection::process_batch_() {
|
|||||||
|
|
||||||
if (payload_size > 0 &&
|
if (payload_size > 0 &&
|
||||||
this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, item.message_type)) {
|
this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, item.message_type)) {
|
||||||
this->deferred_batch_.clear();
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
// Log messages after send attempt for VV debugging
|
||||||
|
// It's safe to use the buffer for logging at this point regardless of send result
|
||||||
|
this->log_batch_item_(item);
|
||||||
|
#endif
|
||||||
|
this->clear_batch_();
|
||||||
} else if (payload_size == 0) {
|
} else if (payload_size == 0) {
|
||||||
// Message too large
|
// Message too large
|
||||||
ESP_LOGW(TAG, "Message too large to send: type=%u", item.message_type);
|
ESP_LOGW(TAG, "Message too large to send: type=%u", item.message_type);
|
||||||
this->deferred_batch_.clear();
|
this->clear_batch_();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1864,7 +1866,7 @@ void APIConnection::process_batch_() {
|
|||||||
this->schedule_batch_();
|
this->schedule_batch_();
|
||||||
} else {
|
} else {
|
||||||
// All items processed
|
// All items processed
|
||||||
this->deferred_batch_.clear();
|
this->clear_batch_();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ namespace api {
|
|||||||
|
|
||||||
// Keepalive timeout in milliseconds
|
// Keepalive timeout in milliseconds
|
||||||
static constexpr uint32_t KEEPALIVE_TIMEOUT_MS = 60000;
|
static constexpr uint32_t KEEPALIVE_TIMEOUT_MS = 60000;
|
||||||
|
// Maximum number of entities to process in a single batch during initial state/info sending
|
||||||
|
static constexpr size_t MAX_INITIAL_PER_BATCH = 20;
|
||||||
|
|
||||||
class APIConnection : public APIServerConnection {
|
class APIConnection : public APIServerConnection {
|
||||||
public:
|
public:
|
||||||
@ -290,12 +292,29 @@ class APIConnection : public APIServerConnection {
|
|||||||
// Helper function to fill common entity state fields
|
// Helper function to fill common entity state fields
|
||||||
static void fill_entity_state_base(esphome::EntityBase *entity, StateResponseProtoMessage &response) {
|
static void fill_entity_state_base(esphome::EntityBase *entity, StateResponseProtoMessage &response) {
|
||||||
response.key = entity->get_object_id_hash();
|
response.key = entity->get_object_id_hash();
|
||||||
|
#ifdef USE_DEVICES
|
||||||
|
response.device_id = entity->get_device_id();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-template helper to encode any ProtoMessage
|
// Non-template helper to encode any ProtoMessage
|
||||||
static uint16_t encode_message_to_buffer(ProtoMessage &msg, uint16_t message_type, APIConnection *conn,
|
static uint16_t encode_message_to_buffer(ProtoMessage &msg, uint16_t message_type, APIConnection *conn,
|
||||||
uint32_t remaining_size, bool is_single);
|
uint32_t remaining_size, bool is_single);
|
||||||
|
|
||||||
|
// Helper method to process multiple entities from an iterator in a batch
|
||||||
|
template<typename Iterator> void process_iterator_batch_(Iterator &iterator) {
|
||||||
|
size_t initial_size = this->deferred_batch_.size();
|
||||||
|
while (!iterator.completed() && (this->deferred_batch_.size() - initial_size) < MAX_INITIAL_PER_BATCH) {
|
||||||
|
iterator.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the batch is full, process it immediately
|
||||||
|
// Note: iterator.advance() already calls schedule_batch_() via schedule_message_()
|
||||||
|
if (this->deferred_batch_.size() >= MAX_INITIAL_PER_BATCH) {
|
||||||
|
this->process_batch_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
static uint16_t try_send_binary_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
static uint16_t try_send_binary_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
bool is_single);
|
bool is_single);
|
||||||
@ -582,7 +601,8 @@ class APIConnection : public APIServerConnection {
|
|||||||
uint8_t service_call_subscription : 1;
|
uint8_t service_call_subscription : 1;
|
||||||
uint8_t next_close : 1;
|
uint8_t next_close : 1;
|
||||||
uint8_t batch_scheduled : 1;
|
uint8_t batch_scheduled : 1;
|
||||||
uint8_t batch_first_message : 1; // For batch buffer allocation
|
uint8_t batch_first_message : 1; // For batch buffer allocation
|
||||||
|
uint8_t should_try_send_immediately : 1; // True after initial states are sent
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
uint8_t log_only_mode : 1;
|
uint8_t log_only_mode : 1;
|
||||||
#endif
|
#endif
|
||||||
@ -609,11 +629,50 @@ class APIConnection : public APIServerConnection {
|
|||||||
|
|
||||||
bool schedule_batch_();
|
bool schedule_batch_();
|
||||||
void process_batch_();
|
void process_batch_();
|
||||||
|
void clear_batch_() {
|
||||||
|
this->deferred_batch_.clear();
|
||||||
|
this->flags_.batch_scheduled = false;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
void log_batch_item_(const DeferredBatch::BatchItem &item);
|
// Helper to log a proto message from a MessageCreator object
|
||||||
|
void log_proto_message_(EntityBase *entity, const MessageCreator &creator, uint16_t message_type) {
|
||||||
|
this->flags_.log_only_mode = true;
|
||||||
|
creator(entity, this, MAX_PACKET_SIZE, true, message_type);
|
||||||
|
this->flags_.log_only_mode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_batch_item_(const DeferredBatch::BatchItem &item) {
|
||||||
|
// Use the helper to log the message
|
||||||
|
this->log_proto_message_(item.entity, item.creator, item.message_type);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Helper method to send a message either immediately or via batching
|
||||||
|
bool send_message_smart_(EntityBase *entity, MessageCreatorPtr creator, uint16_t message_type) {
|
||||||
|
// Try to send immediately if:
|
||||||
|
// 1. We should try to send immediately (should_try_send_immediately = true)
|
||||||
|
// 2. Batch delay is 0 (user has opted in to immediate sending)
|
||||||
|
// 3. Buffer has space available
|
||||||
|
if (this->flags_.should_try_send_immediately && this->get_batch_delay_ms_() == 0 &&
|
||||||
|
this->helper_->can_write_without_blocking()) {
|
||||||
|
// Now actually encode and send
|
||||||
|
if (creator(entity, this, MAX_PACKET_SIZE, true) &&
|
||||||
|
this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, message_type)) {
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
// Log the message in verbose mode
|
||||||
|
this->log_proto_message_(entity, MessageCreator(creator), message_type);
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If immediate send failed, fall through to batching
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to scheduled batching
|
||||||
|
return this->schedule_message_(entity, creator, message_type);
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to schedule a deferred message with known message type
|
// Helper function to schedule a deferred message with known message type
|
||||||
bool schedule_message_(EntityBase *entity, MessageCreator creator, uint16_t message_type) {
|
bool schedule_message_(EntityBase *entity, MessageCreator creator, uint16_t message_type) {
|
||||||
this->deferred_batch_.add_item(entity, std::move(creator), message_type);
|
this->deferred_batch_.add_item(entity, std::move(creator), message_type);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,8 @@
|
|||||||
// See script/api_protobuf/api_protobuf.py
|
// See script/api_protobuf/api_protobuf.py
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/defines.h"
|
||||||
|
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "api_pb2_size.h"
|
#include "api_pb2_size.h"
|
||||||
|
|
||||||
@ -15,6 +17,7 @@ enum EntityCategory : uint32_t {
|
|||||||
ENTITY_CATEGORY_CONFIG = 1,
|
ENTITY_CATEGORY_CONFIG = 1,
|
||||||
ENTITY_CATEGORY_DIAGNOSTIC = 2,
|
ENTITY_CATEGORY_DIAGNOSTIC = 2,
|
||||||
};
|
};
|
||||||
|
#ifdef USE_COVER
|
||||||
enum LegacyCoverState : uint32_t {
|
enum LegacyCoverState : uint32_t {
|
||||||
LEGACY_COVER_STATE_OPEN = 0,
|
LEGACY_COVER_STATE_OPEN = 0,
|
||||||
LEGACY_COVER_STATE_CLOSED = 1,
|
LEGACY_COVER_STATE_CLOSED = 1,
|
||||||
@ -29,6 +32,8 @@ enum LegacyCoverCommand : uint32_t {
|
|||||||
LEGACY_COVER_COMMAND_CLOSE = 1,
|
LEGACY_COVER_COMMAND_CLOSE = 1,
|
||||||
LEGACY_COVER_COMMAND_STOP = 2,
|
LEGACY_COVER_COMMAND_STOP = 2,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_FAN
|
||||||
enum FanSpeed : uint32_t {
|
enum FanSpeed : uint32_t {
|
||||||
FAN_SPEED_LOW = 0,
|
FAN_SPEED_LOW = 0,
|
||||||
FAN_SPEED_MEDIUM = 1,
|
FAN_SPEED_MEDIUM = 1,
|
||||||
@ -38,6 +43,8 @@ enum FanDirection : uint32_t {
|
|||||||
FAN_DIRECTION_FORWARD = 0,
|
FAN_DIRECTION_FORWARD = 0,
|
||||||
FAN_DIRECTION_REVERSE = 1,
|
FAN_DIRECTION_REVERSE = 1,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_LIGHT
|
||||||
enum ColorMode : uint32_t {
|
enum ColorMode : uint32_t {
|
||||||
COLOR_MODE_UNKNOWN = 0,
|
COLOR_MODE_UNKNOWN = 0,
|
||||||
COLOR_MODE_ON_OFF = 1,
|
COLOR_MODE_ON_OFF = 1,
|
||||||
@ -51,6 +58,8 @@ enum ColorMode : uint32_t {
|
|||||||
COLOR_MODE_RGB_COLOR_TEMPERATURE = 47,
|
COLOR_MODE_RGB_COLOR_TEMPERATURE = 47,
|
||||||
COLOR_MODE_RGB_COLD_WARM_WHITE = 51,
|
COLOR_MODE_RGB_COLD_WARM_WHITE = 51,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SENSOR
|
||||||
enum SensorStateClass : uint32_t {
|
enum SensorStateClass : uint32_t {
|
||||||
STATE_CLASS_NONE = 0,
|
STATE_CLASS_NONE = 0,
|
||||||
STATE_CLASS_MEASUREMENT = 1,
|
STATE_CLASS_MEASUREMENT = 1,
|
||||||
@ -62,6 +71,7 @@ enum SensorLastResetType : uint32_t {
|
|||||||
LAST_RESET_NEVER = 1,
|
LAST_RESET_NEVER = 1,
|
||||||
LAST_RESET_AUTO = 2,
|
LAST_RESET_AUTO = 2,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
enum LogLevel : uint32_t {
|
enum LogLevel : uint32_t {
|
||||||
LOG_LEVEL_NONE = 0,
|
LOG_LEVEL_NONE = 0,
|
||||||
LOG_LEVEL_ERROR = 1,
|
LOG_LEVEL_ERROR = 1,
|
||||||
@ -82,6 +92,7 @@ enum ServiceArgType : uint32_t {
|
|||||||
SERVICE_ARG_TYPE_FLOAT_ARRAY = 6,
|
SERVICE_ARG_TYPE_FLOAT_ARRAY = 6,
|
||||||
SERVICE_ARG_TYPE_STRING_ARRAY = 7,
|
SERVICE_ARG_TYPE_STRING_ARRAY = 7,
|
||||||
};
|
};
|
||||||
|
#ifdef USE_CLIMATE
|
||||||
enum ClimateMode : uint32_t {
|
enum ClimateMode : uint32_t {
|
||||||
CLIMATE_MODE_OFF = 0,
|
CLIMATE_MODE_OFF = 0,
|
||||||
CLIMATE_MODE_HEAT_COOL = 1,
|
CLIMATE_MODE_HEAT_COOL = 1,
|
||||||
@ -127,11 +138,15 @@ enum ClimatePreset : uint32_t {
|
|||||||
CLIMATE_PRESET_SLEEP = 6,
|
CLIMATE_PRESET_SLEEP = 6,
|
||||||
CLIMATE_PRESET_ACTIVITY = 7,
|
CLIMATE_PRESET_ACTIVITY = 7,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_NUMBER
|
||||||
enum NumberMode : uint32_t {
|
enum NumberMode : uint32_t {
|
||||||
NUMBER_MODE_AUTO = 0,
|
NUMBER_MODE_AUTO = 0,
|
||||||
NUMBER_MODE_BOX = 1,
|
NUMBER_MODE_BOX = 1,
|
||||||
NUMBER_MODE_SLIDER = 2,
|
NUMBER_MODE_SLIDER = 2,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_LOCK
|
||||||
enum LockState : uint32_t {
|
enum LockState : uint32_t {
|
||||||
LOCK_STATE_NONE = 0,
|
LOCK_STATE_NONE = 0,
|
||||||
LOCK_STATE_LOCKED = 1,
|
LOCK_STATE_LOCKED = 1,
|
||||||
@ -145,6 +160,8 @@ enum LockCommand : uint32_t {
|
|||||||
LOCK_LOCK = 1,
|
LOCK_LOCK = 1,
|
||||||
LOCK_OPEN = 2,
|
LOCK_OPEN = 2,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_MEDIA_PLAYER
|
||||||
enum MediaPlayerState : uint32_t {
|
enum MediaPlayerState : uint32_t {
|
||||||
MEDIA_PLAYER_STATE_NONE = 0,
|
MEDIA_PLAYER_STATE_NONE = 0,
|
||||||
MEDIA_PLAYER_STATE_IDLE = 1,
|
MEDIA_PLAYER_STATE_IDLE = 1,
|
||||||
@ -162,6 +179,8 @@ enum MediaPlayerFormatPurpose : uint32_t {
|
|||||||
MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0,
|
MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0,
|
||||||
MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT = 1,
|
MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT = 1,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_BLUETOOTH_PROXY
|
||||||
enum BluetoothDeviceRequestType : uint32_t {
|
enum BluetoothDeviceRequestType : uint32_t {
|
||||||
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0,
|
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0,
|
||||||
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
|
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
|
||||||
@ -183,6 +202,7 @@ enum BluetoothScannerMode : uint32_t {
|
|||||||
BLUETOOTH_SCANNER_MODE_PASSIVE = 0,
|
BLUETOOTH_SCANNER_MODE_PASSIVE = 0,
|
||||||
BLUETOOTH_SCANNER_MODE_ACTIVE = 1,
|
BLUETOOTH_SCANNER_MODE_ACTIVE = 1,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
enum VoiceAssistantSubscribeFlag : uint32_t {
|
enum VoiceAssistantSubscribeFlag : uint32_t {
|
||||||
VOICE_ASSISTANT_SUBSCRIBE_NONE = 0,
|
VOICE_ASSISTANT_SUBSCRIBE_NONE = 0,
|
||||||
VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO = 1,
|
VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO = 1,
|
||||||
@ -192,6 +212,7 @@ enum VoiceAssistantRequestFlag : uint32_t {
|
|||||||
VOICE_ASSISTANT_REQUEST_USE_VAD = 1,
|
VOICE_ASSISTANT_REQUEST_USE_VAD = 1,
|
||||||
VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD = 2,
|
VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD = 2,
|
||||||
};
|
};
|
||||||
|
#ifdef USE_VOICE_ASSISTANT
|
||||||
enum VoiceAssistantEvent : uint32_t {
|
enum VoiceAssistantEvent : uint32_t {
|
||||||
VOICE_ASSISTANT_ERROR = 0,
|
VOICE_ASSISTANT_ERROR = 0,
|
||||||
VOICE_ASSISTANT_RUN_START = 1,
|
VOICE_ASSISTANT_RUN_START = 1,
|
||||||
@ -216,6 +237,8 @@ enum VoiceAssistantTimerEvent : uint32_t {
|
|||||||
VOICE_ASSISTANT_TIMER_CANCELLED = 2,
|
VOICE_ASSISTANT_TIMER_CANCELLED = 2,
|
||||||
VOICE_ASSISTANT_TIMER_FINISHED = 3,
|
VOICE_ASSISTANT_TIMER_FINISHED = 3,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ALARM_CONTROL_PANEL
|
||||||
enum AlarmControlPanelState : uint32_t {
|
enum AlarmControlPanelState : uint32_t {
|
||||||
ALARM_STATE_DISARMED = 0,
|
ALARM_STATE_DISARMED = 0,
|
||||||
ALARM_STATE_ARMED_HOME = 1,
|
ALARM_STATE_ARMED_HOME = 1,
|
||||||
@ -237,20 +260,27 @@ enum AlarmControlPanelStateCommand : uint32_t {
|
|||||||
ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS = 5,
|
ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS = 5,
|
||||||
ALARM_CONTROL_PANEL_TRIGGER = 6,
|
ALARM_CONTROL_PANEL_TRIGGER = 6,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_TEXT
|
||||||
enum TextMode : uint32_t {
|
enum TextMode : uint32_t {
|
||||||
TEXT_MODE_TEXT = 0,
|
TEXT_MODE_TEXT = 0,
|
||||||
TEXT_MODE_PASSWORD = 1,
|
TEXT_MODE_PASSWORD = 1,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_VALVE
|
||||||
enum ValveOperation : uint32_t {
|
enum ValveOperation : uint32_t {
|
||||||
VALVE_OPERATION_IDLE = 0,
|
VALVE_OPERATION_IDLE = 0,
|
||||||
VALVE_OPERATION_IS_OPENING = 1,
|
VALVE_OPERATION_IS_OPENING = 1,
|
||||||
VALVE_OPERATION_IS_CLOSING = 2,
|
VALVE_OPERATION_IS_CLOSING = 2,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_UPDATE
|
||||||
enum UpdateCommand : uint32_t {
|
enum UpdateCommand : uint32_t {
|
||||||
UPDATE_COMMAND_NONE = 0,
|
UPDATE_COMMAND_NONE = 0,
|
||||||
UPDATE_COMMAND_UPDATE = 1,
|
UPDATE_COMMAND_UPDATE = 1,
|
||||||
UPDATE_COMMAND_CHECK = 2,
|
UPDATE_COMMAND_CHECK = 2,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace enums
|
} // namespace enums
|
||||||
|
|
||||||
@ -273,6 +303,7 @@ class StateResponseProtoMessage : public ProtoMessage {
|
|||||||
public:
|
public:
|
||||||
~StateResponseProtoMessage() override = default;
|
~StateResponseProtoMessage() override = default;
|
||||||
uint32_t key{0};
|
uint32_t key{0};
|
||||||
|
uint32_t device_id{0};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
};
|
};
|
||||||
@ -523,6 +554,7 @@ class SubscribeStatesRequest : public ProtoMessage {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
};
|
};
|
||||||
|
#ifdef USE_BINARY_SENSOR
|
||||||
class ListEntitiesBinarySensorResponse : public InfoResponseProtoMessage {
|
class ListEntitiesBinarySensorResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 12;
|
static constexpr uint16_t MESSAGE_TYPE = 12;
|
||||||
@ -546,7 +578,7 @@ class ListEntitiesBinarySensorResponse : public InfoResponseProtoMessage {
|
|||||||
class BinarySensorStateResponse : public StateResponseProtoMessage {
|
class BinarySensorStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 21;
|
static constexpr uint16_t MESSAGE_TYPE = 21;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 9;
|
static constexpr uint16_t ESTIMATED_SIZE = 13;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "binary_sensor_state_response"; }
|
const char *message_name() const override { return "binary_sensor_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -562,6 +594,8 @@ class BinarySensorStateResponse : public StateResponseProtoMessage {
|
|||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_COVER
|
||||||
class ListEntitiesCoverResponse : public InfoResponseProtoMessage {
|
class ListEntitiesCoverResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 13;
|
static constexpr uint16_t MESSAGE_TYPE = 13;
|
||||||
@ -588,7 +622,7 @@ class ListEntitiesCoverResponse : public InfoResponseProtoMessage {
|
|||||||
class CoverStateResponse : public StateResponseProtoMessage {
|
class CoverStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 22;
|
static constexpr uint16_t MESSAGE_TYPE = 22;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 19;
|
static constexpr uint16_t ESTIMATED_SIZE = 23;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "cover_state_response"; }
|
const char *message_name() const override { return "cover_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -631,6 +665,8 @@ class CoverCommandRequest : public ProtoMessage {
|
|||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_FAN
|
||||||
class ListEntitiesFanResponse : public InfoResponseProtoMessage {
|
class ListEntitiesFanResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 14;
|
static constexpr uint16_t MESSAGE_TYPE = 14;
|
||||||
@ -657,7 +693,7 @@ class ListEntitiesFanResponse : public InfoResponseProtoMessage {
|
|||||||
class FanStateResponse : public StateResponseProtoMessage {
|
class FanStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 23;
|
static constexpr uint16_t MESSAGE_TYPE = 23;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 26;
|
static constexpr uint16_t ESTIMATED_SIZE = 30;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "fan_state_response"; }
|
const char *message_name() const override { return "fan_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -709,6 +745,8 @@ class FanCommandRequest : public ProtoMessage {
|
|||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_LIGHT
|
||||||
class ListEntitiesLightResponse : public InfoResponseProtoMessage {
|
class ListEntitiesLightResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 15;
|
static constexpr uint16_t MESSAGE_TYPE = 15;
|
||||||
@ -738,7 +776,7 @@ class ListEntitiesLightResponse : public InfoResponseProtoMessage {
|
|||||||
class LightStateResponse : public StateResponseProtoMessage {
|
class LightStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 24;
|
static constexpr uint16_t MESSAGE_TYPE = 24;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 63;
|
static constexpr uint16_t ESTIMATED_SIZE = 67;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "light_state_response"; }
|
const char *message_name() const override { return "light_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -810,6 +848,8 @@ class LightCommandRequest : public ProtoMessage {
|
|||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SENSOR
|
||||||
class ListEntitiesSensorResponse : public InfoResponseProtoMessage {
|
class ListEntitiesSensorResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 16;
|
static constexpr uint16_t MESSAGE_TYPE = 16;
|
||||||
@ -837,7 +877,7 @@ class ListEntitiesSensorResponse : public InfoResponseProtoMessage {
|
|||||||
class SensorStateResponse : public StateResponseProtoMessage {
|
class SensorStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 25;
|
static constexpr uint16_t MESSAGE_TYPE = 25;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 12;
|
static constexpr uint16_t ESTIMATED_SIZE = 16;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "sensor_state_response"; }
|
const char *message_name() const override { return "sensor_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -853,6 +893,8 @@ class SensorStateResponse : public StateResponseProtoMessage {
|
|||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SWITCH
|
||||||
class ListEntitiesSwitchResponse : public InfoResponseProtoMessage {
|
class ListEntitiesSwitchResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 17;
|
static constexpr uint16_t MESSAGE_TYPE = 17;
|
||||||
@ -876,7 +918,7 @@ class ListEntitiesSwitchResponse : public InfoResponseProtoMessage {
|
|||||||
class SwitchStateResponse : public StateResponseProtoMessage {
|
class SwitchStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 26;
|
static constexpr uint16_t MESSAGE_TYPE = 26;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 7;
|
static constexpr uint16_t ESTIMATED_SIZE = 11;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "switch_state_response"; }
|
const char *message_name() const override { return "switch_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -910,6 +952,8 @@ class SwitchCommandRequest : public ProtoMessage {
|
|||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_TEXT_SENSOR
|
||||||
class ListEntitiesTextSensorResponse : public InfoResponseProtoMessage {
|
class ListEntitiesTextSensorResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 18;
|
static constexpr uint16_t MESSAGE_TYPE = 18;
|
||||||
@ -932,7 +976,7 @@ class ListEntitiesTextSensorResponse : public InfoResponseProtoMessage {
|
|||||||
class TextSensorStateResponse : public StateResponseProtoMessage {
|
class TextSensorStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 27;
|
static constexpr uint16_t MESSAGE_TYPE = 27;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 16;
|
static constexpr uint16_t ESTIMATED_SIZE = 20;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "text_sensor_state_response"; }
|
const char *message_name() const override { return "text_sensor_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -949,6 +993,7 @@ class TextSensorStateResponse : public StateResponseProtoMessage {
|
|||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
class SubscribeLogsRequest : public ProtoMessage {
|
class SubscribeLogsRequest : public ProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 28;
|
static constexpr uint16_t MESSAGE_TYPE = 28;
|
||||||
@ -987,6 +1032,7 @@ class SubscribeLogsResponse : public ProtoMessage {
|
|||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#ifdef USE_API_NOISE
|
||||||
class NoiseEncryptionSetKeyRequest : public ProtoMessage {
|
class NoiseEncryptionSetKeyRequest : public ProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 124;
|
static constexpr uint16_t MESSAGE_TYPE = 124;
|
||||||
@ -1021,6 +1067,7 @@ class NoiseEncryptionSetKeyResponse : public ProtoMessage {
|
|||||||
protected:
|
protected:
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
class SubscribeHomeassistantServicesRequest : public ProtoMessage {
|
class SubscribeHomeassistantServicesRequest : public ProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 34;
|
static constexpr uint16_t MESSAGE_TYPE = 34;
|
||||||
@ -1226,6 +1273,7 @@ class ExecuteServiceRequest : public ProtoMessage {
|
|||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
};
|
};
|
||||||
|
#ifdef USE_ESP32_CAMERA
|
||||||
class ListEntitiesCameraResponse : public InfoResponseProtoMessage {
|
class ListEntitiesCameraResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 43;
|
static constexpr uint16_t MESSAGE_TYPE = 43;
|
||||||
@ -1283,6 +1331,8 @@ class CameraImageRequest : public ProtoMessage {
|
|||||||
protected:
|
protected:
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_CLIMATE
|
||||||
class ListEntitiesClimateResponse : public InfoResponseProtoMessage {
|
class ListEntitiesClimateResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 46;
|
static constexpr uint16_t MESSAGE_TYPE = 46;
|
||||||
@ -1322,7 +1372,7 @@ class ListEntitiesClimateResponse : public InfoResponseProtoMessage {
|
|||||||
class ClimateStateResponse : public StateResponseProtoMessage {
|
class ClimateStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 47;
|
static constexpr uint16_t MESSAGE_TYPE = 47;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 65;
|
static constexpr uint16_t ESTIMATED_SIZE = 70;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "climate_state_response"; }
|
const char *message_name() const override { return "climate_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -1392,6 +1442,8 @@ class ClimateCommandRequest : public ProtoMessage {
|
|||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_NUMBER
|
||||||
class ListEntitiesNumberResponse : public InfoResponseProtoMessage {
|
class ListEntitiesNumberResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 49;
|
static constexpr uint16_t MESSAGE_TYPE = 49;
|
||||||
@ -1419,7 +1471,7 @@ class ListEntitiesNumberResponse : public InfoResponseProtoMessage {
|
|||||||
class NumberStateResponse : public StateResponseProtoMessage {
|
class NumberStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 50;
|
static constexpr uint16_t MESSAGE_TYPE = 50;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 12;
|
static constexpr uint16_t ESTIMATED_SIZE = 16;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "number_state_response"; }
|
const char *message_name() const override { return "number_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -1453,6 +1505,8 @@ class NumberCommandRequest : public ProtoMessage {
|
|||||||
protected:
|
protected:
|
||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SELECT
|
||||||
class ListEntitiesSelectResponse : public InfoResponseProtoMessage {
|
class ListEntitiesSelectResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 52;
|
static constexpr uint16_t MESSAGE_TYPE = 52;
|
||||||
@ -1475,7 +1529,7 @@ class ListEntitiesSelectResponse : public InfoResponseProtoMessage {
|
|||||||
class SelectStateResponse : public StateResponseProtoMessage {
|
class SelectStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 53;
|
static constexpr uint16_t MESSAGE_TYPE = 53;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 16;
|
static constexpr uint16_t ESTIMATED_SIZE = 20;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "select_state_response"; }
|
const char *message_name() const override { return "select_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -1511,6 +1565,8 @@ class SelectCommandRequest : public ProtoMessage {
|
|||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SIREN
|
||||||
class ListEntitiesSirenResponse : public InfoResponseProtoMessage {
|
class ListEntitiesSirenResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 55;
|
static constexpr uint16_t MESSAGE_TYPE = 55;
|
||||||
@ -1535,7 +1591,7 @@ class ListEntitiesSirenResponse : public InfoResponseProtoMessage {
|
|||||||
class SirenStateResponse : public StateResponseProtoMessage {
|
class SirenStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 56;
|
static constexpr uint16_t MESSAGE_TYPE = 56;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 7;
|
static constexpr uint16_t ESTIMATED_SIZE = 11;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "siren_state_response"; }
|
const char *message_name() const override { return "siren_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -1577,6 +1633,8 @@ class SirenCommandRequest : public ProtoMessage {
|
|||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_LOCK
|
||||||
class ListEntitiesLockResponse : public InfoResponseProtoMessage {
|
class ListEntitiesLockResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 58;
|
static constexpr uint16_t MESSAGE_TYPE = 58;
|
||||||
@ -1602,7 +1660,7 @@ class ListEntitiesLockResponse : public InfoResponseProtoMessage {
|
|||||||
class LockStateResponse : public StateResponseProtoMessage {
|
class LockStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 59;
|
static constexpr uint16_t MESSAGE_TYPE = 59;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 7;
|
static constexpr uint16_t ESTIMATED_SIZE = 11;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "lock_state_response"; }
|
const char *message_name() const override { return "lock_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -1639,6 +1697,8 @@ class LockCommandRequest : public ProtoMessage {
|
|||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_BUTTON
|
||||||
class ListEntitiesButtonResponse : public InfoResponseProtoMessage {
|
class ListEntitiesButtonResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 61;
|
static constexpr uint16_t MESSAGE_TYPE = 61;
|
||||||
@ -1675,6 +1735,8 @@ class ButtonCommandRequest : public ProtoMessage {
|
|||||||
protected:
|
protected:
|
||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_MEDIA_PLAYER
|
||||||
class MediaPlayerSupportedFormat : public ProtoMessage {
|
class MediaPlayerSupportedFormat : public ProtoMessage {
|
||||||
public:
|
public:
|
||||||
std::string format{};
|
std::string format{};
|
||||||
@ -1715,7 +1777,7 @@ class ListEntitiesMediaPlayerResponse : public InfoResponseProtoMessage {
|
|||||||
class MediaPlayerStateResponse : public StateResponseProtoMessage {
|
class MediaPlayerStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 64;
|
static constexpr uint16_t MESSAGE_TYPE = 64;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 14;
|
static constexpr uint16_t ESTIMATED_SIZE = 18;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "media_player_state_response"; }
|
const char *message_name() const override { return "media_player_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -1759,6 +1821,8 @@ class MediaPlayerCommandRequest : public ProtoMessage {
|
|||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_BLUETOOTH_PROXY
|
||||||
class SubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage {
|
class SubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 66;
|
static constexpr uint16_t MESSAGE_TYPE = 66;
|
||||||
@ -2313,6 +2377,8 @@ class BluetoothScannerSetModeRequest : public ProtoMessage {
|
|||||||
protected:
|
protected:
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_VOICE_ASSISTANT
|
||||||
class SubscribeVoiceAssistantRequest : public ProtoMessage {
|
class SubscribeVoiceAssistantRequest : public ProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 89;
|
static constexpr uint16_t MESSAGE_TYPE = 89;
|
||||||
@ -2562,6 +2628,8 @@ class VoiceAssistantSetConfiguration : public ProtoMessage {
|
|||||||
protected:
|
protected:
|
||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ALARM_CONTROL_PANEL
|
||||||
class ListEntitiesAlarmControlPanelResponse : public InfoResponseProtoMessage {
|
class ListEntitiesAlarmControlPanelResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 94;
|
static constexpr uint16_t MESSAGE_TYPE = 94;
|
||||||
@ -2586,7 +2654,7 @@ class ListEntitiesAlarmControlPanelResponse : public InfoResponseProtoMessage {
|
|||||||
class AlarmControlPanelStateResponse : public StateResponseProtoMessage {
|
class AlarmControlPanelStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 95;
|
static constexpr uint16_t MESSAGE_TYPE = 95;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 7;
|
static constexpr uint16_t ESTIMATED_SIZE = 11;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "alarm_control_panel_state_response"; }
|
const char *message_name() const override { return "alarm_control_panel_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -2622,6 +2690,8 @@ class AlarmControlPanelCommandRequest : public ProtoMessage {
|
|||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_TEXT
|
||||||
class ListEntitiesTextResponse : public InfoResponseProtoMessage {
|
class ListEntitiesTextResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 97;
|
static constexpr uint16_t MESSAGE_TYPE = 97;
|
||||||
@ -2647,7 +2717,7 @@ class ListEntitiesTextResponse : public InfoResponseProtoMessage {
|
|||||||
class TextStateResponse : public StateResponseProtoMessage {
|
class TextStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 98;
|
static constexpr uint16_t MESSAGE_TYPE = 98;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 16;
|
static constexpr uint16_t ESTIMATED_SIZE = 20;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "text_state_response"; }
|
const char *message_name() const override { return "text_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -2683,6 +2753,8 @@ class TextCommandRequest : public ProtoMessage {
|
|||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_DATETIME_DATE
|
||||||
class ListEntitiesDateResponse : public InfoResponseProtoMessage {
|
class ListEntitiesDateResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 100;
|
static constexpr uint16_t MESSAGE_TYPE = 100;
|
||||||
@ -2704,7 +2776,7 @@ class ListEntitiesDateResponse : public InfoResponseProtoMessage {
|
|||||||
class DateStateResponse : public StateResponseProtoMessage {
|
class DateStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 101;
|
static constexpr uint16_t MESSAGE_TYPE = 101;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 19;
|
static constexpr uint16_t ESTIMATED_SIZE = 23;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "date_state_response"; }
|
const char *message_name() const override { return "date_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -2743,6 +2815,8 @@ class DateCommandRequest : public ProtoMessage {
|
|||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_DATETIME_TIME
|
||||||
class ListEntitiesTimeResponse : public InfoResponseProtoMessage {
|
class ListEntitiesTimeResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 103;
|
static constexpr uint16_t MESSAGE_TYPE = 103;
|
||||||
@ -2764,7 +2838,7 @@ class ListEntitiesTimeResponse : public InfoResponseProtoMessage {
|
|||||||
class TimeStateResponse : public StateResponseProtoMessage {
|
class TimeStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 104;
|
static constexpr uint16_t MESSAGE_TYPE = 104;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 19;
|
static constexpr uint16_t ESTIMATED_SIZE = 23;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "time_state_response"; }
|
const char *message_name() const override { return "time_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -2803,6 +2877,8 @@ class TimeCommandRequest : public ProtoMessage {
|
|||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_EVENT
|
||||||
class ListEntitiesEventResponse : public InfoResponseProtoMessage {
|
class ListEntitiesEventResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 107;
|
static constexpr uint16_t MESSAGE_TYPE = 107;
|
||||||
@ -2826,7 +2902,7 @@ class ListEntitiesEventResponse : public InfoResponseProtoMessage {
|
|||||||
class EventResponse : public StateResponseProtoMessage {
|
class EventResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 108;
|
static constexpr uint16_t MESSAGE_TYPE = 108;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 14;
|
static constexpr uint16_t ESTIMATED_SIZE = 18;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "event_response"; }
|
const char *message_name() const override { return "event_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -2840,7 +2916,10 @@ class EventResponse : public StateResponseProtoMessage {
|
|||||||
protected:
|
protected:
|
||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||||
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_VALVE
|
||||||
class ListEntitiesValveResponse : public InfoResponseProtoMessage {
|
class ListEntitiesValveResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 109;
|
static constexpr uint16_t MESSAGE_TYPE = 109;
|
||||||
@ -2866,7 +2945,7 @@ class ListEntitiesValveResponse : public InfoResponseProtoMessage {
|
|||||||
class ValveStateResponse : public StateResponseProtoMessage {
|
class ValveStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 110;
|
static constexpr uint16_t MESSAGE_TYPE = 110;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 12;
|
static constexpr uint16_t ESTIMATED_SIZE = 16;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "valve_state_response"; }
|
const char *message_name() const override { return "valve_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -2903,6 +2982,8 @@ class ValveCommandRequest : public ProtoMessage {
|
|||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_DATETIME_DATETIME
|
||||||
class ListEntitiesDateTimeResponse : public InfoResponseProtoMessage {
|
class ListEntitiesDateTimeResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 112;
|
static constexpr uint16_t MESSAGE_TYPE = 112;
|
||||||
@ -2924,7 +3005,7 @@ class ListEntitiesDateTimeResponse : public InfoResponseProtoMessage {
|
|||||||
class DateTimeStateResponse : public StateResponseProtoMessage {
|
class DateTimeStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 113;
|
static constexpr uint16_t MESSAGE_TYPE = 113;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 12;
|
static constexpr uint16_t ESTIMATED_SIZE = 16;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "date_time_state_response"; }
|
const char *message_name() const override { return "date_time_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -2958,6 +3039,8 @@ class DateTimeCommandRequest : public ProtoMessage {
|
|||||||
protected:
|
protected:
|
||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
#ifdef USE_UPDATE
|
||||||
class ListEntitiesUpdateResponse : public InfoResponseProtoMessage {
|
class ListEntitiesUpdateResponse : public InfoResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 116;
|
static constexpr uint16_t MESSAGE_TYPE = 116;
|
||||||
@ -2980,7 +3063,7 @@ class ListEntitiesUpdateResponse : public InfoResponseProtoMessage {
|
|||||||
class UpdateStateResponse : public StateResponseProtoMessage {
|
class UpdateStateResponse : public StateResponseProtoMessage {
|
||||||
public:
|
public:
|
||||||
static constexpr uint16_t MESSAGE_TYPE = 117;
|
static constexpr uint16_t MESSAGE_TYPE = 117;
|
||||||
static constexpr uint16_t ESTIMATED_SIZE = 61;
|
static constexpr uint16_t ESTIMATED_SIZE = 65;
|
||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
const char *message_name() const override { return "update_state_response"; }
|
const char *message_name() const override { return "update_state_response"; }
|
||||||
#endif
|
#endif
|
||||||
@ -3023,6 +3106,7 @@ class UpdateCommandRequest : public ProtoMessage {
|
|||||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
4333
esphome/components/api/api_pb2_dump.cpp
Normal file
4333
esphome/components/api/api_pb2_dump.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -2,9 +2,10 @@
|
|||||||
// See script/api_protobuf/api_protobuf.py
|
// See script/api_protobuf/api_protobuf.py
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "api_pb2.h"
|
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
|
|
||||||
|
#include "api_pb2.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
|
1
esphome/components/ds2484/__init__.py
Normal file
1
esphome/components/ds2484/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
CODEOWNERS = ["@mrk-its"]
|
209
esphome/components/ds2484/ds2484.cpp
Normal file
209
esphome/components/ds2484/ds2484.cpp
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
#include "ds2484.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace ds2484 {
|
||||||
|
static const char *const TAG = "ds2484.onewire";
|
||||||
|
|
||||||
|
void DS2484OneWireBus::setup() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Running setup");
|
||||||
|
this->reset_device();
|
||||||
|
this->search();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DS2484OneWireBus::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "1-wire bus:");
|
||||||
|
this->dump_devices_(TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DS2484OneWireBus::read_status_(uint8_t *status) {
|
||||||
|
for (uint8_t retry_nr = 0; retry_nr < 10; retry_nr++) {
|
||||||
|
if (this->read(status, 1) != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGE(TAG, "read status error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ESP_LOGVV(TAG, "status: %02x", *status);
|
||||||
|
if (!(*status & 1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ESP_LOGE(TAG, "read status error: too many retries");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DS2484OneWireBus::wait_for_completion_() {
|
||||||
|
uint8_t status;
|
||||||
|
return this->read_status_(&status);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DS2484OneWireBus::reset_device() {
|
||||||
|
ESP_LOGVV(TAG, "reset_device");
|
||||||
|
uint8_t device_reset_cmd = 0xf0;
|
||||||
|
uint8_t response;
|
||||||
|
if (this->write(&device_reset_cmd, 1) != i2c::ERROR_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this->wait_for_completion_()) {
|
||||||
|
ESP_LOGE(TAG, "reset_device: can't complete");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint8_t config = (this->active_pullup_ ? 1 : 0) | (this->strong_pullup_ ? 4 : 0);
|
||||||
|
uint8_t write_config[2] = {0xd2, (uint8_t) (config | (~config << 4))};
|
||||||
|
if (this->write(write_config, 2) != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGE(TAG, "reset_device: can't write config");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this->read(&response, 1) != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGE(TAG, "can't read read8 response");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (response != (write_config[1] & 0xf)) {
|
||||||
|
ESP_LOGE(TAG, "configuration didn't update");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
int DS2484OneWireBus::reset_int() {
|
||||||
|
ESP_LOGVV(TAG, "reset");
|
||||||
|
uint8_t reset_cmd = 0xb4;
|
||||||
|
if (this->write(&reset_cmd, 1) != i2c::ERROR_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return this->wait_for_completion_() ? 1 : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void DS2484OneWireBus::write8_(uint8_t value) {
|
||||||
|
uint8_t buffer[2] = {0xa5, value};
|
||||||
|
this->write(buffer, 2);
|
||||||
|
this->wait_for_completion_();
|
||||||
|
};
|
||||||
|
|
||||||
|
void DS2484OneWireBus::write8(uint8_t value) {
|
||||||
|
ESP_LOGVV(TAG, "write8: %02x", value);
|
||||||
|
this->write8_(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
void DS2484OneWireBus::write64(uint64_t value) {
|
||||||
|
ESP_LOGVV(TAG, "write64: %llx", value);
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
this->write8_((value >> (i * 8)) & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DS2484OneWireBus::read8() {
|
||||||
|
uint8_t read8_cmd = 0x96;
|
||||||
|
uint8_t set_read_reg_cmd[2] = {0xe1, 0xe1};
|
||||||
|
uint8_t response = 0;
|
||||||
|
if (this->write(&read8_cmd, 1) != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGE(TAG, "can't write read8 cmd");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
this->wait_for_completion_();
|
||||||
|
if (this->write(set_read_reg_cmd, 2) != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGE(TAG, "can't set read data reg");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (this->read(&response, 1) != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGE(TAG, "can't read read8 response");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t DS2484OneWireBus::read64() {
|
||||||
|
uint8_t response = 0;
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
response |= (this->read8() << (i * 8));
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DS2484OneWireBus::reset_search() {
|
||||||
|
this->last_discrepancy_ = 0;
|
||||||
|
this->last_device_flag_ = false;
|
||||||
|
this->address_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DS2484OneWireBus::one_wire_triple_(bool *branch, bool *id_bit, bool *cmp_id_bit) {
|
||||||
|
uint8_t buffer[2] = {(uint8_t) 0x78, (uint8_t) (*branch ? 0x80u : 0)};
|
||||||
|
uint8_t status;
|
||||||
|
if (!this->read_status_(&status)) {
|
||||||
|
ESP_LOGE(TAG, "one_wire_triple start: read status error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this->write(buffer, 2) != i2c::ERROR_OK) {
|
||||||
|
ESP_LOGV(TAG, "one_wire_triple: can't write cmd");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this->read_status_(&status)) {
|
||||||
|
ESP_LOGE(TAG, "one_wire_triple: read status error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*id_bit = bool(status & 0x20);
|
||||||
|
*cmp_id_bit = bool(status & 0x40);
|
||||||
|
*branch = bool(status & 0x80);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t IRAM_ATTR DS2484OneWireBus::search_int() {
|
||||||
|
ESP_LOGVV(TAG, "search_int");
|
||||||
|
if (this->last_device_flag_) {
|
||||||
|
ESP_LOGVV(TAG, "last device flag set, quitting");
|
||||||
|
return 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t last_zero = 0;
|
||||||
|
uint64_t bit_mask = 1;
|
||||||
|
uint64_t address = this->address_;
|
||||||
|
|
||||||
|
// Initiate search
|
||||||
|
for (uint8_t bit_number = 1; bit_number <= 64; bit_number++, bit_mask <<= 1) {
|
||||||
|
bool branch;
|
||||||
|
|
||||||
|
// compute branch value for the case when there is a discrepancy
|
||||||
|
// (there are devices with both 0s and 1s at this bit)
|
||||||
|
if (bit_number < this->last_discrepancy_) {
|
||||||
|
branch = (address & bit_mask) > 0;
|
||||||
|
} else {
|
||||||
|
branch = bit_number == this->last_discrepancy_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool id_bit, cmp_id_bit;
|
||||||
|
bool branch_before = branch;
|
||||||
|
if (!this->one_wire_triple_(&branch, &id_bit, &cmp_id_bit)) {
|
||||||
|
ESP_LOGW(TAG, "one wire triple error, quitting");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id_bit && cmp_id_bit) {
|
||||||
|
ESP_LOGW(TAG, "no devices on the bus, quitting");
|
||||||
|
// No devices participating in search
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!id_bit && !cmp_id_bit && !branch) {
|
||||||
|
last_zero = bit_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGVV(TAG, "%d %d branch: %d %d", id_bit, cmp_id_bit, branch_before, branch);
|
||||||
|
|
||||||
|
if (branch) {
|
||||||
|
address |= bit_mask;
|
||||||
|
} else {
|
||||||
|
address &= ~bit_mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ESP_LOGVV(TAG, "last_discepancy: %d", last_zero);
|
||||||
|
ESP_LOGVV(TAG, "address: %llx", address);
|
||||||
|
this->last_discrepancy_ = last_zero;
|
||||||
|
if (this->last_discrepancy_ == 0) {
|
||||||
|
// we're at root and have no choices left, so this was the last one.
|
||||||
|
this->last_device_flag_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->address_ = address;
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ds2484
|
||||||
|
} // namespace esphome
|
43
esphome/components/ds2484/ds2484.h
Normal file
43
esphome/components/ds2484/ds2484.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/preferences.h"
|
||||||
|
#include "esphome/components/i2c/i2c.h"
|
||||||
|
#include "esphome/components/one_wire/one_wire.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace ds2484 {
|
||||||
|
|
||||||
|
class DS2484OneWireBus : public one_wire::OneWireBus, public i2c::I2CDevice, public Component {
|
||||||
|
public:
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::BUS - 1.0; }
|
||||||
|
|
||||||
|
bool reset_device();
|
||||||
|
int reset_int() override;
|
||||||
|
void write8(uint8_t) override;
|
||||||
|
void write64(uint64_t) override;
|
||||||
|
uint8_t read8() override;
|
||||||
|
uint64_t read64() override;
|
||||||
|
|
||||||
|
void set_active_pullup(bool value) { this->active_pullup_ = value; }
|
||||||
|
void set_strong_pullup(bool value) { this->strong_pullup_ = value; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void reset_search() override;
|
||||||
|
uint64_t search_int() override;
|
||||||
|
bool read_status_(uint8_t *);
|
||||||
|
bool wait_for_completion_();
|
||||||
|
void write8_(uint8_t);
|
||||||
|
bool one_wire_triple_(bool *branch, bool *id_bit, bool *cmp_id_bit);
|
||||||
|
|
||||||
|
uint64_t address_;
|
||||||
|
uint8_t last_discrepancy_{0};
|
||||||
|
bool last_device_flag_{false};
|
||||||
|
bool active_pullup_{false};
|
||||||
|
bool strong_pullup_{false};
|
||||||
|
};
|
||||||
|
} // namespace ds2484
|
||||||
|
} // namespace esphome
|
37
esphome/components/ds2484/one_wire.py
Normal file
37
esphome/components/ds2484/one_wire.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import i2c
|
||||||
|
from esphome.components.one_wire import OneWireBus
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import CONF_ID
|
||||||
|
|
||||||
|
ds2484_ns = cg.esphome_ns.namespace("ds2484")
|
||||||
|
|
||||||
|
CONF_ACTIVE_PULLUP = "active_pullup"
|
||||||
|
CONF_STRONG_PULLUP = "strong_pullup"
|
||||||
|
|
||||||
|
CODEOWNERS = ["@mrk-its"]
|
||||||
|
DEPENDENCIES = ["i2c"]
|
||||||
|
|
||||||
|
DS2484OneWireBus = ds2484_ns.class_(
|
||||||
|
"DS2484OneWireBus", OneWireBus, i2c.I2CDevice, cg.Component
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(DS2484OneWireBus),
|
||||||
|
cv.Optional(CONF_ACTIVE_PULLUP, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_STRONG_PULLUP, default=False): cv.boolean,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
.extend(i2c.i2c_device_schema(0x18))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await i2c.register_i2c_device(var, config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
cg.add(var.set_active_pullup(config[CONF_ACTIVE_PULLUP]))
|
||||||
|
cg.add(var.set_strong_pullup(config[CONF_STRONG_PULLUP]))
|
@ -63,6 +63,7 @@ BASE_SCHEMA = cv.All(
|
|||||||
cv.Schema(
|
cv.Schema(
|
||||||
{
|
{
|
||||||
cv.Required(CONF_URL): cv.url,
|
cv.Required(CONF_URL): cv.url,
|
||||||
|
cv.Optional(CONF_PATH): cv.string,
|
||||||
cv.Optional(CONF_USERNAME): cv.string,
|
cv.Optional(CONF_USERNAME): cv.string,
|
||||||
cv.Optional(CONF_PASSWORD): cv.string,
|
cv.Optional(CONF_PASSWORD): cv.string,
|
||||||
cv.Exclusive(CONF_FILE, CONF_FILES): validate_yaml_filename,
|
cv.Exclusive(CONF_FILE, CONF_FILES): validate_yaml_filename,
|
||||||
@ -116,6 +117,9 @@ def _process_base_package(config: dict) -> dict:
|
|||||||
)
|
)
|
||||||
files = []
|
files = []
|
||||||
|
|
||||||
|
if base_path := config.get(CONF_PATH):
|
||||||
|
repo_dir = repo_dir / base_path
|
||||||
|
|
||||||
for file in config[CONF_FILES]:
|
for file in config[CONF_FILES]:
|
||||||
if isinstance(file, str):
|
if isinstance(file, str):
|
||||||
files.append({CONF_PATH: file, CONF_VARS: {}})
|
files.append({CONF_PATH: file, CONF_VARS: {}})
|
||||||
|
@ -1,19 +1,76 @@
|
|||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components import binary_sensor
|
from esphome.components import binary_sensor
|
||||||
from esphome.const import CONF_ID
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_DATA,
|
||||||
|
CONF_ID,
|
||||||
|
CONF_NAME,
|
||||||
|
CONF_STATUS,
|
||||||
|
CONF_TYPE,
|
||||||
|
DEVICE_CLASS_CONNECTIVITY,
|
||||||
|
ENTITY_CATEGORY_DIAGNOSTIC,
|
||||||
|
)
|
||||||
|
import esphome.final_validate as fv
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
|
CONF_ENCRYPTION,
|
||||||
|
CONF_PING_PONG_ENABLE,
|
||||||
CONF_PROVIDER,
|
CONF_PROVIDER,
|
||||||
|
CONF_PROVIDERS,
|
||||||
CONF_REMOTE_ID,
|
CONF_REMOTE_ID,
|
||||||
CONF_TRANSPORT_ID,
|
CONF_TRANSPORT_ID,
|
||||||
|
PacketTransport,
|
||||||
packet_transport_sensor_schema,
|
packet_transport_sensor_schema,
|
||||||
|
provider_name_validate,
|
||||||
)
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA = packet_transport_sensor_schema(binary_sensor.binary_sensor_schema())
|
STATUS_SENSOR_SCHEMA = binary_sensor.binary_sensor_schema(
|
||||||
|
device_class=DEVICE_CLASS_CONNECTIVITY,
|
||||||
|
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||||
|
).extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_TRANSPORT_ID): cv.use_id(PacketTransport),
|
||||||
|
cv.Required(CONF_PROVIDER): provider_name_validate,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.typed_schema(
|
||||||
|
{
|
||||||
|
CONF_DATA: packet_transport_sensor_schema(binary_sensor.binary_sensor_schema()),
|
||||||
|
CONF_STATUS: STATUS_SENSOR_SCHEMA,
|
||||||
|
},
|
||||||
|
key=CONF_TYPE,
|
||||||
|
default_type=CONF_DATA,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _final_validate(config):
|
||||||
|
if config[CONF_TYPE] != CONF_STATUS:
|
||||||
|
# Only run this validation if a status sensor is being configured
|
||||||
|
return config
|
||||||
|
full_config = fv.full_config.get()
|
||||||
|
transport_path = full_config.get_path_for_id(config[CONF_TRANSPORT_ID])[:-1]
|
||||||
|
transport_config = full_config.get_config_for_path(transport_path)
|
||||||
|
if transport_config[CONF_PING_PONG_ENABLE] and any(
|
||||||
|
CONF_ENCRYPTION in p
|
||||||
|
for p in transport_config[CONF_PROVIDERS]
|
||||||
|
if p[CONF_NAME] == config[CONF_PROVIDER]
|
||||||
|
):
|
||||||
|
return config
|
||||||
|
raise cv.Invalid(
|
||||||
|
"Status sensor requires ping-pong to be enabled and the nominated provider to use encryption."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = await binary_sensor.new_binary_sensor(config)
|
var = await binary_sensor.new_binary_sensor(config)
|
||||||
comp = await cg.get_variable(config[CONF_TRANSPORT_ID])
|
comp = await cg.get_variable(config[CONF_TRANSPORT_ID])
|
||||||
remote_id = str(config.get(CONF_REMOTE_ID) or config.get(CONF_ID))
|
if config[CONF_TYPE] == CONF_STATUS:
|
||||||
cg.add(comp.add_remote_binary_sensor(config[CONF_PROVIDER], remote_id, var))
|
cg.add(comp.set_provider_status_sensor(config[CONF_PROVIDER], var))
|
||||||
|
cg.add_define("USE_STATUS_SENSOR")
|
||||||
|
else: # CONF_DATA is default
|
||||||
|
remote_id = str(config.get(CONF_REMOTE_ID) or config.get(CONF_ID))
|
||||||
|
cg.add(comp.add_remote_binary_sensor(config[CONF_PROVIDER], remote_id, var))
|
||||||
|
@ -317,8 +317,37 @@ void PacketTransport::update() {
|
|||||||
auto now = millis() / 1000;
|
auto now = millis() / 1000;
|
||||||
if (this->last_key_time_ + this->ping_pong_recyle_time_ < now) {
|
if (this->last_key_time_ + this->ping_pong_recyle_time_ < now) {
|
||||||
this->resend_ping_key_ = this->ping_pong_enable_;
|
this->resend_ping_key_ = this->ping_pong_enable_;
|
||||||
|
ESP_LOGV(TAG, "Ping request, age %u", now - this->last_key_time_);
|
||||||
this->last_key_time_ = now;
|
this->last_key_time_ = now;
|
||||||
}
|
}
|
||||||
|
for (const auto &provider : this->providers_) {
|
||||||
|
uint32_t key_response_age = now - provider.second.last_key_response_time;
|
||||||
|
if (key_response_age > (this->ping_pong_recyle_time_ * 2u)) {
|
||||||
|
#ifdef USE_STATUS_SENSOR
|
||||||
|
if (provider.second.status_sensor != nullptr && provider.second.status_sensor->state) {
|
||||||
|
ESP_LOGI(TAG, "Ping status for %s timeout at %u with age %u", provider.first.c_str(), now, key_response_age);
|
||||||
|
provider.second.status_sensor->publish_state(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_SENSOR
|
||||||
|
for (auto &sensor : this->remote_sensors_[provider.first]) {
|
||||||
|
sensor.second->publish_state(NAN);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_BINARY_SENSOR
|
||||||
|
for (auto &sensor : this->remote_binary_sensors_[provider.first]) {
|
||||||
|
sensor.second->invalidate_state();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#ifdef USE_STATUS_SENSOR
|
||||||
|
if (provider.second.status_sensor != nullptr && !provider.second.status_sensor->state) {
|
||||||
|
ESP_LOGI(TAG, "Ping status for %s restored at %u with age %u", provider.first.c_str(), now, key_response_age);
|
||||||
|
provider.second.status_sensor->publish_state(true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PacketTransport::add_key_(const char *name, uint32_t key) {
|
void PacketTransport::add_key_(const char *name, uint32_t key) {
|
||||||
@ -437,7 +466,8 @@ void PacketTransport::process_(const std::vector<uint8_t> &data) {
|
|||||||
if (decoder.decode(PING_KEY, key) == DECODE_OK) {
|
if (decoder.decode(PING_KEY, key) == DECODE_OK) {
|
||||||
if (key == this->ping_key_) {
|
if (key == this->ping_key_) {
|
||||||
ping_key_seen = true;
|
ping_key_seen = true;
|
||||||
ESP_LOGV(TAG, "Found good ping key %X", (unsigned) key);
|
provider.last_key_response_time = millis() / 1000;
|
||||||
|
ESP_LOGV(TAG, "Found good ping key %X at timestamp %" PRIu32, (unsigned) key, provider.last_key_response_time);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGV(TAG, "Unknown ping key %X", (unsigned) key);
|
ESP_LOGV(TAG, "Unknown ping key %X", (unsigned) key);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||||
#endif
|
#endif
|
||||||
#
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
@ -27,6 +27,10 @@ struct Provider {
|
|||||||
std::vector<uint8_t> encryption_key;
|
std::vector<uint8_t> encryption_key;
|
||||||
const char *name;
|
const char *name;
|
||||||
uint32_t last_code[2];
|
uint32_t last_code[2];
|
||||||
|
uint32_t last_key_response_time;
|
||||||
|
#ifdef USE_STATUS_SENSOR
|
||||||
|
binary_sensor::BinarySensor *status_sensor{nullptr};
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef USE_SENSOR
|
#ifdef USE_SENSOR
|
||||||
@ -75,10 +79,7 @@ class PacketTransport : public PollingComponent {
|
|||||||
|
|
||||||
void add_provider(const char *hostname) {
|
void add_provider(const char *hostname) {
|
||||||
if (this->providers_.count(hostname) == 0) {
|
if (this->providers_.count(hostname) == 0) {
|
||||||
Provider provider;
|
Provider provider{};
|
||||||
provider.encryption_key = std::vector<uint8_t>{};
|
|
||||||
provider.last_code[0] = 0;
|
|
||||||
provider.last_code[1] = 0;
|
|
||||||
provider.name = hostname;
|
provider.name = hostname;
|
||||||
this->providers_[hostname] = provider;
|
this->providers_[hostname] = provider;
|
||||||
#ifdef USE_SENSOR
|
#ifdef USE_SENSOR
|
||||||
@ -97,6 +98,11 @@ class PacketTransport : public PollingComponent {
|
|||||||
void set_provider_encryption(const char *name, std::vector<uint8_t> key) {
|
void set_provider_encryption(const char *name, std::vector<uint8_t> key) {
|
||||||
this->providers_[name].encryption_key = std::move(key);
|
this->providers_[name].encryption_key = std::move(key);
|
||||||
}
|
}
|
||||||
|
#ifdef USE_STATUS_SENSOR
|
||||||
|
void set_provider_status_sensor(const char *name, binary_sensor::BinarySensor *sensor) {
|
||||||
|
this->providers_[name].status_sensor = sensor;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
void set_platform_name(const char *name) { this->platform_name_ = name; }
|
void set_platform_name(const char *name) { this->platform_name_ = name; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -86,6 +86,7 @@
|
|||||||
#define USE_SELECT
|
#define USE_SELECT
|
||||||
#define USE_SENSOR
|
#define USE_SENSOR
|
||||||
#define USE_STATUS_LED
|
#define USE_STATUS_LED
|
||||||
|
#define USE_STATUS_SENSOR
|
||||||
#define USE_SWITCH
|
#define USE_SWITCH
|
||||||
#define USE_TEXT
|
#define USE_TEXT
|
||||||
#define USE_TEXT_SENSOR
|
#define USE_TEXT_SENSOR
|
||||||
|
@ -13,7 +13,7 @@ platformio==6.1.18 # When updating platformio, also update /docker/Dockerfile
|
|||||||
esptool==4.9.0
|
esptool==4.9.0
|
||||||
click==8.1.7
|
click==8.1.7
|
||||||
esphome-dashboard==20250514.0
|
esphome-dashboard==20250514.0
|
||||||
aioesphomeapi==34.0.0
|
aioesphomeapi==34.1.0
|
||||||
zeroconf==0.147.0
|
zeroconf==0.147.0
|
||||||
puremagic==1.29
|
puremagic==1.29
|
||||||
ruamel.yaml==0.18.14 # dashboard_import
|
ruamel.yaml==0.18.14 # dashboard_import
|
||||||
|
@ -813,27 +813,137 @@ class RepeatedTypeInfo(TypeInfo):
|
|||||||
return underlying_size * 2
|
return underlying_size * 2
|
||||||
|
|
||||||
|
|
||||||
def build_enum_type(desc) -> tuple[str, str]:
|
def build_type_usage_map(
|
||||||
"""Builds the enum type."""
|
file_desc: descriptor.FileDescriptorProto,
|
||||||
|
) -> tuple[dict[str, str | None], dict[str, str | None]]:
|
||||||
|
"""Build mappings for both enums and messages to their ifdefs based on usage.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (enum_ifdef_map, message_ifdef_map)
|
||||||
|
"""
|
||||||
|
enum_ifdef_map: dict[str, str | None] = {}
|
||||||
|
message_ifdef_map: dict[str, str | None] = {}
|
||||||
|
|
||||||
|
# Build maps of which types are used by which messages
|
||||||
|
enum_usage: dict[
|
||||||
|
str, set[str]
|
||||||
|
] = {} # enum_name -> set of message names that use it
|
||||||
|
message_usage: dict[
|
||||||
|
str, set[str]
|
||||||
|
] = {} # message_name -> set of message names that use it
|
||||||
|
|
||||||
|
# Build message name to ifdef mapping for quick lookup
|
||||||
|
message_to_ifdef: dict[str, str | None] = {
|
||||||
|
msg.name: get_opt(msg, pb.ifdef) for msg in file_desc.message_type
|
||||||
|
}
|
||||||
|
|
||||||
|
# Analyze field usage
|
||||||
|
for message in file_desc.message_type:
|
||||||
|
for field in message.field:
|
||||||
|
type_name = field.type_name.split(".")[-1] if field.type_name else None
|
||||||
|
if not type_name:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Track enum usage
|
||||||
|
if field.type == 14: # TYPE_ENUM
|
||||||
|
enum_usage.setdefault(type_name, set()).add(message.name)
|
||||||
|
# Track message usage
|
||||||
|
elif field.type == 11: # TYPE_MESSAGE
|
||||||
|
message_usage.setdefault(type_name, set()).add(message.name)
|
||||||
|
|
||||||
|
# Helper to get unique ifdef from a set of messages
|
||||||
|
def get_unique_ifdef(message_names: set[str]) -> str | None:
|
||||||
|
ifdefs: set[str] = {
|
||||||
|
message_to_ifdef[name]
|
||||||
|
for name in message_names
|
||||||
|
if message_to_ifdef.get(name)
|
||||||
|
}
|
||||||
|
return ifdefs.pop() if len(ifdefs) == 1 else None
|
||||||
|
|
||||||
|
# Build enum ifdef map
|
||||||
|
for enum in file_desc.enum_type:
|
||||||
|
if enum.name in enum_usage:
|
||||||
|
enum_ifdef_map[enum.name] = get_unique_ifdef(enum_usage[enum.name])
|
||||||
|
else:
|
||||||
|
enum_ifdef_map[enum.name] = None
|
||||||
|
|
||||||
|
# Build message ifdef map
|
||||||
|
for message in file_desc.message_type:
|
||||||
|
# Explicit ifdef takes precedence
|
||||||
|
explicit_ifdef = message_to_ifdef.get(message.name)
|
||||||
|
if explicit_ifdef:
|
||||||
|
message_ifdef_map[message.name] = explicit_ifdef
|
||||||
|
elif message.name in message_usage:
|
||||||
|
# Inherit ifdef if all parent messages have the same one
|
||||||
|
message_ifdef_map[message.name] = get_unique_ifdef(
|
||||||
|
message_usage[message.name]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
message_ifdef_map[message.name] = None
|
||||||
|
|
||||||
|
# Second pass: propagate ifdefs recursively
|
||||||
|
# Keep iterating until no more changes are made
|
||||||
|
changed = True
|
||||||
|
iterations = 0
|
||||||
|
while changed and iterations < 10: # Add safety limit
|
||||||
|
changed = False
|
||||||
|
iterations += 1
|
||||||
|
for message in file_desc.message_type:
|
||||||
|
# Skip if already has an ifdef
|
||||||
|
if message_ifdef_map.get(message.name):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check if this message is used by other messages
|
||||||
|
if message.name not in message_usage:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Get ifdefs from all messages that use this one
|
||||||
|
parent_ifdefs: set[str] = {
|
||||||
|
message_ifdef_map.get(parent)
|
||||||
|
for parent in message_usage[message.name]
|
||||||
|
if message_ifdef_map.get(parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
# If all parents have the same ifdef, inherit it
|
||||||
|
if len(parent_ifdefs) == 1 and None not in parent_ifdefs:
|
||||||
|
message_ifdef_map[message.name] = parent_ifdefs.pop()
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
return enum_ifdef_map, message_ifdef_map
|
||||||
|
|
||||||
|
|
||||||
|
def build_enum_type(desc, enum_ifdef_map) -> tuple[str, str, str]:
|
||||||
|
"""Builds the enum type.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
desc: The enum descriptor
|
||||||
|
enum_ifdef_map: Mapping of enum names to their ifdefs
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (header_content, cpp_content, dump_cpp_content)
|
||||||
|
"""
|
||||||
name = desc.name
|
name = desc.name
|
||||||
|
|
||||||
out = f"enum {name} : uint32_t {{\n"
|
out = f"enum {name} : uint32_t {{\n"
|
||||||
for v in desc.value:
|
for v in desc.value:
|
||||||
out += f" {v.name} = {v.number},\n"
|
out += f" {v.name} = {v.number},\n"
|
||||||
out += "};\n"
|
out += "};\n"
|
||||||
|
|
||||||
cpp = "#ifdef HAS_PROTO_MESSAGE_DUMP\n"
|
# Regular cpp file has no enum content anymore
|
||||||
cpp += f"template<> const char *proto_enum_to_string<enums::{name}>(enums::{name} value) {{\n"
|
cpp = ""
|
||||||
cpp += " switch (value) {\n"
|
|
||||||
for v in desc.value:
|
|
||||||
cpp += f" case enums::{v.name}:\n"
|
|
||||||
cpp += f' return "{v.name}";\n'
|
|
||||||
cpp += " default:\n"
|
|
||||||
cpp += ' return "UNKNOWN";\n'
|
|
||||||
cpp += " }\n"
|
|
||||||
cpp += "}\n"
|
|
||||||
cpp += "#endif\n"
|
|
||||||
|
|
||||||
return out, cpp
|
# Dump cpp content for enum string conversion
|
||||||
|
dump_cpp = f"template<> const char *proto_enum_to_string<enums::{name}>(enums::{name} value) {{\n"
|
||||||
|
dump_cpp += " switch (value) {\n"
|
||||||
|
for v in desc.value:
|
||||||
|
dump_cpp += f" case enums::{v.name}:\n"
|
||||||
|
dump_cpp += f' return "{v.name}";\n'
|
||||||
|
dump_cpp += " default:\n"
|
||||||
|
dump_cpp += ' return "UNKNOWN";\n'
|
||||||
|
dump_cpp += " }\n"
|
||||||
|
dump_cpp += "}\n"
|
||||||
|
|
||||||
|
return out, cpp, dump_cpp
|
||||||
|
|
||||||
|
|
||||||
def calculate_message_estimated_size(desc: descriptor.DescriptorProto) -> int:
|
def calculate_message_estimated_size(desc: descriptor.DescriptorProto) -> int:
|
||||||
@ -855,7 +965,7 @@ def calculate_message_estimated_size(desc: descriptor.DescriptorProto) -> int:
|
|||||||
def build_message_type(
|
def build_message_type(
|
||||||
desc: descriptor.DescriptorProto,
|
desc: descriptor.DescriptorProto,
|
||||||
base_class_fields: dict[str, list[descriptor.FieldDescriptorProto]] = None,
|
base_class_fields: dict[str, list[descriptor.FieldDescriptorProto]] = None,
|
||||||
) -> tuple[str, str]:
|
) -> tuple[str, str, str]:
|
||||||
public_content: list[str] = []
|
public_content: list[str] = []
|
||||||
protected_content: list[str] = []
|
protected_content: list[str] = []
|
||||||
decode_varint: list[str] = []
|
decode_varint: list[str] = []
|
||||||
@ -886,7 +996,7 @@ def build_message_type(
|
|||||||
f"static constexpr uint16_t ESTIMATED_SIZE = {estimated_size};"
|
f"static constexpr uint16_t ESTIMATED_SIZE = {estimated_size};"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add message_name method for debugging
|
# Add message_name method inline in header
|
||||||
public_content.append("#ifdef HAS_PROTO_MESSAGE_DUMP")
|
public_content.append("#ifdef HAS_PROTO_MESSAGE_DUMP")
|
||||||
snake_name = camel_to_snake(desc.name)
|
snake_name = camel_to_snake(desc.name)
|
||||||
public_content.append(
|
public_content.append(
|
||||||
@ -993,32 +1103,32 @@ def build_message_type(
|
|||||||
public_content.append(prot)
|
public_content.append(prot)
|
||||||
# If no fields to calculate size for, the default implementation in ProtoMessage will be used
|
# If no fields to calculate size for, the default implementation in ProtoMessage will be used
|
||||||
|
|
||||||
o = f"void {desc.name}::dump_to(std::string &out) const {{"
|
# dump_to method declaration in header
|
||||||
if dump:
|
|
||||||
if len(dump) == 1 and len(dump[0]) + len(o) + 3 < 120:
|
|
||||||
o += f" {dump[0]} "
|
|
||||||
else:
|
|
||||||
o += "\n"
|
|
||||||
o += " __attribute__((unused)) char buffer[64];\n"
|
|
||||||
o += f' out.append("{desc.name} {{\\n");\n'
|
|
||||||
o += indent("\n".join(dump)) + "\n"
|
|
||||||
o += ' out.append("}");\n'
|
|
||||||
else:
|
|
||||||
o2 = f'out.append("{desc.name} {{}}");'
|
|
||||||
if len(o) + len(o2) + 3 < 120:
|
|
||||||
o += f" {o2} "
|
|
||||||
else:
|
|
||||||
o += "\n"
|
|
||||||
o += f" {o2}\n"
|
|
||||||
o += "}\n"
|
|
||||||
cpp += "#ifdef HAS_PROTO_MESSAGE_DUMP\n"
|
|
||||||
cpp += o
|
|
||||||
cpp += "#endif\n"
|
|
||||||
prot = "#ifdef HAS_PROTO_MESSAGE_DUMP\n"
|
prot = "#ifdef HAS_PROTO_MESSAGE_DUMP\n"
|
||||||
prot += "void dump_to(std::string &out) const override;\n"
|
prot += "void dump_to(std::string &out) const override;\n"
|
||||||
prot += "#endif\n"
|
prot += "#endif\n"
|
||||||
public_content.append(prot)
|
public_content.append(prot)
|
||||||
|
|
||||||
|
# dump_to implementation will go in dump_cpp
|
||||||
|
dump_impl = f"void {desc.name}::dump_to(std::string &out) const {{"
|
||||||
|
if dump:
|
||||||
|
if len(dump) == 1 and len(dump[0]) + len(dump_impl) + 3 < 120:
|
||||||
|
dump_impl += f" {dump[0]} "
|
||||||
|
else:
|
||||||
|
dump_impl += "\n"
|
||||||
|
dump_impl += " __attribute__((unused)) char buffer[64];\n"
|
||||||
|
dump_impl += f' out.append("{desc.name} {{\\n");\n'
|
||||||
|
dump_impl += indent("\n".join(dump)) + "\n"
|
||||||
|
dump_impl += ' out.append("}");\n'
|
||||||
|
else:
|
||||||
|
o2 = f'out.append("{desc.name} {{}}");'
|
||||||
|
if len(dump_impl) + len(o2) + 3 < 120:
|
||||||
|
dump_impl += f" {o2} "
|
||||||
|
else:
|
||||||
|
dump_impl += "\n"
|
||||||
|
dump_impl += f" {o2}\n"
|
||||||
|
dump_impl += "}\n"
|
||||||
|
|
||||||
if base_class:
|
if base_class:
|
||||||
out = f"class {desc.name} : public {base_class} {{\n"
|
out = f"class {desc.name} : public {base_class} {{\n"
|
||||||
else:
|
else:
|
||||||
@ -1031,7 +1141,11 @@ def build_message_type(
|
|||||||
if len(protected_content) > 0:
|
if len(protected_content) > 0:
|
||||||
out += "\n"
|
out += "\n"
|
||||||
out += "};\n"
|
out += "};\n"
|
||||||
return out, cpp
|
|
||||||
|
# Build dump_cpp content with dump_to implementation
|
||||||
|
dump_cpp = dump_impl
|
||||||
|
|
||||||
|
return out, cpp, dump_cpp
|
||||||
|
|
||||||
|
|
||||||
SOURCE_BOTH = 0
|
SOURCE_BOTH = 0
|
||||||
@ -1119,7 +1233,7 @@ def find_common_fields(
|
|||||||
def build_base_class(
|
def build_base_class(
|
||||||
base_class_name: str,
|
base_class_name: str,
|
||||||
common_fields: list[descriptor.FieldDescriptorProto],
|
common_fields: list[descriptor.FieldDescriptorProto],
|
||||||
) -> tuple[str, str]:
|
) -> tuple[str, str, str]:
|
||||||
"""Build the base class definition and implementation."""
|
"""Build the base class definition and implementation."""
|
||||||
public_content = []
|
public_content = []
|
||||||
protected_content = []
|
protected_content = []
|
||||||
@ -1156,16 +1270,18 @@ def build_base_class(
|
|||||||
out += "};\n"
|
out += "};\n"
|
||||||
|
|
||||||
# No implementation needed for base classes
|
# No implementation needed for base classes
|
||||||
|
dump_cpp = ""
|
||||||
|
|
||||||
return out, cpp
|
return out, cpp, dump_cpp
|
||||||
|
|
||||||
|
|
||||||
def generate_base_classes(
|
def generate_base_classes(
|
||||||
base_class_groups: dict[str, list[descriptor.DescriptorProto]],
|
base_class_groups: dict[str, list[descriptor.DescriptorProto]],
|
||||||
) -> tuple[str, str]:
|
) -> tuple[str, str, str]:
|
||||||
"""Generate all base classes."""
|
"""Generate all base classes."""
|
||||||
all_headers = []
|
all_headers = []
|
||||||
all_cpp = []
|
all_cpp = []
|
||||||
|
all_dump_cpp = []
|
||||||
|
|
||||||
for base_class_name, messages in base_class_groups.items():
|
for base_class_name, messages in base_class_groups.items():
|
||||||
# Find common fields
|
# Find common fields
|
||||||
@ -1173,11 +1289,12 @@ def generate_base_classes(
|
|||||||
|
|
||||||
if common_fields:
|
if common_fields:
|
||||||
# Generate base class
|
# Generate base class
|
||||||
header, cpp = build_base_class(base_class_name, common_fields)
|
header, cpp, dump_cpp = build_base_class(base_class_name, common_fields)
|
||||||
all_headers.append(header)
|
all_headers.append(header)
|
||||||
all_cpp.append(cpp)
|
all_cpp.append(cpp)
|
||||||
|
all_dump_cpp.append(dump_cpp)
|
||||||
|
|
||||||
return "\n".join(all_headers), "\n".join(all_cpp)
|
return "\n".join(all_headers), "\n".join(all_cpp), "\n".join(all_dump_cpp)
|
||||||
|
|
||||||
|
|
||||||
def build_service_message_type(
|
def build_service_message_type(
|
||||||
@ -1244,15 +1361,17 @@ def main() -> None:
|
|||||||
file = d.file[0]
|
file = d.file[0]
|
||||||
content = FILE_HEADER
|
content = FILE_HEADER
|
||||||
content += """\
|
content += """\
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "proto.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "api_pb2_size.h"
|
|
||||||
|
|
||||||
namespace esphome {
|
#include "proto.h"
|
||||||
namespace api {
|
#include "api_pb2_size.h"
|
||||||
|
|
||||||
"""
|
namespace esphome {
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
cpp = FILE_HEADER
|
cpp = FILE_HEADER
|
||||||
cpp += """\
|
cpp += """\
|
||||||
@ -1261,19 +1380,56 @@ def main() -> None:
|
|||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
#include <cinttypes>
|
namespace esphome {
|
||||||
|
namespace api {
|
||||||
|
|
||||||
namespace esphome {
|
"""
|
||||||
namespace api {
|
|
||||||
|
|
||||||
"""
|
# Initialize dump cpp content
|
||||||
|
dump_cpp = FILE_HEADER
|
||||||
|
dump_cpp += """\
|
||||||
|
#include "api_pb2.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
content += "namespace enums {\n\n"
|
content += "namespace enums {\n\n"
|
||||||
|
|
||||||
|
# Build dynamic ifdef mappings for both enums and messages
|
||||||
|
enum_ifdef_map, message_ifdef_map = build_type_usage_map(file)
|
||||||
|
|
||||||
|
# Simple grouping of enums by ifdef
|
||||||
|
current_ifdef = None
|
||||||
|
|
||||||
for enum in file.enum_type:
|
for enum in file.enum_type:
|
||||||
s, c = build_enum_type(enum)
|
s, c, dc = build_enum_type(enum, enum_ifdef_map)
|
||||||
|
enum_ifdef = enum_ifdef_map.get(enum.name)
|
||||||
|
|
||||||
|
# Handle ifdef changes
|
||||||
|
if enum_ifdef != current_ifdef:
|
||||||
|
if current_ifdef is not None:
|
||||||
|
content += "#endif\n"
|
||||||
|
dump_cpp += "#endif\n"
|
||||||
|
if enum_ifdef is not None:
|
||||||
|
content += f"#ifdef {enum_ifdef}\n"
|
||||||
|
dump_cpp += f"#ifdef {enum_ifdef}\n"
|
||||||
|
current_ifdef = enum_ifdef
|
||||||
|
|
||||||
content += s
|
content += s
|
||||||
cpp += c
|
cpp += c
|
||||||
|
dump_cpp += dc
|
||||||
|
|
||||||
|
# Close last ifdef
|
||||||
|
if current_ifdef is not None:
|
||||||
|
content += "#endif\n"
|
||||||
|
dump_cpp += "#endif\n"
|
||||||
|
|
||||||
content += "\n} // namespace enums\n\n"
|
content += "\n} // namespace enums\n\n"
|
||||||
|
|
||||||
@ -1291,26 +1447,61 @@ def main() -> None:
|
|||||||
|
|
||||||
# Generate base classes
|
# Generate base classes
|
||||||
if base_class_fields:
|
if base_class_fields:
|
||||||
base_headers, base_cpp = generate_base_classes(base_class_groups)
|
base_headers, base_cpp, base_dump_cpp = generate_base_classes(base_class_groups)
|
||||||
content += base_headers
|
content += base_headers
|
||||||
cpp += base_cpp
|
cpp += base_cpp
|
||||||
|
dump_cpp += base_dump_cpp
|
||||||
|
|
||||||
# Generate message types with base class information
|
# Generate message types with base class information
|
||||||
|
# Simple grouping by ifdef
|
||||||
|
current_ifdef = None
|
||||||
|
|
||||||
for m in mt:
|
for m in mt:
|
||||||
s, c = build_message_type(m, base_class_fields)
|
s, c, dc = build_message_type(m, base_class_fields)
|
||||||
|
msg_ifdef = message_ifdef_map.get(m.name)
|
||||||
|
|
||||||
|
# Handle ifdef changes
|
||||||
|
if msg_ifdef != current_ifdef:
|
||||||
|
if current_ifdef is not None:
|
||||||
|
content += "#endif\n"
|
||||||
|
if cpp:
|
||||||
|
cpp += "#endif\n"
|
||||||
|
if dump_cpp:
|
||||||
|
dump_cpp += "#endif\n"
|
||||||
|
if msg_ifdef is not None:
|
||||||
|
content += f"#ifdef {msg_ifdef}\n"
|
||||||
|
cpp += f"#ifdef {msg_ifdef}\n"
|
||||||
|
dump_cpp += f"#ifdef {msg_ifdef}\n"
|
||||||
|
current_ifdef = msg_ifdef
|
||||||
|
|
||||||
content += s
|
content += s
|
||||||
cpp += c
|
cpp += c
|
||||||
|
dump_cpp += dc
|
||||||
|
|
||||||
|
# Close last ifdef
|
||||||
|
if current_ifdef is not None:
|
||||||
|
content += "#endif\n"
|
||||||
|
cpp += "#endif\n"
|
||||||
|
dump_cpp += "#endif\n"
|
||||||
|
|
||||||
content += """\
|
content += """\
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
"""
|
"""
|
||||||
cpp += """\
|
cpp += """\
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
dump_cpp += """\
|
||||||
|
|
||||||
|
} // namespace api
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif // HAS_PROTO_MESSAGE_DUMP
|
||||||
|
"""
|
||||||
|
|
||||||
with open(root / "api_pb2.h", "w", encoding="utf-8") as f:
|
with open(root / "api_pb2.h", "w", encoding="utf-8") as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
@ -1318,29 +1509,33 @@ def main() -> None:
|
|||||||
with open(root / "api_pb2.cpp", "w", encoding="utf-8") as f:
|
with open(root / "api_pb2.cpp", "w", encoding="utf-8") as f:
|
||||||
f.write(cpp)
|
f.write(cpp)
|
||||||
|
|
||||||
|
with open(root / "api_pb2_dump.cpp", "w", encoding="utf-8") as f:
|
||||||
|
f.write(dump_cpp)
|
||||||
|
|
||||||
hpp = FILE_HEADER
|
hpp = FILE_HEADER
|
||||||
hpp += """\
|
hpp += """\
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "api_pb2.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "esphome/core/defines.h"
|
|
||||||
|
|
||||||
namespace esphome {
|
#include "api_pb2.h"
|
||||||
namespace api {
|
|
||||||
|
|
||||||
"""
|
namespace esphome {
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
cpp = FILE_HEADER
|
cpp = FILE_HEADER
|
||||||
cpp += """\
|
cpp += """\
|
||||||
#include "api_pb2_service.h"
|
#include "api_pb2_service.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
static const char *const TAG = "api.service";
|
static const char *const TAG = "api.service";
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class_name = "APIServerConnectionBase"
|
class_name = "APIServerConnectionBase"
|
||||||
|
|
||||||
@ -1419,7 +1614,7 @@ def main() -> None:
|
|||||||
needs_conn = get_opt(m, pb.needs_setup_connection, True)
|
needs_conn = get_opt(m, pb.needs_setup_connection, True)
|
||||||
needs_auth = get_opt(m, pb.needs_authentication, True)
|
needs_auth = get_opt(m, pb.needs_authentication, True)
|
||||||
|
|
||||||
ifdef = ifdefs.get(inp, None)
|
ifdef = message_ifdef_map.get(inp, ifdefs.get(inp, None))
|
||||||
|
|
||||||
if ifdef is not None:
|
if ifdef is not None:
|
||||||
hpp += f"#ifdef {ifdef}\n"
|
hpp += f"#ifdef {ifdef}\n"
|
||||||
@ -1476,14 +1671,14 @@ def main() -> None:
|
|||||||
|
|
||||||
hpp += """\
|
hpp += """\
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
"""
|
"""
|
||||||
cpp += """\
|
cpp += """\
|
||||||
|
|
||||||
} // namespace api
|
} // namespace api
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with open(root / "api_pb2_service.h", "w", encoding="utf-8") as f:
|
with open(root / "api_pb2_service.h", "w", encoding="utf-8") as f:
|
||||||
f.write(hpp)
|
f.write(hpp)
|
||||||
@ -1506,6 +1701,8 @@ def main() -> None:
|
|||||||
exec_clang_format(root / "api_pb2_service.cpp")
|
exec_clang_format(root / "api_pb2_service.cpp")
|
||||||
exec_clang_format(root / "api_pb2.h")
|
exec_clang_format(root / "api_pb2.h")
|
||||||
exec_clang_format(root / "api_pb2.cpp")
|
exec_clang_format(root / "api_pb2.cpp")
|
||||||
|
exec_clang_format(root / "api_pb2_dump.h")
|
||||||
|
exec_clang_format(root / "api_pb2_dump.cpp")
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
11
tests/components/ds2484/common.yaml
Normal file
11
tests/components/ds2484/common.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
i2c:
|
||||||
|
- id: i2c_ds2484
|
||||||
|
scl: ${scl_pin}
|
||||||
|
sda: ${sda_pin}
|
||||||
|
|
||||||
|
one_wire:
|
||||||
|
platform: ds2484
|
||||||
|
i2c_id: i2c_ds2484
|
||||||
|
address: 0x18
|
||||||
|
active_pullup: true
|
||||||
|
strong_pullup: false
|
5
tests/components/ds2484/test.esp32-ard.yaml
Normal file
5
tests/components/ds2484/test.esp32-ard.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
scl_pin: GPIO16
|
||||||
|
sda_pin: GPIO17
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
5
tests/components/ds2484/test.esp32-c3-ard.yaml
Normal file
5
tests/components/ds2484/test.esp32-c3-ard.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
scl_pin: GPIO5
|
||||||
|
sda_pin: GPIO4
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
5
tests/components/ds2484/test.esp32-c3-idf.yaml
Normal file
5
tests/components/ds2484/test.esp32-c3-idf.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
scl_pin: GPIO5
|
||||||
|
sda_pin: GPIO4
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
5
tests/components/ds2484/test.esp32-idf.yaml
Normal file
5
tests/components/ds2484/test.esp32-idf.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
scl_pin: GPIO16
|
||||||
|
sda_pin: GPIO17
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
5
tests/components/ds2484/test.esp8266-ard.yaml
Normal file
5
tests/components/ds2484/test.esp8266-ard.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
scl_pin: GPIO5
|
||||||
|
sda_pin: GPIO4
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
5
tests/components/ds2484/test.rp2040-ard.yaml
Normal file
5
tests/components/ds2484/test.rp2040-ard.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
substitutions:
|
||||||
|
scl_pin: GPIO5
|
||||||
|
sda_pin: GPIO4
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
@ -5,7 +5,8 @@ packages:
|
|||||||
- !include package.yaml
|
- !include package.yaml
|
||||||
- github://esphome/esphome/tests/components/template/common.yaml@dev
|
- github://esphome/esphome/tests/components/template/common.yaml@dev
|
||||||
- url: https://github.com/esphome/esphome
|
- url: https://github.com/esphome/esphome
|
||||||
file: tests/components/absolute_humidity/common.yaml
|
path: tests/components/absolute_humidity
|
||||||
|
file: common.yaml
|
||||||
ref: dev
|
ref: dev
|
||||||
refresh: 1d
|
refresh: 1d
|
||||||
|
|
||||||
|
@ -7,7 +7,8 @@ packages:
|
|||||||
shorthand: github://esphome/esphome/tests/components/template/common.yaml@dev
|
shorthand: github://esphome/esphome/tests/components/template/common.yaml@dev
|
||||||
github:
|
github:
|
||||||
url: https://github.com/esphome/esphome
|
url: https://github.com/esphome/esphome
|
||||||
file: tests/components/absolute_humidity/common.yaml
|
path: tests/components/absolute_humidity
|
||||||
|
file: common.yaml
|
||||||
ref: dev
|
ref: dev
|
||||||
refresh: 1d
|
refresh: 1d
|
||||||
|
|
||||||
|
@ -36,5 +36,9 @@ binary_sensor:
|
|||||||
- platform: packet_transport
|
- platform: packet_transport
|
||||||
provider: unencrypted-device
|
provider: unencrypted-device
|
||||||
id: other_binary_sensor_id
|
id: other_binary_sensor_id
|
||||||
|
- platform: packet_transport
|
||||||
|
provider: some-device-name
|
||||||
|
type: status
|
||||||
|
name: Some-Device Status
|
||||||
- platform: template
|
- platform: template
|
||||||
id: binary_sensor_id1
|
id: binary_sensor_id1
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
esphome:
|
||||||
|
name: rapid-transitions-test
|
||||||
|
host:
|
||||||
|
api:
|
||||||
|
batch_delay: 0ms # Enable immediate sending for rapid transitions
|
||||||
|
logger:
|
||||||
|
level: DEBUG
|
||||||
|
|
||||||
|
# Add a sensor that updates frequently to trigger lambda evaluations
|
||||||
|
sensor:
|
||||||
|
- platform: template
|
||||||
|
name: "Update Trigger"
|
||||||
|
id: update_trigger
|
||||||
|
lambda: |-
|
||||||
|
return 0;
|
||||||
|
update_interval: 10ms
|
||||||
|
internal: true
|
||||||
|
|
||||||
|
# Simulate an IR remote binary sensor with rapid ON/OFF transitions
|
||||||
|
binary_sensor:
|
||||||
|
- platform: template
|
||||||
|
name: "Simulated IR Remote Button"
|
||||||
|
id: ir_remote_button
|
||||||
|
lambda: |-
|
||||||
|
// Simulate rapid button presses every ~100ms
|
||||||
|
// Each "press" is ON for ~30ms then OFF
|
||||||
|
uint32_t now = millis();
|
||||||
|
uint32_t press_cycle = now % 100; // 100ms cycle
|
||||||
|
|
||||||
|
// ON for first 30ms of each cycle
|
||||||
|
if (press_cycle < 30) {
|
||||||
|
// Only log state change
|
||||||
|
if (!id(ir_remote_button).state) {
|
||||||
|
ESP_LOGD("test", "Button ON at %u", now);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Only log state change
|
||||||
|
if (id(ir_remote_button).state) {
|
||||||
|
ESP_LOGD("test", "Button OFF at %u", now);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
85
tests/integration/fixtures/device_id_in_state.yaml
Normal file
85
tests/integration/fixtures/device_id_in_state.yaml
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
esphome:
|
||||||
|
name: device-id-state-test
|
||||||
|
# Define areas
|
||||||
|
areas:
|
||||||
|
- id: living_room
|
||||||
|
name: Living Room
|
||||||
|
- id: bedroom
|
||||||
|
name: Bedroom
|
||||||
|
# Define devices
|
||||||
|
devices:
|
||||||
|
- id: temperature_monitor
|
||||||
|
name: Temperature Monitor
|
||||||
|
area_id: living_room
|
||||||
|
- id: humidity_monitor
|
||||||
|
name: Humidity Monitor
|
||||||
|
area_id: bedroom
|
||||||
|
- id: motion_sensor
|
||||||
|
name: Motion Sensor
|
||||||
|
area_id: living_room
|
||||||
|
|
||||||
|
host:
|
||||||
|
api:
|
||||||
|
logger:
|
||||||
|
|
||||||
|
# Test different entity types with device assignments
|
||||||
|
sensor:
|
||||||
|
- platform: template
|
||||||
|
name: Temperature
|
||||||
|
device_id: temperature_monitor
|
||||||
|
lambda: return 25.5;
|
||||||
|
update_interval: 0.1s
|
||||||
|
unit_of_measurement: "°C"
|
||||||
|
|
||||||
|
- platform: template
|
||||||
|
name: Humidity
|
||||||
|
device_id: humidity_monitor
|
||||||
|
lambda: return 65.0;
|
||||||
|
update_interval: 0.1s
|
||||||
|
unit_of_measurement: "%"
|
||||||
|
|
||||||
|
# Test entity without device_id (should have device_id 0)
|
||||||
|
- platform: template
|
||||||
|
name: No Device Sensor
|
||||||
|
lambda: return 100.0;
|
||||||
|
update_interval: 0.1s
|
||||||
|
|
||||||
|
binary_sensor:
|
||||||
|
- platform: template
|
||||||
|
name: Motion Detected
|
||||||
|
device_id: motion_sensor
|
||||||
|
lambda: return true;
|
||||||
|
|
||||||
|
switch:
|
||||||
|
- platform: template
|
||||||
|
name: Temperature Monitor Power
|
||||||
|
device_id: temperature_monitor
|
||||||
|
lambda: return true;
|
||||||
|
turn_on_action:
|
||||||
|
- lambda: |-
|
||||||
|
ESP_LOGD("test", "Turning on");
|
||||||
|
turn_off_action:
|
||||||
|
- lambda: |-
|
||||||
|
ESP_LOGD("test", "Turning off");
|
||||||
|
|
||||||
|
text_sensor:
|
||||||
|
- platform: template
|
||||||
|
name: Temperature Status
|
||||||
|
device_id: temperature_monitor
|
||||||
|
lambda: return {"Normal"};
|
||||||
|
update_interval: 0.1s
|
||||||
|
|
||||||
|
light:
|
||||||
|
- platform: binary
|
||||||
|
name: Motion Light
|
||||||
|
device_id: motion_sensor
|
||||||
|
output: motion_light_output
|
||||||
|
|
||||||
|
output:
|
||||||
|
- platform: template
|
||||||
|
id: motion_light_output
|
||||||
|
type: binary
|
||||||
|
write_action:
|
||||||
|
- lambda: |-
|
||||||
|
ESP_LOGD("test", "Light output: %d", state);
|
||||||
|
|
58
tests/integration/test_batch_delay_zero_rapid_transitions.py
Normal file
58
tests/integration/test_batch_delay_zero_rapid_transitions.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
"""Integration test for API batch_delay: 0 with rapid state transitions."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import time
|
||||||
|
|
||||||
|
from aioesphomeapi import BinarySensorInfo, BinarySensorState, EntityState
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from .types import APIClientConnectedFactory, RunCompiledFunction
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_batch_delay_zero_rapid_transitions(
|
||||||
|
yaml_config: str,
|
||||||
|
run_compiled: RunCompiledFunction,
|
||||||
|
api_client_connected: APIClientConnectedFactory,
|
||||||
|
) -> None:
|
||||||
|
"""Test that rapid binary sensor transitions are preserved with batch_delay: 0ms."""
|
||||||
|
async with run_compiled(yaml_config), api_client_connected() as client:
|
||||||
|
# Track state changes
|
||||||
|
state_changes: list[tuple[bool, float]] = []
|
||||||
|
|
||||||
|
def on_state(state: EntityState) -> None:
|
||||||
|
"""Track state changes with timestamps."""
|
||||||
|
if isinstance(state, BinarySensorState):
|
||||||
|
state_changes.append((state.state, time.monotonic()))
|
||||||
|
|
||||||
|
# Subscribe to state changes
|
||||||
|
client.subscribe_states(on_state)
|
||||||
|
|
||||||
|
# Wait for entity info
|
||||||
|
entity_info, _ = await client.list_entities_services()
|
||||||
|
binary_sensors = [e for e in entity_info if isinstance(e, BinarySensorInfo)]
|
||||||
|
assert len(binary_sensors) == 1, "Expected 1 binary sensor"
|
||||||
|
|
||||||
|
# Collect states for 2 seconds
|
||||||
|
await asyncio.sleep(2.1)
|
||||||
|
|
||||||
|
# Count ON->OFF transitions
|
||||||
|
on_off_count = 0
|
||||||
|
for i in range(1, len(state_changes)):
|
||||||
|
if state_changes[i - 1][0] and not state_changes[i][0]: # ON to OFF
|
||||||
|
on_off_count += 1
|
||||||
|
|
||||||
|
# With batch_delay: 0, we should capture rapid transitions
|
||||||
|
# The test timing can be variable in CI, so we're being conservative
|
||||||
|
# We mainly want to verify that we capture multiple rapid transitions
|
||||||
|
assert on_off_count >= 5, (
|
||||||
|
f"Expected at least 5 ON->OFF transitions with batch_delay: 0ms, got {on_off_count}. "
|
||||||
|
"Rapid transitions may have been lost."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Also verify that state changes are happening frequently
|
||||||
|
assert len(state_changes) >= 10, (
|
||||||
|
f"Expected at least 10 state changes, got {len(state_changes)}"
|
||||||
|
)
|
161
tests/integration/test_device_id_in_state.py
Normal file
161
tests/integration/test_device_id_in_state.py
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
"""Integration test for device_id in entity state responses."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from aioesphomeapi import EntityState
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from .types import APIClientConnectedFactory, RunCompiledFunction
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_device_id_in_state(
|
||||||
|
yaml_config: str,
|
||||||
|
run_compiled: RunCompiledFunction,
|
||||||
|
api_client_connected: APIClientConnectedFactory,
|
||||||
|
) -> None:
|
||||||
|
"""Test that device_id is included in entity state responses."""
|
||||||
|
async with run_compiled(yaml_config), api_client_connected() as client:
|
||||||
|
# Get device info to verify devices are configured
|
||||||
|
device_info = await client.device_info()
|
||||||
|
assert device_info is not None
|
||||||
|
|
||||||
|
# Verify devices exist
|
||||||
|
devices = device_info.devices
|
||||||
|
assert len(devices) >= 3, f"Expected at least 3 devices, got {len(devices)}"
|
||||||
|
|
||||||
|
# Get device IDs for verification
|
||||||
|
device_ids = {device.name: device.device_id for device in devices}
|
||||||
|
assert "Temperature Monitor" in device_ids
|
||||||
|
assert "Humidity Monitor" in device_ids
|
||||||
|
assert "Motion Sensor" in device_ids
|
||||||
|
|
||||||
|
# Get entity list
|
||||||
|
entities = await client.list_entities_services()
|
||||||
|
all_entities = entities[0]
|
||||||
|
|
||||||
|
# Create a mapping of entity key to expected device_id
|
||||||
|
entity_device_mapping: dict[int, int] = {}
|
||||||
|
|
||||||
|
for entity in all_entities:
|
||||||
|
if hasattr(entity, "name") and hasattr(entity, "key"):
|
||||||
|
if entity.name == "Temperature":
|
||||||
|
entity_device_mapping[entity.key] = device_ids[
|
||||||
|
"Temperature Monitor"
|
||||||
|
]
|
||||||
|
elif entity.name == "Humidity":
|
||||||
|
entity_device_mapping[entity.key] = device_ids["Humidity Monitor"]
|
||||||
|
elif entity.name == "Motion Detected":
|
||||||
|
entity_device_mapping[entity.key] = device_ids["Motion Sensor"]
|
||||||
|
elif entity.name == "Temperature Monitor Power":
|
||||||
|
entity_device_mapping[entity.key] = device_ids[
|
||||||
|
"Temperature Monitor"
|
||||||
|
]
|
||||||
|
elif entity.name == "Temperature Status":
|
||||||
|
entity_device_mapping[entity.key] = device_ids[
|
||||||
|
"Temperature Monitor"
|
||||||
|
]
|
||||||
|
elif entity.name == "Motion Light":
|
||||||
|
entity_device_mapping[entity.key] = device_ids["Motion Sensor"]
|
||||||
|
elif entity.name == "No Device Sensor":
|
||||||
|
# Entity without device_id should have device_id 0
|
||||||
|
entity_device_mapping[entity.key] = 0
|
||||||
|
|
||||||
|
assert len(entity_device_mapping) >= 6, (
|
||||||
|
f"Expected at least 6 mapped entities, got {len(entity_device_mapping)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Subscribe to states
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
states: dict[int, EntityState] = {}
|
||||||
|
states_future: asyncio.Future[bool] = loop.create_future()
|
||||||
|
|
||||||
|
def on_state(state: EntityState) -> None:
|
||||||
|
states[state.key] = state
|
||||||
|
# Check if we have states for all mapped entities
|
||||||
|
if len(states) >= len(entity_device_mapping) and not states_future.done():
|
||||||
|
states_future.set_result(True)
|
||||||
|
|
||||||
|
client.subscribe_states(on_state)
|
||||||
|
|
||||||
|
# Wait for states
|
||||||
|
try:
|
||||||
|
await asyncio.wait_for(states_future, timeout=10.0)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
pytest.fail(
|
||||||
|
f"Did not receive all entity states within 10 seconds. "
|
||||||
|
f"Received {len(states)} states, expected {len(entity_device_mapping)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Verify each state has the correct device_id
|
||||||
|
verified_count = 0
|
||||||
|
for key, expected_device_id in entity_device_mapping.items():
|
||||||
|
if key in states:
|
||||||
|
state = states[key]
|
||||||
|
|
||||||
|
assert state.device_id == expected_device_id, (
|
||||||
|
f"State for key {key} has device_id {state.device_id}, "
|
||||||
|
f"expected {expected_device_id}"
|
||||||
|
)
|
||||||
|
verified_count += 1
|
||||||
|
|
||||||
|
assert verified_count >= 6, (
|
||||||
|
f"Only verified {verified_count} states, expected at least 6"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test specific state types to ensure device_id is present
|
||||||
|
# Find a sensor state with device_id
|
||||||
|
sensor_state = next(
|
||||||
|
(
|
||||||
|
s
|
||||||
|
for s in states.values()
|
||||||
|
if hasattr(s, "state")
|
||||||
|
and isinstance(s.state, float)
|
||||||
|
and s.device_id != 0
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
assert sensor_state is not None, "No sensor state with device_id found"
|
||||||
|
assert sensor_state.device_id > 0, "Sensor state should have non-zero device_id"
|
||||||
|
|
||||||
|
# Find a binary sensor state
|
||||||
|
binary_sensor_state = next(
|
||||||
|
(
|
||||||
|
s
|
||||||
|
for s in states.values()
|
||||||
|
if hasattr(s, "state") and isinstance(s.state, bool)
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
assert binary_sensor_state is not None, "No binary sensor state found"
|
||||||
|
assert binary_sensor_state.device_id > 0, (
|
||||||
|
"Binary sensor state should have non-zero device_id"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Find a text sensor state
|
||||||
|
text_sensor_state = next(
|
||||||
|
(
|
||||||
|
s
|
||||||
|
for s in states.values()
|
||||||
|
if hasattr(s, "state") and isinstance(s.state, str)
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
assert text_sensor_state is not None, "No text sensor state found"
|
||||||
|
assert text_sensor_state.device_id > 0, (
|
||||||
|
"Text sensor state should have non-zero device_id"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Verify the "No Device Sensor" has device_id = 0
|
||||||
|
no_device_key = next(
|
||||||
|
(key for key, device_id in entity_device_mapping.items() if device_id == 0),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
assert no_device_key is not None, "No entity mapped to device_id 0"
|
||||||
|
assert no_device_key in states, f"State for key {no_device_key} not found"
|
||||||
|
no_device_state = states[no_device_key]
|
||||||
|
assert no_device_state.device_id == 0, (
|
||||||
|
f"Entity without device_id should have device_id=0, got {no_device_state.device_id}"
|
||||||
|
)
|
@ -74,37 +74,41 @@ async def test_host_mode_empty_string_options(
|
|||||||
# If we got here without protobuf decoding errors, the fix is working
|
# If we got here without protobuf decoding errors, the fix is working
|
||||||
# The bug would have caused "Invalid protobuf message" errors with trailing bytes
|
# The bug would have caused "Invalid protobuf message" errors with trailing bytes
|
||||||
|
|
||||||
# Also verify we can interact with the select entities
|
# Also verify we can receive state updates for select entities
|
||||||
# Subscribe to state changes
|
# This ensures empty strings work properly in state messages too
|
||||||
states: dict[int, EntityState] = {}
|
states: dict[int, EntityState] = {}
|
||||||
state_change_future: asyncio.Future[None] = loop.create_future()
|
states_received_future: asyncio.Future[None] = loop.create_future()
|
||||||
|
expected_select_keys = {empty_first.key, empty_middle.key, empty_last.key}
|
||||||
|
received_select_keys = set()
|
||||||
|
|
||||||
def on_state(state: EntityState) -> None:
|
def on_state(state: EntityState) -> None:
|
||||||
"""Track state changes."""
|
"""Track state changes."""
|
||||||
states[state.key] = state
|
states[state.key] = state
|
||||||
# When we receive the state change for our select, resolve the future
|
# Track which select entities we've received states for
|
||||||
if state.key == empty_first.key and not state_change_future.done():
|
if state.key in expected_select_keys:
|
||||||
state_change_future.set_result(None)
|
received_select_keys.add(state.key)
|
||||||
|
# Once we have all select states, we're done
|
||||||
|
if (
|
||||||
|
received_select_keys == expected_select_keys
|
||||||
|
and not states_received_future.done()
|
||||||
|
):
|
||||||
|
states_received_future.set_result(None)
|
||||||
|
|
||||||
client.subscribe_states(on_state)
|
client.subscribe_states(on_state)
|
||||||
|
|
||||||
# Try setting a select to an empty string option
|
# Wait for initial states with timeout
|
||||||
# This further tests that empty strings are handled correctly
|
|
||||||
client.select_command(empty_first.key, "")
|
|
||||||
|
|
||||||
# Wait for state update with timeout
|
|
||||||
try:
|
try:
|
||||||
await asyncio.wait_for(state_change_future, timeout=5.0)
|
await asyncio.wait_for(states_received_future, timeout=5.0)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
pytest.fail(
|
pytest.fail(
|
||||||
"Did not receive state update after setting select to empty string"
|
f"Did not receive states for all select entities. "
|
||||||
|
f"Expected keys: {expected_select_keys}, Received: {received_select_keys}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Verify the state was set to empty string
|
# Verify we received states for all select entities
|
||||||
assert empty_first.key in states
|
assert empty_first.key in states
|
||||||
select_state = states[empty_first.key]
|
assert empty_middle.key in states
|
||||||
assert hasattr(select_state, "state")
|
assert empty_last.key in states
|
||||||
assert select_state.state == ""
|
|
||||||
|
|
||||||
# The test passes if no protobuf decoding errors occurred
|
# The main test is that we got here without protobuf errors
|
||||||
# With the bug, we would have gotten "Invalid protobuf message" errors
|
# The select entities with empty string options were properly encoded
|
||||||
|
@ -46,14 +46,22 @@ async def test_host_mode_fan_preset(
|
|||||||
# Subscribe to states
|
# Subscribe to states
|
||||||
states: dict[int, FanState] = {}
|
states: dict[int, FanState] = {}
|
||||||
state_event = asyncio.Event()
|
state_event = asyncio.Event()
|
||||||
|
initial_states_received = set()
|
||||||
|
|
||||||
def on_state(state: FanState) -> None:
|
def on_state(state: FanState) -> None:
|
||||||
if isinstance(state, FanState):
|
if isinstance(state, FanState):
|
||||||
states[state.key] = state
|
states[state.key] = state
|
||||||
|
initial_states_received.add(state.key)
|
||||||
state_event.set()
|
state_event.set()
|
||||||
|
|
||||||
client.subscribe_states(on_state)
|
client.subscribe_states(on_state)
|
||||||
|
|
||||||
|
# Wait for initial states to be received for all fans
|
||||||
|
expected_fan_keys = {fan.key for fan in fans}
|
||||||
|
while initial_states_received != expected_fan_keys:
|
||||||
|
state_event.clear()
|
||||||
|
await asyncio.wait_for(state_event.wait(), timeout=2.0)
|
||||||
|
|
||||||
# Test 1: Turn on fan without speed or preset - should set speed to 100%
|
# Test 1: Turn on fan without speed or preset - should set speed to 100%
|
||||||
state_event.clear()
|
state_event.clear()
|
||||||
client.fan_command(
|
client.fan_command(
|
||||||
|
@ -22,36 +22,51 @@ async def test_host_mode_many_entities(
|
|||||||
async with run_compiled(yaml_config), api_client_connected() as client:
|
async with run_compiled(yaml_config), api_client_connected() as client:
|
||||||
# Subscribe to state changes
|
# Subscribe to state changes
|
||||||
states: dict[int, EntityState] = {}
|
states: dict[int, EntityState] = {}
|
||||||
entity_count_future: asyncio.Future[int] = loop.create_future()
|
sensor_count_future: asyncio.Future[int] = loop.create_future()
|
||||||
|
|
||||||
def on_state(state: EntityState) -> None:
|
def on_state(state: EntityState) -> None:
|
||||||
states[state.key] = state
|
states[state.key] = state
|
||||||
# When we have received states from a good number of entities, resolve the future
|
# Count sensor states specifically
|
||||||
if len(states) >= 50 and not entity_count_future.done():
|
sensor_states = [
|
||||||
entity_count_future.set_result(len(states))
|
s
|
||||||
|
for s in states.values()
|
||||||
|
if hasattr(s, "state") and isinstance(s.state, float)
|
||||||
|
]
|
||||||
|
# When we have received states from at least 50 sensors, resolve the future
|
||||||
|
if len(sensor_states) >= 50 and not sensor_count_future.done():
|
||||||
|
sensor_count_future.set_result(len(sensor_states))
|
||||||
|
|
||||||
client.subscribe_states(on_state)
|
client.subscribe_states(on_state)
|
||||||
|
|
||||||
# Wait for states from at least 50 entities with timeout
|
# Wait for states from at least 50 sensors with timeout
|
||||||
try:
|
try:
|
||||||
entity_count = await asyncio.wait_for(entity_count_future, timeout=10.0)
|
sensor_count = await asyncio.wait_for(sensor_count_future, timeout=10.0)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
|
sensor_states = [
|
||||||
|
s
|
||||||
|
for s in states.values()
|
||||||
|
if hasattr(s, "state") and isinstance(s.state, float)
|
||||||
|
]
|
||||||
pytest.fail(
|
pytest.fail(
|
||||||
f"Did not receive states from at least 50 entities within 10 seconds. "
|
f"Did not receive states from at least 50 sensors within 10 seconds. "
|
||||||
f"Received {len(states)} states: {list(states.keys())}"
|
f"Received {len(sensor_states)} sensor states out of {len(states)} total states"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Verify we received a good number of entity states
|
# Verify we received a good number of entity states
|
||||||
assert entity_count >= 50, f"Expected at least 50 entities, got {entity_count}"
|
assert len(states) >= 50, (
|
||||||
assert len(states) >= 50, f"Expected at least 50 states, got {len(states)}"
|
f"Expected at least 50 total states, got {len(states)}"
|
||||||
|
)
|
||||||
|
|
||||||
# Verify we have different entity types by checking some expected values
|
# Verify we have the expected sensor states
|
||||||
sensor_states = [
|
sensor_states = [
|
||||||
s
|
s
|
||||||
for s in states.values()
|
for s in states.values()
|
||||||
if hasattr(s, "state") and isinstance(s.state, float)
|
if hasattr(s, "state") and isinstance(s.state, float)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
assert sensor_count >= 50, (
|
||||||
|
f"Expected at least 50 sensor states, got {sensor_count}"
|
||||||
|
)
|
||||||
assert len(sensor_states) >= 50, (
|
assert len(sensor_states) >= 50, (
|
||||||
f"Expected at least 50 sensor states, got {len(sensor_states)}"
|
f"Expected at least 50 sensor states, got {len(sensor_states)}"
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user