esphome 2025.3.0b2__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.
@@ -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};
esphome/const.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Constants used by esphome."""
2
2
 
3
- __version__ = "2025.3.0b2"
3
+ __version__ = "2025.3.0b3"
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.0b2
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
@@ -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=IgFxQSkYp7H9q4bhgy1oMHYF1LX43GgQEw1e6VauJvU,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
@@ -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
@@ -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.0b2.dist-info/LICENSE,sha256=HzEjkBInJe44L4WvAOPfhPJJDNj6YbnqFyvGWRzArGM,36664
3478
- esphome-2025.3.0b2.dist-info/METADATA,sha256=2m1NmojG95uxTvK4EXhFEqgLMKlObZkyQRPAJLL10H8,3691
3479
- esphome-2025.3.0b2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
3480
- esphome-2025.3.0b2.dist-info/entry_points.txt,sha256=mIxVNuWtbYzeEcaWCl-AQ-97aBOWbnYBAK8nbF6P4M0,50
3481
- esphome-2025.3.0b2.dist-info/top_level.txt,sha256=0GSXEW3cnITpgG3qnsSMz0qoqJHAFyfw7Y8MVtEf1Yk,8
3482
- esphome-2025.3.0b2.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,,