esphome 2025.7.0b1__py3-none-any.whl → 2025.7.0b3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esphome/components/api/__init__.py +19 -5
- esphome/components/api/api_connection.cpp +53 -175
- esphome/components/api/api_connection.h +28 -25
- esphome/components/api/api_frame_helper.cpp +2 -3
- esphome/components/api/api_frame_helper.h +7 -9
- esphome/components/api/api_pb2.cpp +1862 -5133
- esphome/components/api/api_pb2.h +291 -533
- esphome/components/api/api_pb2_dump.cpp +99 -0
- esphome/components/api/api_pb2_service.cpp +4 -0
- esphome/components/api/api_pb2_service.h +6 -0
- esphome/components/api/api_server.cpp +2 -9
- esphome/components/api/api_server.h +7 -33
- esphome/components/api/custom_api_device.h +8 -0
- esphome/components/api/list_entities.cpp +2 -0
- esphome/components/api/list_entities.h +3 -1
- esphome/components/api/proto.h +506 -23
- esphome/components/api/user_services.h +2 -0
- esphome/components/debug/debug_esp32.cpp +2 -0
- esphome/components/esp32/__init__.py +1 -0
- esphome/components/esp32_camera/__init__.py +1 -1
- esphome/components/esp32_touch/esp32_touch_v1.cpp +12 -10
- esphome/components/esp8266/__init__.py +1 -0
- esphome/components/esp_ldo/__init__.py +10 -8
- esphome/components/esp_ldo/esp_ldo.h +3 -0
- esphome/components/gpio/binary_sensor/__init__.py +24 -3
- esphome/components/host/__init__.py +1 -0
- esphome/components/i2s_audio/speaker/__init__.py +1 -1
- esphome/components/ld2410/ld2410.cpp +12 -28
- esphome/components/ld2420/binary_sensor/ld2420_binary_sensor.cpp +2 -2
- esphome/components/ld2420/button/reconfig_buttons.cpp +1 -1
- esphome/components/ld2420/ld2420.cpp +66 -57
- esphome/components/ld2420/ld2420.h +9 -11
- esphome/components/ld2420/number/gate_config_number.cpp +1 -1
- esphome/components/ld2420/select/operating_mode_select.cpp +1 -1
- esphome/components/ld2420/sensor/ld2420_sensor.cpp +2 -2
- esphome/components/ld2420/text_sensor/text_sensor.cpp +2 -2
- esphome/components/libretiny/__init__.py +1 -0
- esphome/components/lvgl/widgets/meter.py +20 -13
- esphome/components/mqtt/mqtt_backend_esp32.cpp +6 -2
- esphome/components/packet_transport/packet_transport.cpp +3 -0
- esphome/components/rp2040/__init__.py +1 -0
- esphome/components/substitutions/__init__.py +5 -2
- esphome/components/sx126x/__init__.py +3 -3
- esphome/components/sx127x/__init__.py +2 -2
- esphome/components/usb_host/usb_host_client.cpp +10 -10
- esphome/components/usb_uart/cp210x.cpp +1 -1
- esphome/components/usb_uart/usb_uart.cpp +41 -44
- esphome/components/usb_uart/usb_uart.h +4 -3
- esphome/const.py +1 -1
- esphome/core/component.cpp +8 -8
- esphome/core/component_iterator.cpp +4 -2
- esphome/core/component_iterator.h +3 -3
- esphome/core/defines.h +1 -1
- esphome/core/entity_helpers.py +6 -0
- esphome/core/helpers.h +1 -1
- esphome/core/scheduler.cpp +9 -12
- esphome/core/scheduler.h +0 -3
- esphome/wizard.py +1 -1
- {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b3.dist-info}/METADATA +2 -2
- {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b3.dist-info}/RECORD +64 -65
- esphome/components/api/api_pb2_size.h +0 -359
- {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b3.dist-info}/WHEEL +0 -0
- {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b3.dist-info}/entry_points.txt +0 -0
- {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b3.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b3.dist-info}/top_level.txt +0 -0
|
@@ -29,9 +29,9 @@ from ..defines import (
|
|
|
29
29
|
)
|
|
30
30
|
from ..helpers import add_lv_use, lvgl_components_required
|
|
31
31
|
from ..lv_validation import (
|
|
32
|
-
angle,
|
|
33
32
|
get_end_value,
|
|
34
33
|
get_start_value,
|
|
34
|
+
lv_angle,
|
|
35
35
|
lv_bool,
|
|
36
36
|
lv_color,
|
|
37
37
|
lv_float,
|
|
@@ -162,7 +162,7 @@ SCALE_SCHEMA = cv.Schema(
|
|
|
162
162
|
cv.Optional(CONF_RANGE_FROM, default=0.0): cv.float_,
|
|
163
163
|
cv.Optional(CONF_RANGE_TO, default=100.0): cv.float_,
|
|
164
164
|
cv.Optional(CONF_ANGLE_RANGE, default=270): cv.int_range(0, 360),
|
|
165
|
-
cv.Optional(CONF_ROTATION):
|
|
165
|
+
cv.Optional(CONF_ROTATION): lv_angle,
|
|
166
166
|
cv.Optional(CONF_INDICATORS): cv.ensure_list(INDICATOR_SCHEMA),
|
|
167
167
|
}
|
|
168
168
|
)
|
|
@@ -187,7 +187,7 @@ class MeterType(WidgetType):
|
|
|
187
187
|
for scale_conf in config.get(CONF_SCALES, ()):
|
|
188
188
|
rotation = 90 + (360 - scale_conf[CONF_ANGLE_RANGE]) / 2
|
|
189
189
|
if CONF_ROTATION in scale_conf:
|
|
190
|
-
rotation = scale_conf[CONF_ROTATION]
|
|
190
|
+
rotation = await lv_angle.process(scale_conf[CONF_ROTATION])
|
|
191
191
|
with LocalVariable(
|
|
192
192
|
"meter_var", "lv_meter_scale_t", lv_expr.meter_add_scale(var)
|
|
193
193
|
) as meter_var:
|
|
@@ -205,21 +205,20 @@ class MeterType(WidgetType):
|
|
|
205
205
|
var,
|
|
206
206
|
meter_var,
|
|
207
207
|
ticks[CONF_COUNT],
|
|
208
|
-
ticks[CONF_WIDTH],
|
|
209
|
-
ticks[CONF_LENGTH],
|
|
208
|
+
await size.process(ticks[CONF_WIDTH]),
|
|
209
|
+
await size.process(ticks[CONF_LENGTH]),
|
|
210
210
|
color,
|
|
211
211
|
)
|
|
212
212
|
if CONF_MAJOR in ticks:
|
|
213
213
|
major = ticks[CONF_MAJOR]
|
|
214
|
-
color = await lv_color.process(major[CONF_COLOR])
|
|
215
214
|
lv.meter_set_scale_major_ticks(
|
|
216
215
|
var,
|
|
217
216
|
meter_var,
|
|
218
217
|
major[CONF_STRIDE],
|
|
219
|
-
major[CONF_WIDTH],
|
|
220
|
-
major[CONF_LENGTH],
|
|
221
|
-
|
|
222
|
-
major[CONF_LABEL_GAP],
|
|
218
|
+
await size.process(major[CONF_WIDTH]),
|
|
219
|
+
await size.process(major[CONF_LENGTH]),
|
|
220
|
+
await lv_color.process(major[CONF_COLOR]),
|
|
221
|
+
await size.process(major[CONF_LABEL_GAP]),
|
|
223
222
|
)
|
|
224
223
|
for indicator in scale_conf.get(CONF_INDICATORS, ()):
|
|
225
224
|
(t, v) = next(iter(indicator.items()))
|
|
@@ -233,7 +232,11 @@ class MeterType(WidgetType):
|
|
|
233
232
|
lv_assign(
|
|
234
233
|
ivar,
|
|
235
234
|
lv_expr.meter_add_needle_line(
|
|
236
|
-
var,
|
|
235
|
+
var,
|
|
236
|
+
meter_var,
|
|
237
|
+
await size.process(v[CONF_WIDTH]),
|
|
238
|
+
color,
|
|
239
|
+
await size.process(v[CONF_R_MOD]),
|
|
237
240
|
),
|
|
238
241
|
)
|
|
239
242
|
if t == CONF_ARC:
|
|
@@ -241,7 +244,11 @@ class MeterType(WidgetType):
|
|
|
241
244
|
lv_assign(
|
|
242
245
|
ivar,
|
|
243
246
|
lv_expr.meter_add_arc(
|
|
244
|
-
var,
|
|
247
|
+
var,
|
|
248
|
+
meter_var,
|
|
249
|
+
await size.process(v[CONF_WIDTH]),
|
|
250
|
+
color,
|
|
251
|
+
await size.process(v[CONF_R_MOD]),
|
|
245
252
|
),
|
|
246
253
|
)
|
|
247
254
|
if t == CONF_TICK_STYLE:
|
|
@@ -257,7 +264,7 @@ class MeterType(WidgetType):
|
|
|
257
264
|
color_start,
|
|
258
265
|
color_end,
|
|
259
266
|
v[CONF_LOCAL],
|
|
260
|
-
v[CONF_WIDTH],
|
|
267
|
+
size.process(v[CONF_WIDTH]),
|
|
261
268
|
),
|
|
262
269
|
)
|
|
263
270
|
if t == CONF_IMAGE:
|
|
@@ -153,11 +153,15 @@ void MQTTBackendESP32::mqtt_event_handler_(const Event &event) {
|
|
|
153
153
|
case MQTT_EVENT_DATA: {
|
|
154
154
|
static std::string topic;
|
|
155
155
|
if (!event.topic.empty()) {
|
|
156
|
+
// When a single message arrives as multiple chunks, the topic will be empty
|
|
157
|
+
// on any but the first message, leading to event.topic being an empty string.
|
|
158
|
+
// To ensure handlers get the correct topic, cache the last seen topic to
|
|
159
|
+
// simulate always receiving the topic from underlying library
|
|
156
160
|
topic = event.topic;
|
|
157
161
|
}
|
|
158
162
|
ESP_LOGV(TAG, "MQTT_EVENT_DATA %s", topic.c_str());
|
|
159
|
-
this->on_message_.call(
|
|
160
|
-
event.
|
|
163
|
+
this->on_message_.call(topic.c_str(), event.data.data(), event.data.size(), event.current_data_offset,
|
|
164
|
+
event.total_data_len);
|
|
161
165
|
} break;
|
|
162
166
|
case MQTT_EVENT_ERROR:
|
|
163
167
|
ESP_LOGE(TAG, "MQTT_EVENT_ERROR");
|
|
@@ -314,6 +314,9 @@ void PacketTransport::send_data_(bool all) {
|
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
void PacketTransport::update() {
|
|
317
|
+
if (!this->ping_pong_enable_) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
317
320
|
auto now = millis() / 1000;
|
|
318
321
|
if (this->last_key_time_ + this->ping_pong_recyle_time_ < now) {
|
|
319
322
|
this->resend_ping_key_ = this->ping_pong_enable_;
|
|
@@ -165,6 +165,7 @@ async def to_code(config):
|
|
|
165
165
|
# Allow LDF to properly discover dependency including those in preprocessor
|
|
166
166
|
# conditionals
|
|
167
167
|
cg.add_platformio_option("lib_ldf_mode", "chain+")
|
|
168
|
+
cg.add_platformio_option("lib_compat_mode", "strict")
|
|
168
169
|
cg.add_platformio_option("board", config[CONF_BOARD])
|
|
169
170
|
cg.add_build_flag("-DUSE_RP2040")
|
|
170
171
|
cg.set_cpp_standard("gnu++20")
|
|
@@ -151,8 +151,11 @@ def _substitute_item(substitutions, item, path, jinja, ignore_missing):
|
|
|
151
151
|
if sub is not None:
|
|
152
152
|
item[k] = sub
|
|
153
153
|
for old, new in replace_keys:
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
if str(new) == str(old):
|
|
155
|
+
item[new] = item[old]
|
|
156
|
+
else:
|
|
157
|
+
item[new] = merge_config(item.get(old), item.get(new))
|
|
158
|
+
del item[old]
|
|
156
159
|
elif isinstance(item, str):
|
|
157
160
|
sub = _expand_substitutions(substitutions, item, path, jinja, ignore_missing)
|
|
158
161
|
if isinstance(sub, JinjaStr) or sub != item:
|
|
@@ -167,8 +167,8 @@ def validate_config(config):
|
|
|
167
167
|
if config[CONF_MODULATION] == "LORA":
|
|
168
168
|
if config[CONF_BANDWIDTH] not in lora_bws:
|
|
169
169
|
raise cv.Invalid(f"{config[CONF_BANDWIDTH]} is not available with LORA")
|
|
170
|
-
if config[CONF_PREAMBLE_SIZE]
|
|
171
|
-
raise cv.Invalid("Minimum
|
|
170
|
+
if config[CONF_PREAMBLE_SIZE] < 6:
|
|
171
|
+
raise cv.Invalid("Minimum 'preamble_size' is 6 with LORA")
|
|
172
172
|
if config[CONF_SPREADING_FACTOR] == 6 and config[CONF_PAYLOAD_LENGTH] == 0:
|
|
173
173
|
raise cv.Invalid("Payload length must be set when spreading factor is 6")
|
|
174
174
|
else:
|
|
@@ -200,7 +200,7 @@ CONFIG_SCHEMA = (
|
|
|
200
200
|
cv.Optional(CONF_PA_RAMP, default="40us"): cv.enum(RAMP),
|
|
201
201
|
cv.Optional(CONF_PAYLOAD_LENGTH, default=0): cv.int_range(min=0, max=256),
|
|
202
202
|
cv.Optional(CONF_PREAMBLE_DETECT, default=2): cv.int_range(min=0, max=4),
|
|
203
|
-
cv.
|
|
203
|
+
cv.Optional(CONF_PREAMBLE_SIZE, default=8): cv.int_range(min=1, max=65535),
|
|
204
204
|
cv.Required(CONF_RST_PIN): pins.internal_gpio_output_pin_schema,
|
|
205
205
|
cv.Optional(CONF_RX_START, default=True): cv.boolean,
|
|
206
206
|
cv.Required(CONF_RF_SWITCH): cv.boolean,
|
|
@@ -164,8 +164,8 @@ def validate_config(config):
|
|
|
164
164
|
raise cv.Invalid(f"{config[CONF_BANDWIDTH]} is not available with LORA")
|
|
165
165
|
if CONF_DIO0_PIN not in config:
|
|
166
166
|
raise cv.Invalid("Cannot use LoRa without dio0_pin")
|
|
167
|
-
if
|
|
168
|
-
raise cv.Invalid("Minimum
|
|
167
|
+
if config[CONF_PREAMBLE_SIZE] < 6:
|
|
168
|
+
raise cv.Invalid("Minimum 'preamble_size' is 6 with LORA")
|
|
169
169
|
if config[CONF_SPREADING_FACTOR] == 6 and config[CONF_PAYLOAD_LENGTH] == 0:
|
|
170
170
|
raise cv.Invalid("Payload length must be set when spreading factor is 6")
|
|
171
171
|
else:
|
|
@@ -70,7 +70,7 @@ static void usbh_print_cfg_desc(const usb_config_desc_t *cfg_desc) {
|
|
|
70
70
|
ESP_LOGV(TAG, "bMaxPower %dmA", cfg_desc->bMaxPower * 2);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
void usb_client_print_device_descriptor(const usb_device_desc_t *devc_desc) {
|
|
73
|
+
static void usb_client_print_device_descriptor(const usb_device_desc_t *devc_desc) {
|
|
74
74
|
if (devc_desc == NULL) {
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
@@ -92,8 +92,8 @@ void usb_client_print_device_descriptor(const usb_device_desc_t *devc_desc) {
|
|
|
92
92
|
ESP_LOGV(TAG, "bNumConfigurations %d", devc_desc->bNumConfigurations);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
void usb_client_print_config_descriptor(const usb_config_desc_t *cfg_desc,
|
|
96
|
-
|
|
95
|
+
static void usb_client_print_config_descriptor(const usb_config_desc_t *cfg_desc,
|
|
96
|
+
print_class_descriptor_cb class_specific_cb) {
|
|
97
97
|
if (cfg_desc == nullptr) {
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
@@ -128,9 +128,9 @@ void usb_client_print_config_descriptor(const usb_config_desc_t *cfg_desc,
|
|
|
128
128
|
static std::string get_descriptor_string(const usb_str_desc_t *desc) {
|
|
129
129
|
char buffer[256];
|
|
130
130
|
if (desc == nullptr)
|
|
131
|
-
return "(
|
|
131
|
+
return "(unspecified)";
|
|
132
132
|
char *p = buffer;
|
|
133
|
-
for (
|
|
133
|
+
for (int i = 0; i != desc->bLength / 2; i++) {
|
|
134
134
|
auto c = desc->wData[i];
|
|
135
135
|
if (c < 0x100)
|
|
136
136
|
*p++ = static_cast<char>(c);
|
|
@@ -169,7 +169,7 @@ void USBClient::setup() {
|
|
|
169
169
|
this->mark_failed();
|
|
170
170
|
return;
|
|
171
171
|
}
|
|
172
|
-
for (auto trq : this->trq_pool_) {
|
|
172
|
+
for (auto *trq : this->trq_pool_) {
|
|
173
173
|
usb_host_transfer_alloc(64, 0, &trq->transfer);
|
|
174
174
|
trq->client = this;
|
|
175
175
|
}
|
|
@@ -197,7 +197,8 @@ void USBClient::loop() {
|
|
|
197
197
|
ESP_LOGD(TAG, "Device descriptor: vid %X pid %X", desc->idVendor, desc->idProduct);
|
|
198
198
|
if (desc->idVendor == this->vid_ && desc->idProduct == this->pid_ || this->vid_ == 0 && this->pid_ == 0) {
|
|
199
199
|
usb_device_info_t dev_info;
|
|
200
|
-
|
|
200
|
+
err = usb_host_device_info(this->device_handle_, &dev_info);
|
|
201
|
+
if (err != ESP_OK) {
|
|
201
202
|
ESP_LOGW(TAG, "Device info failed: %s", esp_err_to_name(err));
|
|
202
203
|
this->disconnect();
|
|
203
204
|
break;
|
|
@@ -336,7 +337,7 @@ static void transfer_callback(usb_transfer_t *xfer) {
|
|
|
336
337
|
* @throws None.
|
|
337
338
|
*/
|
|
338
339
|
void USBClient::transfer_in(uint8_t ep_address, const transfer_cb_t &callback, uint16_t length) {
|
|
339
|
-
auto trq = this->get_trq_();
|
|
340
|
+
auto *trq = this->get_trq_();
|
|
340
341
|
if (trq == nullptr) {
|
|
341
342
|
ESP_LOGE(TAG, "Too many requests queued");
|
|
342
343
|
return;
|
|
@@ -349,7 +350,6 @@ void USBClient::transfer_in(uint8_t ep_address, const transfer_cb_t &callback, u
|
|
|
349
350
|
if (err != ESP_OK) {
|
|
350
351
|
ESP_LOGE(TAG, "Failed to submit transfer, address=%x, length=%d, err=%x", ep_address, length, err);
|
|
351
352
|
this->release_trq(trq);
|
|
352
|
-
this->disconnect();
|
|
353
353
|
}
|
|
354
354
|
}
|
|
355
355
|
|
|
@@ -364,7 +364,7 @@ void USBClient::transfer_in(uint8_t ep_address, const transfer_cb_t &callback, u
|
|
|
364
364
|
* @throws None.
|
|
365
365
|
*/
|
|
366
366
|
void USBClient::transfer_out(uint8_t ep_address, const transfer_cb_t &callback, const uint8_t *data, uint16_t length) {
|
|
367
|
-
auto trq = this->get_trq_();
|
|
367
|
+
auto *trq = this->get_trq_();
|
|
368
368
|
if (trq == nullptr) {
|
|
369
369
|
ESP_LOGE(TAG, "Too many requests queued");
|
|
370
370
|
return;
|
|
@@ -43,7 +43,7 @@ static constexpr uint8_t SET_BAUDRATE = 0x1E; // Set the baud rate.
|
|
|
43
43
|
static constexpr uint8_t SET_CHARS = 0x19; // Set special characters.
|
|
44
44
|
static constexpr uint8_t VENDOR_SPECIFIC = 0xFF; // Vendor specific command.
|
|
45
45
|
|
|
46
|
-
std::vector<CdcEps> USBUartTypeCP210X::
|
|
46
|
+
std::vector<CdcEps> USBUartTypeCP210X::parse_descriptors(usb_device_handle_t dev_hdl) {
|
|
47
47
|
const usb_config_desc_t *config_desc;
|
|
48
48
|
const usb_device_desc_t *device_desc;
|
|
49
49
|
int conf_offset = 0, ep_offset;
|
|
@@ -18,52 +18,48 @@ namespace usb_uart {
|
|
|
18
18
|
*/
|
|
19
19
|
static optional<CdcEps> get_cdc(const usb_config_desc_t *config_desc, uint8_t intf_idx) {
|
|
20
20
|
int conf_offset, ep_offset;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
// look for an interface with an interrupt endpoint (notify), and one with two bulk endpoints (data in/out)
|
|
22
|
+
CdcEps eps{};
|
|
23
|
+
eps.bulk_interface_number = 0xFF;
|
|
24
24
|
for (;;) {
|
|
25
|
-
auto intf_desc = usb_parse_interface_descriptor(config_desc, intf_idx++, 0, &conf_offset);
|
|
25
|
+
const auto *intf_desc = usb_parse_interface_descriptor(config_desc, intf_idx++, 0, &conf_offset);
|
|
26
26
|
if (!intf_desc) {
|
|
27
27
|
ESP_LOGE(TAG, "usb_parse_interface_descriptor failed");
|
|
28
28
|
return nullopt;
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
ESP_LOGD(TAG, "intf_desc: bInterfaceClass=%02X, bInterfaceSubClass=%02X, bInterfaceProtocol=%02X, bNumEndpoints=%d",
|
|
31
|
+
intf_desc->bInterfaceClass, intf_desc->bInterfaceSubClass, intf_desc->bInterfaceProtocol,
|
|
32
|
+
intf_desc->bNumEndpoints);
|
|
33
|
+
for (uint8_t i = 0; i != intf_desc->bNumEndpoints; i++) {
|
|
31
34
|
ep_offset = conf_offset;
|
|
32
|
-
|
|
33
|
-
if (!
|
|
34
|
-
ESP_LOGE(TAG, "
|
|
35
|
+
const auto *ep = usb_parse_endpoint_descriptor_by_index(intf_desc, i, config_desc->wTotalLength, &ep_offset);
|
|
36
|
+
if (!ep) {
|
|
37
|
+
ESP_LOGE(TAG, "Ran out of interfaces at %d before finding all endpoints", i);
|
|
35
38
|
return nullopt;
|
|
36
39
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
ESP_LOGE(TAG, "in_ep: usb_parse_endpoint_descriptor_by_index failed");
|
|
53
|
-
return nullopt;
|
|
40
|
+
ESP_LOGD(TAG, "ep: bEndpointAddress=%02X, bmAttributes=%02X", ep->bEndpointAddress, ep->bmAttributes);
|
|
41
|
+
if (ep->bmAttributes == USB_BM_ATTRIBUTES_XFER_INT) {
|
|
42
|
+
eps.notify_ep = ep;
|
|
43
|
+
eps.interrupt_interface_number = intf_desc->bInterfaceNumber;
|
|
44
|
+
} else if (ep->bmAttributes == USB_BM_ATTRIBUTES_XFER_BULK && ep->bEndpointAddress & usb_host::USB_DIR_IN &&
|
|
45
|
+
(eps.bulk_interface_number == 0xFF || eps.bulk_interface_number == intf_desc->bInterfaceNumber)) {
|
|
46
|
+
eps.in_ep = ep;
|
|
47
|
+
eps.bulk_interface_number = intf_desc->bInterfaceNumber;
|
|
48
|
+
} else if (ep->bmAttributes == USB_BM_ATTRIBUTES_XFER_BULK && !(ep->bEndpointAddress & usb_host::USB_DIR_IN) &&
|
|
49
|
+
(eps.bulk_interface_number == 0xFF || eps.bulk_interface_number == intf_desc->bInterfaceNumber)) {
|
|
50
|
+
eps.out_ep = ep;
|
|
51
|
+
eps.bulk_interface_number = intf_desc->bInterfaceNumber;
|
|
52
|
+
} else {
|
|
53
|
+
ESP_LOGE(TAG, "Unexpected endpoint attributes: %02X", ep->bmAttributes);
|
|
54
|
+
continue;
|
|
54
55
|
}
|
|
55
|
-
if (in_ep->bmAttributes != USB_BM_ATTRIBUTES_XFER_BULK)
|
|
56
|
-
in_ep = nullptr;
|
|
57
56
|
}
|
|
58
|
-
if (in_ep != nullptr && out_ep != nullptr && notify_ep != nullptr)
|
|
59
|
-
|
|
57
|
+
if (eps.in_ep != nullptr && eps.out_ep != nullptr && eps.notify_ep != nullptr)
|
|
58
|
+
return eps;
|
|
60
59
|
}
|
|
61
|
-
if (in_ep->bEndpointAddress & usb_host::USB_DIR_IN)
|
|
62
|
-
return CdcEps{notify_ep, in_ep, out_ep, interface_number};
|
|
63
|
-
return CdcEps{notify_ep, out_ep, in_ep, interface_number};
|
|
64
60
|
}
|
|
65
61
|
|
|
66
|
-
std::vector<CdcEps> USBUartTypeCdcAcm::
|
|
62
|
+
std::vector<CdcEps> USBUartTypeCdcAcm::parse_descriptors(usb_device_handle_t dev_hdl) {
|
|
67
63
|
const usb_config_desc_t *config_desc;
|
|
68
64
|
const usb_device_desc_t *device_desc;
|
|
69
65
|
int desc_offset = 0;
|
|
@@ -78,7 +74,7 @@ std::vector<CdcEps> USBUartTypeCdcAcm::parse_descriptors_(usb_device_handle_t de
|
|
|
78
74
|
ESP_LOGE(TAG, "get_active_config_descriptor failed");
|
|
79
75
|
return {};
|
|
80
76
|
}
|
|
81
|
-
if (device_desc->bDeviceClass == USB_CLASS_COMM) {
|
|
77
|
+
if (device_desc->bDeviceClass == USB_CLASS_COMM || device_desc->bDeviceClass == USB_CLASS_VENDOR_SPEC) {
|
|
82
78
|
// single CDC-ACM device
|
|
83
79
|
if (auto eps = get_cdc(config_desc, 0)) {
|
|
84
80
|
ESP_LOGV(TAG, "Found CDC-ACM device");
|
|
@@ -194,7 +190,7 @@ void USBUartComponent::start_input(USBUartChannel *channel) {
|
|
|
194
190
|
if (!channel->initialised_ || channel->input_started_ ||
|
|
195
191
|
channel->input_buffer_.get_free_space() < channel->cdc_dev_.in_ep->wMaxPacketSize)
|
|
196
192
|
return;
|
|
197
|
-
auto ep = channel->cdc_dev_.in_ep;
|
|
193
|
+
const auto *ep = channel->cdc_dev_.in_ep;
|
|
198
194
|
auto callback = [this, channel](const usb_host::TransferStatus &status) {
|
|
199
195
|
ESP_LOGV(TAG, "Transfer result: length: %u; status %X", status.data_len, status.error_code);
|
|
200
196
|
if (!status.success) {
|
|
@@ -227,7 +223,7 @@ void USBUartComponent::start_output(USBUartChannel *channel) {
|
|
|
227
223
|
if (channel->output_buffer_.is_empty()) {
|
|
228
224
|
return;
|
|
229
225
|
}
|
|
230
|
-
auto ep = channel->cdc_dev_.out_ep;
|
|
226
|
+
const auto *ep = channel->cdc_dev_.out_ep;
|
|
231
227
|
auto callback = [this, channel](const usb_host::TransferStatus &status) {
|
|
232
228
|
ESP_LOGV(TAG, "Output Transfer result: length: %u; status %X", status.data_len, status.error_code);
|
|
233
229
|
channel->output_started_ = false;
|
|
@@ -259,15 +255,15 @@ static void fix_mps(const usb_ep_desc_t *ep) {
|
|
|
259
255
|
}
|
|
260
256
|
}
|
|
261
257
|
void USBUartTypeCdcAcm::on_connected() {
|
|
262
|
-
auto cdc_devs = this->
|
|
258
|
+
auto cdc_devs = this->parse_descriptors(this->device_handle_);
|
|
263
259
|
if (cdc_devs.empty()) {
|
|
264
260
|
this->status_set_error("No CDC-ACM device found");
|
|
265
261
|
this->disconnect();
|
|
266
262
|
return;
|
|
267
263
|
}
|
|
268
264
|
ESP_LOGD(TAG, "Found %zu CDC-ACM devices", cdc_devs.size());
|
|
269
|
-
|
|
270
|
-
for (auto channel : this->channels_) {
|
|
265
|
+
size_t i = 0;
|
|
266
|
+
for (auto *channel : this->channels_) {
|
|
271
267
|
if (i == cdc_devs.size()) {
|
|
272
268
|
ESP_LOGE(TAG, "No configuration found for channel %d", channel->index_);
|
|
273
269
|
this->status_set_warning("No configuration found for channel");
|
|
@@ -277,10 +273,11 @@ void USBUartTypeCdcAcm::on_connected() {
|
|
|
277
273
|
fix_mps(channel->cdc_dev_.in_ep);
|
|
278
274
|
fix_mps(channel->cdc_dev_.out_ep);
|
|
279
275
|
channel->initialised_ = true;
|
|
280
|
-
auto err =
|
|
276
|
+
auto err =
|
|
277
|
+
usb_host_interface_claim(this->handle_, this->device_handle_, channel->cdc_dev_.bulk_interface_number, 0);
|
|
281
278
|
if (err != ESP_OK) {
|
|
282
279
|
ESP_LOGE(TAG, "usb_host_interface_claim failed: %s, channel=%d, intf=%d", esp_err_to_name(err), channel->index_,
|
|
283
|
-
channel->cdc_dev_.
|
|
280
|
+
channel->cdc_dev_.bulk_interface_number);
|
|
284
281
|
this->status_set_error("usb_host_interface_claim failed");
|
|
285
282
|
this->disconnect();
|
|
286
283
|
return;
|
|
@@ -290,7 +287,7 @@ void USBUartTypeCdcAcm::on_connected() {
|
|
|
290
287
|
}
|
|
291
288
|
|
|
292
289
|
void USBUartTypeCdcAcm::on_disconnected() {
|
|
293
|
-
for (auto channel : this->channels_) {
|
|
290
|
+
for (auto *channel : this->channels_) {
|
|
294
291
|
if (channel->cdc_dev_.in_ep != nullptr) {
|
|
295
292
|
usb_host_endpoint_halt(this->device_handle_, channel->cdc_dev_.in_ep->bEndpointAddress);
|
|
296
293
|
usb_host_endpoint_flush(this->device_handle_, channel->cdc_dev_.in_ep->bEndpointAddress);
|
|
@@ -303,7 +300,7 @@ void USBUartTypeCdcAcm::on_disconnected() {
|
|
|
303
300
|
usb_host_endpoint_halt(this->device_handle_, channel->cdc_dev_.notify_ep->bEndpointAddress);
|
|
304
301
|
usb_host_endpoint_flush(this->device_handle_, channel->cdc_dev_.notify_ep->bEndpointAddress);
|
|
305
302
|
}
|
|
306
|
-
usb_host_interface_release(this->handle_, this->device_handle_, channel->cdc_dev_.
|
|
303
|
+
usb_host_interface_release(this->handle_, this->device_handle_, channel->cdc_dev_.bulk_interface_number);
|
|
307
304
|
channel->initialised_ = false;
|
|
308
305
|
channel->input_started_ = false;
|
|
309
306
|
channel->output_started_ = false;
|
|
@@ -314,7 +311,7 @@ void USBUartTypeCdcAcm::on_disconnected() {
|
|
|
314
311
|
}
|
|
315
312
|
|
|
316
313
|
void USBUartTypeCdcAcm::enable_channels() {
|
|
317
|
-
for (auto channel : this->channels_) {
|
|
314
|
+
for (auto *channel : this->channels_) {
|
|
318
315
|
if (!channel->initialised_)
|
|
319
316
|
continue;
|
|
320
317
|
channel->input_started_ = false;
|
|
@@ -25,7 +25,8 @@ struct CdcEps {
|
|
|
25
25
|
const usb_ep_desc_t *notify_ep;
|
|
26
26
|
const usb_ep_desc_t *in_ep;
|
|
27
27
|
const usb_ep_desc_t *out_ep;
|
|
28
|
-
uint8_t
|
|
28
|
+
uint8_t bulk_interface_number;
|
|
29
|
+
uint8_t interrupt_interface_number;
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
enum UARTParityOptions {
|
|
@@ -123,7 +124,7 @@ class USBUartTypeCdcAcm : public USBUartComponent {
|
|
|
123
124
|
USBUartTypeCdcAcm(uint16_t vid, uint16_t pid) : USBUartComponent(vid, pid) {}
|
|
124
125
|
|
|
125
126
|
protected:
|
|
126
|
-
virtual std::vector<CdcEps>
|
|
127
|
+
virtual std::vector<CdcEps> parse_descriptors(usb_device_handle_t dev_hdl);
|
|
127
128
|
void on_connected() override;
|
|
128
129
|
virtual void enable_channels();
|
|
129
130
|
void on_disconnected() override;
|
|
@@ -134,7 +135,7 @@ class USBUartTypeCP210X : public USBUartTypeCdcAcm {
|
|
|
134
135
|
USBUartTypeCP210X(uint16_t vid, uint16_t pid) : USBUartTypeCdcAcm(vid, pid) {}
|
|
135
136
|
|
|
136
137
|
protected:
|
|
137
|
-
std::vector<CdcEps>
|
|
138
|
+
std::vector<CdcEps> parse_descriptors(usb_device_handle_t dev_hdl) override;
|
|
138
139
|
void enable_channels() override;
|
|
139
140
|
};
|
|
140
141
|
class USBUartTypeCH34X : public USBUartTypeCdcAcm {
|
esphome/const.py
CHANGED
esphome/core/component.cpp
CHANGED
|
@@ -138,7 +138,7 @@ void Component::call_dump_config() {
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
|
-
ESP_LOGE(TAG, "
|
|
141
|
+
ESP_LOGE(TAG, " %s is marked FAILED: %s", this->get_component_source(), error_msg);
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
|
|
@@ -191,7 +191,7 @@ bool Component::should_warn_of_blocking(uint32_t blocking_time) {
|
|
|
191
191
|
return false;
|
|
192
192
|
}
|
|
193
193
|
void Component::mark_failed() {
|
|
194
|
-
ESP_LOGE(TAG, "
|
|
194
|
+
ESP_LOGE(TAG, "%s was marked as failed", this->get_component_source());
|
|
195
195
|
this->component_state_ &= ~COMPONENT_STATE_MASK;
|
|
196
196
|
this->component_state_ |= COMPONENT_STATE_FAILED;
|
|
197
197
|
this->status_set_error();
|
|
@@ -229,7 +229,7 @@ void IRAM_ATTR HOT Component::enable_loop_soon_any_context() {
|
|
|
229
229
|
}
|
|
230
230
|
void Component::reset_to_construction_state() {
|
|
231
231
|
if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED) {
|
|
232
|
-
ESP_LOGI(TAG, "
|
|
232
|
+
ESP_LOGI(TAG, "%s is being reset to construction state", this->get_component_source());
|
|
233
233
|
this->component_state_ &= ~COMPONENT_STATE_MASK;
|
|
234
234
|
this->component_state_ |= COMPONENT_STATE_CONSTRUCTION;
|
|
235
235
|
// Clear error status when resetting
|
|
@@ -275,14 +275,14 @@ void Component::status_set_warning(const char *message) {
|
|
|
275
275
|
return;
|
|
276
276
|
this->component_state_ |= STATUS_LED_WARNING;
|
|
277
277
|
App.app_state_ |= STATUS_LED_WARNING;
|
|
278
|
-
ESP_LOGW(TAG, "
|
|
278
|
+
ESP_LOGW(TAG, "%s set Warning flag: %s", this->get_component_source(), message);
|
|
279
279
|
}
|
|
280
280
|
void Component::status_set_error(const char *message) {
|
|
281
281
|
if ((this->component_state_ & STATUS_LED_ERROR) != 0)
|
|
282
282
|
return;
|
|
283
283
|
this->component_state_ |= STATUS_LED_ERROR;
|
|
284
284
|
App.app_state_ |= STATUS_LED_ERROR;
|
|
285
|
-
ESP_LOGE(TAG, "
|
|
285
|
+
ESP_LOGE(TAG, "%s set Error flag: %s", this->get_component_source(), message);
|
|
286
286
|
if (strcmp(message, "unspecified") != 0) {
|
|
287
287
|
// Lazy allocate the error messages vector if needed
|
|
288
288
|
if (!component_error_messages) {
|
|
@@ -303,13 +303,13 @@ void Component::status_clear_warning() {
|
|
|
303
303
|
if ((this->component_state_ & STATUS_LED_WARNING) == 0)
|
|
304
304
|
return;
|
|
305
305
|
this->component_state_ &= ~STATUS_LED_WARNING;
|
|
306
|
-
ESP_LOGW(TAG, "
|
|
306
|
+
ESP_LOGW(TAG, "%s cleared Warning flag", this->get_component_source());
|
|
307
307
|
}
|
|
308
308
|
void Component::status_clear_error() {
|
|
309
309
|
if ((this->component_state_ & STATUS_LED_ERROR) == 0)
|
|
310
310
|
return;
|
|
311
311
|
this->component_state_ &= ~STATUS_LED_ERROR;
|
|
312
|
-
ESP_LOGE(TAG, "
|
|
312
|
+
ESP_LOGE(TAG, "%s cleared Error flag", this->get_component_source());
|
|
313
313
|
}
|
|
314
314
|
void Component::status_momentary_warning(const std::string &name, uint32_t length) {
|
|
315
315
|
this->status_set_warning();
|
|
@@ -403,7 +403,7 @@ uint32_t WarnIfComponentBlockingGuard::finish() {
|
|
|
403
403
|
}
|
|
404
404
|
if (should_warn) {
|
|
405
405
|
const char *src = component_ == nullptr ? "<null>" : component_->get_component_source();
|
|
406
|
-
ESP_LOGW(TAG, "
|
|
406
|
+
ESP_LOGW(TAG, "%s took a long time for an operation (%" PRIu32 " ms)", src, blocking_time);
|
|
407
407
|
ESP_LOGW(TAG, "Components should block for at most 30 ms");
|
|
408
408
|
}
|
|
409
409
|
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
#ifdef USE_API
|
|
6
6
|
#include "esphome/components/api/api_server.h"
|
|
7
|
+
#endif
|
|
8
|
+
#ifdef USE_API_SERVICES
|
|
7
9
|
#include "esphome/components/api/user_services.h"
|
|
8
10
|
#endif
|
|
9
11
|
|
|
@@ -148,7 +150,7 @@ void ComponentIterator::advance() {
|
|
|
148
150
|
}
|
|
149
151
|
break;
|
|
150
152
|
#endif
|
|
151
|
-
#ifdef
|
|
153
|
+
#ifdef USE_API_SERVICES
|
|
152
154
|
case IteratorState ::SERVICE:
|
|
153
155
|
if (this->at_ >= api::global_api_server->get_user_services().size()) {
|
|
154
156
|
advance_platform = true;
|
|
@@ -383,7 +385,7 @@ void ComponentIterator::advance() {
|
|
|
383
385
|
}
|
|
384
386
|
bool ComponentIterator::on_end() { return true; }
|
|
385
387
|
bool ComponentIterator::on_begin() { return true; }
|
|
386
|
-
#ifdef
|
|
388
|
+
#ifdef USE_API_SERVICES
|
|
387
389
|
bool ComponentIterator::on_service(api::UserServiceDescriptor *service) { return true; }
|
|
388
390
|
#endif
|
|
389
391
|
#ifdef USE_CAMERA
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
namespace esphome {
|
|
12
12
|
|
|
13
|
-
#ifdef
|
|
13
|
+
#ifdef USE_API_SERVICES
|
|
14
14
|
namespace api {
|
|
15
15
|
class UserServiceDescriptor;
|
|
16
16
|
} // namespace api
|
|
@@ -45,7 +45,7 @@ class ComponentIterator {
|
|
|
45
45
|
#ifdef USE_TEXT_SENSOR
|
|
46
46
|
virtual bool on_text_sensor(text_sensor::TextSensor *text_sensor) = 0;
|
|
47
47
|
#endif
|
|
48
|
-
#ifdef
|
|
48
|
+
#ifdef USE_API_SERVICES
|
|
49
49
|
virtual bool on_service(api::UserServiceDescriptor *service);
|
|
50
50
|
#endif
|
|
51
51
|
#ifdef USE_CAMERA
|
|
@@ -122,7 +122,7 @@ class ComponentIterator {
|
|
|
122
122
|
#ifdef USE_TEXT_SENSOR
|
|
123
123
|
TEXT_SENSOR,
|
|
124
124
|
#endif
|
|
125
|
-
#ifdef
|
|
125
|
+
#ifdef USE_API_SERVICES
|
|
126
126
|
SERVICE,
|
|
127
127
|
#endif
|
|
128
128
|
#ifdef USE_CAMERA
|
esphome/core/defines.h
CHANGED
esphome/core/entity_helpers.py
CHANGED
|
@@ -187,6 +187,12 @@ def entity_duplicate_validator(platform: str) -> Callable[[ConfigType], ConfigTy
|
|
|
187
187
|
# No name to validate
|
|
188
188
|
return config
|
|
189
189
|
|
|
190
|
+
# Skip validation for internal entities
|
|
191
|
+
# Internal entities are not exposed to Home Assistant and don't use the hash-based
|
|
192
|
+
# entity state tracking system, so name collisions don't matter for them
|
|
193
|
+
if config.get(CONF_INTERNAL, False):
|
|
194
|
+
return config
|
|
195
|
+
|
|
190
196
|
# Get the entity name
|
|
191
197
|
entity_name = config[CONF_NAME]
|
|
192
198
|
|
esphome/core/helpers.h
CHANGED
|
@@ -783,7 +783,7 @@ template<class T> class RAMAllocator {
|
|
|
783
783
|
T *reallocate(T *p, size_t n) { return this->reallocate(p, n, sizeof(T)); }
|
|
784
784
|
|
|
785
785
|
T *reallocate(T *p, size_t n, size_t manual_size) {
|
|
786
|
-
size_t size = n *
|
|
786
|
+
size_t size = n * manual_size;
|
|
787
787
|
T *ptr = nullptr;
|
|
788
788
|
#ifdef USE_ESP32
|
|
789
789
|
if (this->flags_ & Flags::ALLOC_EXTERNAL) {
|