Compare commits
176 Commits
api_reboot
...
multi_devi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4bdd08887e | ||
|
|
1fd8ebf386 | ||
|
|
d2fc3e749c | ||
|
|
71fbcbceaf | ||
|
|
27347b2088 | ||
|
|
599993d1a5 | ||
|
|
bf359cb8e3 | ||
|
|
509a704410 | ||
|
|
1f48e2b01f | ||
|
|
83613726d1 | ||
|
|
796e12bd70 | ||
|
|
ddbe17d3f6 | ||
|
|
591ec36f4a | ||
|
|
41eceb72ef | ||
|
|
0a5f094025 | ||
|
|
ca0f3ba262 | ||
|
|
30f4e782db | ||
|
|
192158ef1a | ||
|
|
602456db40 | ||
|
|
536e45668f | ||
|
|
10bf05ab0d | ||
|
|
5ad1af69e4 | ||
|
|
48f2911434 | ||
|
|
ac3598f12a | ||
|
|
66201be5ca | ||
|
|
ac0b0b652e | ||
|
|
d89ee2df42 | ||
|
|
418e248e5e | ||
|
|
8c2b141049 | ||
|
|
2f8e07302b | ||
|
|
c3776240b6 | ||
|
|
e370872ec1 | ||
|
|
d4e978369a | ||
|
|
8d5d7f5237 | ||
|
|
7ad6dab383 | ||
|
|
612c8d5841 | ||
|
|
a35e476be5 | ||
|
|
87a7157fc4 | ||
|
|
fa34adbf6c | ||
|
|
ac942e0670 | ||
|
|
22e360d479 | ||
|
|
649936200e | ||
|
|
5d6e690c12 | ||
|
|
2f2ecadae7 | ||
|
|
6dfb9eba61 | ||
|
|
24587fe875 | ||
|
|
a1aebe6a2c | ||
|
|
2ad266582f | ||
|
|
1a47164876 | ||
|
|
cd22723623 | ||
|
|
aecaffa2f5 | ||
|
|
87df3596a2 | ||
|
|
41c7852128 | ||
|
|
78ec9856fb | ||
|
|
2a45467bf6 | ||
|
|
7fc5bfd787 | ||
|
|
04f592ba6d | ||
|
|
59889a6286 | ||
|
|
20f946ccaf | ||
|
|
e5e972231c | ||
|
|
dc5cbd4df8 | ||
|
|
754d2874e7 | ||
|
|
06de58ff8b | ||
|
|
7ab9083d77 | ||
|
|
5857f7b9a7 | ||
|
|
a5ea0cd41f | ||
|
|
d677934417 | ||
|
|
ba87a0b63c | ||
|
|
b725bb3dd1 | ||
|
|
c34ba3deb5 | ||
|
|
68b13340fb | ||
|
|
8831999ea6 | ||
|
|
c1853f8b84 | ||
|
|
2b9b7e2853 | ||
|
|
d3b18debf9 | ||
|
|
b01eb28d42 | ||
|
|
02019dd16c | ||
|
|
7be12f5ff6 | ||
|
|
a90d59b6ba | ||
|
|
25ed7c890b | ||
|
|
85e3b63f05 | ||
|
|
a37bac1956 | ||
|
|
818a978dfc | ||
|
|
180aeb7d8e | ||
|
|
0764fa7292 | ||
|
|
17bf533ed7 | ||
|
|
d7eae1c1a0 | ||
|
|
7f2d979255 | ||
|
|
46b419ea8b | ||
|
|
b30b527ff9 | ||
|
|
41b1bfc504 | ||
|
|
f4f14a7507 | ||
|
|
61c29213a7 | ||
|
|
e6d7639209 | ||
|
|
3c07a186b2 | ||
|
|
8a725250a9 | ||
|
|
502b8a6073 | ||
|
|
b03e3b8d4a | ||
|
|
a98e34d190 | ||
|
|
bf8d8b6e63 | ||
|
|
57599f7a98 | ||
|
|
ffccce7ffc | ||
|
|
221e3c6c9c | ||
|
|
fb1679d572 | ||
|
|
c19065f112 | ||
|
|
f2b04a077e | ||
|
|
8e7841c880 | ||
|
|
1873490b24 | ||
|
|
4d231953f4 | ||
|
|
aa4c399657 | ||
|
|
1f99d18982 | ||
|
|
be37178ef8 | ||
|
|
fad86c655e | ||
|
|
4a7958586e | ||
|
|
f44ecd0891 | ||
|
|
3d0392d668 | ||
|
|
d300d2605b | ||
|
|
66cce6a2f2 | ||
|
|
65e3c6bfbb | ||
|
|
2a39060912 | ||
|
|
8714e80978 | ||
|
|
98de53f60b | ||
|
|
41e11e9a0e | ||
|
|
e7a4eac8bd | ||
|
|
1589a131db | ||
|
|
7d84f0e650 | ||
|
|
86fb0e317f | ||
|
|
32088d5ef7 | ||
|
|
63de88dd57 | ||
|
|
153a6440dc | ||
|
|
8937ed2269 | ||
|
|
02e922b56f | ||
|
|
bf9e901ab9 | ||
|
|
1234ef8de2 | ||
|
|
57f4067fbf | ||
|
|
f4a9221232 | ||
|
|
3d4a75148d | ||
|
|
c2c5bd844d | ||
|
|
9624efa21e | ||
|
|
831638210d | ||
|
|
a59a8c563e | ||
|
|
856829bcbb | ||
|
|
dd2b931f61 | ||
|
|
39beccbbb0 | ||
|
|
ff626b428f | ||
|
|
3915e1f012 | ||
|
|
7b460b6224 | ||
|
|
8fb8e79730 | ||
|
|
79bbc475f4 | ||
|
|
cef023283b | ||
|
|
d4fda79ada | ||
|
|
ff0bdcf4cd | ||
|
|
bfbc313144 | ||
|
|
31f2376f15 | ||
|
|
f76ecb6604 | ||
|
|
298cc58433 | ||
|
|
825c0593e1 | ||
|
|
87ed1dc3e3 | ||
|
|
67e9db021c | ||
|
|
3922950951 | ||
|
|
9c4aa0ba53 | ||
|
|
f5f1651b31 | ||
|
|
32f4e4ca13 | ||
|
|
962e0c4c33 | ||
|
|
2c01bc5795 | ||
|
|
0651f7cb3c | ||
|
|
01ac59ce2a | ||
|
|
c1fd597757 | ||
|
|
e79e244eee | ||
|
|
68ecc08111 | ||
|
|
3b5fbc359f | ||
|
|
583e5ea47f | ||
|
|
7b647c3fae | ||
|
|
a8b76c617c | ||
|
|
1bd8985dff | ||
|
|
25b5a6c4ae |
@@ -323,6 +323,7 @@ esphome/components/one_wire/* @ssieb
|
||||
esphome/components/online_image/* @clydebarrow @guillempages
|
||||
esphome/components/opentherm/* @olegtarasov
|
||||
esphome/components/openthread/* @mrene
|
||||
esphome/components/opt3001/* @ccutrer
|
||||
esphome/components/ota/* @esphome/core
|
||||
esphome/components/output/* @esphome/core
|
||||
esphome/components/packet_transport/* @clydebarrow
|
||||
|
||||
@@ -14,8 +14,8 @@ from esphome.const import (
|
||||
CONF_WEB_SERVER,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
CODEOWNERS = ["@grahambrown11", "@hwstar"]
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
@@ -149,6 +149,9 @@ _ALARM_CONTROL_PANEL_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_ALARM_CONTROL_PANEL_SCHEMA.add_extra(entity_duplicate_validator("alarm_control_panel"))
|
||||
|
||||
|
||||
def alarm_control_panel_schema(
|
||||
class_: MockObjClass,
|
||||
*,
|
||||
@@ -190,7 +193,7 @@ ALARM_CONTROL_PANEL_CONDITION_SCHEMA = maybe_simple_id(
|
||||
|
||||
|
||||
async def setup_alarm_control_panel_core_(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "alarm_control_panel")
|
||||
for conf in config.get(CONF_ON_STATE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -28,6 +28,12 @@
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
// Read a maximum of 5 messages per loop iteration to prevent starving other components.
|
||||
// This is a balance between API responsiveness and allowing other components to run.
|
||||
// Since each message could contain multiple protobuf messages when using packet batching,
|
||||
// this limits the number of messages processed, not the number of TCP packets.
|
||||
static constexpr uint8_t MAX_MESSAGES_PER_LOOP = 5;
|
||||
|
||||
static const char *const TAG = "api.connection";
|
||||
static const int ESP32_CAMERA_STOP_STREAM = 5000;
|
||||
|
||||
@@ -109,33 +115,38 @@ void APIConnection::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t now = App.get_loop_component_start_time();
|
||||
// Check if socket has data ready before attempting to read
|
||||
if (this->helper_->is_socket_ready()) {
|
||||
ReadPacketBuffer buffer;
|
||||
err = this->helper_->read_packet(&buffer);
|
||||
if (err == APIError::WOULD_BLOCK) {
|
||||
// pass
|
||||
} else if (err != APIError::OK) {
|
||||
on_fatal_error();
|
||||
if (err == APIError::SOCKET_READ_FAILED && errno == ECONNRESET) {
|
||||
ESP_LOGW(TAG, "%s: Connection reset", this->get_client_combined_info().c_str());
|
||||
} else if (err == APIError::CONNECTION_CLOSED) {
|
||||
ESP_LOGW(TAG, "%s: Connection closed", this->get_client_combined_info().c_str());
|
||||
} else {
|
||||
ESP_LOGW(TAG, "%s: Reading failed: %s errno=%d", this->get_client_combined_info().c_str(),
|
||||
api_error_to_str(err), errno);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
this->last_traffic_ = App.get_loop_component_start_time();
|
||||
// read a packet
|
||||
if (buffer.data_len > 0) {
|
||||
this->read_message(buffer.data_len, buffer.type, &buffer.container[buffer.data_offset]);
|
||||
} else {
|
||||
this->read_message(0, buffer.type, nullptr);
|
||||
}
|
||||
if (this->remove_)
|
||||
// Read up to MAX_MESSAGES_PER_LOOP messages per loop to improve throughput
|
||||
for (uint8_t message_count = 0; message_count < MAX_MESSAGES_PER_LOOP; message_count++) {
|
||||
ReadPacketBuffer buffer;
|
||||
err = this->helper_->read_packet(&buffer);
|
||||
if (err == APIError::WOULD_BLOCK) {
|
||||
// No more data available
|
||||
break;
|
||||
} else if (err != APIError::OK) {
|
||||
on_fatal_error();
|
||||
if (err == APIError::SOCKET_READ_FAILED && errno == ECONNRESET) {
|
||||
ESP_LOGW(TAG, "%s: Connection reset", this->get_client_combined_info().c_str());
|
||||
} else if (err == APIError::CONNECTION_CLOSED) {
|
||||
ESP_LOGW(TAG, "%s: Connection closed", this->get_client_combined_info().c_str());
|
||||
} else {
|
||||
ESP_LOGW(TAG, "%s: Reading failed: %s errno=%d", this->get_client_combined_info().c_str(),
|
||||
api_error_to_str(err), errno);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
this->last_traffic_ = now;
|
||||
// read a packet
|
||||
if (buffer.data_len > 0) {
|
||||
this->read_message(buffer.data_len, buffer.type, &buffer.container[buffer.data_offset]);
|
||||
} else {
|
||||
this->read_message(0, buffer.type, nullptr);
|
||||
}
|
||||
if (this->remove_)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +163,6 @@ void APIConnection::loop() {
|
||||
|
||||
static uint8_t max_ping_retries = 60;
|
||||
static uint16_t ping_retry_interval = 1000;
|
||||
const uint32_t now = App.get_loop_component_start_time();
|
||||
if (this->sent_ping_) {
|
||||
// Disconnect if not responded within 2.5*keepalive
|
||||
if (now - this->last_traffic_ > (KEEPALIVE_TIMEOUT_MS * 5) / 2) {
|
||||
@@ -1619,6 +1629,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
|
||||
|
||||
@@ -274,12 +274,21 @@ APIError APINoiseFrameHelper::init() {
|
||||
}
|
||||
/// Run through handshake messages (if in that phase)
|
||||
APIError APINoiseFrameHelper::loop() {
|
||||
APIError err = state_action_();
|
||||
if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
|
||||
return err;
|
||||
// During handshake phase, process as many actions as possible until we can't progress
|
||||
// socket_->ready() stays true until next main loop, but state_action() will return
|
||||
// WOULD_BLOCK when no more data is available to read
|
||||
while (state_ != State::DATA && this->socket_->ready()) {
|
||||
APIError err = state_action_();
|
||||
if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
|
||||
return err;
|
||||
}
|
||||
if (err == APIError::WOULD_BLOCK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->tx_buf_.empty()) {
|
||||
err = try_send_tx_buf_();
|
||||
APIError err = try_send_tx_buf_();
|
||||
if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -47,11 +47,6 @@ void APIServer::setup() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Schedule reboot if no clients connect within timeout
|
||||
if (this->reboot_timeout_ != 0) {
|
||||
this->schedule_reboot_timeout_();
|
||||
}
|
||||
|
||||
this->socket_ = socket::socket_ip_loop_monitored(SOCK_STREAM, 0); // monitored for incoming connections
|
||||
if (this->socket_ == nullptr) {
|
||||
ESP_LOGW(TAG, "Could not create socket");
|
||||
@@ -111,6 +106,8 @@ void APIServer::setup() {
|
||||
}
|
||||
#endif
|
||||
|
||||
this->last_connected_ = App.get_loop_component_start_time();
|
||||
|
||||
#ifdef USE_ESP32_CAMERA
|
||||
if (esp32_camera::global_esp32_camera != nullptr && !esp32_camera::global_esp32_camera->is_internal()) {
|
||||
esp32_camera::global_esp32_camera->add_image_callback(
|
||||
@@ -124,16 +121,6 @@ void APIServer::setup() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void APIServer::schedule_reboot_timeout_() {
|
||||
this->status_set_warning();
|
||||
this->set_timeout("api_reboot", this->reboot_timeout_, []() {
|
||||
if (!global_api_server->is_connected()) {
|
||||
ESP_LOGE(TAG, "No client connected; rebooting");
|
||||
App.reboot();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void APIServer::loop() {
|
||||
// Accept new clients only if the socket exists and has incoming connections
|
||||
if (this->socket_ && this->socket_->ready()) {
|
||||
@@ -148,12 +135,6 @@ void APIServer::loop() {
|
||||
auto *conn = new APIConnection(std::move(sock), this);
|
||||
this->clients_.emplace_back(conn);
|
||||
conn->start();
|
||||
|
||||
// Clear warning status and cancel reboot when first client connects
|
||||
if (this->clients_.size() == 1 && this->reboot_timeout_ != 0) {
|
||||
this->status_clear_warning();
|
||||
this->cancel_timeout("api_reboot");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,12 +154,6 @@ void APIServer::loop() {
|
||||
std::swap(this->clients_[client_index], this->clients_.back());
|
||||
}
|
||||
this->clients_.pop_back();
|
||||
|
||||
// Schedule reboot when last client disconnects
|
||||
if (this->clients_.empty() && this->reboot_timeout_ != 0) {
|
||||
this->schedule_reboot_timeout_();
|
||||
}
|
||||
|
||||
// Don't increment client_index since we need to process the swapped element
|
||||
} else {
|
||||
// Process active client
|
||||
@@ -188,7 +163,19 @@ void APIServer::loop() {
|
||||
}
|
||||
}
|
||||
|
||||
// Reboot timeout is now handled by connection/disconnection events
|
||||
if (this->reboot_timeout_ != 0) {
|
||||
const uint32_t now = App.get_loop_component_start_time();
|
||||
if (!this->is_connected()) {
|
||||
if (now - this->last_connected_ > this->reboot_timeout_) {
|
||||
ESP_LOGE(TAG, "No client connected; rebooting");
|
||||
App.reboot();
|
||||
}
|
||||
this->status_set_warning();
|
||||
} else {
|
||||
this->last_connected_ = now;
|
||||
this->status_clear_warning();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void APIServer::dump_config() {
|
||||
|
||||
@@ -142,7 +142,6 @@ class APIServer : public Component, public Controller {
|
||||
}
|
||||
|
||||
protected:
|
||||
void schedule_reboot_timeout_();
|
||||
// Pointers and pointer-like types first (4 bytes each)
|
||||
std::unique_ptr<socket::Socket> socket_ = nullptr;
|
||||
Trigger<std::string, std::string> *client_connected_trigger_ = new Trigger<std::string, std::string>();
|
||||
@@ -151,6 +150,7 @@ class APIServer : public Component, public Controller {
|
||||
// 4-byte aligned types
|
||||
uint32_t reboot_timeout_{300000};
|
||||
uint32_t batch_delay_{100};
|
||||
uint32_t last_connected_{0};
|
||||
|
||||
// Vectors and strings (12 bytes each on 32-bit)
|
||||
std::vector<std::unique_ptr<APIConnection>> clients_;
|
||||
|
||||
@@ -60,8 +60,8 @@ from esphome.const import (
|
||||
DEVICE_CLASS_WINDOW,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
from esphome.util import Registry
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
@@ -491,6 +491,9 @@ _BINARY_SENSOR_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_BINARY_SENSOR_SCHEMA.add_extra(entity_duplicate_validator("binary_sensor"))
|
||||
|
||||
|
||||
def binary_sensor_schema(
|
||||
class_: MockObjClass = cv.UNDEFINED,
|
||||
*,
|
||||
@@ -521,7 +524,7 @@ BINARY_SENSOR_SCHEMA.add_extra(cv.deprecated_schema_constant("binary_sensor"))
|
||||
|
||||
|
||||
async def setup_binary_sensor_core_(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "binary_sensor")
|
||||
|
||||
if (device_class := config.get(CONF_DEVICE_CLASS)) is not None:
|
||||
cg.add(var.set_device_class(device_class))
|
||||
|
||||
@@ -18,8 +18,8 @@ from esphome.const import (
|
||||
DEVICE_CLASS_UPDATE,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
@@ -61,6 +61,9 @@ _BUTTON_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_BUTTON_SCHEMA.add_extra(entity_duplicate_validator("button"))
|
||||
|
||||
|
||||
def button_schema(
|
||||
class_: MockObjClass,
|
||||
*,
|
||||
@@ -87,7 +90,7 @@ BUTTON_SCHEMA.add_extra(cv.deprecated_schema_constant("button"))
|
||||
|
||||
|
||||
async def setup_button_core_(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "button")
|
||||
|
||||
for conf in config.get(CONF_ON_PRESS, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
|
||||
@@ -48,8 +48,8 @@ from esphome.const import (
|
||||
CONF_WEB_SERVER,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
|
||||
@@ -247,6 +247,9 @@ _CLIMATE_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_CLIMATE_SCHEMA.add_extra(entity_duplicate_validator("climate"))
|
||||
|
||||
|
||||
def climate_schema(
|
||||
class_: MockObjClass,
|
||||
*,
|
||||
@@ -273,7 +276,7 @@ CLIMATE_SCHEMA.add_extra(cv.deprecated_schema_constant("climate"))
|
||||
|
||||
|
||||
async def setup_climate_core_(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "climate")
|
||||
|
||||
visual = config[CONF_VISUAL]
|
||||
if (min_temp := visual.get(CONF_MIN_TEMPERATURE)) is not None:
|
||||
|
||||
@@ -33,8 +33,8 @@ from esphome.const import (
|
||||
DEVICE_CLASS_WINDOW,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
|
||||
@@ -126,6 +126,9 @@ _COVER_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_COVER_SCHEMA.add_extra(entity_duplicate_validator("cover"))
|
||||
|
||||
|
||||
def cover_schema(
|
||||
class_: MockObjClass,
|
||||
*,
|
||||
@@ -154,7 +157,7 @@ COVER_SCHEMA.add_extra(cv.deprecated_schema_constant("cover"))
|
||||
|
||||
|
||||
async def setup_cover_core_(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "cover")
|
||||
|
||||
if (device_class := config.get(CONF_DEVICE_CLASS)) is not None:
|
||||
cg.add(var.set_device_class(device_class))
|
||||
|
||||
@@ -22,8 +22,8 @@ from esphome.const import (
|
||||
CONF_YEAR,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
CODEOWNERS = ["@rfdarter", "@jesserockz"]
|
||||
|
||||
@@ -84,6 +84,8 @@ _DATETIME_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
|
||||
.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
|
||||
).add_extra(_validate_time_present)
|
||||
|
||||
_DATETIME_SCHEMA.add_extra(entity_duplicate_validator("datetime"))
|
||||
|
||||
|
||||
def date_schema(class_: MockObjClass) -> cv.Schema:
|
||||
schema = cv.Schema(
|
||||
@@ -133,7 +135,7 @@ def datetime_schema(class_: MockObjClass) -> cv.Schema:
|
||||
|
||||
|
||||
async def setup_datetime_core_(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "datetime")
|
||||
|
||||
if (mqtt_id := config.get(CONF_MQTT_ID)) is not None:
|
||||
mqtt_ = cg.new_Pvariable(mqtt_id, var)
|
||||
|
||||
@@ -455,7 +455,7 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
CONF_NAME: "Demo Plain Sensor",
|
||||
},
|
||||
{
|
||||
CONF_NAME: "Demo Temperature Sensor",
|
||||
CONF_NAME: "Demo Temperature Sensor 1",
|
||||
CONF_UNIT_OF_MEASUREMENT: UNIT_CELSIUS,
|
||||
CONF_ICON: ICON_THERMOMETER,
|
||||
CONF_ACCURACY_DECIMALS: 1,
|
||||
@@ -463,7 +463,7 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
CONF_STATE_CLASS: STATE_CLASS_MEASUREMENT,
|
||||
},
|
||||
{
|
||||
CONF_NAME: "Demo Temperature Sensor",
|
||||
CONF_NAME: "Demo Temperature Sensor 2",
|
||||
CONF_UNIT_OF_MEASUREMENT: UNIT_CELSIUS,
|
||||
CONF_ICON: ICON_THERMOMETER,
|
||||
CONF_ACCURACY_DECIMALS: 1,
|
||||
|
||||
@@ -522,6 +522,7 @@ optional<ESPBLEiBeacon> ESPBLEiBeacon::from_manufacturer_data(const ServiceData
|
||||
}
|
||||
|
||||
void ESPBTDevice::parse_scan_rst(const BLEScanResult &scan_result) {
|
||||
this->scan_result_ = &scan_result;
|
||||
for (uint8_t i = 0; i < ESP_BD_ADDR_LEN; i++)
|
||||
this->address_[i] = scan_result.bda[i];
|
||||
this->address_type_ = static_cast<esp_ble_addr_type_t>(scan_result.ble_addr_type);
|
||||
|
||||
@@ -85,6 +85,9 @@ class ESPBTDevice {
|
||||
|
||||
const std::vector<ServiceData> &get_service_datas() const { return service_datas_; }
|
||||
|
||||
// Exposed through a function for use in lambdas
|
||||
const BLEScanResult &get_scan_result() const { return *scan_result_; }
|
||||
|
||||
bool resolve_irk(const uint8_t *irk) const;
|
||||
|
||||
optional<ESPBLEiBeacon> get_ibeacon() const {
|
||||
@@ -111,6 +114,7 @@ class ESPBTDevice {
|
||||
std::vector<ESPBTUUID> service_uuids_{};
|
||||
std::vector<ServiceData> manufacturer_datas_{};
|
||||
std::vector<ServiceData> service_datas_{};
|
||||
const BLEScanResult *scan_result_{nullptr};
|
||||
};
|
||||
|
||||
class ESP32BLETracker;
|
||||
|
||||
@@ -19,7 +19,7 @@ from esphome.const import (
|
||||
CONF_VSYNC_PIN,
|
||||
)
|
||||
from esphome.core import CORE
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
from esphome.core.entity_helpers import setup_entity
|
||||
|
||||
DEPENDENCIES = ["esp32"]
|
||||
|
||||
@@ -284,7 +284,7 @@ SETTERS = {
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "camera")
|
||||
await cg.register_component(var, config)
|
||||
|
||||
for key, setter in SETTERS.items():
|
||||
|
||||
@@ -18,8 +18,8 @@ from esphome.const import (
|
||||
DEVICE_CLASS_MOTION,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
CODEOWNERS = ["@nohat"]
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
@@ -59,6 +59,9 @@ _EVENT_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_EVENT_SCHEMA.add_extra(entity_duplicate_validator("event"))
|
||||
|
||||
|
||||
def event_schema(
|
||||
class_: MockObjClass = cv.UNDEFINED,
|
||||
*,
|
||||
@@ -88,7 +91,7 @@ EVENT_SCHEMA.add_extra(cv.deprecated_schema_constant("event"))
|
||||
|
||||
|
||||
async def setup_event_core_(var, config, *, event_types: list[str]):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "event")
|
||||
|
||||
for conf in config.get(CONF_ON_EVENT, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
|
||||
@@ -32,7 +32,7 @@ from esphome.const import (
|
||||
CONF_WEB_SERVER,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
|
||||
@@ -161,6 +161,9 @@ _FAN_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_FAN_SCHEMA.add_extra(entity_duplicate_validator("fan"))
|
||||
|
||||
|
||||
def fan_schema(
|
||||
class_: cg.Pvariable,
|
||||
*,
|
||||
@@ -225,7 +228,7 @@ def validate_preset_modes(value):
|
||||
|
||||
|
||||
async def setup_fan_core_(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "fan")
|
||||
|
||||
cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE]))
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from collections.abc import MutableMapping
|
||||
import functools
|
||||
import hashlib
|
||||
from itertools import accumulate
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
@@ -468,8 +469,9 @@ class EFont:
|
||||
|
||||
|
||||
class GlyphInfo:
|
||||
def __init__(self, data_len, advance, offset_x, offset_y, width, height):
|
||||
self.data_len = data_len
|
||||
def __init__(self, glyph, data, advance, offset_x, offset_y, width, height):
|
||||
self.glyph = glyph
|
||||
self.bitmap_data = data
|
||||
self.advance = advance
|
||||
self.offset_x = offset_x
|
||||
self.offset_y = offset_y
|
||||
@@ -477,6 +479,62 @@ class GlyphInfo:
|
||||
self.height = height
|
||||
|
||||
|
||||
def glyph_to_glyphinfo(glyph, font, size, bpp):
|
||||
scale = 256 // (1 << bpp)
|
||||
if not font.is_scalable:
|
||||
sizes = [pt_to_px(x.size) for x in font.available_sizes]
|
||||
if size in sizes:
|
||||
font.select_size(sizes.index(size))
|
||||
else:
|
||||
font.set_pixel_sizes(size, 0)
|
||||
flags = FT_LOAD_RENDER
|
||||
if bpp != 1:
|
||||
flags |= FT_LOAD_NO_BITMAP
|
||||
else:
|
||||
flags |= FT_LOAD_TARGET_MONO
|
||||
font.load_char(glyph, flags)
|
||||
width = font.glyph.bitmap.width
|
||||
height = font.glyph.bitmap.rows
|
||||
buffer = font.glyph.bitmap.buffer
|
||||
pitch = font.glyph.bitmap.pitch
|
||||
glyph_data = [0] * ((height * width * bpp + 7) // 8)
|
||||
src_mode = font.glyph.bitmap.pixel_mode
|
||||
pos = 0
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
if src_mode == ft_pixel_mode_mono:
|
||||
pixel = (
|
||||
(1 << bpp) - 1
|
||||
if buffer[y * pitch + x // 8] & (1 << (7 - x % 8))
|
||||
else 0
|
||||
)
|
||||
else:
|
||||
pixel = buffer[y * pitch + x] // scale
|
||||
for bit_num in range(bpp):
|
||||
if pixel & (1 << (bpp - bit_num - 1)):
|
||||
glyph_data[pos // 8] |= 0x80 >> (pos % 8)
|
||||
pos += 1
|
||||
ascender = pt_to_px(font.size.ascender)
|
||||
if ascender == 0:
|
||||
if not font.is_scalable:
|
||||
ascender = size
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"Unable to determine ascender of font %s %s",
|
||||
font.family_name,
|
||||
font.style_name,
|
||||
)
|
||||
return GlyphInfo(
|
||||
glyph,
|
||||
glyph_data,
|
||||
pt_to_px(font.glyph.metrics.horiAdvance),
|
||||
font.glyph.bitmap_left,
|
||||
ascender - font.glyph.bitmap_top,
|
||||
width,
|
||||
height,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
"""
|
||||
Collect all glyph codepoints, construct a map from a codepoint to a font file.
|
||||
@@ -506,98 +564,47 @@ async def to_code(config):
|
||||
|
||||
codepoints = list(point_set)
|
||||
codepoints.sort(key=functools.cmp_to_key(glyph_comparator))
|
||||
glyph_args = {}
|
||||
data = []
|
||||
bpp = config[CONF_BPP]
|
||||
scale = 256 // (1 << bpp)
|
||||
size = config[CONF_SIZE]
|
||||
# create the data array for all glyphs
|
||||
for codepoint in codepoints:
|
||||
font = point_font_map[codepoint]
|
||||
if not font.is_scalable:
|
||||
sizes = [pt_to_px(x.size) for x in font.available_sizes]
|
||||
if size in sizes:
|
||||
font.select_size(sizes.index(size))
|
||||
else:
|
||||
font.set_pixel_sizes(size, 0)
|
||||
flags = FT_LOAD_RENDER
|
||||
if bpp != 1:
|
||||
flags |= FT_LOAD_NO_BITMAP
|
||||
else:
|
||||
flags |= FT_LOAD_TARGET_MONO
|
||||
font.load_char(codepoint, flags)
|
||||
width = font.glyph.bitmap.width
|
||||
height = font.glyph.bitmap.rows
|
||||
buffer = font.glyph.bitmap.buffer
|
||||
pitch = font.glyph.bitmap.pitch
|
||||
glyph_data = [0] * ((height * width * bpp + 7) // 8)
|
||||
src_mode = font.glyph.bitmap.pixel_mode
|
||||
pos = 0
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
if src_mode == ft_pixel_mode_mono:
|
||||
pixel = (
|
||||
(1 << bpp) - 1
|
||||
if buffer[y * pitch + x // 8] & (1 << (7 - x % 8))
|
||||
else 0
|
||||
)
|
||||
else:
|
||||
pixel = buffer[y * pitch + x] // scale
|
||||
for bit_num in range(bpp):
|
||||
if pixel & (1 << (bpp - bit_num - 1)):
|
||||
glyph_data[pos // 8] |= 0x80 >> (pos % 8)
|
||||
pos += 1
|
||||
ascender = pt_to_px(font.size.ascender)
|
||||
if ascender == 0:
|
||||
if not font.is_scalable:
|
||||
ascender = size
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"Unable to determine ascender of font %s", config[CONF_FILE]
|
||||
)
|
||||
glyph_args[codepoint] = GlyphInfo(
|
||||
len(data),
|
||||
pt_to_px(font.glyph.metrics.horiAdvance),
|
||||
font.glyph.bitmap_left,
|
||||
ascender - font.glyph.bitmap_top,
|
||||
width,
|
||||
height,
|
||||
)
|
||||
data += glyph_data
|
||||
|
||||
rhs = [HexInt(x) for x in data]
|
||||
glyph_args = [
|
||||
glyph_to_glyphinfo(x, point_font_map[x], size, bpp) for x in codepoints
|
||||
]
|
||||
rhs = [HexInt(x) for x in flatten([x.bitmap_data for x in glyph_args])]
|
||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||
|
||||
# Create the glyph table that points to data in the above array.
|
||||
glyph_initializer = []
|
||||
for codepoint in codepoints:
|
||||
glyph_initializer.append(
|
||||
cg.StructInitializer(
|
||||
GlyphData,
|
||||
(
|
||||
"a_char",
|
||||
cg.RawExpression(
|
||||
f"(const uint8_t *){cpp_string_escape(codepoint)}"
|
||||
),
|
||||
),
|
||||
(
|
||||
"data",
|
||||
cg.RawExpression(
|
||||
f"{str(prog_arr)} + {str(glyph_args[codepoint].data_len)}"
|
||||
),
|
||||
),
|
||||
("advance", glyph_args[codepoint].advance),
|
||||
("offset_x", glyph_args[codepoint].offset_x),
|
||||
("offset_y", glyph_args[codepoint].offset_y),
|
||||
("width", glyph_args[codepoint].width),
|
||||
("height", glyph_args[codepoint].height),
|
||||
)
|
||||
glyph_initializer = [
|
||||
cg.StructInitializer(
|
||||
GlyphData,
|
||||
(
|
||||
"a_char",
|
||||
cg.RawExpression(f"(const uint8_t *){cpp_string_escape(x.glyph)}"),
|
||||
),
|
||||
(
|
||||
"data",
|
||||
cg.RawExpression(f"{str(prog_arr)} + {str(y - len(x.bitmap_data))}"),
|
||||
),
|
||||
("advance", x.advance),
|
||||
("offset_x", x.offset_x),
|
||||
("offset_y", x.offset_y),
|
||||
("width", x.width),
|
||||
("height", x.height),
|
||||
)
|
||||
for (x, y) in zip(
|
||||
glyph_args, list(accumulate([len(x.bitmap_data) for x in glyph_args]))
|
||||
)
|
||||
]
|
||||
|
||||
glyphs = cg.static_const_array(config[CONF_RAW_GLYPH_ID], glyph_initializer)
|
||||
|
||||
font_height = pt_to_px(base_font.size.height)
|
||||
ascender = pt_to_px(base_font.size.ascender)
|
||||
descender = abs(pt_to_px(base_font.size.descender))
|
||||
g = glyph_to_glyphinfo("x", base_font, size, bpp)
|
||||
xheight = g.height if len(g.bitmap_data) > 1 else 0
|
||||
g = glyph_to_glyphinfo("X", base_font, size, bpp)
|
||||
capheight = g.height if len(g.bitmap_data) > 1 else 0
|
||||
if font_height == 0:
|
||||
if not base_font.is_scalable:
|
||||
font_height = size
|
||||
@@ -610,5 +617,8 @@ async def to_code(config):
|
||||
len(glyph_initializer),
|
||||
ascender,
|
||||
font_height,
|
||||
descender,
|
||||
xheight,
|
||||
capheight,
|
||||
bpp,
|
||||
)
|
||||
|
||||
@@ -45,8 +45,15 @@ void Glyph::scan_area(int *x1, int *y1, int *width, int *height) const {
|
||||
*height = this->glyph_data_->height;
|
||||
}
|
||||
|
||||
Font::Font(const GlyphData *data, int data_nr, int baseline, int height, uint8_t bpp)
|
||||
: baseline_(baseline), height_(height), bpp_(bpp) {
|
||||
Font::Font(const GlyphData *data, int data_nr, int baseline, int height, int descender, int xheight, int capheight,
|
||||
uint8_t bpp)
|
||||
: baseline_(baseline),
|
||||
height_(height),
|
||||
descender_(descender),
|
||||
linegap_(height - baseline - descender),
|
||||
xheight_(xheight),
|
||||
capheight_(capheight),
|
||||
bpp_(bpp) {
|
||||
glyphs_.reserve(data_nr);
|
||||
for (int i = 0; i < data_nr; ++i)
|
||||
glyphs_.emplace_back(&data[i]);
|
||||
|
||||
@@ -50,11 +50,17 @@ class Font
|
||||
public:
|
||||
/** Construct the font with the given glyphs.
|
||||
*
|
||||
* @param glyphs A vector of glyphs, must be sorted lexicographically.
|
||||
* @param data A vector of glyphs, must be sorted lexicographically.
|
||||
* @param data_nr The number of glyphs in data.
|
||||
* @param baseline The y-offset from the top of the text to the baseline.
|
||||
* @param bottom The y-offset from the top of the text to the bottom (i.e. height).
|
||||
* @param height The y-offset from the top of the text to the bottom.
|
||||
* @param descender The y-offset from the baseline to the lowest stroke in the font (e.g. from letters like g or p).
|
||||
* @param xheight The height of lowercase letters, usually measured at the "x" glyph.
|
||||
* @param capheight The height of capital letters, usually measured at the "X" glyph.
|
||||
* @param bpp The bits per pixel used for this font. Used to read data out of the glyph bitmaps.
|
||||
*/
|
||||
Font(const GlyphData *data, int data_nr, int baseline, int height, uint8_t bpp = 1);
|
||||
Font(const GlyphData *data, int data_nr, int baseline, int height, int descender, int xheight, int capheight,
|
||||
uint8_t bpp = 1);
|
||||
|
||||
int match_next_glyph(const uint8_t *str, int *match_length);
|
||||
|
||||
@@ -65,6 +71,11 @@ class Font
|
||||
#endif
|
||||
inline int get_baseline() { return this->baseline_; }
|
||||
inline int get_height() { return this->height_; }
|
||||
inline int get_ascender() { return this->baseline_; }
|
||||
inline int get_descender() { return this->descender_; }
|
||||
inline int get_linegap() { return this->linegap_; }
|
||||
inline int get_xheight() { return this->xheight_; }
|
||||
inline int get_capheight() { return this->capheight_; }
|
||||
inline int get_bpp() { return this->bpp_; }
|
||||
|
||||
const std::vector<Glyph, RAMAllocator<Glyph>> &get_glyphs() const { return glyphs_; }
|
||||
@@ -73,6 +84,10 @@ class Font
|
||||
std::vector<Glyph, RAMAllocator<Glyph>> glyphs_;
|
||||
int baseline_;
|
||||
int height_;
|
||||
int descender_;
|
||||
int linegap_;
|
||||
int xheight_;
|
||||
int capheight_;
|
||||
uint8_t bpp_; // bits per pixel
|
||||
};
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@ from esphome.const import (
|
||||
CONF_WHITE,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
from .automation import LIGHT_STATE_SCHEMA
|
||||
from .effects import (
|
||||
@@ -110,6 +110,8 @@ LIGHT_SCHEMA = (
|
||||
)
|
||||
)
|
||||
|
||||
LIGHT_SCHEMA.add_extra(entity_duplicate_validator("light"))
|
||||
|
||||
BINARY_LIGHT_SCHEMA = LIGHT_SCHEMA.extend(
|
||||
{
|
||||
cv.Optional(CONF_EFFECTS): validate_effects(BINARY_EFFECTS),
|
||||
@@ -207,7 +209,7 @@ def validate_color_temperature_channels(value):
|
||||
|
||||
|
||||
async def setup_light_core_(light_var, output_var, config):
|
||||
await setup_entity(light_var, config)
|
||||
await setup_entity(light_var, config, "light")
|
||||
|
||||
cg.add(light_var.set_restore_mode(config[CONF_RESTORE_MODE]))
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ from esphome.const import (
|
||||
CONF_WEB_SERVER,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
@@ -67,6 +67,9 @@ _LOCK_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_LOCK_SCHEMA.add_extra(entity_duplicate_validator("lock"))
|
||||
|
||||
|
||||
def lock_schema(
|
||||
class_: MockObjClass = cv.UNDEFINED,
|
||||
*,
|
||||
@@ -94,7 +97,7 @@ LOCK_SCHEMA.add_extra(cv.deprecated_schema_constant("lock"))
|
||||
|
||||
|
||||
async def _setup_lock_core(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "lock")
|
||||
|
||||
for conf in config.get(CONF_ON_LOCK, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
|
||||
@@ -184,7 +184,9 @@ CONFIG_SCHEMA = cv.All(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(Logger),
|
||||
cv.Optional(CONF_BAUD_RATE, default=115200): cv.positive_int,
|
||||
cv.Optional(CONF_TX_BUFFER_SIZE, default=512): cv.validate_bytes,
|
||||
cv.Optional(CONF_TX_BUFFER_SIZE, default=512): cv.All(
|
||||
cv.validate_bytes, cv.int_range(min=160, max=65535)
|
||||
),
|
||||
cv.Optional(CONF_DEASSERT_RTS_DTR, default=False): cv.boolean,
|
||||
cv.SplitDefault(
|
||||
CONF_TASK_LOG_BUFFER_SIZE,
|
||||
|
||||
@@ -24,7 +24,7 @@ static const char *const TAG = "logger";
|
||||
// - Messages are serialized through main loop for proper console output
|
||||
// - Fallback to emergency console logging only if ring buffer is full
|
||||
// - WITHOUT task log buffer: Only emergency console output, no callbacks
|
||||
void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char *format, va_list args) { // NOLINT
|
||||
void HOT Logger::log_vprintf_(uint8_t level, const char *tag, int line, const char *format, va_list args) { // NOLINT
|
||||
if (level > this->level_for(tag))
|
||||
return;
|
||||
|
||||
@@ -46,8 +46,8 @@ void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char *
|
||||
bool message_sent = false;
|
||||
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
|
||||
// For non-main tasks, queue the message for callbacks - but only if we have any callbacks registered
|
||||
message_sent = this->log_buffer_->send_message_thread_safe(static_cast<uint8_t>(level), tag,
|
||||
static_cast<uint16_t>(line), current_task, format, args);
|
||||
message_sent =
|
||||
this->log_buffer_->send_message_thread_safe(level, tag, static_cast<uint16_t>(line), current_task, format, args);
|
||||
#endif // USE_ESPHOME_TASK_LOG_BUFFER
|
||||
|
||||
// Emergency console logging for non-main tasks when ring buffer is full or disabled
|
||||
@@ -58,7 +58,7 @@ void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char *
|
||||
// Maximum size for console log messages (includes null terminator)
|
||||
static const size_t MAX_CONSOLE_LOG_MSG_SIZE = 144;
|
||||
char console_buffer[MAX_CONSOLE_LOG_MSG_SIZE]; // MUST be stack allocated for thread safety
|
||||
int buffer_at = 0; // Initialize buffer position
|
||||
uint16_t buffer_at = 0; // Initialize buffer position
|
||||
this->format_log_to_buffer_with_terminator_(level, tag, line, format, args, console_buffer, &buffer_at,
|
||||
MAX_CONSOLE_LOG_MSG_SIZE);
|
||||
this->write_msg_(console_buffer);
|
||||
@@ -69,7 +69,7 @@ void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char *
|
||||
}
|
||||
#else
|
||||
// Implementation for all other platforms
|
||||
void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char *format, va_list args) { // NOLINT
|
||||
void HOT Logger::log_vprintf_(uint8_t level, const char *tag, int line, const char *format, va_list args) { // NOLINT
|
||||
if (level > this->level_for(tag) || global_recursion_guard_)
|
||||
return;
|
||||
|
||||
@@ -85,7 +85,7 @@ void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char *
|
||||
#ifdef USE_STORE_LOG_STR_IN_FLASH
|
||||
// Implementation for ESP8266 with flash string support.
|
||||
// Note: USE_STORE_LOG_STR_IN_FLASH is only defined for ESP8266.
|
||||
void Logger::log_vprintf_(int level, const char *tag, int line, const __FlashStringHelper *format,
|
||||
void Logger::log_vprintf_(uint8_t level, const char *tag, int line, const __FlashStringHelper *format,
|
||||
va_list args) { // NOLINT
|
||||
if (level > this->level_for(tag) || global_recursion_guard_)
|
||||
return;
|
||||
@@ -122,7 +122,7 @@ void Logger::log_vprintf_(int level, const char *tag, int line, const __FlashStr
|
||||
}
|
||||
#endif // USE_STORE_LOG_STR_IN_FLASH
|
||||
|
||||
inline int Logger::level_for(const char *tag) {
|
||||
inline uint8_t Logger::level_for(const char *tag) {
|
||||
auto it = this->log_levels_.find(tag);
|
||||
if (it != this->log_levels_.end())
|
||||
return it->second;
|
||||
@@ -195,13 +195,13 @@ void Logger::loop() {
|
||||
#endif
|
||||
|
||||
void Logger::set_baud_rate(uint32_t baud_rate) { this->baud_rate_ = baud_rate; }
|
||||
void Logger::set_log_level(const std::string &tag, int log_level) { this->log_levels_[tag] = log_level; }
|
||||
void Logger::set_log_level(const std::string &tag, uint8_t log_level) { this->log_levels_[tag] = log_level; }
|
||||
|
||||
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY)
|
||||
UARTSelection Logger::get_uart() const { return this->uart_; }
|
||||
#endif
|
||||
|
||||
void Logger::add_on_log_callback(std::function<void(int, const char *, const char *)> &&callback) {
|
||||
void Logger::add_on_log_callback(std::function<void(uint8_t, const char *, const char *)> &&callback) {
|
||||
this->log_callback_.add(std::move(callback));
|
||||
}
|
||||
float Logger::get_setup_priority() const { return setup_priority::BUS + 500.0f; }
|
||||
@@ -230,7 +230,7 @@ void Logger::dump_config() {
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::set_log_level(int level) {
|
||||
void Logger::set_log_level(uint8_t level) {
|
||||
if (level > ESPHOME_LOG_LEVEL) {
|
||||
level = ESPHOME_LOG_LEVEL;
|
||||
ESP_LOGW(TAG, "Cannot set log level higher than pre-compiled %s", LOG_LEVELS[ESPHOME_LOG_LEVEL]);
|
||||
|
||||
@@ -61,7 +61,7 @@ static const char *const LOG_LEVEL_LETTERS[] = {
|
||||
*
|
||||
* Advanced configuration (pin selection, etc) is not supported.
|
||||
*/
|
||||
enum UARTSelection {
|
||||
enum UARTSelection : uint8_t {
|
||||
#ifdef USE_LIBRETINY
|
||||
UART_SELECTION_DEFAULT = 0,
|
||||
UART_SELECTION_UART0,
|
||||
@@ -129,10 +129,10 @@ class Logger : public Component {
|
||||
#endif
|
||||
|
||||
/// Set the default log level for this logger.
|
||||
void set_log_level(int level);
|
||||
void set_log_level(uint8_t level);
|
||||
/// Set the log level of the specified tag.
|
||||
void set_log_level(const std::string &tag, int log_level);
|
||||
int get_log_level() { return this->current_level_; }
|
||||
void set_log_level(const std::string &tag, uint8_t log_level);
|
||||
uint8_t get_log_level() { return this->current_level_; }
|
||||
|
||||
// ========== INTERNAL METHODS ==========
|
||||
// (In most use cases you won't need these)
|
||||
@@ -140,19 +140,20 @@ class Logger : public Component {
|
||||
void pre_setup();
|
||||
void dump_config() override;
|
||||
|
||||
inline int level_for(const char *tag);
|
||||
inline uint8_t level_for(const char *tag);
|
||||
|
||||
/// Register a callback that will be called for every log message sent
|
||||
void add_on_log_callback(std::function<void(int, const char *, const char *)> &&callback);
|
||||
void add_on_log_callback(std::function<void(uint8_t, const char *, const char *)> &&callback);
|
||||
|
||||
// add a listener for log level changes
|
||||
void add_listener(std::function<void(int)> &&callback) { this->level_callback_.add(std::move(callback)); }
|
||||
void add_listener(std::function<void(uint8_t)> &&callback) { this->level_callback_.add(std::move(callback)); }
|
||||
|
||||
float get_setup_priority() const override;
|
||||
|
||||
void log_vprintf_(int level, const char *tag, int line, const char *format, va_list args); // NOLINT
|
||||
void log_vprintf_(uint8_t level, const char *tag, int line, const char *format, va_list args); // NOLINT
|
||||
#ifdef USE_STORE_LOG_STR_IN_FLASH
|
||||
void log_vprintf_(int level, const char *tag, int line, const __FlashStringHelper *format, va_list args); // NOLINT
|
||||
void log_vprintf_(uint8_t level, const char *tag, int line, const __FlashStringHelper *format,
|
||||
va_list args); // NOLINT
|
||||
#endif
|
||||
|
||||
protected:
|
||||
@@ -160,8 +161,9 @@ class Logger : public Component {
|
||||
|
||||
// Format a log message with printf-style arguments and write it to a buffer with header, footer, and null terminator
|
||||
// It's the caller's responsibility to initialize buffer_at (typically to 0)
|
||||
inline void HOT format_log_to_buffer_with_terminator_(int level, const char *tag, int line, const char *format,
|
||||
va_list args, char *buffer, int *buffer_at, int buffer_size) {
|
||||
inline void HOT format_log_to_buffer_with_terminator_(uint8_t level, const char *tag, int line, const char *format,
|
||||
va_list args, char *buffer, uint16_t *buffer_at,
|
||||
uint16_t buffer_size) {
|
||||
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
|
||||
this->write_header_to_buffer_(level, tag, line, this->get_thread_name_(), buffer, buffer_at, buffer_size);
|
||||
#else
|
||||
@@ -180,7 +182,7 @@ class Logger : public Component {
|
||||
}
|
||||
|
||||
// Helper to format and send a log message to both console and callbacks
|
||||
inline void HOT log_message_to_buffer_and_send_(int level, const char *tag, int line, const char *format,
|
||||
inline void HOT log_message_to_buffer_and_send_(uint8_t level, const char *tag, int line, const char *format,
|
||||
va_list args) {
|
||||
// Format to tx_buffer and prepare for output
|
||||
this->tx_buffer_at_ = 0; // Initialize buffer position
|
||||
@@ -194,11 +196,12 @@ class Logger : public Component {
|
||||
}
|
||||
|
||||
// Write the body of the log message to the buffer
|
||||
inline void write_body_to_buffer_(const char *value, size_t length, char *buffer, int *buffer_at, int buffer_size) {
|
||||
inline void write_body_to_buffer_(const char *value, size_t length, char *buffer, uint16_t *buffer_at,
|
||||
uint16_t buffer_size) {
|
||||
// Calculate available space
|
||||
const int available = buffer_size - *buffer_at;
|
||||
if (available <= 0)
|
||||
if (*buffer_at >= buffer_size)
|
||||
return;
|
||||
const uint16_t available = buffer_size - *buffer_at;
|
||||
|
||||
// Determine copy length (minimum of remaining capacity and string length)
|
||||
const size_t copy_len = (length < static_cast<size_t>(available)) ? length : available;
|
||||
@@ -211,7 +214,7 @@ class Logger : public Component {
|
||||
}
|
||||
|
||||
// Format string to explicit buffer with varargs
|
||||
inline void printf_to_buffer_(char *buffer, int *buffer_at, int buffer_size, const char *format, ...) {
|
||||
inline void printf_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size, const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
this->format_body_to_buffer_(buffer, buffer_at, buffer_size, format, arg);
|
||||
@@ -222,41 +225,50 @@ class Logger : public Component {
|
||||
const char *get_uart_selection_();
|
||||
#endif
|
||||
|
||||
// Group 4-byte aligned members first
|
||||
uint32_t baud_rate_;
|
||||
char *tx_buffer_{nullptr};
|
||||
int tx_buffer_at_{0};
|
||||
int tx_buffer_size_{0};
|
||||
#ifdef USE_ARDUINO
|
||||
Stream *hw_serial_{nullptr};
|
||||
#endif
|
||||
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
|
||||
void *main_task_ = nullptr; // Only used for thread name identification
|
||||
#endif
|
||||
#ifdef USE_ESP32
|
||||
// Task-specific recursion guards:
|
||||
// - Main task uses a dedicated member variable for efficiency
|
||||
// - Other tasks use pthread TLS with a dynamically created key via pthread_key_create
|
||||
pthread_key_t log_recursion_key_; // 4 bytes
|
||||
#endif
|
||||
#ifdef USE_ESP_IDF
|
||||
uart_port_t uart_num_; // 4 bytes (enum defaults to int size)
|
||||
#endif
|
||||
|
||||
// Large objects (internally aligned)
|
||||
std::map<std::string, uint8_t> log_levels_{};
|
||||
CallbackManager<void(uint8_t, const char *, const char *)> log_callback_{};
|
||||
CallbackManager<void(uint8_t)> level_callback_{};
|
||||
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
|
||||
std::unique_ptr<logger::TaskLogBuffer> log_buffer_; // Will be initialized with init_log_buffer
|
||||
#endif
|
||||
|
||||
// Group smaller types together at the end
|
||||
uint16_t tx_buffer_at_{0};
|
||||
uint16_t tx_buffer_size_{0};
|
||||
uint8_t current_level_{ESPHOME_LOG_LEVEL_VERY_VERBOSE};
|
||||
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040)
|
||||
UARTSelection uart_{UART_SELECTION_UART0};
|
||||
#endif
|
||||
#ifdef USE_LIBRETINY
|
||||
UARTSelection uart_{UART_SELECTION_DEFAULT};
|
||||
#endif
|
||||
#ifdef USE_ARDUINO
|
||||
Stream *hw_serial_{nullptr};
|
||||
#endif
|
||||
#ifdef USE_ESP_IDF
|
||||
uart_port_t uart_num_;
|
||||
#endif
|
||||
std::map<std::string, int> log_levels_{};
|
||||
CallbackManager<void(int, const char *, const char *)> log_callback_{};
|
||||
int current_level_{ESPHOME_LOG_LEVEL_VERY_VERBOSE};
|
||||
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
|
||||
std::unique_ptr<logger::TaskLogBuffer> log_buffer_; // Will be initialized with init_log_buffer
|
||||
#endif
|
||||
#ifdef USE_ESP32
|
||||
// Task-specific recursion guards:
|
||||
// - Main task uses a dedicated member variable for efficiency
|
||||
// - Other tasks use pthread TLS with a dynamically created key via pthread_key_create
|
||||
bool main_task_recursion_guard_{false};
|
||||
pthread_key_t log_recursion_key_;
|
||||
#else
|
||||
bool global_recursion_guard_{false}; // Simple global recursion guard for single-task platforms
|
||||
#endif
|
||||
CallbackManager<void(int)> level_callback_{};
|
||||
|
||||
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
|
||||
void *main_task_ = nullptr; // Only used for thread name identification
|
||||
const char *HOT get_thread_name_() {
|
||||
TaskHandle_t current_task = xTaskGetCurrentTaskHandle();
|
||||
if (current_task == main_task_) {
|
||||
@@ -297,11 +309,10 @@ class Logger : public Component {
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void HOT write_header_to_buffer_(int level, const char *tag, int line, const char *thread_name, char *buffer,
|
||||
int *buffer_at, int buffer_size) {
|
||||
inline void HOT write_header_to_buffer_(uint8_t level, const char *tag, int line, const char *thread_name,
|
||||
char *buffer, uint16_t *buffer_at, uint16_t buffer_size) {
|
||||
// Format header
|
||||
if (level < 0)
|
||||
level = 0;
|
||||
// uint8_t level is already bounded 0-255, just ensure it's <= 7
|
||||
if (level > 7)
|
||||
level = 7;
|
||||
|
||||
@@ -320,12 +331,12 @@ class Logger : public Component {
|
||||
this->printf_to_buffer_(buffer, buffer_at, buffer_size, "%s[%s][%s:%03u]: ", color, letter, tag, line);
|
||||
}
|
||||
|
||||
inline void HOT format_body_to_buffer_(char *buffer, int *buffer_at, int buffer_size, const char *format,
|
||||
inline void HOT format_body_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size, const char *format,
|
||||
va_list args) {
|
||||
// Get remaining capacity in the buffer
|
||||
const int remaining = buffer_size - *buffer_at;
|
||||
if (remaining <= 0)
|
||||
if (*buffer_at >= buffer_size)
|
||||
return;
|
||||
const uint16_t remaining = buffer_size - *buffer_at;
|
||||
|
||||
const int ret = vsnprintf(buffer + *buffer_at, remaining, format, args);
|
||||
|
||||
@@ -334,7 +345,7 @@ class Logger : public Component {
|
||||
}
|
||||
|
||||
// Update buffer_at with the formatted length (handle truncation)
|
||||
int formatted_len = (ret >= remaining) ? remaining : ret;
|
||||
uint16_t formatted_len = (ret >= remaining) ? remaining : ret;
|
||||
*buffer_at += formatted_len;
|
||||
|
||||
// Remove all trailing newlines right after formatting
|
||||
@@ -343,18 +354,18 @@ class Logger : public Component {
|
||||
}
|
||||
}
|
||||
|
||||
inline void HOT write_footer_to_buffer_(char *buffer, int *buffer_at, int buffer_size) {
|
||||
static const int RESET_COLOR_LEN = strlen(ESPHOME_LOG_RESET_COLOR);
|
||||
inline void HOT write_footer_to_buffer_(char *buffer, uint16_t *buffer_at, uint16_t buffer_size) {
|
||||
static const uint16_t RESET_COLOR_LEN = strlen(ESPHOME_LOG_RESET_COLOR);
|
||||
this->write_body_to_buffer_(ESPHOME_LOG_RESET_COLOR, RESET_COLOR_LEN, buffer, buffer_at, buffer_size);
|
||||
}
|
||||
};
|
||||
extern Logger *global_logger; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
class LoggerMessageTrigger : public Trigger<int, const char *, const char *> {
|
||||
class LoggerMessageTrigger : public Trigger<uint8_t, const char *, const char *> {
|
||||
public:
|
||||
explicit LoggerMessageTrigger(Logger *parent, int level) {
|
||||
explicit LoggerMessageTrigger(Logger *parent, uint8_t level) {
|
||||
this->level_ = level;
|
||||
parent->add_on_log_callback([this](int level, const char *tag, const char *message) {
|
||||
parent->add_on_log_callback([this](uint8_t level, const char *tag, const char *message) {
|
||||
if (level <= this->level_) {
|
||||
this->trigger(level, tag, message);
|
||||
}
|
||||
@@ -362,7 +373,7 @@ class LoggerMessageTrigger : public Trigger<int, const char *, const char *> {
|
||||
}
|
||||
|
||||
protected:
|
||||
int level_;
|
||||
uint8_t level_;
|
||||
};
|
||||
|
||||
} // namespace logger
|
||||
|
||||
@@ -454,9 +454,13 @@ def container_validator(schema, widget_type: WidgetType):
|
||||
"""
|
||||
|
||||
def validator(value):
|
||||
result = schema
|
||||
if w_sch := widget_type.schema:
|
||||
result = result.extend(w_sch)
|
||||
if isinstance(w_sch, dict):
|
||||
w_sch = cv.Schema(w_sch)
|
||||
# order is important here to preserve extras
|
||||
result = w_sch.extend(schema)
|
||||
else:
|
||||
result = schema
|
||||
ltype = df.TYPE_NONE
|
||||
if value and (layout := value.get(df.CONF_LAYOUT)):
|
||||
if not isinstance(layout, dict):
|
||||
|
||||
@@ -3,7 +3,6 @@ import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID
|
||||
from esphome.core import ID
|
||||
from esphome.cpp_generator import MockObj
|
||||
|
||||
from .defines import (
|
||||
CONF_STYLE_DEFINITIONS,
|
||||
@@ -13,12 +12,13 @@ from .defines import (
|
||||
literal,
|
||||
)
|
||||
from .helpers import add_lv_use
|
||||
from .lvcode import LambdaContext, LocalVariable, lv, lv_assign, lv_variable
|
||||
from .lvcode import LambdaContext, LocalVariable, lv
|
||||
from .schemas import ALL_STYLES, FULL_STYLE_SCHEMA, STYLE_REMAP
|
||||
from .types import ObjUpdateAction, lv_lambda_t, lv_obj_t, lv_obj_t_ptr, lv_style_t
|
||||
from .types import ObjUpdateAction, lv_obj_t, lv_style_t
|
||||
from .widgets import (
|
||||
Widget,
|
||||
add_widgets,
|
||||
collect_parts,
|
||||
set_obj_properties,
|
||||
theme_widget_map,
|
||||
wait_for_widgets,
|
||||
@@ -37,12 +37,18 @@ async def style_set(svar, style):
|
||||
lv.call(f"style_set_{remapped_prop}", svar, literal(value))
|
||||
|
||||
|
||||
async def create_style(style, id_name):
|
||||
style_id = ID(id_name, True, lv_style_t)
|
||||
svar = cg.new_Pvariable(style_id)
|
||||
lv.style_init(svar)
|
||||
await style_set(svar, style)
|
||||
return svar
|
||||
|
||||
|
||||
async def styles_to_code(config):
|
||||
"""Convert styles to C__ code."""
|
||||
for style in config.get(CONF_STYLE_DEFINITIONS, ()):
|
||||
svar = cg.new_Pvariable(style[CONF_ID])
|
||||
lv.style_init(svar)
|
||||
await style_set(svar, style)
|
||||
await create_style(style, style[CONF_ID].id)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
@@ -68,16 +74,18 @@ async def theme_to_code(config):
|
||||
if theme := config.get(CONF_THEME):
|
||||
add_lv_use(CONF_THEME)
|
||||
for w_name, style in theme.items():
|
||||
if not isinstance(style, dict):
|
||||
continue
|
||||
|
||||
lname = "lv_theme_apply_" + w_name
|
||||
apply = lv_variable(lv_lambda_t, lname)
|
||||
theme_widget_map[w_name] = apply
|
||||
ow = Widget.create("obj", MockObj(ID("obj")), obj_spec)
|
||||
async with LambdaContext([(lv_obj_t_ptr, "obj")], where=w_name) as context:
|
||||
await set_obj_properties(ow, style)
|
||||
lv_assign(apply, await context.get_lambda())
|
||||
# Work around Python 3.10 bug with nested async comprehensions
|
||||
# With Python 3.11 this could be simplified
|
||||
styles = {}
|
||||
for part, states in collect_parts(style).items():
|
||||
styles[part] = {
|
||||
state: await create_style(
|
||||
props,
|
||||
"_lv_theme_style_" + w_name + "_" + part + "_" + state,
|
||||
)
|
||||
for state, props in states.items()
|
||||
}
|
||||
theme_widget_map[w_name] = styles
|
||||
|
||||
|
||||
async def add_top_layer(lv_component, config):
|
||||
|
||||
@@ -6,7 +6,7 @@ from esphome.config_validation import Invalid
|
||||
from esphome.const import CONF_DEFAULT, CONF_GROUP, CONF_ID, CONF_STATE, CONF_TYPE
|
||||
from esphome.core import ID, TimePeriod
|
||||
from esphome.coroutine import FakeAwaitable
|
||||
from esphome.cpp_generator import CallExpression, MockObj
|
||||
from esphome.cpp_generator import MockObj
|
||||
|
||||
from ..defines import (
|
||||
CONF_FLEX_ALIGN_CROSS,
|
||||
@@ -453,7 +453,17 @@ async def widget_to_code(w_cnfig, w_type: WidgetType, parent):
|
||||
|
||||
w = Widget.create(wid, var, spec, w_cnfig)
|
||||
if theme := theme_widget_map.get(w_type):
|
||||
lv_add(CallExpression(theme, w.obj))
|
||||
for part, states in theme.items():
|
||||
part = "LV_PART_" + part.upper()
|
||||
for state, style in states.items():
|
||||
state = "LV_STATE_" + state.upper()
|
||||
if state == "LV_STATE_DEFAULT":
|
||||
lv_state = literal(part)
|
||||
elif part == "LV_PART_MAIN":
|
||||
lv_state = literal(state)
|
||||
else:
|
||||
lv_state = join_enums((state, part))
|
||||
lv.obj_add_style(w.obj, style, lv_state)
|
||||
await set_obj_properties(w, w_cnfig)
|
||||
await add_widgets(w, w_cnfig)
|
||||
await spec.to_code(w, w_cnfig)
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_MAX_VALUE, CONF_MIN_VALUE, CONF_MODE, CONF_VALUE
|
||||
|
||||
from ..defines import BAR_MODES, CONF_ANIMATED, CONF_INDICATOR, CONF_MAIN, literal
|
||||
from ..lv_validation import animated, get_start_value, lv_float
|
||||
from ..defines import (
|
||||
BAR_MODES,
|
||||
CONF_ANIMATED,
|
||||
CONF_INDICATOR,
|
||||
CONF_MAIN,
|
||||
CONF_START_VALUE,
|
||||
literal,
|
||||
)
|
||||
from ..lv_validation import animated, lv_int
|
||||
from ..lvcode import lv
|
||||
from ..types import LvNumber, NumberType
|
||||
from . import Widget
|
||||
@@ -10,22 +17,30 @@ from . import Widget
|
||||
# Note this file cannot be called "bar.py" because that name is disallowed.
|
||||
|
||||
CONF_BAR = "bar"
|
||||
BAR_MODIFY_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_VALUE): lv_float,
|
||||
cv.Optional(CONF_ANIMATED, default=True): animated,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def validate_bar(config):
|
||||
if config.get(CONF_MODE) != "LV_BAR_MODE_RANGE" and CONF_START_VALUE in config:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_START_VALUE} is only allowed when {CONF_MODE} is set to 'RANGE'"
|
||||
)
|
||||
if (CONF_MIN_VALUE in config) != (CONF_MAX_VALUE in config):
|
||||
raise cv.Invalid(
|
||||
f"If either {CONF_MIN_VALUE} or {CONF_MAX_VALUE} is set, both must be set"
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
BAR_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_VALUE): lv_float,
|
||||
cv.Optional(CONF_MIN_VALUE, default=0): cv.int_,
|
||||
cv.Optional(CONF_MAX_VALUE, default=100): cv.int_,
|
||||
cv.Optional(CONF_MODE, default="NORMAL"): BAR_MODES.one_of,
|
||||
cv.Optional(CONF_VALUE): lv_int,
|
||||
cv.Optional(CONF_START_VALUE): lv_int,
|
||||
cv.Optional(CONF_MIN_VALUE): lv_int,
|
||||
cv.Optional(CONF_MAX_VALUE): lv_int,
|
||||
cv.Optional(CONF_MODE): BAR_MODES.one_of,
|
||||
cv.Optional(CONF_ANIMATED, default=True): animated,
|
||||
}
|
||||
)
|
||||
).add_extra(validate_bar)
|
||||
|
||||
|
||||
class BarType(NumberType):
|
||||
@@ -35,17 +50,23 @@ class BarType(NumberType):
|
||||
LvNumber("lv_bar_t"),
|
||||
parts=(CONF_MAIN, CONF_INDICATOR),
|
||||
schema=BAR_SCHEMA,
|
||||
modify_schema=BAR_MODIFY_SCHEMA,
|
||||
)
|
||||
|
||||
async def to_code(self, w: Widget, config):
|
||||
var = w.obj
|
||||
if mode := config.get(CONF_MODE):
|
||||
lv.bar_set_mode(var, literal(mode))
|
||||
is_animated = literal(config[CONF_ANIMATED])
|
||||
if CONF_MIN_VALUE in config:
|
||||
lv.bar_set_range(var, config[CONF_MIN_VALUE], config[CONF_MAX_VALUE])
|
||||
lv.bar_set_mode(var, literal(config[CONF_MODE]))
|
||||
value = await get_start_value(config)
|
||||
if value is not None:
|
||||
lv.bar_set_value(var, value, literal(config[CONF_ANIMATED]))
|
||||
lv.bar_set_range(
|
||||
var,
|
||||
await lv_int.process(config[CONF_MIN_VALUE]),
|
||||
await lv_int.process(config[CONF_MAX_VALUE]),
|
||||
)
|
||||
if value := await lv_int.process(config.get(CONF_VALUE)):
|
||||
lv.bar_set_value(var, value, is_animated)
|
||||
if start_value := await lv_int.process(config.get(CONF_START_VALUE)):
|
||||
lv.bar_set_start_value(var, start_value, is_animated)
|
||||
|
||||
@property
|
||||
def animated(self):
|
||||
|
||||
@@ -3,7 +3,7 @@ import esphome.config_validation as cv
|
||||
from esphome.const import CONF_SIZE, CONF_TEXT
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
|
||||
from ..defines import CONF_MAIN, literal
|
||||
from ..defines import CONF_MAIN
|
||||
from ..lv_validation import color, color_retmapper, lv_text
|
||||
from ..lvcode import LocalVariable, lv, lv_expr
|
||||
from ..schemas import TEXT_SCHEMA
|
||||
@@ -34,7 +34,7 @@ class QrCodeType(WidgetType):
|
||||
)
|
||||
|
||||
def get_uses(self):
|
||||
return ("canvas", "img")
|
||||
return ("canvas", "img", "label")
|
||||
|
||||
def obj_creator(self, parent: MockObjClass, config: dict):
|
||||
dark_color = color_retmapper(config[CONF_DARK_COLOR])
|
||||
@@ -45,10 +45,8 @@ class QrCodeType(WidgetType):
|
||||
async def to_code(self, w: Widget, config):
|
||||
if (value := config.get(CONF_TEXT)) is not None:
|
||||
value = await lv_text.process(value)
|
||||
with LocalVariable(
|
||||
"qr_text", cg.const_char_ptr, value, modifier=""
|
||||
) as str_obj:
|
||||
lv.qrcode_update(w.obj, str_obj, literal(f"strlen({str_obj})"))
|
||||
with LocalVariable("qr_text", cg.std_string, value, modifier="") as str_obj:
|
||||
lv.qrcode_update(w.obj, str_obj.c_str(), str_obj.size())
|
||||
|
||||
|
||||
qr_code_spec = QrCodeType()
|
||||
|
||||
@@ -11,9 +11,9 @@ from esphome.const import (
|
||||
CONF_VOLUME,
|
||||
)
|
||||
from esphome.core import CORE
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.coroutine import coroutine_with_priority
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
CODEOWNERS = ["@jesserockz"]
|
||||
|
||||
@@ -81,7 +81,7 @@ IsAnnouncingCondition = media_player_ns.class_(
|
||||
|
||||
|
||||
async def setup_media_player_core_(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "media_player")
|
||||
for conf in config.get(CONF_ON_STATE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
@@ -143,6 +143,8 @@ _MEDIA_PLAYER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
|
||||
}
|
||||
)
|
||||
|
||||
_MEDIA_PLAYER_SCHEMA.add_extra(entity_duplicate_validator("media_player"))
|
||||
|
||||
|
||||
def media_player_schema(
|
||||
class_: MockObjClass,
|
||||
@@ -166,7 +168,6 @@ def media_player_schema(
|
||||
MEDIA_PLAYER_SCHEMA = media_player_schema(MediaPlayer)
|
||||
MEDIA_PLAYER_SCHEMA.add_extra(cv.deprecated_schema_constant("media_player"))
|
||||
|
||||
|
||||
MEDIA_PLAYER_ACTION_SCHEMA = automation.maybe_simple_id(
|
||||
cv.Schema(
|
||||
{
|
||||
|
||||
@@ -68,6 +68,7 @@ def AUTO_LOAD():
|
||||
|
||||
CONF_DISCOVER_IP = "discover_ip"
|
||||
CONF_IDF_SEND_ASYNC = "idf_send_async"
|
||||
CONF_WAIT_FOR_CONNECTION = "wait_for_connection"
|
||||
|
||||
|
||||
def validate_message_just_topic(value):
|
||||
@@ -298,6 +299,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_PUBLISH_NAN_AS_NONE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_WAIT_FOR_CONNECTION, default=False): cv.boolean,
|
||||
}
|
||||
),
|
||||
validate_config,
|
||||
@@ -453,6 +455,8 @@ async def to_code(config):
|
||||
|
||||
cg.add(var.set_publish_nan_as_none(config[CONF_PUBLISH_NAN_AS_NONE]))
|
||||
|
||||
cg.add(var.set_wait_for_connection(config[CONF_WAIT_FOR_CONNECTION]))
|
||||
|
||||
|
||||
MQTT_PUBLISH_ACTION_SCHEMA = cv.Schema(
|
||||
{
|
||||
|
||||
@@ -176,7 +176,8 @@ void MQTTClientComponent::dump_config() {
|
||||
}
|
||||
}
|
||||
bool MQTTClientComponent::can_proceed() {
|
||||
return network::is_disabled() || this->state_ == MQTT_CLIENT_DISABLED || this->is_connected();
|
||||
return network::is_disabled() || this->state_ == MQTT_CLIENT_DISABLED || this->is_connected() ||
|
||||
!this->wait_for_connection_;
|
||||
}
|
||||
|
||||
void MQTTClientComponent::start_dnslookup_() {
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
#ifdef USE_MQTT
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/components/json/json_util.h"
|
||||
#include "esphome/components/network/ip_address.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/log.h"
|
||||
#if defined(USE_ESP32)
|
||||
#include "mqtt_backend_esp32.h"
|
||||
#elif defined(USE_ESP8266)
|
||||
@@ -267,6 +267,8 @@ class MQTTClientComponent : public Component {
|
||||
void set_publish_nan_as_none(bool publish_nan_as_none);
|
||||
bool is_publish_nan_as_none() const;
|
||||
|
||||
void set_wait_for_connection(bool wait_for_connection) { this->wait_for_connection_ = wait_for_connection; }
|
||||
|
||||
protected:
|
||||
void send_device_info_();
|
||||
|
||||
@@ -334,6 +336,7 @@ class MQTTClientComponent : public Component {
|
||||
optional<MQTTClientDisconnectReason> disconnect_reason_{};
|
||||
|
||||
bool publish_nan_as_none_{false};
|
||||
bool wait_for_connection_{false};
|
||||
};
|
||||
|
||||
extern MQTTClientComponent *global_mqtt_client; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
@@ -963,13 +963,12 @@ uint16_t Nextion::recv_ret_string_(std::string &response, uint32_t timeout, bool
|
||||
uint16_t ret = 0;
|
||||
uint8_t c = 0;
|
||||
uint8_t nr_of_ff_bytes = 0;
|
||||
uint64_t start;
|
||||
bool exit_flag = false;
|
||||
bool ff_flag = false;
|
||||
|
||||
start = App.get_loop_component_start_time();
|
||||
const uint32_t start = millis();
|
||||
|
||||
while ((timeout == 0 && this->available()) || App.get_loop_component_start_time() - start <= timeout) {
|
||||
while ((timeout == 0 && this->available()) || millis() - start <= timeout) {
|
||||
if (!this->available()) {
|
||||
App.feed_wdt();
|
||||
delay(1);
|
||||
@@ -1038,7 +1037,7 @@ void Nextion::add_no_result_to_queue_(const std::string &variable_name) {
|
||||
nextion_queue->component = new nextion::NextionComponentBase;
|
||||
nextion_queue->component->set_variable_name(variable_name);
|
||||
|
||||
nextion_queue->queue_time = App.get_loop_component_start_time();
|
||||
nextion_queue->queue_time = millis();
|
||||
|
||||
this->nextion_queue_.push_back(nextion_queue);
|
||||
|
||||
|
||||
@@ -76,8 +76,8 @@ from esphome.const import (
|
||||
DEVICE_CLASS_WIND_SPEED,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
DEVICE_CLASSES = [
|
||||
@@ -207,6 +207,9 @@ _NUMBER_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_NUMBER_SCHEMA.add_extra(entity_duplicate_validator("number"))
|
||||
|
||||
|
||||
def number_schema(
|
||||
class_: MockObjClass,
|
||||
*,
|
||||
@@ -237,7 +240,7 @@ NUMBER_SCHEMA.add_extra(cv.deprecated_schema_constant("number"))
|
||||
async def setup_number_core_(
|
||||
var, config, *, min_value: float, max_value: float, step: float
|
||||
):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "number")
|
||||
|
||||
cg.add(var.traits.set_min_value(min_value))
|
||||
cg.add(var.traits.set_max_value(max_value))
|
||||
|
||||
@@ -34,6 +34,7 @@ MULTI_CONF = True
|
||||
|
||||
CONF_ON_DOWNLOAD_FINISHED = "on_download_finished"
|
||||
CONF_PLACEHOLDER = "placeholder"
|
||||
CONF_UPDATE = "update"
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -167,6 +168,7 @@ SET_URL_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(OnlineImage),
|
||||
cv.Required(CONF_URL): cv.templatable(cv.url),
|
||||
cv.Optional(CONF_UPDATE, default=True): cv.templatable(bool),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -188,6 +190,9 @@ async def online_image_action_to_code(config, action_id, template_arg, args):
|
||||
if CONF_URL in config:
|
||||
template_ = await cg.templatable(config[CONF_URL], args, cg.std_string)
|
||||
cg.add(var.set_url(template_))
|
||||
if CONF_UPDATE in config:
|
||||
template_ = await cg.templatable(config[CONF_UPDATE], args, bool)
|
||||
cg.add(var.set_update(template_))
|
||||
return var
|
||||
|
||||
|
||||
|
||||
@@ -201,9 +201,12 @@ template<typename... Ts> class OnlineImageSetUrlAction : public Action<Ts...> {
|
||||
public:
|
||||
OnlineImageSetUrlAction(OnlineImage *parent) : parent_(parent) {}
|
||||
TEMPLATABLE_VALUE(std::string, url)
|
||||
TEMPLATABLE_VALUE(bool, update)
|
||||
void play(Ts... x) override {
|
||||
this->parent_->set_url(this->url_.value(x...));
|
||||
this->parent_->update();
|
||||
if (this->update_.value(x...)) {
|
||||
this->parent_->update();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -46,7 +46,7 @@ def set_sdkconfig_options(config):
|
||||
add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_PANID", config[CONF_PAN_ID])
|
||||
add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_CHANNEL", config[CONF_CHANNEL])
|
||||
add_idf_sdkconfig_option(
|
||||
"CONFIG_OPENTHREAD_NETWORK_MASTERKEY", f"{config[CONF_NETWORK_KEY]:X}"
|
||||
"CONFIG_OPENTHREAD_NETWORK_MASTERKEY", f"{config[CONF_NETWORK_KEY]:X}".lower()
|
||||
)
|
||||
|
||||
if network_name := config.get(CONF_NETWORK_NAME):
|
||||
@@ -54,14 +54,14 @@ def set_sdkconfig_options(config):
|
||||
|
||||
if (ext_pan_id := config.get(CONF_EXT_PAN_ID)) is not None:
|
||||
add_idf_sdkconfig_option(
|
||||
"CONFIG_OPENTHREAD_NETWORK_EXTPANID", f"{ext_pan_id:X}"
|
||||
"CONFIG_OPENTHREAD_NETWORK_EXTPANID", f"{ext_pan_id:X}".lower()
|
||||
)
|
||||
if (mesh_local_prefix := config.get(CONF_MESH_LOCAL_PREFIX)) is not None:
|
||||
add_idf_sdkconfig_option(
|
||||
"CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX", f"{mesh_local_prefix:X}"
|
||||
"CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX", f"{mesh_local_prefix}".lower()
|
||||
)
|
||||
if (pskc := config.get(CONF_PSKC)) is not None:
|
||||
add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_PSKC", f"{pskc:X}")
|
||||
add_idf_sdkconfig_option("CONFIG_OPENTHREAD_NETWORK_PSKC", f"{pskc:X}".lower())
|
||||
|
||||
if CONF_FORCE_DATASET in config:
|
||||
if config[CONF_FORCE_DATASET]:
|
||||
@@ -98,7 +98,7 @@ _CONNECTION_SCHEMA = cv.Schema(
|
||||
cv.Optional(CONF_EXT_PAN_ID): cv.hex_int,
|
||||
cv.Optional(CONF_NETWORK_NAME): cv.string_strict,
|
||||
cv.Optional(CONF_PSKC): cv.hex_int,
|
||||
cv.Optional(CONF_MESH_LOCAL_PREFIX): cv.hex_int,
|
||||
cv.Optional(CONF_MESH_LOCAL_PREFIX): cv.ipv6network,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ void OpenThreadSrpComponent::setup() {
|
||||
// Copy the mdns services to our local instance so that the c_str pointers remain valid for the lifetime of this
|
||||
// component
|
||||
this->mdns_services_ = this->mdns_->get_services();
|
||||
ESP_LOGW(TAG, "Setting up SRP services. count = %d\n", this->mdns_services_.size());
|
||||
ESP_LOGD(TAG, "Setting up SRP services. count = %d\n", this->mdns_services_.size());
|
||||
for (const auto &service : this->mdns_services_) {
|
||||
otSrpClientBuffersServiceEntry *entry = otSrpClientBuffersAllocateService(instance);
|
||||
if (!entry) {
|
||||
@@ -185,11 +185,11 @@ void OpenThreadSrpComponent::setup() {
|
||||
if (error != OT_ERROR_NONE) {
|
||||
ESP_LOGW(TAG, "Failed to add service: %s", otThreadErrorToString(error));
|
||||
}
|
||||
ESP_LOGW(TAG, "Added service: %s", full_service.c_str());
|
||||
ESP_LOGD(TAG, "Added service: %s", full_service.c_str());
|
||||
}
|
||||
|
||||
otSrpClientEnableAutoStartMode(instance, srp_start_callback, nullptr);
|
||||
ESP_LOGW(TAG, "Finished SRP setup");
|
||||
ESP_LOGD(TAG, "Finished SRP setup");
|
||||
}
|
||||
|
||||
void *OpenThreadSrpComponent::pool_alloc_(size_t size) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Sourced from https://gist.github.com/agners/0338576e0003318b63ec1ea75adc90f9
|
||||
import binascii
|
||||
import ipaddress
|
||||
|
||||
from esphome.const import CONF_CHANNEL
|
||||
|
||||
@@ -37,6 +38,12 @@ def parse_tlv(tlv) -> dict:
|
||||
if tag in TLV_TYPES:
|
||||
if tag == 3:
|
||||
output[TLV_TYPES[tag]] = val.decode("utf-8")
|
||||
elif tag == 7:
|
||||
mesh_local_prefix = binascii.hexlify(val).decode("utf-8")
|
||||
mesh_local_prefix_str = f"{mesh_local_prefix}0000000000000000"
|
||||
ipv6_bytes = bytes.fromhex(mesh_local_prefix_str)
|
||||
ipv6_address = ipaddress.IPv6Address(ipv6_bytes)
|
||||
output[TLV_TYPES[tag]] = f"{ipv6_address}/64"
|
||||
else:
|
||||
output[TLV_TYPES[tag]] = int.from_bytes(val)
|
||||
return output
|
||||
|
||||
0
esphome/components/opt3001/__init__.py
Normal file
0
esphome/components/opt3001/__init__.py
Normal file
122
esphome/components/opt3001/opt3001.cpp
Normal file
122
esphome/components/opt3001/opt3001.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
#include "opt3001.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace opt3001 {
|
||||
|
||||
static const char *const TAG = "opt3001.sensor";
|
||||
|
||||
static const uint8_t OPT3001_REG_RESULT = 0x00;
|
||||
static const uint8_t OPT3001_REG_CONFIGURATION = 0x01;
|
||||
// See datasheet for full description of each bit.
|
||||
static const uint16_t OPT3001_CONFIGURATION_RANGE_FULL = 0b1100000000000000;
|
||||
static const uint16_t OPT3001_CONFIGURATION_CONVERSION_TIME_800 = 0b100000000000;
|
||||
static const uint16_t OPT3001_CONFIGURATION_CONVERSION_MODE_MASK = 0b11000000000;
|
||||
static const uint16_t OPT3001_CONFIGURATION_CONVERSION_MODE_SINGLE_SHOT = 0b01000000000;
|
||||
static const uint16_t OPT3001_CONFIGURATION_CONVERSION_MODE_SHUTDOWN = 0b00000000000;
|
||||
// tl;dr: Configure an automatic-ranged, 800ms single shot reading,
|
||||
// with INT processing disabled
|
||||
static const uint16_t OPT3001_CONFIGURATION_FULL_RANGE_ONE_SHOT = OPT3001_CONFIGURATION_RANGE_FULL |
|
||||
OPT3001_CONFIGURATION_CONVERSION_TIME_800 |
|
||||
OPT3001_CONFIGURATION_CONVERSION_MODE_SINGLE_SHOT;
|
||||
static const uint16_t OPT3001_CONVERSION_TIME_800 = 825; // give it 25 extra ms; it seems to not be ready quite often
|
||||
|
||||
/*
|
||||
opt3001 properties:
|
||||
|
||||
- e (exponent) = high 4 bits of result register
|
||||
- m (mantissa) = low 12 bits of result register
|
||||
- formula: (0.01 * 2^e) * m lx
|
||||
|
||||
*/
|
||||
|
||||
void OPT3001Sensor::read_result_(const std::function<void(float)> &f) {
|
||||
// ensure the single shot flag is clear, indicating it's done
|
||||
uint16_t raw_value;
|
||||
if (this->read(reinterpret_cast<uint8_t *>(&raw_value), 2) != i2c::ERROR_OK) {
|
||||
ESP_LOGW(TAG, "Reading configuration register failed");
|
||||
f(NAN);
|
||||
return;
|
||||
}
|
||||
raw_value = i2c::i2ctohs(raw_value);
|
||||
|
||||
if ((raw_value & OPT3001_CONFIGURATION_CONVERSION_MODE_MASK) != OPT3001_CONFIGURATION_CONVERSION_MODE_SHUTDOWN) {
|
||||
// not ready; wait 10ms and try again
|
||||
ESP_LOGW(TAG, "Data not ready; waiting 10ms");
|
||||
this->set_timeout("opt3001_wait", 10, [this, f]() { read_result_(f); });
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->read_register(OPT3001_REG_RESULT, reinterpret_cast<uint8_t *>(&raw_value), 2) != i2c::ERROR_OK) {
|
||||
ESP_LOGW(TAG, "Reading result register failed");
|
||||
f(NAN);
|
||||
return;
|
||||
}
|
||||
raw_value = i2c::i2ctohs(raw_value);
|
||||
|
||||
uint8_t exponent = raw_value >> 12;
|
||||
uint16_t mantissa = raw_value & 0b111111111111;
|
||||
|
||||
double lx = 0.01 * pow(2.0, double(exponent)) * double(mantissa);
|
||||
f(float(lx));
|
||||
}
|
||||
|
||||
void OPT3001Sensor::read_lx_(const std::function<void(float)> &f) {
|
||||
// turn on (after one-shot sensor automatically powers down)
|
||||
uint16_t start_measurement = i2c::htoi2cs(OPT3001_CONFIGURATION_FULL_RANGE_ONE_SHOT);
|
||||
if (this->write_register(OPT3001_REG_CONFIGURATION, reinterpret_cast<uint8_t *>(&start_measurement), 2) !=
|
||||
i2c::ERROR_OK) {
|
||||
ESP_LOGW(TAG, "Triggering one shot measurement failed");
|
||||
f(NAN);
|
||||
return;
|
||||
}
|
||||
|
||||
this->set_timeout("read", OPT3001_CONVERSION_TIME_800, [this, f]() {
|
||||
if (this->write(&OPT3001_REG_CONFIGURATION, 1, true) != i2c::ERROR_OK) {
|
||||
ESP_LOGW(TAG, "Starting configuration register read failed");
|
||||
f(NAN);
|
||||
return;
|
||||
}
|
||||
|
||||
this->read_result_(f);
|
||||
});
|
||||
}
|
||||
|
||||
void OPT3001Sensor::dump_config() {
|
||||
LOG_SENSOR("", "OPT3001", this);
|
||||
LOG_I2C_DEVICE(this);
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
|
||||
}
|
||||
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
void OPT3001Sensor::update() {
|
||||
// Set a flag and skip just in case the sensor isn't responding,
|
||||
// and we just keep waiting for it in read_result_.
|
||||
// This way we don't end up with potentially boundless "threads"
|
||||
// using up memory and eventually crashing the device
|
||||
if (this->updating_) {
|
||||
return;
|
||||
}
|
||||
this->updating_ = true;
|
||||
|
||||
this->read_lx_([this](float val) {
|
||||
this->updating_ = false;
|
||||
|
||||
if (std::isnan(val)) {
|
||||
this->status_set_warning();
|
||||
this->publish_state(NAN);
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "'%s': Illuminance=%.1flx", this->get_name().c_str(), val);
|
||||
this->status_clear_warning();
|
||||
this->publish_state(val);
|
||||
});
|
||||
}
|
||||
|
||||
float OPT3001Sensor::get_setup_priority() const { return setup_priority::DATA; }
|
||||
|
||||
} // namespace opt3001
|
||||
} // namespace esphome
|
||||
27
esphome/components/opt3001/opt3001.h
Normal file
27
esphome/components/opt3001/opt3001.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace opt3001 {
|
||||
|
||||
/// This class implements support for the i2c-based OPT3001 ambient light sensor.
|
||||
class OPT3001Sensor : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
void dump_config() override;
|
||||
void update() override;
|
||||
float get_setup_priority() const override;
|
||||
|
||||
protected:
|
||||
// checks if one-shot is complete before reading the result and returning it
|
||||
void read_result_(const std::function<void(float)> &f);
|
||||
// begins a one-shot measurement
|
||||
void read_lx_(const std::function<void(float)> &f);
|
||||
|
||||
bool updating_{false};
|
||||
};
|
||||
|
||||
} // namespace opt3001
|
||||
} // namespace esphome
|
||||
35
esphome/components/opt3001/sensor.py
Normal file
35
esphome/components/opt3001/sensor.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, sensor
|
||||
from esphome.const import (
|
||||
DEVICE_CLASS_ILLUMINANCE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_LUX,
|
||||
)
|
||||
|
||||
DEPENDENCIES = ["i2c"]
|
||||
CODEOWNERS = ["@ccutrer"]
|
||||
|
||||
opt3001_ns = cg.esphome_ns.namespace("opt3001")
|
||||
|
||||
OPT3001Sensor = opt3001_ns.class_(
|
||||
"OPT3001Sensor", sensor.Sensor, cg.PollingComponent, i2c.I2CDevice
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
sensor.sensor_schema(
|
||||
OPT3001Sensor,
|
||||
unit_of_measurement=UNIT_LUX,
|
||||
accuracy_decimals=1,
|
||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
.extend(i2c.i2c_device_schema(0x44))
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = await sensor.new_sensor(config)
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
@@ -17,8 +17,8 @@ from esphome.const import (
|
||||
CONF_WEB_SERVER,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
@@ -65,6 +65,9 @@ _SELECT_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_SELECT_SCHEMA.add_extra(entity_duplicate_validator("select"))
|
||||
|
||||
|
||||
def select_schema(
|
||||
class_: MockObjClass,
|
||||
*,
|
||||
@@ -89,7 +92,7 @@ SELECT_SCHEMA.add_extra(cv.deprecated_schema_constant("select"))
|
||||
|
||||
|
||||
async def setup_select_core_(var, config, *, options: list[str]):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "select")
|
||||
|
||||
cg.add(var.traits.set_options(options))
|
||||
|
||||
|
||||
@@ -101,8 +101,8 @@ from esphome.const import (
|
||||
ENTITY_CATEGORY_CONFIG,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
from esphome.util import Registry
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
@@ -318,6 +318,8 @@ _SENSOR_SCHEMA = (
|
||||
)
|
||||
)
|
||||
|
||||
_SENSOR_SCHEMA.add_extra(entity_duplicate_validator("sensor"))
|
||||
|
||||
|
||||
def sensor_schema(
|
||||
class_: MockObjClass = cv.UNDEFINED,
|
||||
@@ -787,7 +789,7 @@ async def build_filters(config):
|
||||
|
||||
|
||||
async def setup_sensor_core_(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "sensor")
|
||||
|
||||
if (device_class := config.get(CONF_DEVICE_CLASS)) is not None:
|
||||
cg.add(var.set_device_class(device_class))
|
||||
|
||||
@@ -20,8 +20,8 @@ from esphome.const import (
|
||||
DEVICE_CLASS_SWITCH,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
@@ -91,6 +91,9 @@ _SWITCH_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_SWITCH_SCHEMA.add_extra(entity_duplicate_validator("switch"))
|
||||
|
||||
|
||||
def switch_schema(
|
||||
class_: MockObjClass,
|
||||
*,
|
||||
@@ -131,7 +134,7 @@ SWITCH_SCHEMA.add_extra(cv.deprecated_schema_constant("switch"))
|
||||
|
||||
|
||||
async def setup_switch_core_(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "switch")
|
||||
|
||||
if (inverted := config.get(CONF_INVERTED)) is not None:
|
||||
cg.add(var.set_inverted(inverted))
|
||||
|
||||
@@ -14,8 +14,8 @@ from esphome.const import (
|
||||
CONF_WEB_SERVER,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
CODEOWNERS = ["@mauritskorse"]
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
@@ -58,6 +58,9 @@ _TEXT_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_TEXT_SCHEMA.add_extra(entity_duplicate_validator("text"))
|
||||
|
||||
|
||||
def text_schema(
|
||||
class_: MockObjClass = cv.UNDEFINED,
|
||||
*,
|
||||
@@ -94,7 +97,7 @@ async def setup_text_core_(
|
||||
max_length: int | None,
|
||||
pattern: str | None,
|
||||
):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "text")
|
||||
|
||||
cg.add(var.traits.set_min_length(min_length))
|
||||
cg.add(var.traits.set_max_length(max_length))
|
||||
|
||||
@@ -21,8 +21,8 @@ from esphome.const import (
|
||||
DEVICE_CLASS_TIMESTAMP,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
from esphome.util import Registry
|
||||
|
||||
DEVICE_CLASSES = [
|
||||
@@ -153,6 +153,9 @@ _TEXT_SENSOR_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_TEXT_SENSOR_SCHEMA.add_extra(entity_duplicate_validator("text_sensor"))
|
||||
|
||||
|
||||
def text_sensor_schema(
|
||||
class_: MockObjClass = cv.UNDEFINED,
|
||||
*,
|
||||
@@ -186,7 +189,7 @@ async def build_filters(config):
|
||||
|
||||
|
||||
async def setup_text_sensor_core_(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "text_sensor")
|
||||
|
||||
if (device_class := config.get(CONF_DEVICE_CLASS)) is not None:
|
||||
cg.add(var.set_device_class(device_class))
|
||||
|
||||
@@ -15,8 +15,8 @@ from esphome.const import (
|
||||
ENTITY_CATEGORY_CONFIG,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
CODEOWNERS = ["@jesserockz"]
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
@@ -58,6 +58,9 @@ _UPDATE_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_UPDATE_SCHEMA.add_extra(entity_duplicate_validator("update"))
|
||||
|
||||
|
||||
def update_schema(
|
||||
class_: MockObjClass = cv.UNDEFINED,
|
||||
*,
|
||||
@@ -87,7 +90,7 @@ UPDATE_SCHEMA.add_extra(cv.deprecated_schema_constant("update"))
|
||||
|
||||
|
||||
async def setup_update_core_(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "update")
|
||||
|
||||
if device_class_config := config.get(CONF_DEVICE_CLASS):
|
||||
cg.add(var.set_device_class(device_class_config))
|
||||
|
||||
@@ -6,7 +6,7 @@ from esphome.components.esp32 import (
|
||||
only_on_variant,
|
||||
)
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID
|
||||
from esphome.const import CONF_DEVICES, CONF_ID
|
||||
from esphome.cpp_types import Component
|
||||
|
||||
AUTO_LOAD = ["bytebuffer"]
|
||||
@@ -16,7 +16,6 @@ usb_host_ns = cg.esphome_ns.namespace("usb_host")
|
||||
USBHost = usb_host_ns.class_("USBHost", Component)
|
||||
USBClient = usb_host_ns.class_("USBClient", Component)
|
||||
|
||||
CONF_DEVICES = "devices"
|
||||
CONF_VID = "vid"
|
||||
CONF_PID = "pid"
|
||||
CONF_ENABLE_HUBS = "enable_hubs"
|
||||
|
||||
@@ -22,8 +22,8 @@ from esphome.const import (
|
||||
DEVICE_CLASS_WATER,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
|
||||
@@ -103,6 +103,9 @@ _VALVE_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
_VALVE_SCHEMA.add_extra(entity_duplicate_validator("valve"))
|
||||
|
||||
|
||||
def valve_schema(
|
||||
class_: MockObjClass = cv.UNDEFINED,
|
||||
*,
|
||||
@@ -132,7 +135,7 @@ VALVE_SCHEMA.add_extra(cv.deprecated_schema_constant("valve"))
|
||||
|
||||
|
||||
async def _setup_valve_core(var, config):
|
||||
await setup_entity(var, config)
|
||||
await setup_entity(var, config, "valve")
|
||||
|
||||
if device_class_config := config.get(CONF_DEVICE_CLASS):
|
||||
cg.add(var.set_device_class(device_class_config))
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
"""Helpers for config validation using voluptuous."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import contextmanager
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from ipaddress import AddressValueError, IPv4Address, ip_address
|
||||
from ipaddress import (
|
||||
AddressValueError,
|
||||
IPv4Address,
|
||||
IPv4Network,
|
||||
IPv6Address,
|
||||
IPv6Network,
|
||||
ip_address,
|
||||
ip_network,
|
||||
)
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
@@ -21,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,
|
||||
@@ -347,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.
|
||||
|
||||
@@ -1176,6 +1194,14 @@ def ipv4address(value):
|
||||
return address
|
||||
|
||||
|
||||
def ipv6address(value):
|
||||
try:
|
||||
address = IPv6Address(value)
|
||||
except AddressValueError as exc:
|
||||
raise Invalid(f"{value} is not a valid IPv6 address") from exc
|
||||
return address
|
||||
|
||||
|
||||
def ipv4address_multi_broadcast(value):
|
||||
address = ipv4address(value)
|
||||
if not (address.is_multicast or (address == IPv4Address("255.255.255.255"))):
|
||||
@@ -1193,6 +1219,33 @@ def ipaddress(value):
|
||||
return address
|
||||
|
||||
|
||||
def ipv4network(value):
|
||||
"""Validate that the value is a valid IPv4 network."""
|
||||
try:
|
||||
network = IPv4Network(value, strict=False)
|
||||
except ValueError as exc:
|
||||
raise Invalid(f"{value} is not a valid IPv4 network") from exc
|
||||
return network
|
||||
|
||||
|
||||
def ipv6network(value):
|
||||
"""Validate that the value is a valid IPv6 network."""
|
||||
try:
|
||||
network = IPv6Network(value, strict=False)
|
||||
except ValueError as exc:
|
||||
raise Invalid(f"{value} is not a valid IPv6 network") from exc
|
||||
return network
|
||||
|
||||
|
||||
def ipnetwork(value):
|
||||
"""Validate that the value is a valid IP network."""
|
||||
try:
|
||||
network = ip_network(value, strict=False)
|
||||
except ValueError as exc:
|
||||
raise Invalid(f"{value} is not a valid IP network") from exc
|
||||
return network
|
||||
|
||||
|
||||
def _valid_topic(value):
|
||||
"""Validate that this is a valid topic name/filter."""
|
||||
if value is None: # Used to disable publishing and subscribing
|
||||
@@ -1853,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,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1921,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,8 @@ 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"
|
||||
CONF_DIO_PIN = "dio_pin"
|
||||
|
||||
@@ -522,6 +522,9 @@ class EsphomeCore:
|
||||
# Dict to track platform entity counts for pre-allocation
|
||||
# Key: platform name (e.g. "sensor", "binary_sensor"), Value: count
|
||||
self.platform_counts: defaultdict[str, int] = defaultdict(int)
|
||||
# Track entity unique IDs to handle duplicates
|
||||
# Set of (device_id, platform, sanitized_name) tuples
|
||||
self.unique_ids: set[tuple[str, str, str]] = set()
|
||||
# Whether ESPHome was started in verbose mode
|
||||
self.verbose = False
|
||||
# Whether ESPHome was started in quiet mode
|
||||
@@ -553,6 +556,7 @@ class EsphomeCore:
|
||||
self.loaded_integrations = set()
|
||||
self.component_ids = set()
|
||||
self.platform_counts = defaultdict(int)
|
||||
self.unique_ids = set()
|
||||
PIN_SCHEMA_REGISTRY.reset()
|
||||
|
||||
@property
|
||||
|
||||
@@ -257,6 +257,17 @@ void Application::teardown_components(uint32_t timeout_ms) {
|
||||
}
|
||||
|
||||
void Application::calculate_looping_components_() {
|
||||
// Count total components that need looping
|
||||
size_t total_looping = 0;
|
||||
for (auto *obj : this->components_) {
|
||||
if (obj->has_overridden_loop()) {
|
||||
total_looping++;
|
||||
}
|
||||
}
|
||||
|
||||
// Pre-reserve vector to avoid reallocations
|
||||
this->looping_components_.reserve(total_looping);
|
||||
|
||||
// First add all active components
|
||||
for (auto *obj : this->components_) {
|
||||
if (obj->has_overridden_loop() &&
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
#include "esphome/core/preferences.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
|
||||
@@ -87,7 +94,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;
|
||||
@@ -102,11 +109,17 @@ class Application {
|
||||
this->name_ = name;
|
||||
this->friendly_name_ = friendly_name;
|
||||
}
|
||||
this->area_ = area;
|
||||
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_; }
|
||||
|
||||
@@ -264,6 +277,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) {
|
||||
@@ -285,7 +304,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_; }
|
||||
@@ -334,6 +361,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) {
|
||||
@@ -610,6 +643,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
|
||||
@@ -676,7 +715,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
|
||||
@@ -11,7 +11,14 @@ const StringRef &EntityBase::get_name() const { return this->name_; }
|
||||
void EntityBase::set_name(const char *name) {
|
||||
this->name_ = StringRef(name);
|
||||
if (this->name_.empty()) {
|
||||
this->name_ = StringRef(App.get_friendly_name());
|
||||
#ifdef USE_DEVICES
|
||||
if (this->device_ != nullptr) {
|
||||
this->name_ = StringRef(this->device_->get_name());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
this->name_ = StringRef(App.get_friendly_name());
|
||||
}
|
||||
this->flags_.has_own_name = false;
|
||||
} else {
|
||||
this->flags_.has_own_name = true;
|
||||
@@ -47,19 +54,7 @@ void EntityBase::set_object_id(const char *object_id) {
|
||||
}
|
||||
|
||||
// Calculate Object ID Hash from Entity Name
|
||||
void EntityBase::calc_object_id_() {
|
||||
// Check if `App.get_friendly_name()` is constant or dynamic.
|
||||
if (!this->flags_.has_own_name && App.is_name_add_mac_suffix_enabled()) {
|
||||
// `App.get_friendly_name()` is dynamic.
|
||||
const auto object_id = str_sanitize(str_snake_case(App.get_friendly_name()));
|
||||
// FNV-1 hash
|
||||
this->object_id_hash_ = fnv1_hash(object_id);
|
||||
} else {
|
||||
// `App.get_friendly_name()` is constant.
|
||||
// FNV-1 hash
|
||||
this->object_id_hash_ = fnv1_hash(this->object_id_c_str_);
|
||||
}
|
||||
}
|
||||
void EntityBase::calc_object_id_() { this->object_id_hash_ = fnv1_hash(this->get_object_id()); }
|
||||
|
||||
uint32_t EntityBase::get_object_id_hash() { return this->object_id_hash_; }
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
#include "helpers.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifdef USE_DEVICES
|
||||
#include "device.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
|
||||
enum EntityCategory : uint8_t {
|
||||
@@ -51,6 +55,17 @@ 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 {
|
||||
if (this->device_ == nullptr) {
|
||||
return 0; // No device set, return 0
|
||||
}
|
||||
return this->device_->get_device_id();
|
||||
}
|
||||
void set_device(Device *device) { this->device_ = device; }
|
||||
#endif
|
||||
|
||||
// Check if this entity has state
|
||||
bool has_state() const { return this->flags_.has_state; }
|
||||
|
||||
@@ -67,6 +82,9 @@ class EntityBase {
|
||||
const char *object_id_c_str_{nullptr};
|
||||
const char *icon_c_str_{nullptr};
|
||||
uint32_t object_id_hash_{};
|
||||
#ifdef USE_DEVICES
|
||||
Device *device_{};
|
||||
#endif
|
||||
|
||||
// Bit-packed flags to save memory (1 byte instead of 5)
|
||||
struct EntityFlags {
|
||||
|
||||
@@ -1,5 +1,116 @@
|
||||
from esphome.const import CONF_ID
|
||||
from collections.abc import Callable
|
||||
import logging
|
||||
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_DEVICE_ID,
|
||||
CONF_DISABLED_BY_DEFAULT,
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_ICON,
|
||||
CONF_ID,
|
||||
CONF_INTERNAL,
|
||||
CONF_NAME,
|
||||
)
|
||||
from esphome.core import CORE, ID
|
||||
from esphome.cpp_generator import MockObj, add, get_variable
|
||||
import esphome.final_validate as fv
|
||||
from esphome.helpers import sanitize, snake_case
|
||||
from esphome.types import ConfigType
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_base_entity_object_id(
|
||||
name: str, friendly_name: str | None, device_name: str | None = None
|
||||
) -> str:
|
||||
"""Calculate the base object ID for an entity that will be set via set_object_id().
|
||||
|
||||
This function calculates what object_id_c_str_ should be set to in C++.
|
||||
|
||||
The C++ EntityBase::get_object_id() (entity_base.cpp lines 38-49) works as:
|
||||
- If !has_own_name && is_name_add_mac_suffix_enabled():
|
||||
return str_sanitize(str_snake_case(App.get_friendly_name())) // Dynamic
|
||||
- Else:
|
||||
return object_id_c_str_ ?? "" // What we set via set_object_id()
|
||||
|
||||
Since we're calculating what to pass to set_object_id(), we always need to
|
||||
generate the object_id the same way, regardless of name_add_mac_suffix setting.
|
||||
|
||||
Args:
|
||||
name: The entity name (empty string if no name)
|
||||
friendly_name: The friendly name from CORE.friendly_name
|
||||
device_name: The device name if entity is on a sub-device
|
||||
|
||||
Returns:
|
||||
The base object ID to use for duplicate checking and to pass to set_object_id()
|
||||
"""
|
||||
|
||||
if name:
|
||||
# Entity has its own name (has_own_name will be true)
|
||||
base_str = name
|
||||
elif device_name:
|
||||
# Entity has empty name and is on a sub-device
|
||||
# C++ EntityBase::set_name() uses device->get_name() when device is set
|
||||
base_str = device_name
|
||||
elif friendly_name:
|
||||
# Entity has empty name (has_own_name will be false)
|
||||
# C++ uses App.get_friendly_name() which returns friendly_name or device name
|
||||
base_str = friendly_name
|
||||
else:
|
||||
# Fallback to device name
|
||||
base_str = CORE.name
|
||||
|
||||
return sanitize(snake_case(base_str))
|
||||
|
||||
|
||||
async def setup_entity(var: MockObj, config: ConfigType, platform: str) -> None:
|
||||
"""Set up generic properties of an Entity.
|
||||
|
||||
This function sets up the common entity properties like name, icon,
|
||||
entity category, etc.
|
||||
|
||||
Args:
|
||||
var: The entity variable to set up
|
||||
config: Configuration dictionary containing entity settings
|
||||
platform: The platform name (e.g., "sensor", "binary_sensor")
|
||||
"""
|
||||
# Get device info
|
||||
device_name: str | None = None
|
||||
if CONF_DEVICE_ID in config:
|
||||
device_id_obj: ID = config[CONF_DEVICE_ID]
|
||||
device: MockObj = await get_variable(device_id_obj)
|
||||
add(var.set_device(device))
|
||||
# Get device name for object ID calculation
|
||||
device_name = device_id_obj.id
|
||||
|
||||
add(var.set_name(config[CONF_NAME]))
|
||||
|
||||
# Calculate base object_id using the same logic as C++
|
||||
# This must match the C++ behavior in esphome/core/entity_base.cpp
|
||||
base_object_id = get_base_entity_object_id(
|
||||
config[CONF_NAME], CORE.friendly_name, device_name
|
||||
)
|
||||
|
||||
if not config[CONF_NAME]:
|
||||
_LOGGER.debug(
|
||||
"Entity has empty name, using '%s' as object_id base", base_object_id
|
||||
)
|
||||
|
||||
# Set the object ID
|
||||
add(var.set_object_id(base_object_id))
|
||||
_LOGGER.debug(
|
||||
"Setting object_id '%s' for entity '%s' on platform '%s'",
|
||||
base_object_id,
|
||||
config[CONF_NAME],
|
||||
platform,
|
||||
)
|
||||
add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
|
||||
if CONF_INTERNAL in config:
|
||||
add(var.set_internal(config[CONF_INTERNAL]))
|
||||
if CONF_ICON in config:
|
||||
add(var.set_icon(config[CONF_ICON]))
|
||||
if CONF_ENTITY_CATEGORY in config:
|
||||
add(var.set_entity_category(config[CONF_ENTITY_CATEGORY]))
|
||||
|
||||
|
||||
def inherit_property_from(property_to_inherit, parent_id_property, transform=None):
|
||||
@@ -54,3 +165,48 @@ def inherit_property_from(property_to_inherit, parent_id_property, transform=Non
|
||||
return config
|
||||
|
||||
return inherit_property
|
||||
|
||||
|
||||
def entity_duplicate_validator(platform: str) -> Callable[[ConfigType], ConfigType]:
|
||||
"""Create a validator function to check for duplicate entity names.
|
||||
|
||||
This validator is meant to be used with schema.add_extra() for entity base schemas.
|
||||
|
||||
Args:
|
||||
platform: The platform name (e.g., "sensor", "binary_sensor")
|
||||
|
||||
Returns:
|
||||
A validator function that checks for duplicate names
|
||||
"""
|
||||
|
||||
def validator(config: ConfigType) -> ConfigType:
|
||||
if CONF_NAME not in config:
|
||||
# No name to validate
|
||||
return config
|
||||
|
||||
# Get the entity name and device info
|
||||
entity_name = config[CONF_NAME]
|
||||
device_id = "" # Empty string for main device
|
||||
|
||||
if CONF_DEVICE_ID in config:
|
||||
device_id_obj = config[CONF_DEVICE_ID]
|
||||
# Use the device ID string directly for uniqueness
|
||||
device_id = device_id_obj.id
|
||||
|
||||
# For duplicate detection, just use the sanitized name
|
||||
name_key = sanitize(snake_case(entity_name))
|
||||
|
||||
# Check for duplicates
|
||||
unique_key = (device_id, platform, name_key)
|
||||
if unique_key in CORE.unique_ids:
|
||||
device_prefix = f" on device '{device_id}'" if device_id else ""
|
||||
raise cv.Invalid(
|
||||
f"Duplicate {platform} entity with name '{entity_name}' found{device_prefix}. "
|
||||
f"Each entity on a device must have a unique name within its platform."
|
||||
)
|
||||
|
||||
# Add to tracking set
|
||||
CORE.unique_ids.add(unique_key)
|
||||
return config
|
||||
|
||||
return validator
|
||||
|
||||
@@ -29,7 +29,7 @@ void HOT esp_log_vprintf_(int level, const char *tag, int line, const char *form
|
||||
if (log == nullptr)
|
||||
return;
|
||||
|
||||
log->log_vprintf_(level, tag, line, format, args);
|
||||
log->log_vprintf_(static_cast<uint8_t>(level), tag, line, format, args);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ void HOT esp_log_vprintf_(int level, const char *tag, int line, const __FlashStr
|
||||
if (log == nullptr)
|
||||
return;
|
||||
|
||||
log->log_vprintf_(level, tag, line, format, args);
|
||||
log->log_vprintf_(static_cast<uint8_t>(level), tag, line, format, args);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -319,13 +319,17 @@ bool HOT Scheduler::cancel_item_(Component *component, const std::string &name,
|
||||
return ret;
|
||||
}
|
||||
uint64_t Scheduler::millis_() {
|
||||
// Get the current 32-bit millis value
|
||||
const uint32_t now = millis();
|
||||
// Check for rollover by comparing with last value
|
||||
if (now < this->last_millis_) {
|
||||
// Detected rollover (happens every ~49.7 days)
|
||||
this->millis_major_++;
|
||||
ESP_LOGD(TAG, "Incrementing scheduler major at %" PRIu64 "ms",
|
||||
now + (static_cast<uint64_t>(this->millis_major_) << 32));
|
||||
}
|
||||
this->last_millis_ = now;
|
||||
// Combine major (high 32 bits) and now (low 32 bits) into 64-bit time
|
||||
return now + (static_cast<uint64_t>(this->millis_major_) << 32);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,12 +29,16 @@ class Scheduler {
|
||||
|
||||
protected:
|
||||
struct SchedulerItem {
|
||||
// Ordered by size to minimize padding
|
||||
Component *component;
|
||||
std::string name;
|
||||
enum Type { TIMEOUT, INTERVAL } type;
|
||||
uint32_t interval;
|
||||
// 64-bit time to handle millis() rollover. The scheduler combines the 32-bit millis()
|
||||
// with a 16-bit rollover counter to create a 64-bit time that won't roll over for
|
||||
// billions of years. This ensures correct scheduling even when devices run for months.
|
||||
uint64_t next_execution_;
|
||||
std::string name;
|
||||
std::function<void()> callback;
|
||||
enum Type : uint8_t { TIMEOUT, INTERVAL } type;
|
||||
bool remove;
|
||||
|
||||
static bool cmp(const std::unique_ptr<SchedulerItem> &a, const std::unique_ptr<SchedulerItem> &b);
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import logging
|
||||
|
||||
from esphome.const import (
|
||||
CONF_DISABLED_BY_DEFAULT,
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_ICON,
|
||||
CONF_INTERNAL,
|
||||
CONF_NAME,
|
||||
CONF_SAFE_MODE,
|
||||
CONF_SETUP_PRIORITY,
|
||||
CONF_TYPE_ID,
|
||||
@@ -16,7 +11,6 @@ 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.types import ConfigFragmentType, ConfigType
|
||||
from esphome.util import Registry, RegistryEntry
|
||||
|
||||
@@ -96,22 +90,6 @@ async def register_parented(var, value):
|
||||
add(var.set_parent(paren))
|
||||
|
||||
|
||||
async def setup_entity(var, config):
|
||||
"""Set up generic properties of an Entity"""
|
||||
add(var.set_name(config[CONF_NAME]))
|
||||
if not config[CONF_NAME]:
|
||||
add(var.set_object_id(sanitize(snake_case(CORE.friendly_name))))
|
||||
else:
|
||||
add(var.set_object_id(sanitize(snake_case(config[CONF_NAME]))))
|
||||
add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
|
||||
if CONF_INTERNAL in config:
|
||||
add(var.set_internal(config[CONF_INTERNAL]))
|
||||
if CONF_ICON in config:
|
||||
add(var.set_icon(config[CONF_ICON]))
|
||||
if CONF_ENTITY_CATEGORY in config:
|
||||
add(var.set_entity_category(config[CONF_ENTITY_CATEGORY]))
|
||||
|
||||
|
||||
def extract_registry_entry_config(
|
||||
registry: Registry,
|
||||
full_config: ConfigType,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -5,7 +5,7 @@ import fnmatch
|
||||
import functools
|
||||
import inspect
|
||||
from io import BytesIO, TextIOBase, TextIOWrapper
|
||||
from ipaddress import _BaseAddress
|
||||
from ipaddress import _BaseAddress, _BaseNetwork
|
||||
import logging
|
||||
import math
|
||||
import os
|
||||
@@ -621,6 +621,7 @@ ESPHomeDumper.add_multi_representer(str, ESPHomeDumper.represent_stringify)
|
||||
ESPHomeDumper.add_multi_representer(int, ESPHomeDumper.represent_int)
|
||||
ESPHomeDumper.add_multi_representer(float, ESPHomeDumper.represent_float)
|
||||
ESPHomeDumper.add_multi_representer(_BaseAddress, ESPHomeDumper.represent_stringify)
|
||||
ESPHomeDumper.add_multi_representer(_BaseNetwork, ESPHomeDumper.represent_stringify)
|
||||
ESPHomeDumper.add_multi_representer(MACAddress, ESPHomeDumper.represent_stringify)
|
||||
ESPHomeDumper.add_multi_representer(TimePeriod, ESPHomeDumper.represent_stringify)
|
||||
ESPHomeDumper.add_multi_representer(Lambda, ESPHomeDumper.represent_lambda)
|
||||
|
||||
@@ -13,7 +13,7 @@ platformio==6.1.18 # When updating platformio, also update /docker/Dockerfile
|
||||
esptool==4.9.0
|
||||
click==8.1.7
|
||||
esphome-dashboard==20250514.0
|
||||
aioesphomeapi==33.1.0
|
||||
aioesphomeapi==33.1.1
|
||||
zeroconf==0.147.0
|
||||
puremagic==1.29
|
||||
ruamel.yaml==0.18.14 # dashboard_import
|
||||
|
||||
@@ -12,12 +12,12 @@ sensor:
|
||||
frequency: 60Hz
|
||||
phase_a:
|
||||
name: Channel A
|
||||
voltage: Voltage
|
||||
current: Current
|
||||
active_power: Active Power
|
||||
power_factor: Power Factor
|
||||
forward_active_energy: Forward Active Energy
|
||||
reverse_active_energy: Reverse Active Energy
|
||||
voltage: Channel A Voltage
|
||||
current: Channel A Current
|
||||
active_power: Channel A Active Power
|
||||
power_factor: Channel A Power Factor
|
||||
forward_active_energy: Channel A Forward Active Energy
|
||||
reverse_active_energy: Channel A Reverse Active Energy
|
||||
calibration:
|
||||
current_gain: 3116628
|
||||
voltage_gain: -757178
|
||||
@@ -25,12 +25,12 @@ sensor:
|
||||
phase_angle: 188
|
||||
phase_b:
|
||||
name: Channel B
|
||||
voltage: Voltage
|
||||
current: Current
|
||||
active_power: Active Power
|
||||
power_factor: Power Factor
|
||||
forward_active_energy: Forward Active Energy
|
||||
reverse_active_energy: Reverse Active Energy
|
||||
voltage: Channel B Voltage
|
||||
current: Channel B Current
|
||||
active_power: Channel B Active Power
|
||||
power_factor: Channel B Power Factor
|
||||
forward_active_energy: Channel B Forward Active Energy
|
||||
reverse_active_energy: Channel B Reverse Active Energy
|
||||
calibration:
|
||||
current_gain: 3133655
|
||||
voltage_gain: -755235
|
||||
@@ -38,12 +38,12 @@ sensor:
|
||||
phase_angle: 188
|
||||
phase_c:
|
||||
name: Channel C
|
||||
voltage: Voltage
|
||||
current: Current
|
||||
active_power: Active Power
|
||||
power_factor: Power Factor
|
||||
forward_active_energy: Forward Active Energy
|
||||
reverse_active_energy: Reverse Active Energy
|
||||
voltage: Channel C Voltage
|
||||
current: Channel C Current
|
||||
active_power: Channel C Active Power
|
||||
power_factor: Channel C Power Factor
|
||||
forward_active_energy: Channel C Forward Active Energy
|
||||
reverse_active_energy: Channel C Reverse Active Energy
|
||||
calibration:
|
||||
current_gain: 3111158
|
||||
voltage_gain: -743813
|
||||
@@ -51,6 +51,6 @@ sensor:
|
||||
phase_angle: 180
|
||||
neutral:
|
||||
name: Neutral
|
||||
current: Current
|
||||
current: Neutral Current
|
||||
calibration:
|
||||
current_gain: 3189
|
||||
|
||||
@@ -26,7 +26,7 @@ alarm_control_panel:
|
||||
ESP_LOGD("TEST", "State change %s", LOG_STR_ARG(alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())));
|
||||
- platform: template
|
||||
id: alarmcontrolpanel2
|
||||
name: Alarm Panel
|
||||
name: Alarm Panel 2
|
||||
codes:
|
||||
- "1234"
|
||||
requires_code_to_arm: true
|
||||
|
||||
@@ -26,7 +26,7 @@ binary_sensor:
|
||||
|
||||
sensor:
|
||||
- platform: binary_sensor_map
|
||||
name: Binary Sensor Map
|
||||
name: Binary Sensor Map Group
|
||||
type: group
|
||||
channels:
|
||||
- binary_sensor: bin1
|
||||
@@ -36,7 +36,7 @@ sensor:
|
||||
- binary_sensor: bin3
|
||||
value: 100.0
|
||||
- platform: binary_sensor_map
|
||||
name: Binary Sensor Map
|
||||
name: Binary Sensor Map Sum
|
||||
type: sum
|
||||
channels:
|
||||
- binary_sensor: bin1
|
||||
@@ -46,7 +46,7 @@ sensor:
|
||||
- binary_sensor: bin3
|
||||
value: 100.0
|
||||
- platform: binary_sensor_map
|
||||
name: Binary Sensor Map
|
||||
name: Binary Sensor Map Bayesian
|
||||
type: bayesian
|
||||
prior: 0.4
|
||||
observations:
|
||||
|
||||
@@ -5,7 +5,7 @@ one_wire:
|
||||
sensor:
|
||||
- platform: dallas_temp
|
||||
address: 0x1C0000031EDD2A28
|
||||
name: Dallas Temperature
|
||||
name: Dallas Temperature 1
|
||||
resolution: 9
|
||||
- platform: dallas_temp
|
||||
name: Dallas Temperature
|
||||
name: Dallas Temperature 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
|
||||
|
||||
@@ -7,20 +7,20 @@ climate:
|
||||
protocol: mitsubishi_heavy_zm
|
||||
horizontal_default: left
|
||||
vertical_default: up
|
||||
name: HeatpumpIR Climate
|
||||
name: HeatpumpIR Climate Mitsubishi
|
||||
min_temperature: 18
|
||||
max_temperature: 30
|
||||
- platform: heatpumpir
|
||||
protocol: daikin
|
||||
horizontal_default: mleft
|
||||
vertical_default: mup
|
||||
name: HeatpumpIR Climate
|
||||
name: HeatpumpIR Climate Daikin
|
||||
min_temperature: 18
|
||||
max_temperature: 30
|
||||
- platform: heatpumpir
|
||||
protocol: panasonic_altdke
|
||||
horizontal_default: mright
|
||||
vertical_default: mdown
|
||||
name: HeatpumpIR Climate
|
||||
name: HeatpumpIR Climate Panasonic
|
||||
min_temperature: 18
|
||||
max_temperature: 30
|
||||
|
||||
@@ -114,7 +114,7 @@ light:
|
||||
warm_white_color_temperature: 500 mireds
|
||||
- platform: rgb
|
||||
id: test_rgb_light_initial_state
|
||||
name: RGB Light
|
||||
name: RGB Light Initial State
|
||||
red: test_ledc_1
|
||||
green: test_ledc_2
|
||||
blue: test_ledc_3
|
||||
|
||||
@@ -6,13 +6,13 @@ i2c:
|
||||
sensor:
|
||||
- platform: ltr390
|
||||
uv:
|
||||
name: LTR390 UV
|
||||
name: LTR390 UV 1
|
||||
uv_index:
|
||||
name: LTR390 UVI
|
||||
name: LTR390 UVI 1
|
||||
light:
|
||||
name: LTR390 Light
|
||||
name: LTR390 Light 1
|
||||
ambient_light:
|
||||
name: LTR390 ALS
|
||||
name: LTR390 ALS 1
|
||||
gain: X3
|
||||
resolution: 18
|
||||
window_correction_factor: 1.0
|
||||
@@ -20,13 +20,13 @@ sensor:
|
||||
update_interval: 60s
|
||||
- platform: ltr390
|
||||
uv:
|
||||
name: LTR390 UV
|
||||
name: LTR390 UV 2
|
||||
uv_index:
|
||||
name: LTR390 UVI
|
||||
name: LTR390 UVI 2
|
||||
light:
|
||||
name: LTR390 Light
|
||||
name: LTR390 Light 2
|
||||
ambient_light:
|
||||
name: LTR390 ALS
|
||||
name: LTR390 ALS 2
|
||||
gain:
|
||||
ambient_light: X9
|
||||
uv: X3
|
||||
|
||||
@@ -24,33 +24,33 @@ sensor:
|
||||
widget: lv_arc
|
||||
- platform: lvgl
|
||||
widget: slider_id
|
||||
name: LVGL Slider
|
||||
name: LVGL Slider Sensor
|
||||
- platform: lvgl
|
||||
widget: bar_id
|
||||
id: lvgl_bar_sensor
|
||||
name: LVGL Bar
|
||||
name: LVGL Bar Sensor
|
||||
- platform: lvgl
|
||||
widget: spinbox_id
|
||||
name: LVGL Spinbox
|
||||
name: LVGL Spinbox Sensor
|
||||
|
||||
number:
|
||||
- platform: lvgl
|
||||
widget: slider_id
|
||||
name: LVGL Slider
|
||||
name: LVGL Slider Number
|
||||
update_on_release: true
|
||||
restore_value: true
|
||||
- platform: lvgl
|
||||
widget: lv_arc
|
||||
id: lvgl_arc_number
|
||||
name: LVGL Arc
|
||||
name: LVGL Arc Number
|
||||
- platform: lvgl
|
||||
widget: bar_id
|
||||
id: lvgl_bar_number
|
||||
name: LVGL Bar
|
||||
name: LVGL Bar Number
|
||||
- platform: lvgl
|
||||
widget: spinbox_id
|
||||
id: lvgl_spinbox_number
|
||||
name: LVGL Spinbox
|
||||
name: LVGL Spinbox Number
|
||||
|
||||
light:
|
||||
- platform: lvgl
|
||||
|
||||
@@ -646,7 +646,9 @@ lvgl:
|
||||
on_click:
|
||||
lvgl.qrcode.update:
|
||||
id: lv_qr
|
||||
text: homeassistant.io
|
||||
text:
|
||||
format: "A string with a number %d"
|
||||
args: ['(int)(random_uint32() % 1000)']
|
||||
|
||||
- slider:
|
||||
min_value: 0
|
||||
@@ -728,12 +730,15 @@ lvgl:
|
||||
value: 30
|
||||
max_value: 100
|
||||
min_value: 10
|
||||
start_value: 20
|
||||
mode: range
|
||||
on_click:
|
||||
then:
|
||||
- lvgl.bar.update:
|
||||
id: bar_id
|
||||
value: !lambda return (int)((float)rand() / RAND_MAX * 100);
|
||||
start_value: !lambda return (int)((float)rand() / RAND_MAX * 100);
|
||||
mode: symmetrical
|
||||
- logger.log:
|
||||
format: "bar value %f"
|
||||
args: [x]
|
||||
|
||||
@@ -170,4 +170,4 @@ switch:
|
||||
otc_active:
|
||||
name: "Boiler Outside temperature compensation active"
|
||||
ch2_active:
|
||||
name: "Boiler Central Heating 2 active"
|
||||
name: "Boiler Central Heating 2 active status"
|
||||
|
||||
@@ -8,4 +8,6 @@ openthread:
|
||||
pan_id: 0x8f28
|
||||
ext_pan_id: 0xd63e8e3e495ebbc3
|
||||
pskc: 0xc23a76e98f1a6483639b1ac1271e2e27
|
||||
mesh_local_prefix: fd53:145f:ed22:ad81::/64
|
||||
force_dataset: true
|
||||
|
||||
|
||||
10
tests/components/opt3001/common.yaml
Normal file
10
tests/components/opt3001/common.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
i2c:
|
||||
- id: i2c_opt3001
|
||||
scl: ${scl_pin}
|
||||
sda: ${sda_pin}
|
||||
|
||||
sensor:
|
||||
- platform: opt3001
|
||||
name: Living Room Brightness
|
||||
address: 0x44
|
||||
update_interval: 30s
|
||||
5
tests/components/opt3001/test.esp32-ard.yaml
Normal file
5
tests/components/opt3001/test.esp32-ard.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
substitutions:
|
||||
scl_pin: GPIO16
|
||||
sda_pin: GPIO17
|
||||
|
||||
<<: !include common.yaml
|
||||
5
tests/components/opt3001/test.esp32-c3-ard.yaml
Normal file
5
tests/components/opt3001/test.esp32-c3-ard.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
substitutions:
|
||||
scl_pin: GPIO5
|
||||
sda_pin: GPIO4
|
||||
|
||||
<<: !include common.yaml
|
||||
5
tests/components/opt3001/test.esp32-c3-idf.yaml
Normal file
5
tests/components/opt3001/test.esp32-c3-idf.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
substitutions:
|
||||
scl_pin: GPIO5
|
||||
sda_pin: GPIO4
|
||||
|
||||
<<: !include common.yaml
|
||||
5
tests/components/opt3001/test.esp32-idf.yaml
Normal file
5
tests/components/opt3001/test.esp32-idf.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
substitutions:
|
||||
scl_pin: GPIO16
|
||||
sda_pin: GPIO17
|
||||
|
||||
<<: !include common.yaml
|
||||
5
tests/components/opt3001/test.esp8266-ard.yaml
Normal file
5
tests/components/opt3001/test.esp8266-ard.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
substitutions:
|
||||
scl_pin: GPIO5
|
||||
sda_pin: GPIO4
|
||||
|
||||
<<: !include common.yaml
|
||||
5
tests/components/opt3001/test.rp2040-ard.yaml
Normal file
5
tests/components/opt3001/test.rp2040-ard.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
substitutions:
|
||||
scl_pin: GPIO5
|
||||
sda_pin: GPIO4
|
||||
|
||||
<<: !include common.yaml
|
||||
@@ -5,7 +5,7 @@ packages:
|
||||
- !include package.yaml
|
||||
- github://esphome/esphome/tests/components/template/common.yaml@dev
|
||||
- url: https://github.com/esphome/esphome
|
||||
file: tests/components/binary_sensor_map/common.yaml
|
||||
file: tests/components/absolute_humidity/common.yaml
|
||||
ref: dev
|
||||
refresh: 1d
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ packages:
|
||||
shorthand: github://esphome/esphome/tests/components/template/common.yaml@dev
|
||||
github:
|
||||
url: https://github.com/esphome/esphome
|
||||
file: tests/components/binary_sensor_map/common.yaml
|
||||
file: tests/components/absolute_humidity/common.yaml
|
||||
ref: dev
|
||||
refresh: 1d
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ button:
|
||||
address: 0x00
|
||||
command: 0x0B
|
||||
- platform: template
|
||||
name: RC5
|
||||
name: RC5 Raw
|
||||
on_press:
|
||||
remote_transmitter.transmit_raw:
|
||||
code: [1000, -1000]
|
||||
|
||||
@@ -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);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user