esphome 2025.3.0b1__py3-none-any.whl → 2025.3.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.
@@ -7094,6 +7094,16 @@ void VoiceAssistantTimerEventResponse::dump_to(std::string &out) const {
7094
7094
  out.append("}");
7095
7095
  }
7096
7096
  #endif
7097
+ bool VoiceAssistantAnnounceRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
7098
+ switch (field_id) {
7099
+ case 4: {
7100
+ this->start_conversation = value.as_bool();
7101
+ return true;
7102
+ }
7103
+ default:
7104
+ return false;
7105
+ }
7106
+ }
7097
7107
  bool VoiceAssistantAnnounceRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
7098
7108
  switch (field_id) {
7099
7109
  case 1: {
@@ -7104,6 +7114,10 @@ bool VoiceAssistantAnnounceRequest::decode_length(uint32_t field_id, ProtoLength
7104
7114
  this->text = value.as_string();
7105
7115
  return true;
7106
7116
  }
7117
+ case 3: {
7118
+ this->preannounce_media_id = value.as_string();
7119
+ return true;
7120
+ }
7107
7121
  default:
7108
7122
  return false;
7109
7123
  }
@@ -7111,6 +7125,8 @@ bool VoiceAssistantAnnounceRequest::decode_length(uint32_t field_id, ProtoLength
7111
7125
  void VoiceAssistantAnnounceRequest::encode(ProtoWriteBuffer buffer) const {
7112
7126
  buffer.encode_string(1, this->media_id);
7113
7127
  buffer.encode_string(2, this->text);
7128
+ buffer.encode_string(3, this->preannounce_media_id);
7129
+ buffer.encode_bool(4, this->start_conversation);
7114
7130
  }
7115
7131
  #ifdef HAS_PROTO_MESSAGE_DUMP
7116
7132
  void VoiceAssistantAnnounceRequest::dump_to(std::string &out) const {
@@ -7123,6 +7139,14 @@ void VoiceAssistantAnnounceRequest::dump_to(std::string &out) const {
7123
7139
  out.append(" text: ");
7124
7140
  out.append("'").append(this->text).append("'");
7125
7141
  out.append("\n");
7142
+
7143
+ out.append(" preannounce_media_id: ");
7144
+ out.append("'").append(this->preannounce_media_id).append("'");
7145
+ out.append("\n");
7146
+
7147
+ out.append(" start_conversation: ");
7148
+ out.append(YESNO(this->start_conversation));
7149
+ out.append("\n");
7126
7150
  out.append("}");
7127
7151
  }
7128
7152
  #endif
@@ -1832,6 +1832,8 @@ class VoiceAssistantAnnounceRequest : public ProtoMessage {
1832
1832
  public:
1833
1833
  std::string media_id{};
1834
1834
  std::string text{};
1835
+ std::string preannounce_media_id{};
1836
+ bool start_conversation{false};
1835
1837
  void encode(ProtoWriteBuffer buffer) const override;
1836
1838
  #ifdef HAS_PROTO_MESSAGE_DUMP
1837
1839
  void dump_to(std::string &out) const override;
@@ -1839,6 +1841,7 @@ class VoiceAssistantAnnounceRequest : public ProtoMessage {
1839
1841
 
1840
1842
  protected:
1841
1843
  bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
1844
+ bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
1842
1845
  };
1843
1846
  class VoiceAssistantAnnounceFinished : public ProtoMessage {
1844
1847
  public:
@@ -118,4 +118,4 @@ def final_validate_audio_schema(
118
118
 
119
119
 
120
120
  async def to_code(config):
121
- cg.add_library("esphome/esp-audio-libs", "1.1.1")
121
+ cg.add_library("esphome/esp-audio-libs", "1.1.2")
@@ -66,19 +66,30 @@ esp_err_t AudioDecoder::start(AudioFileType audio_file_type) {
66
66
  case AudioFileType::FLAC:
67
67
  this->flac_decoder_ = make_unique<esp_audio_libs::flac::FLACDecoder>();
68
68
  this->free_buffer_required_ =
69
- this->output_transfer_buffer_->capacity(); // We'll revise this after reading the header
69
+ this->output_transfer_buffer_->capacity(); // Adjusted and reallocated after reading the header
70
70
  break;
71
71
  #endif
72
72
  #ifdef USE_AUDIO_MP3_SUPPORT
73
73
  case AudioFileType::MP3:
74
74
  this->mp3_decoder_ = esp_audio_libs::helix_decoder::MP3InitDecoder();
75
+
76
+ // MP3 always has 1152 samples per chunk
75
77
  this->free_buffer_required_ = 1152 * sizeof(int16_t) * 2; // samples * size per sample * channels
78
+
79
+ // Always reallocate the output transfer buffer to the smallest necessary size
80
+ this->output_transfer_buffer_->reallocate(this->free_buffer_required_);
76
81
  break;
77
82
  #endif
78
83
  case AudioFileType::WAV:
79
84
  this->wav_decoder_ = make_unique<esp_audio_libs::wav_decoder::WAVDecoder>();
80
85
  this->wav_decoder_->reset();
86
+
87
+ // Processing WAVs doesn't actually require a specific amount of buffer size, as it is already in PCM format.
88
+ // Thus, we don't reallocate to a minimum size.
81
89
  this->free_buffer_required_ = 1024;
90
+ if (this->output_transfer_buffer_->capacity() < this->free_buffer_required_) {
91
+ this->output_transfer_buffer_->reallocate(this->free_buffer_required_);
92
+ }
82
93
  break;
83
94
  case AudioFileType::NONE:
84
95
  default:
@@ -116,10 +127,18 @@ AudioDecoderState AudioDecoder::decode(bool stop_gracefully) {
116
127
 
117
128
  uint32_t decoding_start = millis();
118
129
 
130
+ bool first_loop_iteration = true;
131
+
132
+ size_t bytes_processed = 0;
133
+ size_t bytes_available_before_processing = 0;
134
+
119
135
  while (state == FileDecoderState::MORE_TO_PROCESS) {
120
136
  // Transfer decoded out
121
137
  if (!this->pause_output_) {
122
- size_t bytes_written = this->output_transfer_buffer_->transfer_data_to_sink(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS));
138
+ // Never shift the data in the output transfer buffer to avoid unnecessary, slow data moves
139
+ size_t bytes_written =
140
+ this->output_transfer_buffer_->transfer_data_to_sink(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS), false);
141
+
123
142
  if (this->audio_stream_info_.has_value()) {
124
143
  this->accumulated_frames_written_ += this->audio_stream_info_.value().bytes_to_frames(bytes_written);
125
144
  this->playback_ms_ +=
@@ -138,12 +157,24 @@ AudioDecoderState AudioDecoder::decode(bool stop_gracefully) {
138
157
 
139
158
  // Decode more audio
140
159
 
141
- size_t bytes_read = this->input_transfer_buffer_->transfer_data_from_source(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS));
160
+ // Only shift data on the first loop iteration to avoid unnecessary, slow moves
161
+ size_t bytes_read = this->input_transfer_buffer_->transfer_data_from_source(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS),
162
+ first_loop_iteration);
142
163
 
143
- if ((this->potentially_failed_count_ > 0) && (bytes_read == 0)) {
164
+ if (!first_loop_iteration && (this->input_transfer_buffer_->available() < bytes_processed)) {
165
+ // Less data is available than what was processed in last iteration, so don't attempt to decode.
166
+ // This attempts to avoid the decoder from consistently trying to decode an incomplete frame. The transfer buffer
167
+ // will shift the remaining data to the start and copy more from the source the next time the decode function is
168
+ // called
169
+ break;
170
+ }
171
+
172
+ bytes_available_before_processing = this->input_transfer_buffer_->available();
173
+
174
+ if ((this->potentially_failed_count_ > 10) && (bytes_read == 0)) {
144
175
  // Failed to decode in last attempt and there is no new data
145
176
 
146
- if (this->input_transfer_buffer_->free() == 0) {
177
+ if ((this->input_transfer_buffer_->free() == 0) && first_loop_iteration) {
147
178
  // The input buffer is full. Since it previously failed on the exact same data, we can never recover
148
179
  state = FileDecoderState::FAILED;
149
180
  } else {
@@ -175,6 +206,9 @@ AudioDecoderState AudioDecoder::decode(bool stop_gracefully) {
175
206
  }
176
207
  }
177
208
 
209
+ first_loop_iteration = false;
210
+ bytes_processed = bytes_available_before_processing - this->input_transfer_buffer_->available();
211
+
178
212
  if (state == FileDecoderState::POTENTIALLY_FAILED) {
179
213
  ++this->potentially_failed_count_;
180
214
  } else if (state == FileDecoderState::END_OF_FILE) {
@@ -207,13 +241,11 @@ FileDecoderState AudioDecoder::decode_flac_() {
207
241
  size_t bytes_consumed = this->flac_decoder_->get_bytes_index();
208
242
  this->input_transfer_buffer_->decrease_buffer_length(bytes_consumed);
209
243
 
244
+ // Reallocate the output transfer buffer to the smallest necessary size
210
245
  this->free_buffer_required_ = flac_decoder_->get_output_buffer_size_bytes();
211
- if (this->output_transfer_buffer_->capacity() < this->free_buffer_required_) {
212
- // Output buffer is not big enough
213
- if (!this->output_transfer_buffer_->reallocate(this->free_buffer_required_)) {
214
- // Couldn't reallocate output buffer
215
- return FileDecoderState::FAILED;
216
- }
246
+ if (!this->output_transfer_buffer_->reallocate(this->free_buffer_required_)) {
247
+ // Couldn't reallocate output buffer
248
+ return FileDecoderState::FAILED;
217
249
  }
218
250
 
219
251
  this->audio_stream_info_ =
@@ -259,14 +259,14 @@ AudioReaderState AudioReader::file_read_() {
259
259
  }
260
260
 
261
261
  AudioReaderState AudioReader::http_read_() {
262
- this->output_transfer_buffer_->transfer_data_to_sink(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS));
262
+ this->output_transfer_buffer_->transfer_data_to_sink(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS), false);
263
263
 
264
264
  if (esp_http_client_is_complete_data_received(this->client_)) {
265
265
  if (this->output_transfer_buffer_->available() == 0) {
266
266
  this->cleanup_connection_();
267
267
  return AudioReaderState::FINISHED;
268
268
  }
269
- } else {
269
+ } else if (this->output_transfer_buffer_->free() > 0) {
270
270
  size_t bytes_to_read = this->output_transfer_buffer_->free();
271
271
  int received_len =
272
272
  esp_http_client_read(this->client_, (char *) this->output_transfer_buffer_->get_buffer_end(), bytes_to_read);
@@ -93,8 +93,9 @@ AudioResamplerState AudioResampler::resample(bool stop_gracefully, int32_t *ms_d
93
93
  }
94
94
 
95
95
  if (!this->pause_output_) {
96
- // Move audio data to the sink
97
- this->output_transfer_buffer_->transfer_data_to_sink(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS));
96
+ // Move audio data to the sink without shifting the data in the output transfer buffer to avoid unnecessary, slow
97
+ // data moves
98
+ this->output_transfer_buffer_->transfer_data_to_sink(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS), false);
98
99
  } else {
99
100
  // If paused, block to avoid wasting CPU resources
100
101
  delay(READ_WRITE_TIMEOUT_MS);
@@ -115,6 +116,7 @@ AudioResamplerState AudioResampler::resample(bool stop_gracefully, int32_t *ms_d
115
116
 
116
117
  if ((this->input_stream_info_.get_sample_rate() != this->output_stream_info_.get_sample_rate()) ||
117
118
  (this->input_stream_info_.get_bits_per_sample() != this->output_stream_info_.get_bits_per_sample())) {
119
+ // Adjust gain by -3 dB to avoid clipping due to the resampling process
118
120
  esp_audio_libs::resampler::ResamplerResults results =
119
121
  this->resampler_->resample(this->input_transfer_buffer_->get_buffer_start(),
120
122
  this->output_transfer_buffer_->get_buffer_end(), frames_available, frames_free, -3);
@@ -33,12 +33,17 @@ size_t AudioTransferBuffer::free() const {
33
33
  if (this->buffer_size_ == 0) {
34
34
  return 0;
35
35
  }
36
- return this->buffer_size_ - (this->buffer_length_ - (this->data_start_ - this->buffer_));
36
+ return this->buffer_size_ - (this->buffer_length_ + (this->data_start_ - this->buffer_));
37
37
  }
38
38
 
39
39
  void AudioTransferBuffer::decrease_buffer_length(size_t bytes) {
40
40
  this->buffer_length_ -= bytes;
41
- this->data_start_ += bytes;
41
+ if (this->buffer_length_ > 0) {
42
+ this->data_start_ += bytes;
43
+ } else {
44
+ // All the data in the buffer has been consumed, reset the start pointer
45
+ this->data_start_ = this->buffer_;
46
+ }
42
47
  }
43
48
 
44
49
  void AudioTransferBuffer::increase_buffer_length(size_t bytes) { this->buffer_length_ += bytes; }
@@ -71,7 +76,7 @@ bool AudioTransferBuffer::has_buffered_data() const {
71
76
 
72
77
  bool AudioTransferBuffer::reallocate(size_t new_buffer_size) {
73
78
  if (this->buffer_length_ > 0) {
74
- // Already has data in the buffer, fail
79
+ // Buffer currently has data, so reallocation is impossible
75
80
  return false;
76
81
  }
77
82
  this->deallocate_buffer_();
@@ -106,12 +111,14 @@ void AudioTransferBuffer::deallocate_buffer_() {
106
111
  this->buffer_length_ = 0;
107
112
  }
108
113
 
109
- size_t AudioSourceTransferBuffer::transfer_data_from_source(TickType_t ticks_to_wait) {
110
- // Shift data in buffer to start
111
- if (this->buffer_length_ > 0) {
112
- memmove(this->buffer_, this->data_start_, this->buffer_length_);
114
+ size_t AudioSourceTransferBuffer::transfer_data_from_source(TickType_t ticks_to_wait, bool pre_shift) {
115
+ if (pre_shift) {
116
+ // Shift data in buffer to start
117
+ if (this->buffer_length_ > 0) {
118
+ memmove(this->buffer_, this->data_start_, this->buffer_length_);
119
+ }
120
+ this->data_start_ = this->buffer_;
113
121
  }
114
- this->data_start_ = this->buffer_;
115
122
 
116
123
  size_t bytes_to_read = this->free();
117
124
  size_t bytes_read = 0;
@@ -125,7 +132,7 @@ size_t AudioSourceTransferBuffer::transfer_data_from_source(TickType_t ticks_to_
125
132
  return bytes_read;
126
133
  }
127
134
 
128
- size_t AudioSinkTransferBuffer::transfer_data_to_sink(TickType_t ticks_to_wait) {
135
+ size_t AudioSinkTransferBuffer::transfer_data_to_sink(TickType_t ticks_to_wait, bool post_shift) {
129
136
  size_t bytes_written = 0;
130
137
  if (this->available()) {
131
138
  #ifdef USE_SPEAKER
@@ -139,11 +146,14 @@ size_t AudioSinkTransferBuffer::transfer_data_to_sink(TickType_t ticks_to_wait)
139
146
  }
140
147
 
141
148
  this->decrease_buffer_length(bytes_written);
149
+ }
142
150
 
151
+ if (post_shift) {
143
152
  // Shift unwritten data to the start of the buffer
144
153
  memmove(this->buffer_, this->data_start_, this->buffer_length_);
145
154
  this->data_start_ = this->buffer_;
146
155
  }
156
+
147
157
  return bytes_written;
148
158
  }
149
159
 
@@ -60,6 +60,7 @@ class AudioTransferBuffer {
60
60
 
61
61
  protected:
62
62
  /// @brief Allocates the transfer buffer in external memory, if available.
63
+ /// @param buffer_size The number of bytes to allocate
63
64
  /// @return True is successful, false otherwise.
64
65
  bool allocate_buffer_(size_t buffer_size);
65
66
 
@@ -89,8 +90,10 @@ class AudioSinkTransferBuffer : public AudioTransferBuffer {
89
90
 
90
91
  /// @brief Writes any available data in the transfer buffer to the sink.
91
92
  /// @param ticks_to_wait FreeRTOS ticks to block while waiting for the sink to have enough space
93
+ /// @param post_shift If true, all remaining data is moved to the start of the buffer after transferring to the sink.
94
+ /// Defaults to true.
92
95
  /// @return Number of bytes written
93
- size_t transfer_data_to_sink(TickType_t ticks_to_wait);
96
+ size_t transfer_data_to_sink(TickType_t ticks_to_wait, bool post_shift = true);
94
97
 
95
98
  /// @brief Adds a ring buffer as the transfer buffer's sink.
96
99
  /// @param ring_buffer weak_ptr to the allocated ring buffer
@@ -125,8 +128,10 @@ class AudioSourceTransferBuffer : public AudioTransferBuffer {
125
128
 
126
129
  /// @brief Reads any available data from the sink into the transfer buffer.
127
130
  /// @param ticks_to_wait FreeRTOS ticks to block while waiting for the source to have enough data
131
+ /// @param pre_shift If true, any unwritten data is moved to the start of the buffer before transferring from the
132
+ /// source. Defaults to true.
128
133
  /// @return Number of bytes read
129
- size_t transfer_data_from_source(TickType_t ticks_to_wait);
134
+ size_t transfer_data_from_source(TickType_t ticks_to_wait, bool pre_shift = true);
130
135
 
131
136
  /// @brief Adds a ring buffer as the transfer buffer's source.
132
137
  /// @param ring_buffer weak_ptr to the allocated ring buffer
@@ -146,6 +146,13 @@ def check_missing_glyphs(file, codepoints, warning: bool = False):
146
146
  raise cv.Invalid(message)
147
147
 
148
148
 
149
+ def pt_to_px(pt):
150
+ """
151
+ Convert a point size to pixels, rounding up to the nearest pixel
152
+ """
153
+ return (pt + 63) // 64
154
+
155
+
149
156
  def validate_font_config(config):
150
157
  """
151
158
  Check for duplicate codepoints, then check that all requested codepoints actually
@@ -172,42 +179,43 @@ def validate_font_config(config):
172
179
  )
173
180
  # Make setpoints and glyphspoints disjoint
174
181
  setpoints.difference_update(glyphspoints)
175
- if fileconf[CONF_TYPE] == TYPE_LOCAL_BITMAP:
176
- if any(x >= 256 for x in setpoints.copy().union(glyphspoints)):
177
- raise cv.Invalid("Codepoints in bitmap fonts must be in the range 0-255")
178
- else:
179
- # for TT fonts, check that glyphs are actually present
180
- # Check extras against their own font, exclude from parent font codepoints
181
- for extra in config[CONF_EXTRAS]:
182
- points = {ord(x) for x in flatten(extra[CONF_GLYPHS])}
183
- glyphspoints.difference_update(points)
184
- setpoints.difference_update(points)
185
- check_missing_glyphs(extra[CONF_FILE], points)
186
-
187
- # A named glyph that can't be provided is an error
188
-
189
- check_missing_glyphs(fileconf, glyphspoints)
190
- # A missing glyph from a set is a warning.
191
- if not config[CONF_IGNORE_MISSING_GLYPHS]:
192
- check_missing_glyphs(fileconf, setpoints, warning=True)
182
+ # check that glyphs are actually present
183
+ # Check extras against their own font, exclude from parent font codepoints
184
+ for extra in config[CONF_EXTRAS]:
185
+ points = {ord(x) for x in flatten(extra[CONF_GLYPHS])}
186
+ glyphspoints.difference_update(points)
187
+ setpoints.difference_update(points)
188
+ check_missing_glyphs(extra[CONF_FILE], points)
189
+
190
+ # A named glyph that can't be provided is an error
191
+
192
+ check_missing_glyphs(fileconf, glyphspoints)
193
+ # A missing glyph from a set is a warning.
194
+ if not config[CONF_IGNORE_MISSING_GLYPHS]:
195
+ check_missing_glyphs(fileconf, setpoints, warning=True)
193
196
 
194
197
  # Populate the default after the above checks so that use of the default doesn't trigger errors
198
+ font = FONT_CACHE[fileconf]
195
199
  if not config[CONF_GLYPHS] and not config[CONF_GLYPHSETS]:
196
- if fileconf[CONF_TYPE] == TYPE_LOCAL_BITMAP:
197
- config[CONF_GLYPHS] = [DEFAULT_GLYPHS]
198
- else:
199
- # set a default glyphset, intersected with what the font actually offers
200
- font = FONT_CACHE[fileconf]
201
- config[CONF_GLYPHS] = [
202
- chr(x)
203
- for x in glyphsets.unicodes_per_glyphset(DEFAULT_GLYPHSET)
204
- if font.get_char_index(x) != 0
205
- ]
206
-
207
- if config[CONF_FILE][CONF_TYPE] == TYPE_LOCAL_BITMAP:
208
- if CONF_SIZE in config:
200
+ # set a default glyphset, intersected with what the font actually offers
201
+ config[CONF_GLYPHS] = [
202
+ chr(x)
203
+ for x in glyphsets.unicodes_per_glyphset(DEFAULT_GLYPHSET)
204
+ if font.get_char_index(x) != 0
205
+ ]
206
+
207
+ if font.has_fixed_sizes:
208
+ sizes = [pt_to_px(x.size) for x in font.available_sizes]
209
+ if not sizes:
210
+ raise cv.Invalid(
211
+ f"Font {FontCache.get_name(fileconf)} has no available sizes"
212
+ )
213
+ if CONF_SIZE not in config:
214
+ config[CONF_SIZE] = sizes[0]
215
+ elif config[CONF_SIZE] not in sizes:
216
+ sizes = ", ".join(str(x) for x in sizes)
209
217
  raise cv.Invalid(
210
- "Size is not a valid option for bitmap fonts, which are inherently fixed size"
218
+ f"Font {FontCache.get_name(fileconf)} only has size{'s' if len(sizes) != 1 else ''} {sizes} available"
211
219
  )
212
220
  elif CONF_SIZE not in config:
213
221
  config[CONF_SIZE] = 20
@@ -215,14 +223,7 @@ def validate_font_config(config):
215
223
  return config
216
224
 
217
225
 
218
- FONT_EXTENSIONS = (".ttf", ".woff", ".otf")
219
- BITMAP_EXTENSIONS = (".bdf", ".pcf")
220
-
221
-
222
- def validate_bitmap_file(value):
223
- if not any(map(value.lower().endswith, BITMAP_EXTENSIONS)):
224
- raise cv.Invalid(f"Only {', '.join(BITMAP_EXTENSIONS)} files are supported.")
225
- return CORE.relative_config_path(cv.file_(value))
226
+ FONT_EXTENSIONS = (".ttf", ".woff", ".otf", "bdf", ".pcf")
226
227
 
227
228
 
228
229
  def validate_truetype_file(value):
@@ -246,7 +247,6 @@ def add_local_file(value):
246
247
 
247
248
 
248
249
  TYPE_LOCAL = "local"
249
- TYPE_LOCAL_BITMAP = "local_bitmap"
250
250
  TYPE_GFONTS = "gfonts"
251
251
  TYPE_WEB = "web"
252
252
  LOCAL_SCHEMA = cv.All(
@@ -258,15 +258,6 @@ LOCAL_SCHEMA = cv.All(
258
258
  add_local_file,
259
259
  )
260
260
 
261
- LOCAL_BITMAP_SCHEMA = cv.All(
262
- cv.Schema(
263
- {
264
- cv.Required(CONF_PATH): validate_bitmap_file,
265
- }
266
- ),
267
- add_local_file,
268
- )
269
-
270
261
  FULLPATH_SCHEMA = cv.maybe_simple_value(
271
262
  {cv.Required(CONF_PATH): cv.string}, key=CONF_PATH
272
263
  )
@@ -403,15 +394,6 @@ def validate_file_shorthand(value):
403
394
  }
404
395
  )
405
396
 
406
- extension = Path(value).suffix
407
- if extension in BITMAP_EXTENSIONS:
408
- return font_file_schema(
409
- {
410
- CONF_TYPE: TYPE_LOCAL_BITMAP,
411
- CONF_PATH: value,
412
- }
413
- )
414
-
415
397
  return font_file_schema(
416
398
  {
417
399
  CONF_TYPE: TYPE_LOCAL,
@@ -424,7 +406,6 @@ TYPED_FILE_SCHEMA = cv.typed_schema(
424
406
  {
425
407
  TYPE_LOCAL: LOCAL_SCHEMA,
426
408
  TYPE_GFONTS: GFONTS_SCHEMA,
427
- TYPE_LOCAL_BITMAP: LOCAL_BITMAP_SCHEMA,
428
409
  TYPE_WEB: WEB_FONT_SCHEMA,
429
410
  }
430
411
  )
@@ -522,11 +503,13 @@ async def to_code(config):
522
503
  bpp = config[CONF_BPP]
523
504
  mode = ft_pixel_mode_grays
524
505
  scale = 256 // (1 << bpp)
506
+ size = config[CONF_SIZE]
525
507
  # create the data array for all glyphs
526
508
  for codepoint in codepoints:
527
509
  font = point_font_map[codepoint]
528
- if not font.has_fixed_sizes:
529
- font.set_pixel_sizes(config[CONF_SIZE], 0)
510
+ format = font.get_format().decode("utf-8")
511
+ if format != "PCF":
512
+ font.set_pixel_sizes(size, 0)
530
513
  font.load_char(codepoint)
531
514
  font.glyph.render(mode)
532
515
  width = font.glyph.bitmap.width
@@ -550,17 +533,17 @@ async def to_code(config):
550
533
  if pixel & (1 << (bpp - bit_num - 1)):
551
534
  glyph_data[pos // 8] |= 0x80 >> (pos % 8)
552
535
  pos += 1
553
- ascender = font.size.ascender // 64
536
+ ascender = pt_to_px(font.size.ascender)
554
537
  if ascender == 0:
555
538
  if font.has_fixed_sizes:
556
- ascender = font.available_sizes[0].height
539
+ ascender = size
557
540
  else:
558
541
  _LOGGER.error(
559
542
  "Unable to determine ascender of font %s", config[CONF_FILE]
560
543
  )
561
544
  glyph_args[codepoint] = GlyphInfo(
562
545
  len(data),
563
- font.glyph.metrics.horiAdvance // 64,
546
+ pt_to_px(font.glyph.metrics.horiAdvance),
564
547
  font.glyph.bitmap_left,
565
548
  ascender - font.glyph.bitmap_top,
566
549
  width,
@@ -599,11 +582,11 @@ async def to_code(config):
599
582
 
600
583
  glyphs = cg.static_const_array(config[CONF_RAW_GLYPH_ID], glyph_initializer)
601
584
 
602
- font_height = base_font.size.height // 64
603
- ascender = base_font.size.ascender // 64
585
+ font_height = pt_to_px(base_font.size.height)
586
+ ascender = pt_to_px(base_font.size.ascender)
604
587
  if font_height == 0:
605
588
  if base_font.has_fixed_sizes:
606
- font_height = base_font.available_sizes[0].height
589
+ font_height = size
607
590
  ascender = font_height
608
591
  else:
609
592
  _LOGGER.error("Unable to determine height of font %s", config[CONF_FILE])
@@ -132,6 +132,10 @@ void Graph::draw(Display *buff, uint16_t x_offset, uint16_t y_offset, Color colo
132
132
  yrange = ymax - ymin;
133
133
  }
134
134
 
135
+ // Store graph limts
136
+ this->graph_limit_max_ = ymax;
137
+ this->graph_limit_min_ = ymin;
138
+
135
139
  /// Draw grid
136
140
  if (!std::isnan(this->gridspacing_y_)) {
137
141
  for (int y = yn; y <= ym; y++) {
@@ -161,11 +161,15 @@ class Graph : public Component {
161
161
  uint32_t get_duration() { return duration_; }
162
162
  uint32_t get_width() { return width_; }
163
163
  uint32_t get_height() { return height_; }
164
+ float get_graph_limit_min() { return graph_limit_min_; }
165
+ float get_graph_limit_max() { return graph_limit_max_; }
164
166
 
165
167
  protected:
166
168
  uint32_t duration_; /// in seconds
167
169
  uint32_t width_; /// in pixels
168
170
  uint32_t height_; /// in pixels
171
+ float graph_limit_min_{NAN};
172
+ float graph_limit_max_{NAN};
169
173
  float min_value_{NAN};
170
174
  float max_value_{NAN};
171
175
  float min_range_{1.0};
@@ -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.5.1",
94
+ ref="mdns-v1.8.0",
95
95
  path="components/mdns",
96
96
  )
97
97
 
@@ -177,11 +177,15 @@ void SourceSpeaker::set_mute_state(bool mute_state) {
177
177
  this->parent_->get_output_speaker()->set_mute_state(mute_state);
178
178
  }
179
179
 
180
+ bool SourceSpeaker::get_mute_state() { return this->parent_->get_output_speaker()->get_mute_state(); }
181
+
180
182
  void SourceSpeaker::set_volume(float volume) {
181
183
  this->volume_ = volume;
182
184
  this->parent_->get_output_speaker()->set_volume(volume);
183
185
  }
184
186
 
187
+ float SourceSpeaker::get_volume() { return this->parent_->get_output_speaker()->get_volume(); }
188
+
185
189
  size_t SourceSpeaker::process_data_from_source(TickType_t ticks_to_wait) {
186
190
  if (!this->transfer_buffer_.use_count()) {
187
191
  return 0;
@@ -490,7 +494,8 @@ void MixerSpeaker::audio_mixer_task(void *params) {
490
494
  break;
491
495
  }
492
496
 
493
- output_transfer_buffer->transfer_data_to_sink(pdMS_TO_TICKS(TASK_DELAY_MS));
497
+ // Never shift the data in the output transfer buffer to avoid unnecessary, slow data moves
498
+ output_transfer_buffer->transfer_data_to_sink(pdMS_TO_TICKS(TASK_DELAY_MS), false);
494
499
 
495
500
  const uint32_t output_frames_free =
496
501
  this_mixer->audio_stream_info_.value().bytes_to_frames(output_transfer_buffer->free());
@@ -53,9 +53,11 @@ class SourceSpeaker : public speaker::Speaker, public Component {
53
53
 
54
54
  /// @brief Mute state changes are passed to the parent's output speaker
55
55
  void set_mute_state(bool mute_state) override;
56
+ bool get_mute_state() override;
56
57
 
57
58
  /// @brief Volume state changes are passed to the parent's output speaker
58
59
  void set_volume(float volume) override;
60
+ float get_volume() override;
59
61
 
60
62
  void set_pause_state(bool pause_state) override { this->pause_state_ = pause_state; }
61
63
  bool get_pause_state() const override { return this->pause_state_; }
@@ -34,9 +34,11 @@ class ResamplerSpeaker : public Component, public speaker::Speaker {
34
34
 
35
35
  /// @brief Mute state changes are passed to the parent's output speaker
36
36
  void set_mute_state(bool mute_state) override;
37
+ bool get_mute_state() override { return this->output_speaker_->get_mute_state(); }
37
38
 
38
39
  /// @brief Volume state changes are passed to the parent's output speaker
39
40
  void set_volume(float volume) override;
41
+ float get_volume() override { return this->output_speaker_->get_volume(); }
40
42
 
41
43
  void set_output_speaker(speaker::Speaker *speaker) { this->output_speaker_ = speaker; }
42
44
  void set_task_stack_in_psram(bool task_stack_in_psram) { this->task_stack_in_psram_ = task_stack_in_psram; }
@@ -76,7 +76,7 @@ class Speaker {
76
76
  }
77
77
  #endif
78
78
  };
79
- float get_volume() { return this->volume_; }
79
+ virtual float get_volume() { return this->volume_; }
80
80
 
81
81
  virtual void set_mute_state(bool mute_state) {
82
82
  this->mute_state_ = mute_state;
@@ -90,7 +90,7 @@ class Speaker {
90
90
  }
91
91
  #endif
92
92
  }
93
- bool get_mute_state() { return this->mute_state_; }
93
+ virtual bool get_mute_state() { return this->mute_state_; }
94
94
 
95
95
  #ifdef USE_AUDIO_DAC
96
96
  void set_audio_dac(audio_dac::AudioDac *audio_dac) { this->audio_dac_ = audio_dac; }
esphome/const.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Constants used by esphome."""
2
2
 
3
- __version__ = "2025.3.0b1"
3
+ __version__ = "2025.3.0b3"
4
4
 
5
5
  ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
6
6
  VALID_SUBSTITUTIONS_CHARACTERS = (
esphome/core/helpers.h CHANGED
@@ -719,6 +719,25 @@ template<class T> class RAMAllocator {
719
719
  return ptr;
720
720
  }
721
721
 
722
+ T *reallocate(T *p, size_t n) { return this->reallocate(p, n, sizeof(T)); }
723
+
724
+ T *reallocate(T *p, size_t n, size_t manual_size) {
725
+ size_t size = n * sizeof(T);
726
+ T *ptr = nullptr;
727
+ #ifdef USE_ESP32
728
+ if (this->flags_ & Flags::ALLOC_EXTERNAL) {
729
+ ptr = static_cast<T *>(heap_caps_realloc(p, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
730
+ }
731
+ if (ptr == nullptr && this->flags_ & Flags::ALLOC_INTERNAL) {
732
+ ptr = static_cast<T *>(heap_caps_realloc(p, size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
733
+ }
734
+ #else
735
+ // Ignore ALLOC_EXTERNAL/ALLOC_INTERNAL flags if external allocation is not supported
736
+ ptr = static_cast<T *>(realloc(p, size)); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
737
+ #endif
738
+ return ptr;
739
+ }
740
+
722
741
  void deallocate(T *p, size_t n) {
723
742
  free(p); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
724
743
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: esphome
3
- Version: 2025.3.0b1
3
+ Version: 2025.3.0b3
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
@@ -23,13 +23,13 @@ Classifier: Topic :: Home Automation
23
23
  Requires-Python: >=3.9.0
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
- Requires-Dist: cryptography ==43.0.0
26
+ Requires-Dist: cryptography ==44.0.2
27
27
  Requires-Dist: voluptuous ==0.14.2
28
28
  Requires-Dist: PyYAML ==6.0.2
29
29
  Requires-Dist: paho-mqtt ==1.6.1
30
30
  Requires-Dist: colorama ==0.4.6
31
31
  Requires-Dist: icmplib ==3.0.4
32
- Requires-Dist: tornado ==6.4
32
+ Requires-Dist: tornado ==6.4.2
33
33
  Requires-Dist: tzlocal ==5.2
34
34
  Requires-Dist: tzdata >=2021.1
35
35
  Requires-Dist: pyserial ==3.5
@@ -37,7 +37,7 @@ Requires-Dist: platformio ==6.1.16
37
37
  Requires-Dist: esptool ==4.8.1
38
38
  Requires-Dist: click ==8.1.7
39
39
  Requires-Dist: esphome-dashboard ==20250212.0
40
- Requires-Dist: aioesphomeapi ==29.5.1
40
+ Requires-Dist: aioesphomeapi ==29.6.0
41
41
  Requires-Dist: zeroconf ==0.146.1
42
42
  Requires-Dist: puremagic ==1.27
43
43
  Requires-Dist: ruamel.yaml ==0.18.6
@@ -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=eMy1kilz--IvtICGjV7izKUPI4NMIfTvYUDFTYp-qqw,40764
8
+ esphome/const.py,sha256=gRnH5u1m9aFv6gSK3arX-BBWulzgNpPYP88e5YWZkRo,40764
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
@@ -187,8 +187,8 @@ esphome/components/api/api_connection.h,sha256=32R1sK8nuRgfFY4Epu8mP92D6xYxkaa1J
187
187
  esphome/components/api/api_frame_helper.cpp,sha256=KspV-UWWUkMXk23gNzsZt-hedf1Kld3L-1zUT6VVgbo,33019
188
188
  esphome/components/api/api_frame_helper.h,sha256=bn6Q2TvN6fulMFGUSm7fsxwlURlQAjl8EmMSPAj5uls,5543
189
189
  esphome/components/api/api_noise_context.h,sha256=0i3J3wchJitnQBTJeQm1380t0duhsz7WxJDrlUBF8mE,405
190
- esphome/components/api/api_pb2.cpp,sha256=NBLsmsH33diCiYBtY11ouSTHNoEqoznqbFJBRFoj3CE,246138
191
- esphome/components/api/api_pb2.h,sha256=yCBbWaT5LRrCMy1vQdxg-sjuSgabKPKIM8mdXD6idZo,70583
190
+ esphome/components/api/api_pb2.cpp,sha256=8o0AeBOfenhR6wwRgRcqZ1pa0Mfnxk8Ur24_b9_K-b4,246814
191
+ esphome/components/api/api_pb2.h,sha256=U1XsowoK_R0loAeomzaKzOL54Ap7L-s839GFc6QidS0,70724
192
192
  esphome/components/api/api_pb2_service.cpp,sha256=xYIanFE-N_3LRJgp-1_5Ey88_BMlYZao1QjztZEaNPo,53963
193
193
  esphome/components/api/api_pb2_service.h,sha256=XgdMInOdOxFQZ0X7EDt8rQWX9Z0TSS2LDWsga5vNckg,22581
194
194
  esphome/components/api/api_server.cpp,sha256=bg8zJLznGBt-Io1IbaODwK1veeM3dXBRb_oQwvbhhhc,11311
@@ -250,17 +250,17 @@ esphome/components/atm90e32/sensor.py,sha256=w_EO5YH8pD_eswo7hKN0R_CGBrpxiIURMyG
250
250
  esphome/components/atm90e32/button/__init__.py,sha256=JeiwKgbG4jAu00wKXTc9IE4-fyb5cUqfKKygasxqI7w,1434
251
251
  esphome/components/atm90e32/button/atm90e32_button.cpp,sha256=uAKV5NiBBR6T1-scHJtFwW4gVIlZulyncLR2xluKAT8,551
252
252
  esphome/components/atm90e32/button/atm90e32_button.h,sha256=aEzRVASEwVsIDCLQyLbRjRwDtfOVEb0vLdnV1DnmSYM,634
253
- esphome/components/audio/__init__.py,sha256=WhQlK3Era94-XeMCwjLEtljU0yTqb_edjN3Gi6l-jrc,3729
253
+ esphome/components/audio/__init__.py,sha256=2vSC3U8ZhLG3lgN3MCJcIrnsRj7n0Bf6GAee95LHhCE,3729
254
254
  esphome/components/audio/audio.cpp,sha256=McWhPhfL41LchHiFqS_96W_cmL5zgs4KrDN3u5WZTQU,2212
255
255
  esphome/components/audio/audio.h,sha256=8h4vtUxwHz89T9AUSHuUv_ajDrqSJDw57Hqt5G-fbw4,6180
256
- esphome/components/audio/audio_decoder.cpp,sha256=pkMkPjfn6QyV8-p7CPyH8XQ3PaI5suJ_NAn6Kgt_FGQ,13280
256
+ esphome/components/audio/audio_decoder.cpp,sha256=OEfJYRCCT3bFDHrETdjIzpf2SYa92bBPINcGMP_49EI,14922
257
257
  esphome/components/audio/audio_decoder.h,sha256=hpPJjrHsK_N2crCVvsrlu7zivx4oQHQz5hr-mlW6fl0,5351
258
- esphome/components/audio/audio_reader.cpp,sha256=qVQBosYU5EL1UgcK4XqZTg7u8_T-C3Ue7zOa_G52YEM,8783
258
+ esphome/components/audio/audio_reader.cpp,sha256=c8bk2EdfNh3TTafGKyWOvEEbrzMFpo7H8uP1P4ia4Kk,8837
259
259
  esphome/components/audio/audio_reader.h,sha256=1FwkJAunr3OOy2DGOmlKHfD3cwOrmBVPQvDj7Z0DTuk,3188
260
- esphome/components/audio/audio_resampler.cpp,sha256=AOhua5Rdh-bCHTweeQglmE1Me5CXfH5hadv3CbUusik,6712
260
+ esphome/components/audio/audio_resampler.cpp,sha256=7Ygx683D8nMLCgAzv4aphUAxGZabjRhLYwJzlj3fWZU,6896
261
261
  esphome/components/audio/audio_resampler.h,sha256=0tJRuN39XDl1148jGytNVt_U8blkwSlCdiCIVqba8H0,4288
262
- esphome/components/audio/audio_transfer_buffer.cpp,sha256=FZoB0Nqeo8msNNT0Eh5ojhqFOkOY_RYalszji3PacvA,4612
263
- esphome/components/audio/audio_transfer_buffer.h,sha256=UktdKhGVmQOumU_IPG2eAccKF5wAoRHTwE_8_ywOmeo,5308
262
+ esphome/components/audio/audio_transfer_buffer.cpp,sha256=ECdf825_lf5VAte-C_-rpL_PcQH5H2jghD7pge19eb4,4890
263
+ esphome/components/audio/audio_transfer_buffer.h,sha256=Bbo4SX8G9YNiGEX69UW0hHoVGKNLS6WibUMZqfGhsHU,5739
264
264
  esphome/components/audio_adc/__init__.py,sha256=OZiwnU7-mCWxrjIFsp4HsKdUTvtwo4lxoGS3cylL9_E,1195
265
265
  esphome/components/audio_adc/audio_adc.h,sha256=BpdWqyewyVX48IN2J3BEeZ5EB9Yhu0pKsa8VCjxx8r8,284
266
266
  esphome/components/audio_adc/automation.h,sha256=oJ6yN2M4B-z3Up--H0oUKrP8HROEe8aqOtOCGMj00Yg,537
@@ -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=sa2miIdrA8C2brb4mBkgJfxh4ECUqJEotFzEM6ISGQE,19549
955
+ esphome/components/font/__init__.py,sha256=r7IpPuAOAJuPyz9tvnb_q9T9QTLuH2-ti-D3iDGOG9A,18893
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
@@ -1014,8 +1014,8 @@ esphome/components/gps/time/__init__.py,sha256=iuZWg8qhi8uMoah4B2z4OyAsXndE9z6oH
1014
1014
  esphome/components/gps/time/gps_time.cpp,sha256=XEslYAhMq8ZViWF0QfoO95JiISUj0TLeuRcU4CnJq_8,958
1015
1015
  esphome/components/gps/time/gps_time.h,sha256=LTbCT36s68Sjifw0Qv6yxo5aiv2NK6Zreh1Rmtkxsqk,624
1016
1016
  esphome/components/graph/__init__.py,sha256=cxfJJTEGoaQ_3EAo5_cWUvLWAUjeoNyI4mqoxwkm_cc,7819
1017
- esphome/components/graph/graph.cpp,sha256=1pwQFl5M0L4eJJhlL5x1uAsVNBOHnTXvvKd695WHhos,12241
1018
- esphome/components/graph/graph.h,sha256=hEOwQKaakerdidM9Gw6gibKu0zmdZZ1MCa1qXGga6xo,6021
1017
+ esphome/components/graph/graph.cpp,sha256=khFAaKpn7t67RtQFtbp-5GnjxGcTHHQS19hYjj4yJVc,12331
1018
+ esphome/components/graph/graph.h,sha256=_QYsue2vhTKTLdKW39b_JVcPMwzhlyx5201fIuYJMrw,6201
1019
1019
  esphome/components/graphical_display_menu/__init__.py,sha256=YGbv_JsuWmW3HumvMZq0EwJszFmaXGbNYrrl9OPhNEc,3557
1020
1020
  esphome/components/graphical_display_menu/graphical_display_menu.cpp,sha256=_1xbdf6a_krZS-xD8D4kRW32QPz68zWs-MrXLOYYThU,9146
1021
1021
  esphome/components/graphical_display_menu/graphical_display_menu.h,sha256=wxHyShfCIFDgvppSatvxAYPSnGNjYF9uuh-sloI53MI,2957
@@ -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=2ZqUJplTxMPO6svlrtBNrnMUF0KWd0lVEwJfNkQlsPI,2909
1703
+ esphome/components/mdns/__init__.py,sha256=W8e7xs4Zl1eRRdvMthYrmHXPUCmbaqTg_vfB7QAG8xw,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
@@ -1770,8 +1770,8 @@ esphome/components/mitsubishi/mitsubishi.h,sha256=DDSRb5mYr2RsocbBTQahdGJaHtH-k6
1770
1770
  esphome/components/mixer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1771
1771
  esphome/components/mixer/speaker/__init__.py,sha256=DhnzGW-FbnvPZujuaVusNPA2VmsqQoqMp9IHYeL8zfs,5701
1772
1772
  esphome/components/mixer/speaker/automation.h,sha256=cqmoTEvMNipbgyD50kxumgyk95R8C3OuO5jdxFJDL1c,503
1773
- esphome/components/mixer/speaker/mixer_speaker.cpp,sha256=4zdUCQwLsLaA0ix6Wh0aenXtCPzchI9TEaUVyvfuU_I,25841
1774
- esphome/components/mixer/speaker/mixer_speaker.h,sha256=-oequjCoO4s_ZSGouE8xE9XlP4IKWSAW4gWOa5XkuDc,10016
1773
+ esphome/components/mixer/speaker/mixer_speaker.cpp,sha256=IiyFORg63uESGT2_tDZ5bFSIXSTlpuFSbrneBrqTFew,26145
1774
+ esphome/components/mixer/speaker/mixer_speaker.h,sha256=mbu6UBIRpLlVDffJRf0OJvzmjgKKukPG45y18rTw4Xs,10081
1775
1775
  esphome/components/mlx90393/__init__.py,sha256=Ao5t2TsBxYT6KIJJ4Nnbg5_drJijuBxe7SIdBe31Fjs,34
1776
1776
  esphome/components/mlx90393/sensor.py,sha256=s_Xjx1xzZC28YZaPwxzn2Z0VJr_ioMfZxRrS_QtrHw0,4966
1777
1777
  esphome/components/mlx90393/sensor_mlx90393.cpp,sha256=2rhoxM7wx2pE_cYvjEzNJ0FYoFYpnYUSGWuaNnXRqhQ,2846
@@ -2355,7 +2355,7 @@ esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp,sha256=qU
2355
2355
  esphome/components/resampler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2356
2356
  esphome/components/resampler/speaker/__init__.py,sha256=qOJ7qHILE_zRH6ttxPg8eF318k8DZPTvnraz3RhBme4,3250
2357
2357
  esphome/components/resampler/speaker/resampler_speaker.cpp,sha256=3eZWLASOLQmQkXYqj5XPtdBkyAlaQdiHRzq-_7Bxgi0,11187
2358
- esphome/components/resampler/speaker/resampler_speaker.h,sha256=CE0ktVw_8BkChNKaYrwXC_wp0djRUv8NO4jsTXdqJlU,3533
2358
+ esphome/components/resampler/speaker/resampler_speaker.h,sha256=a1BFzJNc01-ke1Re9o6JoeYBEwlCFf43SrPrqsqq-HU,3696
2359
2359
  esphome/components/resistance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2360
2360
  esphome/components/resistance/resistance_sensor.cpp,sha256=rIrw4eeVqvWbNPawY6AukH2VAFxT0X_JYaAIPy9FB_w,1179
2361
2361
  esphome/components/resistance/resistance_sensor.h,sha256=lOuc0sTlOs2fuw0CVOPCv5DHR5DrSeQDTjZU4sykeNA,1117
@@ -2685,7 +2685,7 @@ esphome/components/sonoff_d1/sonoff_d1.cpp,sha256=9xT42oxeLJ5CGrZ7wqIH5KVTkwW3XY
2685
2685
  esphome/components/sonoff_d1/sonoff_d1.h,sha256=FNHcaqGktpV3S19A1LD2wtpRpEqA0h6g9GFb36pMy_E,3457
2686
2686
  esphome/components/speaker/__init__.py,sha256=2juDem8QadLMwzFp8Rvl-KeIbE-iIEsCtDa9vyZcQVA,4373
2687
2687
  esphome/components/speaker/automation.h,sha256=tVSTV49GvHk0bCEgLz3rNYFe8B1F0kXLgE-WihuRaV8,2320
2688
- esphome/components/speaker/speaker.h,sha256=8jV7BbOiNYc-GsuVU97YNnzKxnoERvRABx9Ma2oAS8Q,4696
2688
+ esphome/components/speaker/speaker.h,sha256=WHAQzuNxkaUxCfPySHUONoun0Uudw917KVlnI71_Mjo,4712
2689
2689
  esphome/components/speaker/media_player/__init__.py,sha256=-bV3Fps2AGFUEW8C35py8ATO6bZhrWDGzW2YLM7kpnc,15436
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
@@ -3438,7 +3438,7 @@ esphome/core/entity_helpers.py,sha256=s5lYCG5hu_1SROtSWgzI0T6802l5-I8udGy1_6HNSd
3438
3438
  esphome/core/gpio.h,sha256=kLkCnPxu4_1CsLR4BI_Baj1lDGoRIh8uubbwsIkJPIA,2575
3439
3439
  esphome/core/hal.h,sha256=e3qFkax3jfncEusf3kwXCts0Ai7D4XspJgh-VqVDcK4,844
3440
3440
  esphome/core/helpers.cpp,sha256=ao-3IMSjDWjdSxZw-oLVMhV2A-ltlKquFbGzzohaHB4,25024
3441
- esphome/core/helpers.h,sha256=QQ5VGztPT4H3t5-GIpiV1ROJOWZEJsmhTWrWYZviltE,29533
3441
+ esphome/core/helpers.h,sha256=Glb9nMEmRl9rQElEy8sXkqNmUdwHdnGA4raehWkB8wI,30298
3442
3442
  esphome/core/log.cpp,sha256=MDCx87ytW6Fz6basxYUpagkubFzUKO1ysvU5RXbXoII,1581
3443
3443
  esphome/core/log.h,sha256=hnRVgv7LjfmCpFAFa5Trt_HmmChAm64j8a9c_N3GQXw,6493
3444
3444
  esphome/core/macros.h,sha256=YRip3XYzXw2pg3AFpBFA0Js-Y5GMtPkuCp2km2g5uhc,196
@@ -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.0b1.dist-info/LICENSE,sha256=HzEjkBInJe44L4WvAOPfhPJJDNj6YbnqFyvGWRzArGM,36664
3478
- esphome-2025.3.0b1.dist-info/METADATA,sha256=Ka3_OI2peFksolJTjPwBMknAjZNpfF6ujG1Uwfj4zr8,3689
3479
- esphome-2025.3.0b1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
3480
- esphome-2025.3.0b1.dist-info/entry_points.txt,sha256=mIxVNuWtbYzeEcaWCl-AQ-97aBOWbnYBAK8nbF6P4M0,50
3481
- esphome-2025.3.0b1.dist-info/top_level.txt,sha256=0GSXEW3cnITpgG3qnsSMz0qoqJHAFyfw7Y8MVtEf1Yk,8
3482
- esphome-2025.3.0b1.dist-info/RECORD,,
3477
+ esphome-2025.3.0b3.dist-info/LICENSE,sha256=HzEjkBInJe44L4WvAOPfhPJJDNj6YbnqFyvGWRzArGM,36664
3478
+ esphome-2025.3.0b3.dist-info/METADATA,sha256=EpO47tRzjK6pyJGru626GK2LUW_a_Zd9ybDSWxX3xV0,3691
3479
+ esphome-2025.3.0b3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
3480
+ esphome-2025.3.0b3.dist-info/entry_points.txt,sha256=mIxVNuWtbYzeEcaWCl-AQ-97aBOWbnYBAK8nbF6P4M0,50
3481
+ esphome-2025.3.0b3.dist-info/top_level.txt,sha256=0GSXEW3cnITpgG3qnsSMz0qoqJHAFyfw7Y8MVtEf1Yk,8
3482
+ esphome-2025.3.0b3.dist-info/RECORD,,