mirror of
https://github.com/esphome/esphome.git
synced 2025-08-10 12:27:46 +00:00
Merge branch 'multi_device' into integration
This commit is contained in:
@@ -188,6 +188,17 @@ message DeviceInfoRequest {
|
||||
// Empty
|
||||
}
|
||||
|
||||
message AreaInfo {
|
||||
uint32 area_id = 1;
|
||||
string name = 2;
|
||||
}
|
||||
|
||||
message DeviceInfo {
|
||||
uint32 device_id = 1;
|
||||
string name = 2;
|
||||
uint32 area_id = 3;
|
||||
}
|
||||
|
||||
message DeviceInfoResponse {
|
||||
option (id) = 10;
|
||||
option (source) = SOURCE_SERVER;
|
||||
@@ -236,6 +247,12 @@ message DeviceInfoResponse {
|
||||
|
||||
// Supports receiving and saving api encryption key
|
||||
bool api_encryption_supported = 19;
|
||||
|
||||
repeated DeviceInfo devices = 20;
|
||||
repeated AreaInfo areas = 21;
|
||||
|
||||
// Top-level area info to phase out suggested_area
|
||||
AreaInfo area = 22;
|
||||
}
|
||||
|
||||
message ListEntitiesRequest {
|
||||
@@ -280,6 +297,7 @@ message ListEntitiesBinarySensorResponse {
|
||||
bool disabled_by_default = 7;
|
||||
string icon = 8;
|
||||
EntityCategory entity_category = 9;
|
||||
uint32 device_id = 10;
|
||||
}
|
||||
message BinarySensorStateResponse {
|
||||
option (id) = 21;
|
||||
@@ -315,6 +333,7 @@ message ListEntitiesCoverResponse {
|
||||
string icon = 10;
|
||||
EntityCategory entity_category = 11;
|
||||
bool supports_stop = 12;
|
||||
uint32 device_id = 13;
|
||||
}
|
||||
|
||||
enum LegacyCoverState {
|
||||
@@ -388,6 +407,7 @@ message ListEntitiesFanResponse {
|
||||
string icon = 10;
|
||||
EntityCategory entity_category = 11;
|
||||
repeated string supported_preset_modes = 12;
|
||||
uint32 device_id = 13;
|
||||
}
|
||||
enum FanSpeed {
|
||||
FAN_SPEED_LOW = 0;
|
||||
@@ -471,6 +491,7 @@ message ListEntitiesLightResponse {
|
||||
bool disabled_by_default = 13;
|
||||
string icon = 14;
|
||||
EntityCategory entity_category = 15;
|
||||
uint32 device_id = 16;
|
||||
}
|
||||
message LightStateResponse {
|
||||
option (id) = 24;
|
||||
@@ -563,6 +584,7 @@ message ListEntitiesSensorResponse {
|
||||
SensorLastResetType legacy_last_reset_type = 11;
|
||||
bool disabled_by_default = 12;
|
||||
EntityCategory entity_category = 13;
|
||||
uint32 device_id = 14;
|
||||
}
|
||||
message SensorStateResponse {
|
||||
option (id) = 25;
|
||||
@@ -595,6 +617,7 @@ message ListEntitiesSwitchResponse {
|
||||
bool disabled_by_default = 7;
|
||||
EntityCategory entity_category = 8;
|
||||
string device_class = 9;
|
||||
uint32 device_id = 10;
|
||||
}
|
||||
message SwitchStateResponse {
|
||||
option (id) = 26;
|
||||
@@ -632,6 +655,7 @@ message ListEntitiesTextSensorResponse {
|
||||
bool disabled_by_default = 6;
|
||||
EntityCategory entity_category = 7;
|
||||
string device_class = 8;
|
||||
uint32 device_id = 9;
|
||||
}
|
||||
message TextSensorStateResponse {
|
||||
option (id) = 27;
|
||||
@@ -814,6 +838,7 @@ message ListEntitiesCameraResponse {
|
||||
bool disabled_by_default = 5;
|
||||
string icon = 6;
|
||||
EntityCategory entity_category = 7;
|
||||
uint32 device_id = 8;
|
||||
}
|
||||
|
||||
message CameraImageResponse {
|
||||
@@ -916,6 +941,7 @@ message ListEntitiesClimateResponse {
|
||||
bool supports_target_humidity = 23;
|
||||
float visual_min_humidity = 24;
|
||||
float visual_max_humidity = 25;
|
||||
uint32 device_id = 26;
|
||||
}
|
||||
message ClimateStateResponse {
|
||||
option (id) = 47;
|
||||
@@ -999,6 +1025,7 @@ message ListEntitiesNumberResponse {
|
||||
string unit_of_measurement = 11;
|
||||
NumberMode mode = 12;
|
||||
string device_class = 13;
|
||||
uint32 device_id = 14;
|
||||
}
|
||||
message NumberStateResponse {
|
||||
option (id) = 50;
|
||||
@@ -1039,6 +1066,7 @@ message ListEntitiesSelectResponse {
|
||||
repeated string options = 6;
|
||||
bool disabled_by_default = 7;
|
||||
EntityCategory entity_category = 8;
|
||||
uint32 device_id = 9;
|
||||
}
|
||||
message SelectStateResponse {
|
||||
option (id) = 53;
|
||||
@@ -1081,6 +1109,7 @@ message ListEntitiesSirenResponse {
|
||||
bool supports_duration = 8;
|
||||
bool supports_volume = 9;
|
||||
EntityCategory entity_category = 10;
|
||||
uint32 device_id = 11;
|
||||
}
|
||||
message SirenStateResponse {
|
||||
option (id) = 56;
|
||||
@@ -1144,6 +1173,7 @@ message ListEntitiesLockResponse {
|
||||
|
||||
// Not yet implemented:
|
||||
string code_format = 11;
|
||||
uint32 device_id = 12;
|
||||
}
|
||||
message LockStateResponse {
|
||||
option (id) = 59;
|
||||
@@ -1183,6 +1213,7 @@ message ListEntitiesButtonResponse {
|
||||
bool disabled_by_default = 6;
|
||||
EntityCategory entity_category = 7;
|
||||
string device_class = 8;
|
||||
uint32 device_id = 9;
|
||||
}
|
||||
message ButtonCommandRequest {
|
||||
option (id) = 62;
|
||||
@@ -1238,6 +1269,8 @@ message ListEntitiesMediaPlayerResponse {
|
||||
bool supports_pause = 8;
|
||||
|
||||
repeated MediaPlayerSupportedFormat supported_formats = 9;
|
||||
|
||||
uint32 device_id = 10;
|
||||
}
|
||||
message MediaPlayerStateResponse {
|
||||
option (id) = 64;
|
||||
@@ -1778,6 +1811,7 @@ message ListEntitiesAlarmControlPanelResponse {
|
||||
uint32 supported_features = 8;
|
||||
bool requires_code = 9;
|
||||
bool requires_code_to_arm = 10;
|
||||
uint32 device_id = 11;
|
||||
}
|
||||
|
||||
message AlarmControlPanelStateResponse {
|
||||
@@ -1823,6 +1857,7 @@ message ListEntitiesTextResponse {
|
||||
uint32 max_length = 9;
|
||||
string pattern = 10;
|
||||
TextMode mode = 11;
|
||||
uint32 device_id = 12;
|
||||
}
|
||||
message TextStateResponse {
|
||||
option (id) = 98;
|
||||
@@ -1863,6 +1898,7 @@ message ListEntitiesDateResponse {
|
||||
string icon = 5;
|
||||
bool disabled_by_default = 6;
|
||||
EntityCategory entity_category = 7;
|
||||
uint32 device_id = 8;
|
||||
}
|
||||
message DateStateResponse {
|
||||
option (id) = 101;
|
||||
@@ -1906,6 +1942,7 @@ message ListEntitiesTimeResponse {
|
||||
string icon = 5;
|
||||
bool disabled_by_default = 6;
|
||||
EntityCategory entity_category = 7;
|
||||
uint32 device_id = 8;
|
||||
}
|
||||
message TimeStateResponse {
|
||||
option (id) = 104;
|
||||
@@ -1952,6 +1989,7 @@ message ListEntitiesEventResponse {
|
||||
string device_class = 8;
|
||||
|
||||
repeated string event_types = 9;
|
||||
uint32 device_id = 10;
|
||||
}
|
||||
message EventResponse {
|
||||
option (id) = 108;
|
||||
@@ -1983,6 +2021,7 @@ message ListEntitiesValveResponse {
|
||||
bool assumed_state = 9;
|
||||
bool supports_position = 10;
|
||||
bool supports_stop = 11;
|
||||
uint32 device_id = 12;
|
||||
}
|
||||
|
||||
enum ValveOperation {
|
||||
@@ -2029,6 +2068,7 @@ message ListEntitiesDateTimeResponse {
|
||||
string icon = 5;
|
||||
bool disabled_by_default = 6;
|
||||
EntityCategory entity_category = 7;
|
||||
uint32 device_id = 8;
|
||||
}
|
||||
message DateTimeStateResponse {
|
||||
option (id) = 113;
|
||||
@@ -2069,6 +2109,7 @@ message ListEntitiesUpdateResponse {
|
||||
bool disabled_by_default = 6;
|
||||
EntityCategory entity_category = 7;
|
||||
string device_class = 8;
|
||||
uint32 device_id = 9;
|
||||
}
|
||||
message UpdateStateResponse {
|
||||
option (id) = 117;
|
||||
|
@@ -1621,6 +1621,23 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
|
||||
#endif
|
||||
#ifdef USE_API_NOISE
|
||||
resp.api_encryption_supported = true;
|
||||
#endif
|
||||
#ifdef USE_DEVICES
|
||||
for (auto const &device : App.get_devices()) {
|
||||
DeviceInfo device_info;
|
||||
device_info.device_id = device->get_device_id();
|
||||
device_info.name = device->get_name();
|
||||
device_info.area_id = device->get_area_id();
|
||||
resp.devices.push_back(device_info);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_AREAS
|
||||
for (auto const &area : App.get_areas()) {
|
||||
AreaInfo area_info;
|
||||
area_info.area_id = area->get_area_id();
|
||||
area_info.name = area->get_name();
|
||||
resp.areas.push_back(area_info);
|
||||
}
|
||||
#endif
|
||||
return resp;
|
||||
}
|
||||
|
@@ -301,6 +301,9 @@ class APIConnection : public APIServerConnection {
|
||||
response.icon = entity->get_icon();
|
||||
response.disabled_by_default = entity->is_disabled_by_default();
|
||||
response.entity_category = static_cast<enums::EntityCategory>(entity->get_entity_category());
|
||||
#ifdef USE_DEVICES
|
||||
response.device_id = entity->get_device_id();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Helper function to fill common entity state fields
|
||||
|
@@ -812,6 +812,103 @@ void PingResponse::dump_to(std::string &out) const { out.append("PingResponse {}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void DeviceInfoRequest::dump_to(std::string &out) const { out.append("DeviceInfoRequest {}"); }
|
||||
#endif
|
||||
bool AreaInfo::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
switch (field_id) {
|
||||
case 1: {
|
||||
this->area_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool AreaInfo::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||
switch (field_id) {
|
||||
case 2: {
|
||||
this->name = value.as_string();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void AreaInfo::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_uint32(1, this->area_id);
|
||||
buffer.encode_string(2, this->name);
|
||||
}
|
||||
void AreaInfo::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->area_id, false);
|
||||
ProtoSize::add_string_field(total_size, 1, this->name, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void AreaInfo::dump_to(std::string &out) const {
|
||||
__attribute__((unused)) char buffer[64];
|
||||
out.append("AreaInfo {\n");
|
||||
out.append(" area_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->area_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
|
||||
out.append(" name: ");
|
||||
out.append("'").append(this->name).append("'");
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
bool DeviceInfo::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
switch (field_id) {
|
||||
case 1: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
case 3: {
|
||||
this->area_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool DeviceInfo::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||
switch (field_id) {
|
||||
case 2: {
|
||||
this->name = value.as_string();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void DeviceInfo::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_uint32(1, this->device_id);
|
||||
buffer.encode_string(2, this->name);
|
||||
buffer.encode_uint32(3, this->area_id);
|
||||
}
|
||||
void DeviceInfo::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
ProtoSize::add_string_field(total_size, 1, this->name, false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->area_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void DeviceInfo::dump_to(std::string &out) const {
|
||||
__attribute__((unused)) char buffer[64];
|
||||
out.append("DeviceInfo {\n");
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
|
||||
out.append(" name: ");
|
||||
out.append("'").append(this->name).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" area_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->area_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
bool DeviceInfoResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
switch (field_id) {
|
||||
case 1: {
|
||||
@@ -896,6 +993,18 @@ bool DeviceInfoResponse::decode_length(uint32_t field_id, ProtoLengthDelimited v
|
||||
this->bluetooth_mac_address = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 20: {
|
||||
this->devices.push_back(value.as_message<DeviceInfo>());
|
||||
return true;
|
||||
}
|
||||
case 21: {
|
||||
this->areas.push_back(value.as_message<AreaInfo>());
|
||||
return true;
|
||||
}
|
||||
case 22: {
|
||||
this->area = value.as_message<AreaInfo>();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -920,6 +1029,13 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_string(16, this->suggested_area);
|
||||
buffer.encode_string(18, this->bluetooth_mac_address);
|
||||
buffer.encode_bool(19, this->api_encryption_supported);
|
||||
for (auto &it : this->devices) {
|
||||
buffer.encode_message<DeviceInfo>(20, it, true);
|
||||
}
|
||||
for (auto &it : this->areas) {
|
||||
buffer.encode_message<AreaInfo>(21, it, true);
|
||||
}
|
||||
buffer.encode_message<AreaInfo>(22, this->area);
|
||||
}
|
||||
void DeviceInfoResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_bool_field(total_size, 1, this->uses_password, false);
|
||||
@@ -941,6 +1057,9 @@ void DeviceInfoResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 2, this->suggested_area, false);
|
||||
ProtoSize::add_string_field(total_size, 2, this->bluetooth_mac_address, false);
|
||||
ProtoSize::add_bool_field(total_size, 2, this->api_encryption_supported, false);
|
||||
ProtoSize::add_repeated_message(total_size, 2, this->devices);
|
||||
ProtoSize::add_repeated_message(total_size, 2, this->areas);
|
||||
ProtoSize::add_message_object(total_size, 2, this->area, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void DeviceInfoResponse::dump_to(std::string &out) const {
|
||||
@@ -1026,6 +1145,22 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
|
||||
out.append(" api_encryption_supported: ");
|
||||
out.append(YESNO(this->api_encryption_supported));
|
||||
out.append("\n");
|
||||
|
||||
for (const auto &it : this->devices) {
|
||||
out.append(" devices: ");
|
||||
it.dump_to(out);
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
for (const auto &it : this->areas) {
|
||||
out.append(" areas: ");
|
||||
it.dump_to(out);
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
out.append(" area: ");
|
||||
this->area.dump_to(out);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -1052,6 +1187,10 @@ bool ListEntitiesBinarySensorResponse::decode_varint(uint32_t field_id, ProtoVar
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 10: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -1102,6 +1241,7 @@ void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(7, this->disabled_by_default);
|
||||
buffer.encode_string(8, this->icon);
|
||||
buffer.encode_enum<enums::EntityCategory>(9, this->entity_category);
|
||||
buffer.encode_uint32(10, this->device_id);
|
||||
}
|
||||
void ListEntitiesBinarySensorResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -1113,6 +1253,7 @@ void ListEntitiesBinarySensorResponse::calculate_size(uint32_t &total_size) cons
|
||||
ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default, false);
|
||||
ProtoSize::add_string_field(total_size, 1, this->icon, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesBinarySensorResponse::dump_to(std::string &out) const {
|
||||
@@ -1154,6 +1295,11 @@ void ListEntitiesBinarySensorResponse::dump_to(std::string &out) const {
|
||||
out.append(" entity_category: ");
|
||||
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -1236,6 +1382,10 @@ bool ListEntitiesCoverResponse::decode_varint(uint32_t field_id, ProtoVarInt val
|
||||
this->supports_stop = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
case 13: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -1289,6 +1439,7 @@ void ListEntitiesCoverResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_string(10, this->icon);
|
||||
buffer.encode_enum<enums::EntityCategory>(11, this->entity_category);
|
||||
buffer.encode_bool(12, this->supports_stop);
|
||||
buffer.encode_uint32(13, this->device_id);
|
||||
}
|
||||
void ListEntitiesCoverResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -1303,6 +1454,7 @@ void ListEntitiesCoverResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->icon, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_bool_field(total_size, 1, this->supports_stop, false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesCoverResponse::dump_to(std::string &out) const {
|
||||
@@ -1356,6 +1508,11 @@ void ListEntitiesCoverResponse::dump_to(std::string &out) const {
|
||||
out.append(" supports_stop: ");
|
||||
out.append(YESNO(this->supports_stop));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -1565,6 +1722,10 @@ bool ListEntitiesFanResponse::decode_varint(uint32_t field_id, ProtoVarInt value
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 13: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -1620,6 +1781,7 @@ void ListEntitiesFanResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
for (auto &it : this->supported_preset_modes) {
|
||||
buffer.encode_string(12, it, true);
|
||||
}
|
||||
buffer.encode_uint32(13, this->device_id);
|
||||
}
|
||||
void ListEntitiesFanResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -1638,6 +1800,7 @@ void ListEntitiesFanResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, it, true);
|
||||
}
|
||||
}
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesFanResponse::dump_to(std::string &out) const {
|
||||
@@ -1694,6 +1857,11 @@ void ListEntitiesFanResponse::dump_to(std::string &out) const {
|
||||
out.append("'").append(it).append("'");
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -1987,6 +2155,10 @@ bool ListEntitiesLightResponse::decode_varint(uint32_t field_id, ProtoVarInt val
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 16: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -2055,6 +2227,7 @@ void ListEntitiesLightResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(13, this->disabled_by_default);
|
||||
buffer.encode_string(14, this->icon);
|
||||
buffer.encode_enum<enums::EntityCategory>(15, this->entity_category);
|
||||
buffer.encode_uint32(16, this->device_id);
|
||||
}
|
||||
void ListEntitiesLightResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -2080,6 +2253,7 @@ void ListEntitiesLightResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default, false);
|
||||
ProtoSize::add_string_field(total_size, 1, this->icon, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_uint32_field(total_size, 2, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesLightResponse::dump_to(std::string &out) const {
|
||||
@@ -2151,6 +2325,11 @@ void ListEntitiesLightResponse::dump_to(std::string &out) const {
|
||||
out.append(" entity_category: ");
|
||||
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -2658,6 +2837,10 @@ bool ListEntitiesSensorResponse::decode_varint(uint32_t field_id, ProtoVarInt va
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 14: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -2716,6 +2899,7 @@ void ListEntitiesSensorResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_enum<enums::SensorLastResetType>(11, this->legacy_last_reset_type);
|
||||
buffer.encode_bool(12, this->disabled_by_default);
|
||||
buffer.encode_enum<enums::EntityCategory>(13, this->entity_category);
|
||||
buffer.encode_uint32(14, this->device_id);
|
||||
}
|
||||
void ListEntitiesSensorResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -2731,6 +2915,7 @@ void ListEntitiesSensorResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->legacy_last_reset_type), false);
|
||||
ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesSensorResponse::dump_to(std::string &out) const {
|
||||
@@ -2789,6 +2974,11 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const {
|
||||
out.append(" entity_category: ");
|
||||
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -2860,6 +3050,10 @@ bool ListEntitiesSwitchResponse::decode_varint(uint32_t field_id, ProtoVarInt va
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 10: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -2910,6 +3104,7 @@ void ListEntitiesSwitchResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(7, this->disabled_by_default);
|
||||
buffer.encode_enum<enums::EntityCategory>(8, this->entity_category);
|
||||
buffer.encode_string(9, this->device_class);
|
||||
buffer.encode_uint32(10, this->device_id);
|
||||
}
|
||||
void ListEntitiesSwitchResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -2921,6 +3116,7 @@ void ListEntitiesSwitchResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_string_field(total_size, 1, this->device_class, false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesSwitchResponse::dump_to(std::string &out) const {
|
||||
@@ -2962,6 +3158,11 @@ void ListEntitiesSwitchResponse::dump_to(std::string &out) const {
|
||||
out.append(" device_class: ");
|
||||
out.append("'").append(this->device_class).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -3061,6 +3262,10 @@ bool ListEntitiesTextSensorResponse::decode_varint(uint32_t field_id, ProtoVarIn
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 9: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -3110,6 +3315,7 @@ void ListEntitiesTextSensorResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(6, this->disabled_by_default);
|
||||
buffer.encode_enum<enums::EntityCategory>(7, this->entity_category);
|
||||
buffer.encode_string(8, this->device_class);
|
||||
buffer.encode_uint32(9, this->device_id);
|
||||
}
|
||||
void ListEntitiesTextSensorResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -3120,6 +3326,7 @@ void ListEntitiesTextSensorResponse::calculate_size(uint32_t &total_size) const
|
||||
ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_string_field(total_size, 1, this->device_class, false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesTextSensorResponse::dump_to(std::string &out) const {
|
||||
@@ -3157,6 +3364,11 @@ void ListEntitiesTextSensorResponse::dump_to(std::string &out) const {
|
||||
out.append(" device_class: ");
|
||||
out.append("'").append(this->device_class).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -3922,6 +4134,10 @@ bool ListEntitiesCameraResponse::decode_varint(uint32_t field_id, ProtoVarInt va
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 8: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -3966,6 +4182,7 @@ void ListEntitiesCameraResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(5, this->disabled_by_default);
|
||||
buffer.encode_string(6, this->icon);
|
||||
buffer.encode_enum<enums::EntityCategory>(7, this->entity_category);
|
||||
buffer.encode_uint32(8, this->device_id);
|
||||
}
|
||||
void ListEntitiesCameraResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -3975,6 +4192,7 @@ void ListEntitiesCameraResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default, false);
|
||||
ProtoSize::add_string_field(total_size, 1, this->icon, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesCameraResponse::dump_to(std::string &out) const {
|
||||
@@ -4008,6 +4226,11 @@ void ListEntitiesCameraResponse::dump_to(std::string &out) const {
|
||||
out.append(" entity_category: ");
|
||||
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -4156,6 +4379,10 @@ bool ListEntitiesClimateResponse::decode_varint(uint32_t field_id, ProtoVarInt v
|
||||
this->supports_target_humidity = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
case 26: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -4262,6 +4489,7 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(23, this->supports_target_humidity);
|
||||
buffer.encode_float(24, this->visual_min_humidity);
|
||||
buffer.encode_float(25, this->visual_max_humidity);
|
||||
buffer.encode_uint32(26, this->device_id);
|
||||
}
|
||||
void ListEntitiesClimateResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -4313,6 +4541,7 @@ void ListEntitiesClimateResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_bool_field(total_size, 2, this->supports_target_humidity, false);
|
||||
ProtoSize::add_fixed_field<4>(total_size, 2, this->visual_min_humidity != 0.0f, false);
|
||||
ProtoSize::add_fixed_field<4>(total_size, 2, this->visual_max_humidity != 0.0f, false);
|
||||
ProtoSize::add_uint32_field(total_size, 2, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesClimateResponse::dump_to(std::string &out) const {
|
||||
@@ -4436,6 +4665,11 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const {
|
||||
sprintf(buffer, "%g", this->visual_max_humidity);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -4901,6 +5135,10 @@ bool ListEntitiesNumberResponse::decode_varint(uint32_t field_id, ProtoVarInt va
|
||||
this->mode = value.as_enum<enums::NumberMode>();
|
||||
return true;
|
||||
}
|
||||
case 14: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -4971,6 +5209,7 @@ void ListEntitiesNumberResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_string(11, this->unit_of_measurement);
|
||||
buffer.encode_enum<enums::NumberMode>(12, this->mode);
|
||||
buffer.encode_string(13, this->device_class);
|
||||
buffer.encode_uint32(14, this->device_id);
|
||||
}
|
||||
void ListEntitiesNumberResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -4986,6 +5225,7 @@ void ListEntitiesNumberResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->unit_of_measurement, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->mode), false);
|
||||
ProtoSize::add_string_field(total_size, 1, this->device_class, false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesNumberResponse::dump_to(std::string &out) const {
|
||||
@@ -5046,6 +5286,11 @@ void ListEntitiesNumberResponse::dump_to(std::string &out) const {
|
||||
out.append(" device_class: ");
|
||||
out.append("'").append(this->device_class).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -5151,6 +5396,10 @@ bool ListEntitiesSelectResponse::decode_varint(uint32_t field_id, ProtoVarInt va
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 9: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -5202,6 +5451,7 @@ void ListEntitiesSelectResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
}
|
||||
buffer.encode_bool(7, this->disabled_by_default);
|
||||
buffer.encode_enum<enums::EntityCategory>(8, this->entity_category);
|
||||
buffer.encode_uint32(9, this->device_id);
|
||||
}
|
||||
void ListEntitiesSelectResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -5216,6 +5466,7 @@ void ListEntitiesSelectResponse::calculate_size(uint32_t &total_size) const {
|
||||
}
|
||||
ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesSelectResponse::dump_to(std::string &out) const {
|
||||
@@ -5255,6 +5506,11 @@ void ListEntitiesSelectResponse::dump_to(std::string &out) const {
|
||||
out.append(" entity_category: ");
|
||||
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -5378,6 +5634,10 @@ bool ListEntitiesSirenResponse::decode_varint(uint32_t field_id, ProtoVarInt val
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 11: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -5431,6 +5691,7 @@ void ListEntitiesSirenResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(8, this->supports_duration);
|
||||
buffer.encode_bool(9, this->supports_volume);
|
||||
buffer.encode_enum<enums::EntityCategory>(10, this->entity_category);
|
||||
buffer.encode_uint32(11, this->device_id);
|
||||
}
|
||||
void ListEntitiesSirenResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -5447,6 +5708,7 @@ void ListEntitiesSirenResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_bool_field(total_size, 1, this->supports_duration, false);
|
||||
ProtoSize::add_bool_field(total_size, 1, this->supports_volume, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesSirenResponse::dump_to(std::string &out) const {
|
||||
@@ -5494,6 +5756,11 @@ void ListEntitiesSirenResponse::dump_to(std::string &out) const {
|
||||
out.append(" entity_category: ");
|
||||
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -5683,6 +5950,10 @@ bool ListEntitiesLockResponse::decode_varint(uint32_t field_id, ProtoVarInt valu
|
||||
this->requires_code = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
case 12: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -5735,6 +6006,7 @@ void ListEntitiesLockResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(9, this->supports_open);
|
||||
buffer.encode_bool(10, this->requires_code);
|
||||
buffer.encode_string(11, this->code_format);
|
||||
buffer.encode_uint32(12, this->device_id);
|
||||
}
|
||||
void ListEntitiesLockResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -5748,6 +6020,7 @@ void ListEntitiesLockResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_bool_field(total_size, 1, this->supports_open, false);
|
||||
ProtoSize::add_bool_field(total_size, 1, this->requires_code, false);
|
||||
ProtoSize::add_string_field(total_size, 1, this->code_format, false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesLockResponse::dump_to(std::string &out) const {
|
||||
@@ -5797,6 +6070,11 @@ void ListEntitiesLockResponse::dump_to(std::string &out) const {
|
||||
out.append(" code_format: ");
|
||||
out.append("'").append(this->code_format).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -5922,6 +6200,10 @@ bool ListEntitiesButtonResponse::decode_varint(uint32_t field_id, ProtoVarInt va
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 9: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -5971,6 +6253,7 @@ void ListEntitiesButtonResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(6, this->disabled_by_default);
|
||||
buffer.encode_enum<enums::EntityCategory>(7, this->entity_category);
|
||||
buffer.encode_string(8, this->device_class);
|
||||
buffer.encode_uint32(9, this->device_id);
|
||||
}
|
||||
void ListEntitiesButtonResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -5981,6 +6264,7 @@ void ListEntitiesButtonResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_string_field(total_size, 1, this->device_class, false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesButtonResponse::dump_to(std::string &out) const {
|
||||
@@ -6018,6 +6302,11 @@ void ListEntitiesButtonResponse::dump_to(std::string &out) const {
|
||||
out.append(" device_class: ");
|
||||
out.append("'").append(this->device_class).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -6135,6 +6424,10 @@ bool ListEntitiesMediaPlayerResponse::decode_varint(uint32_t field_id, ProtoVarI
|
||||
this->supports_pause = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
case 10: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -6187,6 +6480,7 @@ void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
for (auto &it : this->supported_formats) {
|
||||
buffer.encode_message<MediaPlayerSupportedFormat>(9, it, true);
|
||||
}
|
||||
buffer.encode_uint32(10, this->device_id);
|
||||
}
|
||||
void ListEntitiesMediaPlayerResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -6198,6 +6492,7 @@ void ListEntitiesMediaPlayerResponse::calculate_size(uint32_t &total_size) const
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_bool_field(total_size, 1, this->supports_pause, false);
|
||||
ProtoSize::add_repeated_message(total_size, 1, this->supported_formats);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const {
|
||||
@@ -6241,6 +6536,11 @@ void ListEntitiesMediaPlayerResponse::dump_to(std::string &out) const {
|
||||
it.dump_to(out);
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -8551,6 +8851,10 @@ bool ListEntitiesAlarmControlPanelResponse::decode_varint(uint32_t field_id, Pro
|
||||
this->requires_code_to_arm = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
case 11: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -8598,6 +8902,7 @@ void ListEntitiesAlarmControlPanelResponse::encode(ProtoWriteBuffer buffer) cons
|
||||
buffer.encode_uint32(8, this->supported_features);
|
||||
buffer.encode_bool(9, this->requires_code);
|
||||
buffer.encode_bool(10, this->requires_code_to_arm);
|
||||
buffer.encode_uint32(11, this->device_id);
|
||||
}
|
||||
void ListEntitiesAlarmControlPanelResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -8610,6 +8915,7 @@ void ListEntitiesAlarmControlPanelResponse::calculate_size(uint32_t &total_size)
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->supported_features, false);
|
||||
ProtoSize::add_bool_field(total_size, 1, this->requires_code, false);
|
||||
ProtoSize::add_bool_field(total_size, 1, this->requires_code_to_arm, false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesAlarmControlPanelResponse::dump_to(std::string &out) const {
|
||||
@@ -8656,6 +8962,11 @@ void ListEntitiesAlarmControlPanelResponse::dump_to(std::string &out) const {
|
||||
out.append(" requires_code_to_arm: ");
|
||||
out.append(YESNO(this->requires_code_to_arm));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -8783,6 +9094,10 @@ bool ListEntitiesTextResponse::decode_varint(uint32_t field_id, ProtoVarInt valu
|
||||
this->mode = value.as_enum<enums::TextMode>();
|
||||
return true;
|
||||
}
|
||||
case 12: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -8835,6 +9150,7 @@ void ListEntitiesTextResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_uint32(9, this->max_length);
|
||||
buffer.encode_string(10, this->pattern);
|
||||
buffer.encode_enum<enums::TextMode>(11, this->mode);
|
||||
buffer.encode_uint32(12, this->device_id);
|
||||
}
|
||||
void ListEntitiesTextResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -8848,6 +9164,7 @@ void ListEntitiesTextResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->max_length, false);
|
||||
ProtoSize::add_string_field(total_size, 1, this->pattern, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->mode), false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesTextResponse::dump_to(std::string &out) const {
|
||||
@@ -8899,6 +9216,11 @@ void ListEntitiesTextResponse::dump_to(std::string &out) const {
|
||||
out.append(" mode: ");
|
||||
out.append(proto_enum_to_string<enums::TextMode>(this->mode));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -9014,6 +9336,10 @@ bool ListEntitiesDateResponse::decode_varint(uint32_t field_id, ProtoVarInt valu
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 8: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -9058,6 +9384,7 @@ void ListEntitiesDateResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_string(5, this->icon);
|
||||
buffer.encode_bool(6, this->disabled_by_default);
|
||||
buffer.encode_enum<enums::EntityCategory>(7, this->entity_category);
|
||||
buffer.encode_uint32(8, this->device_id);
|
||||
}
|
||||
void ListEntitiesDateResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -9067,6 +9394,7 @@ void ListEntitiesDateResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->icon, false);
|
||||
ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesDateResponse::dump_to(std::string &out) const {
|
||||
@@ -9100,6 +9428,11 @@ void ListEntitiesDateResponse::dump_to(std::string &out) const {
|
||||
out.append(" entity_category: ");
|
||||
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -9255,6 +9588,10 @@ bool ListEntitiesTimeResponse::decode_varint(uint32_t field_id, ProtoVarInt valu
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 8: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -9299,6 +9636,7 @@ void ListEntitiesTimeResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_string(5, this->icon);
|
||||
buffer.encode_bool(6, this->disabled_by_default);
|
||||
buffer.encode_enum<enums::EntityCategory>(7, this->entity_category);
|
||||
buffer.encode_uint32(8, this->device_id);
|
||||
}
|
||||
void ListEntitiesTimeResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -9308,6 +9646,7 @@ void ListEntitiesTimeResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->icon, false);
|
||||
ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesTimeResponse::dump_to(std::string &out) const {
|
||||
@@ -9341,6 +9680,11 @@ void ListEntitiesTimeResponse::dump_to(std::string &out) const {
|
||||
out.append(" entity_category: ");
|
||||
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -9496,6 +9840,10 @@ bool ListEntitiesEventResponse::decode_varint(uint32_t field_id, ProtoVarInt val
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 10: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -9552,6 +9900,7 @@ void ListEntitiesEventResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
for (auto &it : this->event_types) {
|
||||
buffer.encode_string(9, it, true);
|
||||
}
|
||||
buffer.encode_uint32(10, this->device_id);
|
||||
}
|
||||
void ListEntitiesEventResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -9567,6 +9916,7 @@ void ListEntitiesEventResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, it, true);
|
||||
}
|
||||
}
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesEventResponse::dump_to(std::string &out) const {
|
||||
@@ -9610,6 +9960,11 @@ void ListEntitiesEventResponse::dump_to(std::string &out) const {
|
||||
out.append("'").append(it).append("'");
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -9678,6 +10033,10 @@ bool ListEntitiesValveResponse::decode_varint(uint32_t field_id, ProtoVarInt val
|
||||
this->supports_stop = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
case 12: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -9730,6 +10089,7 @@ void ListEntitiesValveResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(9, this->assumed_state);
|
||||
buffer.encode_bool(10, this->supports_position);
|
||||
buffer.encode_bool(11, this->supports_stop);
|
||||
buffer.encode_uint32(12, this->device_id);
|
||||
}
|
||||
void ListEntitiesValveResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -9743,6 +10103,7 @@ void ListEntitiesValveResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_bool_field(total_size, 1, this->assumed_state, false);
|
||||
ProtoSize::add_bool_field(total_size, 1, this->supports_position, false);
|
||||
ProtoSize::add_bool_field(total_size, 1, this->supports_stop, false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesValveResponse::dump_to(std::string &out) const {
|
||||
@@ -9792,6 +10153,11 @@ void ListEntitiesValveResponse::dump_to(std::string &out) const {
|
||||
out.append(" supports_stop: ");
|
||||
out.append(YESNO(this->supports_stop));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -9923,6 +10289,10 @@ bool ListEntitiesDateTimeResponse::decode_varint(uint32_t field_id, ProtoVarInt
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 8: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -9967,6 +10337,7 @@ void ListEntitiesDateTimeResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_string(5, this->icon);
|
||||
buffer.encode_bool(6, this->disabled_by_default);
|
||||
buffer.encode_enum<enums::EntityCategory>(7, this->entity_category);
|
||||
buffer.encode_uint32(8, this->device_id);
|
||||
}
|
||||
void ListEntitiesDateTimeResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -9976,6 +10347,7 @@ void ListEntitiesDateTimeResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->icon, false);
|
||||
ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesDateTimeResponse::dump_to(std::string &out) const {
|
||||
@@ -10009,6 +10381,11 @@ void ListEntitiesDateTimeResponse::dump_to(std::string &out) const {
|
||||
out.append(" entity_category: ");
|
||||
out.append(proto_enum_to_string<enums::EntityCategory>(this->entity_category));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
@@ -10114,6 +10491,10 @@ bool ListEntitiesUpdateResponse::decode_varint(uint32_t field_id, ProtoVarInt va
|
||||
this->entity_category = value.as_enum<enums::EntityCategory>();
|
||||
return true;
|
||||
}
|
||||
case 9: {
|
||||
this->device_id = value.as_uint32();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -10163,6 +10544,7 @@ void ListEntitiesUpdateResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(6, this->disabled_by_default);
|
||||
buffer.encode_enum<enums::EntityCategory>(7, this->entity_category);
|
||||
buffer.encode_string(8, this->device_class);
|
||||
buffer.encode_uint32(9, this->device_id);
|
||||
}
|
||||
void ListEntitiesUpdateResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_string_field(total_size, 1, this->object_id, false);
|
||||
@@ -10173,6 +10555,7 @@ void ListEntitiesUpdateResponse::calculate_size(uint32_t &total_size) const {
|
||||
ProtoSize::add_bool_field(total_size, 1, this->disabled_by_default, false);
|
||||
ProtoSize::add_enum_field(total_size, 1, static_cast<uint32_t>(this->entity_category), false);
|
||||
ProtoSize::add_string_field(total_size, 1, this->device_class, false);
|
||||
ProtoSize::add_uint32_field(total_size, 1, this->device_id, false);
|
||||
}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void ListEntitiesUpdateResponse::dump_to(std::string &out) const {
|
||||
@@ -10210,6 +10593,11 @@ void ListEntitiesUpdateResponse::dump_to(std::string &out) const {
|
||||
out.append(" device_class: ");
|
||||
out.append("'").append(this->device_class).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" device_id: ");
|
||||
sprintf(buffer, "%" PRIu32, this->device_id);
|
||||
out.append(buffer);
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
#endif
|
||||
|
@@ -264,6 +264,7 @@ class InfoResponseProtoMessage : public ProtoMessage {
|
||||
bool disabled_by_default{false};
|
||||
std::string icon{};
|
||||
enums::EntityCategory entity_category{};
|
||||
uint32_t device_id{0};
|
||||
|
||||
protected:
|
||||
};
|
||||
@@ -415,10 +416,39 @@ class DeviceInfoRequest : public ProtoMessage {
|
||||
|
||||
protected:
|
||||
};
|
||||
class AreaInfo : public ProtoMessage {
|
||||
public:
|
||||
uint32_t area_id{0};
|
||||
std::string name{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||
};
|
||||
class DeviceInfo : public ProtoMessage {
|
||||
public:
|
||||
uint32_t device_id{0};
|
||||
std::string name{};
|
||||
uint32_t area_id{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
void dump_to(std::string &out) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||
};
|
||||
class DeviceInfoResponse : public ProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 10;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 129;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 219;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "device_info_response"; }
|
||||
#endif
|
||||
@@ -441,6 +471,9 @@ class DeviceInfoResponse : public ProtoMessage {
|
||||
std::string suggested_area{};
|
||||
std::string bluetooth_mac_address{};
|
||||
bool api_encryption_supported{false};
|
||||
std::vector<DeviceInfo> devices{};
|
||||
std::vector<AreaInfo> areas{};
|
||||
AreaInfo area{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(uint32_t &total_size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
@@ -493,7 +526,7 @@ class SubscribeStatesRequest : public ProtoMessage {
|
||||
class ListEntitiesBinarySensorResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 12;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 56;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 60;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_binary_sensor_response"; }
|
||||
#endif
|
||||
@@ -532,7 +565,7 @@ class BinarySensorStateResponse : public StateResponseProtoMessage {
|
||||
class ListEntitiesCoverResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 13;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 62;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 66;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_cover_response"; }
|
||||
#endif
|
||||
@@ -601,7 +634,7 @@ class CoverCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesFanResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 14;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 73;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 77;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_fan_response"; }
|
||||
#endif
|
||||
@@ -679,7 +712,7 @@ class FanCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesLightResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 15;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 85;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 90;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_light_response"; }
|
||||
#endif
|
||||
@@ -780,7 +813,7 @@ class LightCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesSensorResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 16;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 73;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 77;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_sensor_response"; }
|
||||
#endif
|
||||
@@ -823,7 +856,7 @@ class SensorStateResponse : public StateResponseProtoMessage {
|
||||
class ListEntitiesSwitchResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 17;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 56;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 60;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_switch_response"; }
|
||||
#endif
|
||||
@@ -880,7 +913,7 @@ class SwitchCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesTextSensorResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 18;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 54;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 58;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_text_sensor_response"; }
|
||||
#endif
|
||||
@@ -1196,7 +1229,7 @@ class ExecuteServiceRequest : public ProtoMessage {
|
||||
class ListEntitiesCameraResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 43;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 45;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 49;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_camera_response"; }
|
||||
#endif
|
||||
@@ -1253,7 +1286,7 @@ class CameraImageRequest : public ProtoMessage {
|
||||
class ListEntitiesClimateResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 46;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 151;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 156;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_climate_response"; }
|
||||
#endif
|
||||
@@ -1362,7 +1395,7 @@ class ClimateCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesNumberResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 49;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 80;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 84;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_number_response"; }
|
||||
#endif
|
||||
@@ -1423,7 +1456,7 @@ class NumberCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesSelectResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 52;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 63;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 67;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_select_response"; }
|
||||
#endif
|
||||
@@ -1481,7 +1514,7 @@ class SelectCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesSirenResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 55;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 67;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 71;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_siren_response"; }
|
||||
#endif
|
||||
@@ -1547,7 +1580,7 @@ class SirenCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesLockResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 58;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 60;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 64;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_lock_response"; }
|
||||
#endif
|
||||
@@ -1609,7 +1642,7 @@ class LockCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesButtonResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 61;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 54;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 58;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_button_response"; }
|
||||
#endif
|
||||
@@ -1662,7 +1695,7 @@ class MediaPlayerSupportedFormat : public ProtoMessage {
|
||||
class ListEntitiesMediaPlayerResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 63;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 81;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 85;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_media_player_response"; }
|
||||
#endif
|
||||
@@ -2532,7 +2565,7 @@ class VoiceAssistantSetConfiguration : public ProtoMessage {
|
||||
class ListEntitiesAlarmControlPanelResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 94;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 53;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 57;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_alarm_control_panel_response"; }
|
||||
#endif
|
||||
@@ -2592,7 +2625,7 @@ class AlarmControlPanelCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesTextResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 97;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 64;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 68;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_text_response"; }
|
||||
#endif
|
||||
@@ -2653,7 +2686,7 @@ class TextCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesDateResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 100;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 45;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 49;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_date_response"; }
|
||||
#endif
|
||||
@@ -2713,7 +2746,7 @@ class DateCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesTimeResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 103;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 45;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 49;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_time_response"; }
|
||||
#endif
|
||||
@@ -2773,7 +2806,7 @@ class TimeCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesEventResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 107;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 72;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 76;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_event_response"; }
|
||||
#endif
|
||||
@@ -2811,7 +2844,7 @@ class EventResponse : public StateResponseProtoMessage {
|
||||
class ListEntitiesValveResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 109;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 60;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 64;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_valve_response"; }
|
||||
#endif
|
||||
@@ -2873,7 +2906,7 @@ class ValveCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesDateTimeResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 112;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 45;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 49;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_date_time_response"; }
|
||||
#endif
|
||||
@@ -2928,7 +2961,7 @@ class DateTimeCommandRequest : public ProtoMessage {
|
||||
class ListEntitiesUpdateResponse : public InfoResponseProtoMessage {
|
||||
public:
|
||||
static constexpr uint16_t MESSAGE_TYPE = 116;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 54;
|
||||
static constexpr uint16_t ESTIMATED_SIZE = 58;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
static constexpr const char *message_name() { return "list_entities_update_response"; }
|
||||
#endif
|
||||
|
@@ -1,5 +1,7 @@
|
||||
"""Helpers for config validation using voluptuous."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import contextmanager
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
@@ -29,6 +31,7 @@ from esphome.const import (
|
||||
CONF_COMMAND_RETAIN,
|
||||
CONF_COMMAND_TOPIC,
|
||||
CONF_DAY,
|
||||
CONF_DEVICE_ID,
|
||||
CONF_DISABLED_BY_DEFAULT,
|
||||
CONF_DISCOVERY,
|
||||
CONF_ENTITY_CATEGORY,
|
||||
@@ -355,6 +358,13 @@ def icon(value):
|
||||
)
|
||||
|
||||
|
||||
def sub_device_id(value: str | None) -> core.ID:
|
||||
# Lazy import to avoid circular imports
|
||||
from esphome.core.config import Device
|
||||
|
||||
return use_id(Device)(value)
|
||||
|
||||
|
||||
def boolean(value):
|
||||
"""Validate the given config option to be a boolean.
|
||||
|
||||
@@ -1896,6 +1906,7 @@ ENTITY_BASE_SCHEMA = Schema(
|
||||
Optional(CONF_DISABLED_BY_DEFAULT, default=False): boolean,
|
||||
Optional(CONF_ICON): icon,
|
||||
Optional(CONF_ENTITY_CATEGORY): entity_category,
|
||||
Optional(CONF_DEVICE_ID): sub_device_id,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1964,7 +1975,7 @@ class Version:
|
||||
return f"{self.major}.{self.minor}.{self.patch}"
|
||||
|
||||
@classmethod
|
||||
def parse(cls, value: str) -> "Version":
|
||||
def parse(cls, value: str) -> Version:
|
||||
match = re.match(r"^(\d+).(\d+).(\d+)-?\w*$", value)
|
||||
if match is None:
|
||||
raise ValueError(f"Not a valid version number {value}")
|
||||
|
@@ -56,6 +56,8 @@ CONF_AP = "ap"
|
||||
CONF_APPARENT_POWER = "apparent_power"
|
||||
CONF_ARDUINO_VERSION = "arduino_version"
|
||||
CONF_AREA = "area"
|
||||
CONF_AREA_ID = "area_id"
|
||||
CONF_AREAS = "areas"
|
||||
CONF_ARGS = "args"
|
||||
CONF_ASSUMED_STATE = "assumed_state"
|
||||
CONF_AT = "at"
|
||||
@@ -217,6 +219,7 @@ CONF_DEST = "dest"
|
||||
CONF_DEVICE = "device"
|
||||
CONF_DEVICE_CLASS = "device_class"
|
||||
CONF_DEVICE_FACTOR = "device_factor"
|
||||
CONF_DEVICE_ID = "device_id"
|
||||
CONF_DEVICES = "devices"
|
||||
CONF_DIELECTRIC_CONSTANT = "dielectric_constant"
|
||||
CONF_DIMENSIONS = "dimensions"
|
||||
|
@@ -10,6 +10,13 @@
|
||||
#include "esphome/core/runtime_stats.h"
|
||||
#include "esphome/core/scheduler.h"
|
||||
|
||||
#ifdef USE_DEVICES
|
||||
#include "esphome/core/device.h"
|
||||
#endif
|
||||
#ifdef USE_AREAS
|
||||
#include "esphome/core/area.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_SOCKET_SELECT_SUPPORT
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
@@ -88,7 +95,7 @@ static const uint32_t TEARDOWN_TIMEOUT_REBOOT_MS = 1000; // 1 second for quick
|
||||
|
||||
class Application {
|
||||
public:
|
||||
void pre_setup(const std::string &name, const std::string &friendly_name, const char *area, const char *comment,
|
||||
void pre_setup(const std::string &name, const std::string &friendly_name, const char *comment,
|
||||
const char *compilation_time, bool name_add_mac_suffix) {
|
||||
arch_init();
|
||||
this->name_add_mac_suffix_ = name_add_mac_suffix;
|
||||
@@ -103,11 +110,18 @@ class Application {
|
||||
this->name_ = name;
|
||||
this->friendly_name_ = friendly_name;
|
||||
}
|
||||
this->area_ = area;
|
||||
// area is now handled through the areas system
|
||||
this->comment_ = comment;
|
||||
this->compilation_time_ = compilation_time;
|
||||
}
|
||||
|
||||
#ifdef USE_DEVICES
|
||||
void register_device(Device *device) { this->devices_.push_back(device); }
|
||||
#endif
|
||||
#ifdef USE_AREAS
|
||||
void register_area(Area *area) { this->areas_.push_back(area); }
|
||||
#endif
|
||||
|
||||
void set_current_component(Component *component) { this->current_component_ = component; }
|
||||
Component *get_current_component() { return this->current_component_; }
|
||||
|
||||
@@ -265,6 +279,12 @@ class Application {
|
||||
#ifdef USE_UPDATE
|
||||
void reserve_update(size_t count) { this->updates_.reserve(count); }
|
||||
#endif
|
||||
#ifdef USE_AREAS
|
||||
void reserve_area(size_t count) { this->areas_.reserve(count); }
|
||||
#endif
|
||||
#ifdef USE_DEVICES
|
||||
void reserve_device(size_t count) { this->devices_.reserve(count); }
|
||||
#endif
|
||||
|
||||
/// Register the component in this Application instance.
|
||||
template<class C> C *register_component(C *c) {
|
||||
@@ -286,7 +306,15 @@ class Application {
|
||||
const std::string &get_friendly_name() const { return this->friendly_name_; }
|
||||
|
||||
/// Get the area of this Application set by pre_setup().
|
||||
std::string get_area() const { return this->area_ == nullptr ? "" : this->area_; }
|
||||
const char *get_area() const {
|
||||
#ifdef USE_AREAS
|
||||
// If we have areas registered, return the name of the first one (which is the top-level area)
|
||||
if (!this->areas_.empty() && this->areas_[0] != nullptr) {
|
||||
return this->areas_[0]->get_name();
|
||||
}
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
|
||||
/// Get the comment of this Application set by pre_setup().
|
||||
std::string get_comment() const { return this->comment_; }
|
||||
@@ -347,6 +375,12 @@ class Application {
|
||||
|
||||
uint8_t get_app_state() const { return this->app_state_; }
|
||||
|
||||
#ifdef USE_DEVICES
|
||||
const std::vector<Device *> &get_devices() { return this->devices_; }
|
||||
#endif
|
||||
#ifdef USE_AREAS
|
||||
const std::vector<Area *> &get_areas() { return this->areas_; }
|
||||
#endif
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
const std::vector<binary_sensor::BinarySensor *> &get_binary_sensors() { return this->binary_sensors_; }
|
||||
binary_sensor::BinarySensor *get_binary_sensor_by_key(uint32_t key, bool include_internal = false) {
|
||||
@@ -623,6 +657,12 @@ class Application {
|
||||
uint16_t current_loop_index_{0};
|
||||
bool in_loop_{false};
|
||||
|
||||
#ifdef USE_DEVICES
|
||||
std::vector<Device *> devices_{};
|
||||
#endif
|
||||
#ifdef USE_AREAS
|
||||
std::vector<Area *> areas_{};
|
||||
#endif
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
std::vector<binary_sensor::BinarySensor *> binary_sensors_{};
|
||||
#endif
|
||||
@@ -689,7 +729,6 @@ class Application {
|
||||
|
||||
std::string name_;
|
||||
std::string friendly_name_;
|
||||
const char *area_{nullptr};
|
||||
const char *comment_{nullptr};
|
||||
const char *compilation_time_{nullptr};
|
||||
bool name_add_mac_suffix_;
|
||||
|
19
esphome/core/area.h
Normal file
19
esphome/core/area.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace esphome {
|
||||
|
||||
class Area {
|
||||
public:
|
||||
void set_area_id(uint32_t area_id) { this->area_id_ = area_id; }
|
||||
uint32_t get_area_id() { return this->area_id_; }
|
||||
void set_name(const char *name) { this->name_ = name; }
|
||||
const char *get_name() { return this->name_; }
|
||||
|
||||
protected:
|
||||
uint32_t area_id_{};
|
||||
const char *name_ = "";
|
||||
};
|
||||
|
||||
} // namespace esphome
|
@@ -1,18 +1,24 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from esphome import automation
|
||||
from esphome import automation, core
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_AREA,
|
||||
CONF_AREA_ID,
|
||||
CONF_AREAS,
|
||||
CONF_BUILD_PATH,
|
||||
CONF_COMMENT,
|
||||
CONF_COMPILE_PROCESS_LIMIT,
|
||||
CONF_DEBUG_SCHEDULER,
|
||||
CONF_DEVICES,
|
||||
CONF_ESPHOME,
|
||||
CONF_FRIENDLY_NAME,
|
||||
CONF_ID,
|
||||
CONF_INCLUDES,
|
||||
CONF_LIBRARIES,
|
||||
CONF_MIN_VERSION,
|
||||
@@ -32,7 +38,13 @@ from esphome.const import (
|
||||
__version__ as ESPHOME_VERSION,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.helpers import copy_file_if_changed, get_str_env, walk_files
|
||||
from esphome.helpers import (
|
||||
copy_file_if_changed,
|
||||
fnv1a_32bit_hash,
|
||||
get_str_env,
|
||||
walk_files,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -48,7 +60,8 @@ LoopTrigger = cg.esphome_ns.class_(
|
||||
ProjectUpdateTrigger = cg.esphome_ns.class_(
|
||||
"ProjectUpdateTrigger", cg.Component, automation.Trigger.template(cg.std_string)
|
||||
)
|
||||
|
||||
Device = cg.esphome_ns.class_("Device")
|
||||
Area = cg.esphome_ns.class_("Area")
|
||||
|
||||
VALID_INCLUDE_EXTS = {".h", ".hpp", ".tcc", ".ino", ".cpp", ".c"}
|
||||
|
||||
@@ -71,6 +84,56 @@ def validate_hostname(config):
|
||||
return config
|
||||
|
||||
|
||||
def validate_ids_and_references(config: ConfigType) -> ConfigType:
|
||||
"""Validate that there are no hash collisions between IDs and that area_id references are valid.
|
||||
|
||||
This validation is critical because we use 32-bit hashes for performance on microcontrollers.
|
||||
By detecting collisions at compile time, we prevent any runtime issues while maintaining
|
||||
optimal performance on 32-bit platforms. In practice, with typical deployments having only
|
||||
a handful of areas and devices, hash collisions are virtually impossible.
|
||||
"""
|
||||
|
||||
# Helper to check hash collisions
|
||||
def check_hash_collision(
|
||||
id_obj: core.ID,
|
||||
hash_dict: dict[int, str],
|
||||
item_type: str,
|
||||
path: list[str | int],
|
||||
) -> None:
|
||||
hash_val: int = fnv1a_32bit_hash(id_obj.id)
|
||||
if hash_val in hash_dict and hash_dict[hash_val] != id_obj.id:
|
||||
raise cv.Invalid(
|
||||
f"{item_type} ID '{id_obj.id}' with hash {hash_val} collides with "
|
||||
f"existing {item_type.lower()} ID '{hash_dict[hash_val]}'",
|
||||
path=path,
|
||||
)
|
||||
hash_dict[hash_val] = id_obj.id
|
||||
|
||||
# Collect all areas
|
||||
all_areas: list[dict[str, str | core.ID]] = []
|
||||
if CONF_AREA in config:
|
||||
all_areas.append(config[CONF_AREA])
|
||||
all_areas.extend(config[CONF_AREAS])
|
||||
|
||||
# Validate area hash collisions and collect IDs
|
||||
area_hashes: dict[int, str] = {}
|
||||
area_ids: set[str] = set()
|
||||
for area in all_areas:
|
||||
area_id: core.ID = area[CONF_ID]
|
||||
check_hash_collision(area_id, area_hashes, "Area", [CONF_AREAS, area_id.id])
|
||||
area_ids.add(area_id.id)
|
||||
|
||||
# Validate device hash collisions and area references
|
||||
device_hashes: dict[int, str] = {}
|
||||
for device in config[CONF_DEVICES]:
|
||||
device_id: core.ID = device[CONF_ID]
|
||||
check_hash_collision(
|
||||
device_id, device_hashes, "Device", [CONF_DEVICES, device_id.id]
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def valid_include(value):
|
||||
# Look for "<...>" includes
|
||||
if value.startswith("<") and value.endswith(">"):
|
||||
@@ -111,13 +174,32 @@ if "ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT" in os.environ:
|
||||
else:
|
||||
_compile_process_limit_default = cv.UNDEFINED
|
||||
|
||||
AREA_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_ID): cv.declare_id(Area),
|
||||
cv.Required(CONF_NAME): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
DEVICE_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_ID): cv.declare_id(Device),
|
||||
cv.Required(CONF_NAME): cv.string,
|
||||
cv.Optional(CONF_AREA_ID): cv.use_id(Area),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def validate_area_config(config: dict | str) -> dict[str, str | core.ID]:
|
||||
return cv.maybe_simple_value(AREA_SCHEMA, key=CONF_NAME)(config)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_NAME): cv.valid_name,
|
||||
cv.Optional(CONF_FRIENDLY_NAME, ""): cv.string,
|
||||
cv.Optional(CONF_AREA, ""): cv.string,
|
||||
cv.Optional(CONF_AREA): validate_area_config,
|
||||
cv.Optional(CONF_COMMENT): cv.string,
|
||||
cv.Required(CONF_BUILD_PATH): cv.string,
|
||||
cv.Optional(CONF_PLATFORMIO_OPTIONS, default={}): cv.Schema(
|
||||
@@ -167,11 +249,17 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(
|
||||
CONF_COMPILE_PROCESS_LIMIT, default=_compile_process_limit_default
|
||||
): cv.int_range(min=1, max=get_usable_cpu_count()),
|
||||
cv.Optional(CONF_AREAS, default=[]): cv.ensure_list(AREA_SCHEMA),
|
||||
cv.Optional(CONF_DEVICES, default=[]): cv.ensure_list(DEVICE_SCHEMA),
|
||||
}
|
||||
),
|
||||
validate_hostname,
|
||||
)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = cv.All(validate_ids_and_references)
|
||||
|
||||
|
||||
PRELOAD_CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_NAME): cv.valid_name,
|
||||
@@ -336,7 +424,7 @@ async def _add_platform_reserves() -> None:
|
||||
|
||||
|
||||
@coroutine_with_priority(100.0)
|
||||
async def to_code(config):
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
cg.add_global(cg.global_ns.namespace("esphome").using)
|
||||
# These can be used by user lambdas, put them to default scope
|
||||
cg.add_global(cg.RawExpression("using std::isnan"))
|
||||
@@ -347,7 +435,6 @@ async def to_code(config):
|
||||
cg.App.pre_setup(
|
||||
config[CONF_NAME],
|
||||
config[CONF_FRIENDLY_NAME],
|
||||
config[CONF_AREA],
|
||||
config.get(CONF_COMMENT, ""),
|
||||
cg.RawExpression('__DATE__ ", " __TIME__'),
|
||||
config[CONF_NAME_ADD_MAC_SUFFIX],
|
||||
@@ -417,3 +504,50 @@ async def to_code(config):
|
||||
|
||||
if config[CONF_PLATFORMIO_OPTIONS]:
|
||||
CORE.add_job(_add_platformio_options, config[CONF_PLATFORMIO_OPTIONS])
|
||||
|
||||
# Process areas
|
||||
all_areas: list[dict[str, str | core.ID]] = []
|
||||
if CONF_AREA in config:
|
||||
all_areas.append(config[CONF_AREA])
|
||||
all_areas.extend(config[CONF_AREAS])
|
||||
|
||||
if all_areas:
|
||||
cg.add(cg.RawStatement(f"App.reserve_area({len(all_areas)});"))
|
||||
cg.add_define("USE_AREAS")
|
||||
|
||||
for area_conf in all_areas:
|
||||
area_id: core.ID = area_conf[CONF_ID]
|
||||
area_id_hash: int = fnv1a_32bit_hash(area_id.id)
|
||||
area_name: str = area_conf[CONF_NAME]
|
||||
|
||||
area_var = cg.new_Pvariable(area_id)
|
||||
cg.add(area_var.set_area_id(area_id_hash))
|
||||
cg.add(area_var.set_name(area_name))
|
||||
cg.add(cg.App.register_area(area_var))
|
||||
|
||||
# Process devices
|
||||
devices: list[dict[str, str | core.ID]] = config[CONF_DEVICES]
|
||||
if not devices:
|
||||
return
|
||||
|
||||
# Reserve space for devices
|
||||
cg.add(cg.RawStatement(f"App.reserve_device({len(devices)});"))
|
||||
cg.add_define("USE_DEVICES")
|
||||
|
||||
# Process each device
|
||||
for dev_conf in devices:
|
||||
device_id: core.ID = dev_conf[CONF_ID]
|
||||
device_id_hash = fnv1a_32bit_hash(device_id.id)
|
||||
device_name: str = dev_conf[CONF_NAME]
|
||||
|
||||
dev = cg.new_Pvariable(device_id)
|
||||
cg.add(dev.set_device_id(device_id_hash))
|
||||
cg.add(dev.set_name(device_name))
|
||||
|
||||
# Set area if specified
|
||||
if CONF_AREA_ID in dev_conf:
|
||||
area_id: core.ID = dev_conf[CONF_AREA_ID]
|
||||
area_id_hash = fnv1a_32bit_hash(area_id.id)
|
||||
cg.add(dev.set_area_id(area_id_hash))
|
||||
|
||||
cg.add(cg.App.register_device(dev))
|
||||
|
@@ -20,6 +20,7 @@
|
||||
|
||||
// Feature flags
|
||||
#define USE_ALARM_CONTROL_PANEL
|
||||
#define USE_AREAS
|
||||
#define USE_BINARY_SENSOR
|
||||
#define USE_BUTTON
|
||||
#define USE_CLIMATE
|
||||
@@ -29,6 +30,7 @@
|
||||
#define USE_DATETIME_DATETIME
|
||||
#define USE_DATETIME_TIME
|
||||
#define USE_DEEP_SLEEP
|
||||
#define USE_DEVICES
|
||||
#define USE_DISPLAY
|
||||
#define USE_ESP32_IMPROV_STATE_CALLBACK
|
||||
#define USE_EVENT
|
||||
|
20
esphome/core/device.h
Normal file
20
esphome/core/device.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
namespace esphome {
|
||||
|
||||
class Device {
|
||||
public:
|
||||
void set_device_id(uint32_t device_id) { this->device_id_ = device_id; }
|
||||
uint32_t get_device_id() { return this->device_id_; }
|
||||
void set_name(const char *name) { this->name_ = name; }
|
||||
const char *get_name() { return this->name_; }
|
||||
void set_area_id(uint32_t area_id) { this->area_id_ = area_id; }
|
||||
uint32_t get_area_id() { return this->area_id_; }
|
||||
|
||||
protected:
|
||||
uint32_t device_id_{};
|
||||
uint32_t area_id_{};
|
||||
const char *name_ = "";
|
||||
};
|
||||
|
||||
} // namespace esphome
|
@@ -51,6 +51,12 @@ class EntityBase {
|
||||
std::string get_icon() const;
|
||||
void set_icon(const char *icon);
|
||||
|
||||
#ifdef USE_DEVICES
|
||||
// Get/set this entity's device id
|
||||
uint32_t get_device_id() const { return this->device_id_; }
|
||||
void set_device_id(const uint32_t device_id) { this->device_id_ = device_id; }
|
||||
#endif
|
||||
|
||||
// Check if this entity has state
|
||||
bool has_state() const { return this->flags_.has_state; }
|
||||
|
||||
@@ -67,6 +73,9 @@ class EntityBase {
|
||||
const char *object_id_c_str_{nullptr};
|
||||
const char *icon_c_str_{nullptr};
|
||||
uint32_t object_id_hash_{};
|
||||
#ifdef USE_DEVICES
|
||||
uint32_t device_id_{};
|
||||
#endif
|
||||
|
||||
// Bit-packed flags to save memory (1 byte instead of 5)
|
||||
struct EntityFlags {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
|
||||
from esphome.const import (
|
||||
CONF_DEVICE_ID,
|
||||
CONF_DISABLED_BY_DEFAULT,
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_ICON,
|
||||
@@ -16,7 +17,7 @@ from esphome.core import CORE, ID, coroutine
|
||||
from esphome.coroutine import FakeAwaitable
|
||||
from esphome.cpp_generator import add, get_variable
|
||||
from esphome.cpp_types import App
|
||||
from esphome.helpers import sanitize, snake_case
|
||||
from esphome.helpers import fnv1a_32bit_hash, sanitize, snake_case
|
||||
from esphome.types import ConfigFragmentType, ConfigType
|
||||
from esphome.util import Registry, RegistryEntry
|
||||
|
||||
@@ -110,6 +111,9 @@ async def setup_entity(var, config):
|
||||
add(var.set_icon(config[CONF_ICON]))
|
||||
if CONF_ENTITY_CATEGORY in config:
|
||||
add(var.set_entity_category(config[CONF_ENTITY_CATEGORY]))
|
||||
if CONF_DEVICE_ID in config:
|
||||
device_id: ID = config[CONF_DEVICE_ID]
|
||||
add(var.set_device_id(fnv1a_32bit_hash(device_id.id)))
|
||||
|
||||
|
||||
def extract_registry_entry_config(
|
||||
|
@@ -1,25 +1,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unicodedata
|
||||
|
||||
from esphome.const import ALLOWED_NAME_CHARS
|
||||
from esphome.helpers import slugify
|
||||
|
||||
|
||||
def strip_accents(value):
|
||||
return "".join(
|
||||
c
|
||||
for c in unicodedata.normalize("NFD", str(value))
|
||||
if unicodedata.category(c) != "Mn"
|
||||
)
|
||||
|
||||
|
||||
def friendly_name_slugify(value):
|
||||
value = (
|
||||
strip_accents(value)
|
||||
.lower()
|
||||
.replace(" ", "-")
|
||||
.replace("_", "-")
|
||||
.replace("--", "-")
|
||||
.strip("-")
|
||||
)
|
||||
return "".join(c for c in value if c in ALLOWED_NAME_CHARS)
|
||||
def friendly_name_slugify(value: str) -> str:
|
||||
"""Convert a friendly name to a slug with dashes instead of underscores."""
|
||||
# First use the standard slugify, then convert underscores to dashes
|
||||
return slugify(value).replace("_", "-")
|
||||
|
@@ -29,6 +29,53 @@ def ensure_unique_string(preferred_string, current_strings):
|
||||
return test_string
|
||||
|
||||
|
||||
def fnv1a_32bit_hash(string: str) -> int:
|
||||
"""FNV-1a 32-bit hash function.
|
||||
|
||||
Note: This uses 32-bit hash instead of 64-bit for several reasons:
|
||||
1. ESPHome targets 32-bit microcontrollers with limited RAM (often <320KB)
|
||||
2. Using 64-bit hashes would double the RAM usage for storing IDs
|
||||
3. 64-bit operations are slower on 32-bit processors
|
||||
|
||||
While there's a ~50% collision probability at ~77,000 unique IDs,
|
||||
ESPHome validates for collisions at compile time, preventing any
|
||||
runtime issues. In practice, most ESPHome installations only have
|
||||
a handful of area_ids and device_ids (typically <10 areas and <100
|
||||
devices), making collisions virtually impossible.
|
||||
"""
|
||||
hash_value = 2166136261
|
||||
for char in string:
|
||||
hash_value ^= ord(char)
|
||||
hash_value = (hash_value * 16777619) & 0xFFFFFFFF
|
||||
return hash_value
|
||||
|
||||
|
||||
def strip_accents(value: str) -> str:
|
||||
"""Remove accents from a string."""
|
||||
import unicodedata
|
||||
|
||||
return "".join(
|
||||
c
|
||||
for c in unicodedata.normalize("NFD", str(value))
|
||||
if unicodedata.category(c) != "Mn"
|
||||
)
|
||||
|
||||
|
||||
def slugify(value: str) -> str:
|
||||
"""Convert a string to a valid C++ identifier slug."""
|
||||
from esphome.const import ALLOWED_NAME_CHARS
|
||||
|
||||
value = (
|
||||
strip_accents(value)
|
||||
.lower()
|
||||
.replace(" ", "_")
|
||||
.replace("-", "_")
|
||||
.replace("__", "_")
|
||||
.strip("_")
|
||||
)
|
||||
return "".join(c for c in value if c in ALLOWED_NAME_CHARS)
|
||||
|
||||
|
||||
def indent_all_but_first_and_last(text, padding=" "):
|
||||
lines = text.splitlines(True)
|
||||
if len(lines) <= 2:
|
||||
|
@@ -2,7 +2,9 @@ esphome:
|
||||
debug_scheduler: true
|
||||
platformio_options:
|
||||
board_build.flash_mode: dio
|
||||
area: testing
|
||||
area:
|
||||
id: testing_area
|
||||
name: Testing Area
|
||||
on_boot:
|
||||
logger.log: on_boot
|
||||
on_shutdown:
|
||||
@@ -17,4 +19,20 @@ esphome:
|
||||
version: "1.1"
|
||||
on_update:
|
||||
logger.log: on_update
|
||||
areas:
|
||||
- id: another_area
|
||||
name: Another area
|
||||
devices:
|
||||
- id: other_device
|
||||
name: Another device
|
||||
area_id: another_area
|
||||
- id: test_device
|
||||
name: Test device in main area
|
||||
area_id: testing_area # Reference the main area (not in areas)
|
||||
- id: no_area_device
|
||||
name: Device without area # This device has no area_id
|
||||
|
||||
binary_sensor:
|
||||
- platform: template
|
||||
name: Other device sensor
|
||||
device_id: other_device
|
||||
|
@@ -12,7 +12,7 @@
|
||||
using namespace esphome;
|
||||
|
||||
void setup() {
|
||||
App.pre_setup("livingroom", "LivingRoom", "LivingRoomArea", "comment", __DATE__ ", " __TIME__, false);
|
||||
App.pre_setup("livingroom", "LivingRoom", "comment", __DATE__ ", " __TIME__, false);
|
||||
auto *log = new logger::Logger(115200, 512); // NOLINT
|
||||
log->pre_setup();
|
||||
log->set_uart_selection(logger::UART_SELECTION_UART0);
|
||||
|
57
tests/integration/fixtures/areas_and_devices.yaml
Normal file
57
tests/integration/fixtures/areas_and_devices.yaml
Normal file
@@ -0,0 +1,57 @@
|
||||
esphome:
|
||||
name: areas-devices-test
|
||||
# Define top-level area
|
||||
area:
|
||||
id: living_room_area
|
||||
name: Living Room
|
||||
# Define additional areas
|
||||
areas:
|
||||
- id: bedroom_area
|
||||
name: Bedroom
|
||||
- id: kitchen_area
|
||||
name: Kitchen
|
||||
# Define devices with area assignments
|
||||
devices:
|
||||
- id: light_controller_device
|
||||
name: Light Controller
|
||||
area_id: living_room_area # Uses top-level area
|
||||
- id: temp_sensor_device
|
||||
name: Temperature Sensor
|
||||
area_id: bedroom_area
|
||||
- id: motion_detector_device
|
||||
name: Motion Detector
|
||||
area_id: living_room_area # Reuses top-level area
|
||||
- id: smart_switch_device
|
||||
name: Smart Switch
|
||||
area_id: kitchen_area
|
||||
|
||||
host:
|
||||
api:
|
||||
logger:
|
||||
|
||||
# Sensors assigned to different devices
|
||||
sensor:
|
||||
- platform: template
|
||||
name: Light Controller Sensor
|
||||
device_id: light_controller_device
|
||||
lambda: return 1.0;
|
||||
update_interval: 0.1s
|
||||
|
||||
- platform: template
|
||||
name: Temperature Sensor Reading
|
||||
device_id: temp_sensor_device
|
||||
lambda: return 2.0;
|
||||
update_interval: 0.1s
|
||||
|
||||
- platform: template
|
||||
name: Motion Detector Status
|
||||
device_id: motion_detector_device
|
||||
lambda: return 3.0;
|
||||
update_interval: 0.1s
|
||||
|
||||
- platform: template
|
||||
name: Smart Switch Power
|
||||
device_id: smart_switch_device
|
||||
lambda: return 4.0;
|
||||
update_interval: 0.1s
|
||||
|
15
tests/integration/fixtures/legacy_area.yaml
Normal file
15
tests/integration/fixtures/legacy_area.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
esphome:
|
||||
name: legacy-area-test
|
||||
# Using legacy string-based area configuration
|
||||
area: Master Bedroom
|
||||
|
||||
host:
|
||||
api:
|
||||
logger:
|
||||
|
||||
# Simple sensor to ensure the device compiles and runs
|
||||
sensor:
|
||||
- platform: template
|
||||
name: Test Sensor
|
||||
lambda: return 42.0;
|
||||
update_interval: 1s
|
121
tests/integration/test_areas_and_devices.py
Normal file
121
tests/integration/test_areas_and_devices.py
Normal file
@@ -0,0 +1,121 @@
|
||||
"""Integration test for areas and devices feature."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
|
||||
from aioesphomeapi import EntityState
|
||||
import pytest
|
||||
|
||||
from .types import APIClientConnectedFactory, RunCompiledFunction
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_areas_and_devices(
|
||||
yaml_config: str,
|
||||
run_compiled: RunCompiledFunction,
|
||||
api_client_connected: APIClientConnectedFactory,
|
||||
) -> None:
|
||||
"""Test areas and devices configuration with entity mapping."""
|
||||
async with run_compiled(yaml_config), api_client_connected() as client:
|
||||
# Get device info which includes areas and devices
|
||||
device_info = await client.device_info()
|
||||
assert device_info is not None
|
||||
|
||||
# Verify areas are reported
|
||||
areas = device_info.areas
|
||||
assert len(areas) >= 2, f"Expected at least 2 areas, got {len(areas)}"
|
||||
|
||||
# Find our specific areas
|
||||
main_area = next((a for a in areas if a.name == "Living Room"), None)
|
||||
bedroom_area = next((a for a in areas if a.name == "Bedroom"), None)
|
||||
kitchen_area = next((a for a in areas if a.name == "Kitchen"), None)
|
||||
|
||||
assert main_area is not None, "Living Room area not found"
|
||||
assert bedroom_area is not None, "Bedroom area not found"
|
||||
assert kitchen_area is not None, "Kitchen area not found"
|
||||
|
||||
# Verify devices are reported
|
||||
devices = device_info.devices
|
||||
assert len(devices) >= 4, f"Expected at least 4 devices, got {len(devices)}"
|
||||
|
||||
# Find our specific devices
|
||||
light_controller = next(
|
||||
(d for d in devices if d.name == "Light Controller"), None
|
||||
)
|
||||
temp_sensor = next((d for d in devices if d.name == "Temperature Sensor"), None)
|
||||
motion_detector = next(
|
||||
(d for d in devices if d.name == "Motion Detector"), None
|
||||
)
|
||||
smart_switch = next((d for d in devices if d.name == "Smart Switch"), None)
|
||||
|
||||
assert light_controller is not None, "Light Controller device not found"
|
||||
assert temp_sensor is not None, "Temperature Sensor device not found"
|
||||
assert motion_detector is not None, "Motion Detector device not found"
|
||||
assert smart_switch is not None, "Smart Switch device not found"
|
||||
|
||||
# Verify device area assignments
|
||||
assert light_controller.area_id == main_area.area_id, (
|
||||
"Light Controller should be in Living Room"
|
||||
)
|
||||
assert temp_sensor.area_id == bedroom_area.area_id, (
|
||||
"Temperature Sensor should be in Bedroom"
|
||||
)
|
||||
assert motion_detector.area_id == main_area.area_id, (
|
||||
"Motion Detector should be in Living Room"
|
||||
)
|
||||
assert smart_switch.area_id == kitchen_area.area_id, (
|
||||
"Smart Switch should be in Kitchen"
|
||||
)
|
||||
|
||||
# Verify suggested_area is set to the top-level area name
|
||||
assert device_info.suggested_area == "Living Room", (
|
||||
f"Expected suggested_area to be 'Living Room', got '{device_info.suggested_area}'"
|
||||
)
|
||||
|
||||
# Get entity list to verify device_id mapping
|
||||
entities = await client.list_entities_services()
|
||||
|
||||
# Collect sensor entities
|
||||
sensor_entities = [e for e in entities[0] if hasattr(e, "device_id")]
|
||||
assert len(sensor_entities) >= 4, (
|
||||
f"Expected at least 4 sensor entities, got {len(sensor_entities)}"
|
||||
)
|
||||
|
||||
# Subscribe to states to get sensor values
|
||||
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 all expected sensor states
|
||||
if len(states) >= 4 and not states_future.done():
|
||||
states_future.set_result(True)
|
||||
|
||||
client.subscribe_states(on_state)
|
||||
|
||||
# Wait for sensor states
|
||||
try:
|
||||
await asyncio.wait_for(states_future, timeout=10.0)
|
||||
except asyncio.TimeoutError:
|
||||
pytest.fail(
|
||||
f"Did not receive all sensor states within 10 seconds. "
|
||||
f"Received {len(states)} states"
|
||||
)
|
||||
|
||||
# Verify we have sensor entities with proper device_id assignments
|
||||
device_id_mapping = {
|
||||
"Light Controller Sensor": light_controller.device_id,
|
||||
"Temperature Sensor Reading": temp_sensor.device_id,
|
||||
"Motion Detector Status": motion_detector.device_id,
|
||||
"Smart Switch Power": smart_switch.device_id,
|
||||
}
|
||||
|
||||
for entity in sensor_entities:
|
||||
if entity.name in device_id_mapping:
|
||||
expected_device_id = device_id_mapping[entity.name]
|
||||
assert entity.device_id == expected_device_id, (
|
||||
f"{entity.name} has device_id {entity.device_id}, "
|
||||
f"expected {expected_device_id}"
|
||||
)
|
41
tests/integration/test_legacy_area.py
Normal file
41
tests/integration/test_legacy_area.py
Normal file
@@ -0,0 +1,41 @@
|
||||
"""Integration test for legacy string-based area configuration."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from .types import APIClientConnectedFactory, RunCompiledFunction
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_legacy_area(
|
||||
yaml_config: str,
|
||||
run_compiled: RunCompiledFunction,
|
||||
api_client_connected: APIClientConnectedFactory,
|
||||
) -> None:
|
||||
"""Test legacy string-based area configuration."""
|
||||
async with run_compiled(yaml_config), api_client_connected() as client:
|
||||
# Get device info which includes areas
|
||||
device_info = await client.device_info()
|
||||
assert device_info is not None
|
||||
|
||||
# Verify the area is reported (should be converted to structured format)
|
||||
areas = device_info.areas
|
||||
assert len(areas) == 1, f"Expected exactly 1 area, got {len(areas)}"
|
||||
|
||||
# Find the area - should be slugified from "Master Bedroom"
|
||||
area = areas[0]
|
||||
assert area.name == "Master Bedroom", (
|
||||
f"Expected area name 'Master Bedroom', got '{area.name}'"
|
||||
)
|
||||
|
||||
# Verify area.id is set (it should be a hash)
|
||||
assert area.area_id > 0, "Area ID should be a positive hash value"
|
||||
|
||||
# The suggested_area field should be set for backward compatibility
|
||||
assert device_info.suggested_area == "Master Bedroom", (
|
||||
f"Expected suggested_area to be 'Master Bedroom', got '{device_info.suggested_area}'"
|
||||
)
|
||||
|
||||
# Verify deprecated warning would have been logged during compilation
|
||||
# (We can't check logs directly in integration tests, but the code should work)
|
256
tests/unit_tests/core/test_config.py
Normal file
256
tests/unit_tests/core/test_config.py
Normal file
@@ -0,0 +1,256 @@
|
||||
"""Unit tests for core config functionality including areas and devices."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome import config, config_validation as cv, core, yaml_util
|
||||
from esphome.config import Config
|
||||
from esphome.const import CONF_AREA, CONF_AREAS, CONF_DEVICES
|
||||
from esphome.core import CORE
|
||||
from esphome.core.config import Area, validate_area_config
|
||||
|
||||
FIXTURES_DIR = Path(__file__).parent.parent / "fixtures" / "core" / "config"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def yaml_file(tmp_path: Path) -> Callable[[str], str]:
|
||||
"""Create a temporary YAML file for testing."""
|
||||
|
||||
def _yaml_file(content: str) -> str:
|
||||
yaml_path = tmp_path / "test.yaml"
|
||||
yaml_path.write_text(content)
|
||||
return str(yaml_path)
|
||||
|
||||
return _yaml_file
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset_core():
|
||||
"""Reset CORE after each test."""
|
||||
yield
|
||||
CORE.reset()
|
||||
|
||||
|
||||
def load_config_from_yaml(
|
||||
yaml_file: Callable[[str], str], yaml_content: str
|
||||
) -> Config | None:
|
||||
"""Load configuration from YAML content."""
|
||||
yaml_path = yaml_file(yaml_content)
|
||||
parsed_yaml = yaml_util.load_yaml(yaml_path)
|
||||
|
||||
# Mock yaml_util.load_yaml to return our parsed content
|
||||
with (
|
||||
patch.object(yaml_util, "load_yaml", return_value=parsed_yaml),
|
||||
patch.object(CORE, "config_path", yaml_path),
|
||||
):
|
||||
return config.read_config({})
|
||||
|
||||
|
||||
def load_config_from_fixture(
|
||||
yaml_file: Callable[[str], str], fixture_name: str
|
||||
) -> Config | None:
|
||||
"""Load configuration from a fixture file."""
|
||||
fixture_path = FIXTURES_DIR / fixture_name
|
||||
yaml_content = fixture_path.read_text()
|
||||
return load_config_from_yaml(yaml_file, yaml_content)
|
||||
|
||||
|
||||
def test_validate_area_config_with_string() -> None:
|
||||
"""Test that string area config is converted to structured format."""
|
||||
result: dict[str, Any] = validate_area_config("Living Room")
|
||||
|
||||
assert isinstance(result, dict)
|
||||
assert "id" in result
|
||||
assert "name" in result
|
||||
assert result["name"] == "Living Room"
|
||||
assert isinstance(result["id"], core.ID)
|
||||
assert result["id"].is_declaration
|
||||
assert not result["id"].is_manual
|
||||
|
||||
|
||||
def test_validate_area_config_with_dict() -> None:
|
||||
"""Test that structured area config passes through unchanged."""
|
||||
area_id = cv.declare_id(Area)("test_area")
|
||||
input_config: dict[str, Any] = {
|
||||
"id": area_id,
|
||||
"name": "Test Area",
|
||||
}
|
||||
|
||||
result: dict[str, Any] = validate_area_config(input_config)
|
||||
|
||||
assert result == input_config
|
||||
assert result["id"] == area_id
|
||||
assert result["name"] == "Test Area"
|
||||
|
||||
|
||||
def test_device_with_valid_area_id(yaml_file: Callable[[str], str]) -> None:
|
||||
"""Test that device with valid area_id works correctly."""
|
||||
result = load_config_from_fixture(yaml_file, "valid_area_device.yaml")
|
||||
assert result is not None
|
||||
|
||||
esphome_config = result["esphome"]
|
||||
|
||||
# Verify areas were parsed correctly
|
||||
assert CONF_AREAS in esphome_config
|
||||
areas = esphome_config[CONF_AREAS]
|
||||
assert len(areas) == 1
|
||||
assert areas[0]["id"].id == "bedroom_area"
|
||||
assert areas[0]["name"] == "Bedroom"
|
||||
|
||||
# Verify devices were parsed correctly
|
||||
assert CONF_DEVICES in esphome_config
|
||||
devices = esphome_config[CONF_DEVICES]
|
||||
assert len(devices) == 1
|
||||
assert devices[0]["id"].id == "test_device"
|
||||
assert devices[0]["name"] == "Test Device"
|
||||
assert devices[0]["area_id"].id == "bedroom_area"
|
||||
|
||||
|
||||
def test_multiple_areas_and_devices(yaml_file: Callable[[str], str]) -> None:
|
||||
"""Test multiple areas and devices configuration."""
|
||||
result = load_config_from_fixture(yaml_file, "multiple_areas_devices.yaml")
|
||||
assert result is not None
|
||||
|
||||
esphome_config = result["esphome"]
|
||||
|
||||
# Verify main area
|
||||
assert CONF_AREA in esphome_config
|
||||
main_area = esphome_config[CONF_AREA]
|
||||
assert main_area["id"].id == "main_area"
|
||||
assert main_area["name"] == "Main Area"
|
||||
|
||||
# Verify additional areas
|
||||
assert CONF_AREAS in esphome_config
|
||||
areas = esphome_config[CONF_AREAS]
|
||||
assert len(areas) == 2
|
||||
area_ids = {area["id"].id for area in areas}
|
||||
assert area_ids == {"area1", "area2"}
|
||||
|
||||
# Verify devices
|
||||
assert CONF_DEVICES in esphome_config
|
||||
devices = esphome_config[CONF_DEVICES]
|
||||
assert len(devices) == 3
|
||||
|
||||
# Check device-area associations
|
||||
device_area_map = {dev["id"].id: dev["area_id"].id for dev in devices}
|
||||
assert device_area_map == {
|
||||
"device1": "main_area",
|
||||
"device2": "area1",
|
||||
"device3": "area2",
|
||||
}
|
||||
|
||||
|
||||
def test_legacy_string_area(
|
||||
yaml_file: Callable[[str], str], caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test legacy string area configuration with deprecation warning."""
|
||||
result = load_config_from_fixture(yaml_file, "legacy_string_area.yaml")
|
||||
assert result is not None
|
||||
|
||||
esphome_config = result["esphome"]
|
||||
|
||||
# Verify the string was converted to structured format
|
||||
assert CONF_AREA in esphome_config
|
||||
area = esphome_config[CONF_AREA]
|
||||
assert isinstance(area, dict)
|
||||
assert area["name"] == "Living Room"
|
||||
assert isinstance(area["id"], core.ID)
|
||||
assert area["id"].is_declaration
|
||||
assert not area["id"].is_manual
|
||||
|
||||
|
||||
def test_area_id_collision(
|
||||
yaml_file: Callable[[str], str], capsys: pytest.CaptureFixture[str]
|
||||
) -> None:
|
||||
"""Test that duplicate area IDs are detected."""
|
||||
result = load_config_from_fixture(yaml_file, "area_id_collision.yaml")
|
||||
assert result is None
|
||||
|
||||
# Check for the specific error message in stdout
|
||||
captured = capsys.readouterr()
|
||||
# Exact duplicates are now caught by IDPassValidationStep
|
||||
assert "ID duplicate_id redefined! Check esphome->area->id." in captured.out
|
||||
|
||||
|
||||
def test_device_without_area(yaml_file: Callable[[str], str]) -> None:
|
||||
"""Test that devices without area_id work correctly."""
|
||||
result = load_config_from_fixture(yaml_file, "device_without_area.yaml")
|
||||
assert result is not None
|
||||
|
||||
esphome_config = result["esphome"]
|
||||
|
||||
# Verify device was parsed
|
||||
assert CONF_DEVICES in esphome_config
|
||||
devices = esphome_config[CONF_DEVICES]
|
||||
assert len(devices) == 1
|
||||
|
||||
device = devices[0]
|
||||
assert device["id"].id == "test_device"
|
||||
assert device["name"] == "Test Device"
|
||||
|
||||
# Verify no area_id is present
|
||||
assert "area_id" not in device
|
||||
|
||||
|
||||
def test_device_with_invalid_area_id(
|
||||
yaml_file: Callable[[str], str], capsys: pytest.CaptureFixture[str]
|
||||
) -> None:
|
||||
"""Test that device with non-existent area_id fails validation."""
|
||||
result = load_config_from_fixture(yaml_file, "device_invalid_area.yaml")
|
||||
assert result is None
|
||||
|
||||
# Check for the specific error message in stdout
|
||||
captured = capsys.readouterr()
|
||||
print(captured.out)
|
||||
assert (
|
||||
"Couldn't find ID 'nonexistent_area'. Please check you have defined an ID with that name in your configuration."
|
||||
in captured.out
|
||||
)
|
||||
|
||||
|
||||
def test_device_id_hash_collision(
|
||||
yaml_file: Callable[[str], str], capsys: pytest.CaptureFixture[str]
|
||||
) -> None:
|
||||
"""Test that device IDs with hash collisions are detected."""
|
||||
result = load_config_from_fixture(yaml_file, "device_id_collision.yaml")
|
||||
assert result is None
|
||||
|
||||
# Check for the specific error message about hash collision
|
||||
captured = capsys.readouterr()
|
||||
# The error message shows the ID that collides and includes the hash value
|
||||
assert (
|
||||
"Device ID 'd6ka' with hash 3082558663 collides with existing device ID 'test_2258'"
|
||||
in captured.out
|
||||
)
|
||||
|
||||
|
||||
def test_area_id_hash_collision(
|
||||
yaml_file: Callable[[str], str], capsys: pytest.CaptureFixture[str]
|
||||
) -> None:
|
||||
"""Test that area IDs with hash collisions are detected."""
|
||||
result = load_config_from_fixture(yaml_file, "area_id_hash_collision.yaml")
|
||||
assert result is None
|
||||
|
||||
# Check for the specific error message about hash collision
|
||||
captured = capsys.readouterr()
|
||||
# The error message shows the ID that collides and includes the hash value
|
||||
assert (
|
||||
"Area ID 'd6ka' with hash 3082558663 collides with existing area ID 'test_2258'"
|
||||
in captured.out
|
||||
)
|
||||
|
||||
|
||||
def test_device_duplicate_id(
|
||||
yaml_file: Callable[[str], str], capsys: pytest.CaptureFixture[str]
|
||||
) -> None:
|
||||
"""Test that duplicate device IDs are detected by IDPassValidationStep."""
|
||||
result = load_config_from_fixture(yaml_file, "device_duplicate_id.yaml")
|
||||
assert result is None
|
||||
|
||||
# Check for the specific error message from IDPassValidationStep
|
||||
captured = capsys.readouterr()
|
||||
assert "ID duplicate_device redefined!" in captured.out
|
10
tests/unit_tests/fixtures/core/config/area_id_collision.yaml
Normal file
10
tests/unit_tests/fixtures/core/config/area_id_collision.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
esphome:
|
||||
name: test-collision
|
||||
area:
|
||||
id: duplicate_id
|
||||
name: Area 1
|
||||
areas:
|
||||
- id: duplicate_id
|
||||
name: Area 2
|
||||
|
||||
host:
|
@@ -0,0 +1,10 @@
|
||||
esphome:
|
||||
name: test
|
||||
areas:
|
||||
- id: test_2258
|
||||
name: "Area 1"
|
||||
- id: d6ka
|
||||
name: "Area 2"
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
@@ -0,0 +1,10 @@
|
||||
esphome:
|
||||
name: test
|
||||
devices:
|
||||
- id: duplicate_device
|
||||
name: "Device 1"
|
||||
- id: duplicate_device
|
||||
name: "Device 2"
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
@@ -0,0 +1,10 @@
|
||||
esphome:
|
||||
name: test
|
||||
devices:
|
||||
- id: test_2258
|
||||
name: "Device 1"
|
||||
- id: d6ka
|
||||
name: "Device 2"
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
@@ -0,0 +1,12 @@
|
||||
esphome:
|
||||
name: test
|
||||
areas:
|
||||
- id: valid_area
|
||||
name: "Valid Area"
|
||||
devices:
|
||||
- id: test_device
|
||||
name: "Test Device"
|
||||
area_id: nonexistent_area
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
@@ -0,0 +1,7 @@
|
||||
esphome:
|
||||
name: test-device-no-area
|
||||
devices:
|
||||
- id: test_device
|
||||
name: Test Device
|
||||
|
||||
host:
|
@@ -0,0 +1,5 @@
|
||||
esphome:
|
||||
name: test-legacy-area
|
||||
area: Living Room
|
||||
|
||||
host:
|
@@ -0,0 +1,22 @@
|
||||
esphome:
|
||||
name: test-multiple
|
||||
area:
|
||||
id: main_area
|
||||
name: Main Area
|
||||
areas:
|
||||
- id: area1
|
||||
name: Area 1
|
||||
- id: area2
|
||||
name: Area 2
|
||||
devices:
|
||||
- id: device1
|
||||
name: Device 1
|
||||
area_id: main_area
|
||||
- id: device2
|
||||
name: Device 2
|
||||
area_id: area1
|
||||
- id: device3
|
||||
name: Device 3
|
||||
area_id: area2
|
||||
|
||||
host:
|
11
tests/unit_tests/fixtures/core/config/valid_area_device.yaml
Normal file
11
tests/unit_tests/fixtures/core/config/valid_area_device.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
esphome:
|
||||
name: test-valid-area
|
||||
areas:
|
||||
- id: bedroom_area
|
||||
name: Bedroom
|
||||
devices:
|
||||
- id: test_device
|
||||
name: Test Device
|
||||
area_id: bedroom_area
|
||||
|
||||
host:
|
Reference in New Issue
Block a user