esphome 2025.3.1__py3-none-any.whl → 2025.3.3__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.
@@ -72,6 +72,8 @@ void CST226Touchscreen::continue_setup_() {
72
72
  if (this->read16_(0xD1F8, buffer, 4)) {
73
73
  this->x_raw_max_ = buffer[0] + (buffer[1] << 8);
74
74
  this->y_raw_max_ = buffer[2] + (buffer[3] << 8);
75
+ if (this->swap_x_y_)
76
+ std::swap(this->x_raw_max_, this->y_raw_max_);
75
77
  } else {
76
78
  this->x_raw_max_ = this->display_->get_native_width();
77
79
  this->y_raw_max_ = this->display_->get_native_height();
@@ -555,10 +555,10 @@ void Display::get_text_bounds(int x, int y, const char *text, BaseFont *font, Te
555
555
 
556
556
  switch (x_align) {
557
557
  case TextAlign::RIGHT:
558
- *x1 = x - *width;
558
+ *x1 = x - *width - x_offset;
559
559
  break;
560
560
  case TextAlign::CENTER_HORIZONTAL:
561
- *x1 = x - (*width) / 2;
561
+ *x1 = x - (*width + x_offset) / 2;
562
562
  break;
563
563
  case TextAlign::LEFT:
564
564
  default:
@@ -34,26 +34,29 @@ void EKTF2232Touchscreen::setup() {
34
34
 
35
35
  // Get touch resolution
36
36
  uint8_t received[4];
37
- if (this->x_raw_max_ == this->x_raw_min_) {
38
- this->write(GET_X_RES, 4);
39
- if (this->read(received, 4)) {
40
- ESP_LOGE(TAG, "Failed to read X resolution!");
41
- this->interrupt_pin_->detach_interrupt();
42
- this->mark_failed();
43
- return;
37
+ if (this->x_raw_max_ == 0 || this->y_raw_max_ == 0) {
38
+ auto err = this->write(GET_X_RES, 4);
39
+ if (err == i2c::ERROR_OK) {
40
+ err = this->read(received, 4);
41
+ if (err == i2c::ERROR_OK) {
42
+ this->x_raw_max_ = ((received[2])) | ((received[3] & 0xf0) << 4);
43
+ err = this->write(GET_Y_RES, 4);
44
+ if (err == i2c::ERROR_OK) {
45
+ err = this->read(received, 4);
46
+ if (err == i2c::ERROR_OK) {
47
+ this->y_raw_max_ = ((received[2])) | ((received[3] & 0xf0) << 4);
48
+ }
49
+ }
50
+ }
44
51
  }
45
- this->x_raw_max_ = ((received[2])) | ((received[3] & 0xf0) << 4);
46
- }
47
-
48
- if (this->y_raw_max_ == this->y_raw_min_) {
49
- this->write(GET_Y_RES, 4);
50
- if (this->read(received, 4)) {
51
- ESP_LOGE(TAG, "Failed to read Y resolution!");
52
+ if (err != i2c::ERROR_OK) {
53
+ ESP_LOGE(TAG, "Failed to read calibration values!");
52
54
  this->interrupt_pin_->detach_interrupt();
53
55
  this->mark_failed();
54
56
  return;
55
57
  }
56
- this->y_raw_max_ = ((received[2])) | ((received[3] & 0xf0) << 4);
58
+ if (this->swap_x_y_)
59
+ std::swap(this->x_raw_max_, this->y_raw_max_);
57
60
  }
58
61
  this->set_power_state(true);
59
62
  }
@@ -7,7 +7,15 @@ from pathlib import Path
7
7
  import re
8
8
 
9
9
  import esphome_glyphsets as glyphsets
10
- from freetype import Face, ft_pixel_mode_grays, ft_pixel_mode_mono
10
+
11
+ # pylint: disable=no-name-in-module
12
+ from freetype import (
13
+ FT_LOAD_NO_BITMAP,
14
+ FT_LOAD_RENDER,
15
+ FT_LOAD_TARGET_MONO,
16
+ Face,
17
+ ft_pixel_mode_mono,
18
+ )
11
19
  import requests
12
20
 
13
21
  from esphome import external_files
@@ -204,7 +212,7 @@ def validate_font_config(config):
204
212
  if font.get_char_index(x) != 0
205
213
  ]
206
214
 
207
- if font.has_fixed_sizes:
215
+ if not font.is_scalable:
208
216
  sizes = [pt_to_px(x.size) for x in font.available_sizes]
209
217
  if not sizes:
210
218
  raise cv.Invalid(
@@ -501,17 +509,23 @@ async def to_code(config):
501
509
  glyph_args = {}
502
510
  data = []
503
511
  bpp = config[CONF_BPP]
504
- mode = ft_pixel_mode_grays
505
512
  scale = 256 // (1 << bpp)
506
513
  size = config[CONF_SIZE]
507
514
  # create the data array for all glyphs
508
515
  for codepoint in codepoints:
509
516
  font = point_font_map[codepoint]
510
- format = font.get_format().decode("utf-8")
511
- if format != "PCF":
517
+ if not font.is_scalable:
518
+ sizes = [pt_to_px(x.size) for x in font.available_sizes]
519
+ if size in sizes:
520
+ font.select_size(sizes.index(size))
521
+ else:
512
522
  font.set_pixel_sizes(size, 0)
513
- font.load_char(codepoint)
514
- font.glyph.render(mode)
523
+ flags = FT_LOAD_RENDER
524
+ if bpp != 1:
525
+ flags |= FT_LOAD_NO_BITMAP
526
+ else:
527
+ flags |= FT_LOAD_TARGET_MONO
528
+ font.load_char(codepoint, flags)
515
529
  width = font.glyph.bitmap.width
516
530
  height = font.glyph.bitmap.rows
517
531
  buffer = font.glyph.bitmap.buffer
@@ -535,7 +549,7 @@ async def to_code(config):
535
549
  pos += 1
536
550
  ascender = pt_to_px(font.size.ascender)
537
551
  if ascender == 0:
538
- if font.has_fixed_sizes:
552
+ if not font.is_scalable:
539
553
  ascender = size
540
554
  else:
541
555
  _LOGGER.error(
@@ -585,7 +599,7 @@ async def to_code(config):
585
599
  font_height = pt_to_px(base_font.size.height)
586
600
  ascender = pt_to_px(base_font.size.ascender)
587
601
  if font_height == 0:
588
- if base_font.has_fixed_sizes:
602
+ if not base_font.is_scalable:
589
603
  font_height = size
590
604
  ascender = font_height
591
605
  else:
@@ -60,20 +60,25 @@ void GT911Touchscreen::setup() {
60
60
  }
61
61
  }
62
62
  }
63
- if (err == i2c::ERROR_OK) {
64
- err = this->write(GET_MAX_VALUES, 2);
63
+ if (this->x_raw_max_ == 0 || this->y_raw_max_ == 0) {
64
+ // no calibration? Attempt to read the max values from the touchscreen.
65
65
  if (err == i2c::ERROR_OK) {
66
- err = this->read(data, sizeof(data));
66
+ err = this->write(GET_MAX_VALUES, 2);
67
67
  if (err == i2c::ERROR_OK) {
68
- if (this->x_raw_max_ == this->x_raw_min_) {
68
+ err = this->read(data, sizeof(data));
69
+ if (err == i2c::ERROR_OK) {
69
70
  this->x_raw_max_ = encode_uint16(data[1], data[0]);
70
- }
71
- if (this->y_raw_max_ == this->y_raw_min_) {
72
71
  this->y_raw_max_ = encode_uint16(data[3], data[2]);
72
+ if (this->swap_x_y_)
73
+ std::swap(this->x_raw_max_, this->y_raw_max_);
73
74
  }
74
- esph_log_d(TAG, "calibration max_x/max_y %d/%d", this->x_raw_max_, this->y_raw_max_);
75
75
  }
76
76
  }
77
+ if (err != i2c::ERROR_OK) {
78
+ ESP_LOGE(TAG, "Failed to read calibration values from touchscreen!");
79
+ this->mark_failed();
80
+ return;
81
+ }
77
82
  }
78
83
  if (err != i2c::ERROR_OK) {
79
84
  ESP_LOGE(TAG, "Failed to communicate!");
@@ -15,6 +15,7 @@ namespace esphome {
15
15
  namespace ld2450 {
16
16
 
17
17
  static const char *const TAG = "ld2450";
18
+ static const char *const NO_MAC("08:05:04:03:02:01");
18
19
  static const char *const UNKNOWN_MAC("unknown");
19
20
 
20
21
  // LD2450 UART Serial Commands
@@ -614,12 +615,12 @@ bool LD2450Component::handle_ack_data_(uint8_t *buffer, uint8_t len) {
614
615
  ESP_LOGV(TAG, "MAC address: %s", this->mac_.c_str());
615
616
  #ifdef USE_TEXT_SENSOR
616
617
  if (this->mac_text_sensor_ != nullptr) {
617
- this->mac_text_sensor_->publish_state(this->mac_);
618
+ this->mac_text_sensor_->publish_state(this->mac_ == NO_MAC ? UNKNOWN_MAC : this->mac_);
618
619
  }
619
620
  #endif
620
621
  #ifdef USE_SWITCH
621
622
  if (this->bluetooth_switch_ != nullptr) {
622
- this->bluetooth_switch_->publish_state(this->mac_ != UNKNOWN_MAC);
623
+ this->bluetooth_switch_->publish_state(this->mac_ != NO_MAC);
623
624
  }
624
625
  #endif
625
626
  break;
@@ -1,7 +1,9 @@
1
1
  import esphome.codegen as cg
2
- from esphome.components.switch import Switch, new_switch, switch_schema
2
+ from esphome.components.switch import Switch, register_switch, switch_schema
3
3
  import esphome.config_validation as cv
4
+ from esphome.const import CONF_ID
4
5
  from esphome.cpp_generator import MockObj
6
+ from esphome.cpp_types import Component
5
7
 
6
8
  from ..defines import CONF_WIDGET, literal
7
9
  from ..lvcode import (
@@ -18,7 +20,7 @@ from ..lvcode import (
18
20
  from ..types import LV_EVENT, LV_STATE, lv_pseudo_button_t, lvgl_ns
19
21
  from ..widgets import get_widgets, wait_for_widgets
20
22
 
21
- LVGLSwitch = lvgl_ns.class_("LVGLSwitch", Switch)
23
+ LVGLSwitch = lvgl_ns.class_("LVGLSwitch", Switch, Component)
22
24
  CONFIG_SCHEMA = switch_schema(LVGLSwitch).extend(
23
25
  {
24
26
  cv.Required(CONF_WIDGET): cv.use_id(lv_pseudo_button_t),
@@ -27,21 +29,24 @@ CONFIG_SCHEMA = switch_schema(LVGLSwitch).extend(
27
29
 
28
30
 
29
31
  async def to_code(config):
30
- switch = await new_switch(config)
31
32
  widget = await get_widgets(config, CONF_WIDGET)
32
33
  widget = widget[0]
33
34
  await wait_for_widgets()
34
- async with LambdaContext(EVENT_ARG) as checked_ctx:
35
- checked_ctx.add(switch.publish_state(widget.get_value()))
35
+ switch_id = MockObj(config[CONF_ID], "->")
36
+ v = literal("v")
36
37
  async with LambdaContext([(cg.bool_, "v")]) as control:
37
- with LvConditional(MockObj("v")) as cond:
38
+ with LvConditional(v) as cond:
38
39
  widget.add_state(LV_STATE.CHECKED)
39
40
  cond.else_()
40
41
  widget.clear_state(LV_STATE.CHECKED)
41
42
  lv.event_send(widget.obj, API_EVENT, cg.nullptr)
42
- control.add(switch.publish_state(literal("v")))
43
+ control.add(switch_id.publish_state(v))
44
+ switch = cg.new_Pvariable(config[CONF_ID], await control.get_lambda())
45
+ await cg.register_component(switch, config)
46
+ await register_switch(switch, config)
47
+ async with LambdaContext(EVENT_ARG) as checked_ctx:
48
+ checked_ctx.add(switch.publish_state(widget.get_value()))
43
49
  async with LvContext() as ctx:
44
- lv_add(switch.set_control_lambda(await control.get_lambda()))
45
50
  ctx.add(
46
51
  lvgl_static.add_event_cb(
47
52
  widget.obj,
@@ -10,26 +10,15 @@
10
10
  namespace esphome {
11
11
  namespace lvgl {
12
12
 
13
- class LVGLSwitch : public switch_::Switch {
13
+ class LVGLSwitch : public switch_::Switch, public Component {
14
14
  public:
15
- void set_control_lambda(std::function<void(bool)> state_lambda) {
16
- this->state_lambda_ = std::move(state_lambda);
17
- if (this->initial_state_.has_value()) {
18
- this->state_lambda_(this->initial_state_.value());
19
- this->initial_state_.reset();
20
- }
21
- }
15
+ LVGLSwitch(std::function<void(bool)> state_lambda) : state_lambda_(std::move(state_lambda)) {}
16
+
17
+ void setup() override { this->write_state(this->get_initial_state_with_restore_mode().value_or(false)); }
22
18
 
23
19
  protected:
24
- void write_state(bool value) override {
25
- if (this->state_lambda_ != nullptr) {
26
- this->state_lambda_(value);
27
- } else {
28
- this->initial_state_ = value;
29
- }
30
- }
20
+ void write_state(bool value) override { this->state_lambda_(value); }
31
21
  std::function<void(bool)> state_lambda_{};
32
- optional<bool> initial_state_{};
33
22
  };
34
23
 
35
24
  } // namespace lvgl
@@ -91,7 +91,7 @@ async def to_code(config):
91
91
  add_idf_component(
92
92
  name="mdns",
93
93
  repo="https://github.com/espressif/esp-protocols.git",
94
- ref="mdns-v1.8.0",
94
+ ref="mdns-v1.8.2",
95
95
  path="components/mdns",
96
96
  )
97
97
 
@@ -56,7 +56,8 @@ const char *media_player_command_to_string(MediaPlayerCommand command) {
56
56
 
57
57
  void MediaPlayerCall::validate_() {
58
58
  if (this->media_url_.has_value()) {
59
- if (this->command_.has_value()) {
59
+ if (this->command_.has_value() && this->command_.value() != MEDIA_PLAYER_COMMAND_ENQUEUE) {
60
+ // Don't remove an enqueue command
60
61
  ESP_LOGW(TAG, "MediaPlayerCall: Setting both command and media_url is not needed.");
61
62
  this->command_.reset();
62
63
  }
@@ -100,7 +100,7 @@ void SpeakerMediaPlayer::setup() {
100
100
 
101
101
  if (!this->single_pipeline_()) {
102
102
  this->media_pipeline_ = make_unique<AudioPipeline>(this->media_speaker_, this->buffer_size_,
103
- this->task_stack_in_psram_, "ann", MEDIA_PIPELINE_TASK_PRIORITY);
103
+ this->task_stack_in_psram_, "med", MEDIA_PIPELINE_TASK_PRIORITY);
104
104
 
105
105
  if (this->media_pipeline_ == nullptr) {
106
106
  ESP_LOGE(TAG, "Failed to create media pipeline");
@@ -138,77 +138,64 @@ void SpeakerMediaPlayer::watch_media_commands_() {
138
138
  }
139
139
 
140
140
  MediaCallCommand media_command;
141
- esp_err_t err = ESP_OK;
142
141
 
143
142
  if (xQueueReceive(this->media_control_command_queue_, &media_command, 0) == pdTRUE) {
144
- bool new_url = media_command.new_url.has_value() && media_command.new_url.value();
145
- bool new_file = media_command.new_file.has_value() && media_command.new_file.value();
143
+ bool enqueue = media_command.enqueue.has_value() && media_command.enqueue.value();
146
144
 
147
- if (new_url || new_file) {
148
- bool enqueue = media_command.enqueue.has_value() && media_command.enqueue.value();
145
+ if (media_command.url.has_value() || media_command.file.has_value()) {
146
+ PlaylistItem playlist_item;
147
+ if (media_command.url.has_value()) {
148
+ playlist_item.url = *media_command.url.value();
149
+ delete media_command.url.value();
150
+ }
151
+ if (media_command.file.has_value()) {
152
+ playlist_item.file = media_command.file.value();
153
+ }
149
154
 
150
155
  if (this->single_pipeline_() || (media_command.announce.has_value() && media_command.announce.value())) {
151
- // Announcement playlist/pipeline
152
-
153
156
  if (!enqueue) {
154
- // Clear the queue and ensure the loaded next item doesn't start playing
157
+ // Ensure the loaded next item doesn't start playing, clear the queue, start the file, and unpause
155
158
  this->cancel_timeout("next_ann");
156
159
  this->announcement_playlist_.clear();
157
- }
158
-
159
- PlaylistItem playlist_item;
160
- if (new_url) {
161
- playlist_item.url = this->announcement_url_;
162
- if (!enqueue) {
163
- // Not adding to the queue, so directly start playback and internally unpause the pipeline
164
- this->announcement_pipeline_->start_url(playlist_item.url.value());
165
- this->announcement_pipeline_->set_pause_state(false);
166
- }
167
- } else {
168
- playlist_item.file = this->announcement_file_;
169
- if (!enqueue) {
170
- // Not adding to the queue, so directly start playback and internally unpause the pipeline
160
+ if (media_command.file.has_value()) {
171
161
  this->announcement_pipeline_->start_file(playlist_item.file.value());
172
- this->announcement_pipeline_->set_pause_state(false);
162
+ } else if (media_command.url.has_value()) {
163
+ this->announcement_pipeline_->start_url(playlist_item.url.value());
173
164
  }
165
+ this->announcement_pipeline_->set_pause_state(false);
174
166
  }
175
167
  this->announcement_playlist_.push_back(playlist_item);
176
168
  } else {
177
- // Media playlist/pipeline
178
-
179
169
  if (!enqueue) {
180
- // Clear the queue and ensure the loaded next item doesn't start playing
170
+ // Ensure the loaded next item doesn't start playing, clear the queue, start the file, and unpause
181
171
  this->cancel_timeout("next_media");
182
172
  this->media_playlist_.clear();
183
- }
184
-
185
- this->is_paused_ = false;
186
- PlaylistItem playlist_item;
187
- if (new_url) {
188
- playlist_item.url = this->media_url_;
189
- if (!enqueue) {
190
- // Not adding to the queue, so directly start playback and internally unpause the pipeline
191
- this->media_pipeline_->start_url(playlist_item.url.value());
192
- this->media_pipeline_->set_pause_state(false);
193
- }
194
- } else {
195
- playlist_item.file = this->media_file_;
196
- if (!enqueue) {
197
- // Not adding to the queue, so directly start playback and internally unpause the pipeline
198
- this->media_pipeline_->start_file(playlist_item.file.value());
173
+ if (this->is_paused_) {
174
+ // If paused, stop the media pipeline and unpause it after confirming its stopped. This avoids playing a
175
+ // short segment of the paused file before starting the new one.
176
+ this->media_pipeline_->stop();
177
+ this->set_retry("unpause_med", 50, 3, [this](const uint8_t remaining_attempts) {
178
+ if (this->media_pipeline_state_ == AudioPipelineState::STOPPED) {
179
+ this->media_pipeline_->set_pause_state(false);
180
+ this->is_paused_ = false;
181
+ return RetryResult::DONE;
182
+ }
183
+ return RetryResult::RETRY;
184
+ });
185
+ } else {
186
+ // Not paused, just directly start the file
187
+ if (media_command.file.has_value()) {
188
+ this->media_pipeline_->start_file(playlist_item.file.value());
189
+ } else if (media_command.url.has_value()) {
190
+ this->media_pipeline_->start_url(playlist_item.url.value());
191
+ }
199
192
  this->media_pipeline_->set_pause_state(false);
193
+ this->is_paused_ = false;
200
194
  }
201
195
  }
202
196
  this->media_playlist_.push_back(playlist_item);
203
197
  }
204
198
 
205
- if (err != ESP_OK) {
206
- ESP_LOGE(TAG, "Error starting the audio pipeline: %s", esp_err_to_name(err));
207
- this->status_set_error();
208
- } else {
209
- this->status_clear_error();
210
- }
211
-
212
199
  return; // Don't process the new file play command further
213
200
  }
214
201
 
@@ -232,19 +219,37 @@ void SpeakerMediaPlayer::watch_media_commands_() {
232
219
  this->is_paused_ = true;
233
220
  break;
234
221
  case media_player::MEDIA_PLAYER_COMMAND_STOP:
222
+ // Pipelines do not stop immediately after calling the stop command, so confirm its stopped before unpausing.
223
+ // This avoids an audible short segment playing after receiving the stop command in a paused state.
235
224
  if (this->single_pipeline_() || (media_command.announce.has_value() && media_command.announce.value())) {
236
225
  if (this->announcement_pipeline_ != nullptr) {
237
226
  this->cancel_timeout("next_ann");
238
227
  this->announcement_playlist_.clear();
239
228
  this->announcement_pipeline_->stop();
229
+ this->set_retry("unpause_ann", 50, 3, [this](const uint8_t remaining_attempts) {
230
+ if (this->announcement_pipeline_state_ == AudioPipelineState::STOPPED) {
231
+ this->announcement_pipeline_->set_pause_state(false);
232
+ return RetryResult::DONE;
233
+ }
234
+ return RetryResult::RETRY;
235
+ });
240
236
  }
241
237
  } else {
242
238
  if (this->media_pipeline_ != nullptr) {
243
239
  this->cancel_timeout("next_media");
244
240
  this->media_playlist_.clear();
245
241
  this->media_pipeline_->stop();
242
+ this->set_retry("unpause_med", 50, 3, [this](const uint8_t remaining_attempts) {
243
+ if (this->media_pipeline_state_ == AudioPipelineState::STOPPED) {
244
+ this->media_pipeline_->set_pause_state(false);
245
+ this->is_paused_ = false;
246
+ return RetryResult::DONE;
247
+ }
248
+ return RetryResult::RETRY;
249
+ });
246
250
  }
247
251
  }
252
+
248
253
  break;
249
254
  case media_player::MEDIA_PLAYER_COMMAND_TOGGLE:
250
255
  if (this->media_pipeline_ != nullptr) {
@@ -361,11 +366,11 @@ void SpeakerMediaPlayer::loop() {
361
366
  }
362
367
 
363
368
  if (timeout_ms > 0) {
364
- // Pause pipeline internally to facilitiate delay between items
369
+ // Pause pipeline internally to facilitate the delay between items
365
370
  this->announcement_pipeline_->set_pause_state(true);
366
- // Internally unpause the pipeline after the delay between playlist items
367
- this->set_timeout("next_ann", timeout_ms,
368
- [this]() { this->announcement_pipeline_->set_pause_state(this->is_paused_); });
371
+ // Internally unpause the pipeline after the delay between playlist items. Announcements do not follow the
372
+ // media player's pause state.
373
+ this->set_timeout("next_ann", timeout_ms, [this]() { this->announcement_pipeline_->set_pause_state(false); });
369
374
  }
370
375
  }
371
376
  } else {
@@ -401,9 +406,10 @@ void SpeakerMediaPlayer::loop() {
401
406
  }
402
407
 
403
408
  if (timeout_ms > 0) {
404
- // Pause pipeline internally to facilitiate delay between items
409
+ // Pause pipeline internally to facilitate the delay between items
405
410
  this->media_pipeline_->set_pause_state(true);
406
- // Internally unpause the pipeline after the delay between playlist items
411
+ // Internally unpause the pipeline after the delay between playlist items, if the media player state is
412
+ // not paused.
407
413
  this->set_timeout("next_media", timeout_ms,
408
414
  [this]() { this->media_pipeline_->set_pause_state(this->is_paused_); });
409
415
  }
@@ -429,12 +435,10 @@ void SpeakerMediaPlayer::play_file(audio::AudioFile *media_file, bool announceme
429
435
 
430
436
  MediaCallCommand media_command;
431
437
 
432
- media_command.new_file = true;
438
+ media_command.file = media_file;
433
439
  if (this->single_pipeline_() || announcement) {
434
- this->announcement_file_ = media_file;
435
440
  media_command.announce = true;
436
441
  } else {
437
- this->media_file_ = media_file;
438
442
  media_command.announce = false;
439
443
  }
440
444
  media_command.enqueue = enqueue;
@@ -456,14 +460,8 @@ void SpeakerMediaPlayer::control(const media_player::MediaPlayerCall &call) {
456
460
  }
457
461
 
458
462
  if (call.get_media_url().has_value()) {
459
- std::string new_uri = call.get_media_url().value();
460
-
461
- media_command.new_url = true;
462
- if (this->single_pipeline_() || (call.get_announcement().has_value() && call.get_announcement().value())) {
463
- this->announcement_url_ = new_uri;
464
- } else {
465
- this->media_url_ = new_uri;
466
- }
463
+ media_command.url = new std::string(
464
+ call.get_media_url().value()); // Must be manually deleted after receiving media_command from a queue
467
465
 
468
466
  if (call.get_command().has_value()) {
469
467
  if (call.get_command().value() == media_player::MEDIA_PLAYER_COMMAND_ENQUEUE) {
@@ -24,8 +24,8 @@ struct MediaCallCommand {
24
24
  optional<media_player::MediaPlayerCommand> command;
25
25
  optional<float> volume;
26
26
  optional<bool> announce;
27
- optional<bool> new_url;
28
- optional<bool> new_file;
27
+ optional<std::string *> url; // Must be manually deleted after receiving this struct from a queue
28
+ optional<audio::AudioFile *> file;
29
29
  optional<bool> enqueue;
30
30
  };
31
31
 
@@ -109,15 +109,11 @@ class SpeakerMediaPlayer : public Component, public media_player::MediaPlayer {
109
109
 
110
110
  optional<media_player::MediaPlayerSupportedFormat> media_format_;
111
111
  AudioPipelineState media_pipeline_state_{AudioPipelineState::STOPPED};
112
- std::string media_url_{}; // only modified by control function
113
- audio::AudioFile *media_file_{}; // only modified by play_file function
114
112
  bool media_repeat_one_{false};
115
113
  uint32_t media_playlist_delay_ms_{0};
116
114
 
117
115
  optional<media_player::MediaPlayerSupportedFormat> announcement_format_;
118
116
  AudioPipelineState announcement_pipeline_state_{AudioPipelineState::STOPPED};
119
- std::string announcement_url_{}; // only modified by control function
120
- audio::AudioFile *announcement_file_{}; // only modified by play_file function
121
117
  bool announcement_repeat_one_{false};
122
118
  uint32_t announcement_playlist_delay_ms_{0};
123
119
 
esphome/const.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Constants used by esphome."""
2
2
 
3
- __version__ = "2025.3.1"
3
+ __version__ = "2025.3.3"
4
4
 
5
5
  ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
6
6
  VALID_SUBSTITUTIONS_CHARACTERS = (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: esphome
3
- Version: 2025.3.1
3
+ Version: 2025.3.3
4
4
  Summary: ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems.
5
5
  Author-email: The ESPHome Authors <esphome@nabucasa.com>
6
6
  License: MIT
@@ -5,7 +5,7 @@ esphome/codegen.py,sha256=GePHUM7xdXb_Pil59SHVsXg2F4VBPgkH-Fz2PDX8Z54,1873
5
5
  esphome/config.py,sha256=fFrDYbhWY1xn_onAl_0jwlg9D8NkK_FdKULTlnjZtxs,39832
6
6
  esphome/config_helpers.py,sha256=MKf_wzO35nn41FvigXE0iYKDslPgL2ruf8R-EPtTT2I,3256
7
7
  esphome/config_validation.py,sha256=9KOhLHQXmDbahg6zHynXfXDfAL2bciu35_SHxHrzZ2M,63705
8
- esphome/const.py,sha256=Z-fLrCBLlybH5KtmXHQNv8bjBDCoOb0JPyjE6tSTtdI,40762
8
+ esphome/const.py,sha256=-khONIbIZaEVV6rouwuo3K6u9_qn4jMlFdB1EY1Y5HY,40762
9
9
  esphome/coroutine.py,sha256=j_14z8dIIzIBeuNO30D4c1RJvMMt1xZFZ58Evd-EvJA,9344
10
10
  esphome/cpp_generator.py,sha256=1g-y3fxWSrd5Kpbz6DrJXaQajjuwQiTIaTRIz9n7svI,31237
11
11
  esphome/cpp_helpers.py,sha256=6C2vNbOIhZKi43xRVlk5hp9GfshfBn-rc5D_ZFUEYaE,4801
@@ -568,7 +568,7 @@ esphome/components/cse7766/cse7766.h,sha256=RE_q5Sa2n8PLkQsO3C9Nt11g6PS_5XBIVD1w
568
568
  esphome/components/cse7766/sensor.py,sha256=rHZGEUgTD8j6V9u8kTKSfRWQ67HzqIeHa9YaC5j6K70,4082
569
569
  esphome/components/cst226/__init__.py,sha256=Xbt13-GS0lUNexCt3EYip3UvO15P2cdJdepZWoDqBw8,130
570
570
  esphome/components/cst226/touchscreen/__init__.py,sha256=cGkF2fb0drtC0Xnz_quMC-uYSoqnXXMTzzEpjr6aP74,1215
571
- esphome/components/cst226/touchscreen/cst226_touchscreen.cpp,sha256=tvs9x9I5xijYH83nesN3Vyo-CzXiw4ups0yJ7heV8p8,2792
571
+ esphome/components/cst226/touchscreen/cst226_touchscreen.cpp,sha256=OsPEVSYsvG6bJmAtkS4muGEQwY31wrg7R0AxctEUohw,2874
572
572
  esphome/components/cst226/touchscreen/cst226_touchscreen.h,sha256=x5q0en-w0ebNgoBznouwrZd1VD_gy9J6accuyQhMcmw,1221
573
573
  esphome/components/cst816/__init__.py,sha256=7XLTtm_EM7-QP8ZfGtLQi1KBroiWOqeRMBTjTbXt-8Q,130
574
574
  esphome/components/cst816/binary_sensor/__init__.py,sha256=xOKwMOe_N3twSMYNb5y2i_tUCQ7umUDA6rUrGg51NAc,190
@@ -686,7 +686,7 @@ esphome/components/dht12/dht12.cpp,sha256=l9vUeg6oc_XRIifT6pft_Jjk4WmS08rLkWv_af
686
686
  esphome/components/dht12/dht12.h,sha256=zHdQNIDC7nPMblvyEkTfXMeGCLmYRB7ZL_SXuB2PEWY,788
687
687
  esphome/components/dht12/sensor.py,sha256=9P1JtUF2VRYtEE1j8GHlsob1EHF5n3DC7mGuGV_fE_w,1684
688
688
  esphome/components/display/__init__.py,sha256=cKo4ldiSbNxcJKEITCDODtgS9kKzQJoPtJIc7mMapsQ,6760
689
- esphome/components/display/display.cpp,sha256=sFhBJ90cclkXNTMtx-mvPqVVS0K9diD7NvHLgAJEzkM,32372
689
+ esphome/components/display/display.cpp,sha256=wXZdyEDufmv6QK-R3if2rBl9rPnHU8vzrCaPRQ33_Wk,32394
690
690
  esphome/components/display/display.h,sha256=uIs9FRgOYUXvOuEJ1NWsXtfja0a3SWCdmx-gGbhrfC0,32346
691
691
  esphome/components/display/display_buffer.cpp,sha256=0jL60x2WNyDTNgjK2Iv7R4ZlA57cbIt1-J_QvGFKlbM,1896
692
692
  esphome/components/display/display_buffer.h,sha256=RkFqe72PZtSKR60mWlb79FDqVQQFsefcEOdOMwIjuGc,809
@@ -732,7 +732,7 @@ esphome/components/ee895/ee895.h,sha256=PlW9Q8XFN6_V0SJxD3k-upafHEXvSLbvRb5JINp5
732
732
  esphome/components/ee895/sensor.py,sha256=UUaWHFHVHqwubCzEJ4da-SzXezojdFc8_QQh70449w4,2172
733
733
  esphome/components/ektf2232/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
734
734
  esphome/components/ektf2232/touchscreen/__init__.py,sha256=sJg6n62UTHjwDvsFPtJe4tkNxiWqOXrdMjLj6TUufdE,1271
735
- esphome/components/ektf2232/touchscreen/ektf2232.cpp,sha256=gZ2uurraay8lbuSn0IvLW3eC_LJEa7cj64KWQd0Mu1I,3496
735
+ esphome/components/ektf2232/touchscreen/ektf2232.cpp,sha256=F7uBZmlEn8T3nfkJ96GOVbvP923PmigyvJC_vS1UOIY,3640
736
736
  esphome/components/ektf2232/touchscreen/ektf2232.h,sha256=7Lr7YYdTWZOUUfMdg1nVw2JVjvhVhn2XvZKbMc1GFlY,827
737
737
  esphome/components/emc2101/__init__.py,sha256=2kE5cXQkG9tkU87DFLKxB0cX5WUqdAvZWzZnJaZ9RjQ,2808
738
738
  esphome/components/emc2101/emc2101.cpp,sha256=SdeT5uVNWEQ77lHbtH0KOyckCr1PfHB67Q6zQXqzJRg,6921
@@ -952,7 +952,7 @@ esphome/components/fingerprint_grow/binary_sensor.py,sha256=NeVcqVCpmjGdnfimIIWS
952
952
  esphome/components/fingerprint_grow/fingerprint_grow.cpp,sha256=xtHEpnp1Ei_5s5SS5Vfxt8vG_PoPMmeUjbOQHWrn5G0,18675
953
953
  esphome/components/fingerprint_grow/fingerprint_grow.h,sha256=UEkLR4Cqas_XYlTLAwscXCAMRoprWeQZEZ_3vTsI-BM,11206
954
954
  esphome/components/fingerprint_grow/sensor.py,sha256=eazvZvdtt1Rl8o3Aw6eYKn-kb2sNDfZKHegxpFFdQeg,2244
955
- esphome/components/font/__init__.py,sha256=r7IpPuAOAJuPyz9tvnb_q9T9QTLuH2-ti-D3iDGOG9A,18893
955
+ esphome/components/font/__init__.py,sha256=dfieu9eop8dl0oGvc19EMQVq6qH8HiyA4FrlFOnUMFY,19199
956
956
  esphome/components/font/font.cpp,sha256=dxZID-p7toxsAe3JZIc6syEdleARl-H3IRWoUIFGUOY,5361
957
957
  esphome/components/font/font.h,sha256=lBUD-bX8qK0Us0tVjq9i38EJVG6p9w4npKnW1L_ILx0,2024
958
958
  esphome/components/fs3000/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1039,7 +1039,7 @@ esphome/components/gt911/binary_sensor/__init__.py,sha256=fx8W9VhBGssxRD21iTQGva
1039
1039
  esphome/components/gt911/binary_sensor/gt911_button.cpp,sha256=KACuxHcVbk3TZdSPy-8kO4j0LZZZmdAy4VWMicnaoLY,586
1040
1040
  esphome/components/gt911/binary_sensor/gt911_button.h,sha256=3QCm3g8Ca9VtsKKjWgc_Bre4Dc3RhXgaLt1Mq3iEKd8,714
1041
1041
  esphome/components/gt911/touchscreen/__init__.py,sha256=Hx69_ljCE1F-dP5BzEoQ7vIcOTy9_AsnDBb9FH3pCpU,1155
1042
- esphome/components/gt911/touchscreen/gt911_touchscreen.cpp,sha256=a9GWnw4Ykn5neAD1RXayC8dZ950pPRhZnL-h3p9V8KQ,4505
1042
+ esphome/components/gt911/touchscreen/gt911_touchscreen.cpp,sha256=pxFm2WgskgUy2hK13nAXqp72GpvjH9dbVk-LqYS_ggs,4684
1043
1043
  esphome/components/gt911/touchscreen/gt911_touchscreen.h,sha256=q-ZvP6OEGk8TU9eNfWI5-Bj5lVz-DXkxEGEiSzYr2L0,1026
1044
1044
  esphome/components/haier/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1045
1045
  esphome/components/haier/automation.h,sha256=xHnMbqHWFwtibKxgqLraPeNlKLWv2_AT7VX0aMVYtr8,3688
@@ -1396,7 +1396,7 @@ esphome/components/ld2420/text_sensor/text_sensor.cpp,sha256=T8Hlo3rGbyEpKMlFHTf
1396
1396
  esphome/components/ld2420/text_sensor/text_sensor.h,sha256=aK91ri0NvHth3ya0zN1OeX81v1nqveoiJcOfqCpaAJI,672
1397
1397
  esphome/components/ld2450/__init__.py,sha256=5QeRhMvHdL4UVu4Qv80Ly78UOXU28kzWEAPxPKpNVNQ,1280
1398
1398
  esphome/components/ld2450/binary_sensor.py,sha256=SyIw9c-4JqNm8JKuzSKA9rVWaVCGsYAslV0VbhqJnoM,1755
1399
- esphome/components/ld2450/ld2450.cpp,sha256=UMc-kzDOsVHR100J5Zjl8SiUUhrvgh5PydOz9_7I_EM,29993
1399
+ esphome/components/ld2450/ld2450.cpp,sha256=WMUKdVmBpT6f4RhJTo8Ep0oA4MnwlYfSEYsTbx4MLtc,30079
1400
1400
  esphome/components/ld2450/ld2450.h,sha256=7mTGWij9R__PpeonHR7TbxZkvJVdmIiaAoU7jB5fR2U,7984
1401
1401
  esphome/components/ld2450/sensor.py,sha256=bEowM_OzazFp3kSAnyGtw0W8AsX2K5znbCYU4DObqNQ,6570
1402
1402
  esphome/components/ld2450/text_sensor.py,sha256=msgqwIFvkSrewI7MP_KPKMWdMOEpPFOj0hhsfudUfho,2009
@@ -1541,8 +1541,8 @@ esphome/components/lvgl/number/lvgl_number.h,sha256=UshgT5_EvfaA0nWWChjxoyIPy_0W
1541
1541
  esphome/components/lvgl/select/__init__.py,sha256=KOlRVSjCt8TFrjrGPywpjKmQUUAzJUHuA_acLCp6-EI,1011
1542
1542
  esphome/components/lvgl/select/lvgl_select.h,sha256=_nqOOVDNKcOEph6-EZ40VhjkgMdFRjVJB3OTl6tVIso,1659
1543
1543
  esphome/components/lvgl/sensor/__init__.py,sha256=TCK3N05hAW1OjDYV1S5DUZd5JcmfpzWrcVwuA6PXf1c,1116
1544
- esphome/components/lvgl/switch/__init__.py,sha256=7C81PMNEHFu2jxPHH7Mbthq0iQQz7AZ496eyhIjgnhQ,1713
1545
- esphome/components/lvgl/switch/lvgl_switch.h,sha256=PF9vT-HtLnGTdMRdHhfcgnlKeSUDnkiFJoLok_zurnQ,868
1544
+ esphome/components/lvgl/switch/__init__.py,sha256=d63-MV2Hbz_fNh_qWTEbe0K_g4eJX0x63TW2XyIrhe0,1909
1545
+ esphome/components/lvgl/switch/lvgl_switch.h,sha256=EUG9PQfryUD8EHP_GmYMGElOrBQG0Yd8FHyFFfBEvbw,686
1546
1546
  esphome/components/lvgl/text/__init__.py,sha256=6P8kh6XRVX1Falw3Up0YsN4HIb9CyJShXHjNQb_Rsw4,1544
1547
1547
  esphome/components/lvgl/text/lvgl_text.h,sha256=H0tLRmOMCKTelGj-kLF0J6CGoOPQo142cP-CTOk4Rog,914
1548
1548
  esphome/components/lvgl/text_sensor/__init__.py,sha256=UtZwQ09zNCVaR48v7UodRSa-rY-1XF9YBg-jPTRNKRg,1103
@@ -1700,7 +1700,7 @@ esphome/components/mcp9808/sensor.py,sha256=71l_lBZ7F3dausUP94mdMUx-1QuGJJqi273u
1700
1700
  esphome/components/md5/__init__.py,sha256=UMOzKlaVJtzYULytE5P3aZOdVPKrdJAQb-NLxUQ4UUE,119
1701
1701
  esphome/components/md5/md5.cpp,sha256=4wfJNvWDF_kpq0_mOYpcjSvX3azczAzID3Ow82VFBWk,1711
1702
1702
  esphome/components/md5/md5.h,sha256=eTAX-Ijoj30lVdQQ30wdcYKVNeFvC_0AYOzXw3wGfAQ,1591
1703
- esphome/components/mdns/__init__.py,sha256=W8e7xs4Zl1eRRdvMthYrmHXPUCmbaqTg_vfB7QAG8xw,2909
1703
+ esphome/components/mdns/__init__.py,sha256=FZE-Ry4W8diC96M0af5xgPwN1G51TlctWL0vw5SfzYI,2909
1704
1704
  esphome/components/mdns/mdns_component.cpp,sha256=kSNKYHmAAhHTE0UERqH1ZxGbqaPeEWgQ2ox7u3yjdxo,3675
1705
1705
  esphome/components/mdns/mdns_component.h,sha256=C-95CGy4G0lI3PN97akmKtVnET5iiJze3vAMD1LkJSI,1239
1706
1706
  esphome/components/mdns/mdns_esp32.cpp,sha256=5KEGkIa4M8HyHUDH9CYabLtD_NTVlaDQzZk3Nha1aiI,1710
@@ -1710,7 +1710,7 @@ esphome/components/mdns/mdns_libretiny.cpp,sha256=j3uX11MTYYO1WEN6X-UyuqMt9i6Fz0
1710
1710
  esphome/components/mdns/mdns_rp2040.cpp,sha256=AzSFWtVJtq2dA9wJIFkvZvk8r_7oYbdFVtGVRxNBSgg,1306
1711
1711
  esphome/components/media_player/__init__.py,sha256=5JO0c-8j-kOBXCOaN-FiYlQh0vw9DHEnTuj_muZAalc,8337
1712
1712
  esphome/components/media_player/automation.h,sha256=1aQDiCcXCfbwi2WrU8WyaPnW9MfR95-f9MhFNBhQ3kI,3685
1713
- esphome/components/media_player/media_player.cpp,sha256=G5OfVIbtJxe5QzpaaX4BC_kVWwbzN-CfMi-LSo12eUg,4354
1713
+ esphome/components/media_player/media_player.cpp,sha256=VIaMoEUzX7Z95Ng8iCfBWEG3_2469WETuhokRRF2KP4,4453
1714
1714
  esphome/components/media_player/media_player.h,sha256=dXDuZ2apylAj78YccKfoJzX_qscoUN-5KYGKYxiwYv4,3252
1715
1715
  esphome/components/mhz19/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1716
1716
  esphome/components/mhz19/mhz19.cpp,sha256=CBBVBMqGUsrc-4PMOaBDuKCAFNr43Kukt3a018kQI0k,3924
@@ -2690,8 +2690,8 @@ esphome/components/speaker/media_player/__init__.py,sha256=-bV3Fps2AGFUEW8C35py8
2690
2690
  esphome/components/speaker/media_player/audio_pipeline.cpp,sha256=CxWJFkt3IUb4o1w6ajh2rnINUqUSOK6RigEeFEGkMus,22365
2691
2691
  esphome/components/speaker/media_player/audio_pipeline.h,sha256=MYt7_kp4IJDSTnXWqLaXIkbbNkGx6F_imSryFo2UUkc,5000
2692
2692
  esphome/components/speaker/media_player/automation.h,sha256=I8psUHnJ8T3fkM05h1yEYDxb0yWe6Vjz7i30OSVA3Is,683
2693
- esphome/components/speaker/media_player/speaker_media_player.cpp,sha256=cAzlSzzeUKRRssimFqNDz4qA98D-qcAgy8OMTHCiZQs,22777
2694
- esphome/components/speaker/media_player/speaker_media_player.h,sha256=iQ9mszQDH9RAI7RSiccMaQfR8W6vR_H4m_HoceqMhx8,5758
2693
+ esphome/components/speaker/media_player/speaker_media_player.cpp,sha256=4qbWSTcEBXKeqxqBF10K_M6C7ONjMev4OAdMyG-HrFo,23489
2694
+ esphome/components/speaker/media_player/speaker_media_player.h,sha256=wteJb_rXEK2LUTdehGsAMldDl0KLWpP8aySHsPYIIDc,5533
2695
2695
  esphome/components/speed/__init__.py,sha256=Bfyz1MHHvLHj93TfN53E2uhKXKLYtp0k4st6Xb3760o,74
2696
2696
  esphome/components/speed/fan/__init__.py,sha256=zhurjCYLG9V-soV-LF4mEGxqyrcQuQ_KLdFq0LpyAKA,1798
2697
2697
  esphome/components/speed/fan/speed_fan.cpp,sha256=vjrhZZ4Rto6uEmw8396tF9QrAXZvZSKKiIC-_T2LtYc,1472
@@ -3474,9 +3474,9 @@ esphome/dashboard/util/itertools.py,sha256=8eLrWEWmICLtXNxkKdYPQV0c_N4GEz8m9Npnb
3474
3474
  esphome/dashboard/util/password.py,sha256=cQz3b9B-ijTe7zS6BeCW0hc3pWv6JjC78jmnycYYAh8,321
3475
3475
  esphome/dashboard/util/subprocess.py,sha256=T8EW6dbU4LPd2DG1dRrdh8li71tt6J1isn411poMhkk,1022
3476
3476
  esphome/dashboard/util/text.py,sha256=ENDnfN4O0NdA3CKVJjQYabFbwbrsIhVKrAMQe53qYu4,534
3477
- esphome-2025.3.1.dist-info/LICENSE,sha256=HzEjkBInJe44L4WvAOPfhPJJDNj6YbnqFyvGWRzArGM,36664
3478
- esphome-2025.3.1.dist-info/METADATA,sha256=CwwM_TlOJ86BSoNW80T3-5088bU4a_ElSaJs1_FtJe4,3689
3479
- esphome-2025.3.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
3480
- esphome-2025.3.1.dist-info/entry_points.txt,sha256=mIxVNuWtbYzeEcaWCl-AQ-97aBOWbnYBAK8nbF6P4M0,50
3481
- esphome-2025.3.1.dist-info/top_level.txt,sha256=0GSXEW3cnITpgG3qnsSMz0qoqJHAFyfw7Y8MVtEf1Yk,8
3482
- esphome-2025.3.1.dist-info/RECORD,,
3477
+ esphome-2025.3.3.dist-info/LICENSE,sha256=HzEjkBInJe44L4WvAOPfhPJJDNj6YbnqFyvGWRzArGM,36664
3478
+ esphome-2025.3.3.dist-info/METADATA,sha256=zMM-fhpwN7TvL0-7hSWi8VNSeYNlyq-xZUN1oYnFkTk,3689
3479
+ esphome-2025.3.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
3480
+ esphome-2025.3.3.dist-info/entry_points.txt,sha256=mIxVNuWtbYzeEcaWCl-AQ-97aBOWbnYBAK8nbF6P4M0,50
3481
+ esphome-2025.3.3.dist-info/top_level.txt,sha256=0GSXEW3cnITpgG3qnsSMz0qoqJHAFyfw7Y8MVtEf1Yk,8
3482
+ esphome-2025.3.3.dist-info/RECORD,,