esphome 2025.9.0b1__py3-none-any.whl → 2025.9.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.
Files changed (48) hide show
  1. esphome/__main__.py +146 -68
  2. esphome/components/adc/__init__.py +1 -26
  3. esphome/components/adc/sensor.py +20 -0
  4. esphome/components/ade7880/ade7880.cpp +1 -1
  5. esphome/components/api/api_connection.cpp +4 -11
  6. esphome/components/api/api_connection.h +0 -1
  7. esphome/components/api/api_pb2.cpp +0 -8
  8. esphome/components/api/api_pb2.h +0 -4
  9. esphome/components/api/api_pb2_dump.cpp +1 -7
  10. esphome/components/api/api_pb2_service.cpp +0 -14
  11. esphome/components/api/api_pb2_service.h +1 -3
  12. esphome/components/api/client.py +5 -3
  13. esphome/components/bluetooth_proxy/bluetooth_proxy.h +3 -1
  14. esphome/components/captive_portal/captive_index.h +77 -97
  15. esphome/components/esp32_ble/ble_uuid.cpp +30 -9
  16. esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp +4 -3
  17. esphome/components/esp32_ble_client/ble_client_base.h +8 -5
  18. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +2 -3
  19. esphome/components/ethernet/__init__.py +11 -0
  20. esphome/components/ethernet/ethernet_component.cpp +52 -2
  21. esphome/components/ethernet/ethernet_component.h +4 -0
  22. esphome/components/factory_reset/button/factory_reset_button.cpp +18 -1
  23. esphome/components/factory_reset/button/factory_reset_button.h +6 -1
  24. esphome/components/factory_reset/switch/factory_reset_switch.cpp +18 -1
  25. esphome/components/factory_reset/switch/factory_reset_switch.h +5 -1
  26. esphome/components/ina2xx_base/__init__.py +4 -2
  27. esphome/components/md5/md5.cpp +3 -2
  28. esphome/components/mqtt/mqtt_client.cpp +1 -1
  29. esphome/components/openthread/openthread.cpp +41 -7
  30. esphome/components/openthread/openthread.h +11 -0
  31. esphome/components/select/select.cpp +3 -3
  32. esphome/components/select/select_call.cpp +1 -1
  33. esphome/components/web_server/server_index_v2.h +149 -149
  34. esphome/components/wifi/wifi_component.cpp +1 -1
  35. esphome/components/wifi_info/wifi_info_text_sensor.h +3 -2
  36. esphome/const.py +2 -1
  37. esphome/core/defines.h +1 -0
  38. esphome/core/helpers.cpp +8 -7
  39. esphome/core/helpers.h +29 -0
  40. esphome/core/scheduler.cpp +4 -4
  41. esphome/core/scheduler.h +1 -1
  42. esphome/dashboard/web_server.py +2 -5
  43. {esphome-2025.9.0b1.dist-info → esphome-2025.9.0b3.dist-info}/METADATA +2 -2
  44. {esphome-2025.9.0b1.dist-info → esphome-2025.9.0b3.dist-info}/RECORD +48 -48
  45. {esphome-2025.9.0b1.dist-info → esphome-2025.9.0b3.dist-info}/WHEEL +0 -0
  46. {esphome-2025.9.0b1.dist-info → esphome-2025.9.0b3.dist-info}/entry_points.txt +0 -0
  47. {esphome-2025.9.0b1.dist-info → esphome-2025.9.0b3.dist-info}/licenses/LICENSE +0 -0
  48. {esphome-2025.9.0b1.dist-info → esphome-2025.9.0b3.dist-info}/top_level.txt +0 -0
esphome/__main__.py CHANGED
@@ -15,9 +15,11 @@ import argcomplete
15
15
 
16
16
  from esphome import const, writer, yaml_util
17
17
  import esphome.codegen as cg
18
+ from esphome.components.mqtt import CONF_DISCOVER_IP
18
19
  from esphome.config import iter_component_configs, read_config, strip_default_ids
19
20
  from esphome.const import (
20
21
  ALLOWED_NAME_CHARS,
22
+ CONF_API,
21
23
  CONF_BAUD_RATE,
22
24
  CONF_BROKER,
23
25
  CONF_DEASSERT_RTS_DTR,
@@ -43,6 +45,7 @@ from esphome.const import (
43
45
  SECRETS_FILES,
44
46
  )
45
47
  from esphome.core import CORE, EsphomeError, coroutine
48
+ from esphome.enum import StrEnum
46
49
  from esphome.helpers import get_bool_env, indent, is_ip_address
47
50
  from esphome.log import AnsiFore, color, setup_log
48
51
  from esphome.types import ConfigType
@@ -106,13 +109,15 @@ def choose_prompt(options, purpose: str = None):
106
109
  return options[opt - 1][1]
107
110
 
108
111
 
112
+ class Purpose(StrEnum):
113
+ UPLOADING = "uploading"
114
+ LOGGING = "logging"
115
+
116
+
109
117
  def choose_upload_log_host(
110
118
  default: list[str] | str | None,
111
119
  check_default: str | None,
112
- show_ota: bool,
113
- show_mqtt: bool,
114
- show_api: bool,
115
- purpose: str | None = None,
120
+ purpose: Purpose,
116
121
  ) -> list[str]:
117
122
  # Convert to list for uniform handling
118
123
  defaults = [default] if isinstance(default, str) else default or []
@@ -132,13 +137,30 @@ def choose_upload_log_host(
132
137
  ]
133
138
  resolved.append(choose_prompt(options, purpose=purpose))
134
139
  elif device == "OTA":
135
- if CORE.address and (
136
- (show_ota and "ota" in CORE.config)
137
- or (show_api and "api" in CORE.config)
140
+ # ensure IP adresses are used first
141
+ if is_ip_address(CORE.address) and (
142
+ (purpose == Purpose.LOGGING and has_api())
143
+ or (purpose == Purpose.UPLOADING and has_ota())
138
144
  ):
139
145
  resolved.append(CORE.address)
140
- elif show_mqtt and has_mqtt_logging():
141
- resolved.append("MQTT")
146
+
147
+ if purpose == Purpose.LOGGING:
148
+ if has_api() and has_mqtt_ip_lookup():
149
+ resolved.append("MQTTIP")
150
+
151
+ if has_mqtt_logging():
152
+ resolved.append("MQTT")
153
+
154
+ if has_api() and has_non_ip_address():
155
+ resolved.append(CORE.address)
156
+
157
+ elif purpose == Purpose.UPLOADING:
158
+ if has_ota() and has_mqtt_ip_lookup():
159
+ resolved.append("MQTTIP")
160
+
161
+ if has_ota() and has_non_ip_address():
162
+ resolved.append(CORE.address)
163
+
142
164
  else:
143
165
  resolved.append(device)
144
166
  if not resolved:
@@ -149,39 +171,111 @@ def choose_upload_log_host(
149
171
  options = [
150
172
  (f"{port.path} ({port.description})", port.path) for port in get_serial_ports()
151
173
  ]
152
- if (show_ota and "ota" in CORE.config) or (show_api and "api" in CORE.config):
153
- options.append((f"Over The Air ({CORE.address})", CORE.address))
154
- if show_mqtt and has_mqtt_logging():
155
- mqtt_config = CORE.config[CONF_MQTT]
156
- options.append((f"MQTT ({mqtt_config[CONF_BROKER]})", "MQTT"))
174
+
175
+ if purpose == Purpose.LOGGING:
176
+ if has_mqtt_logging():
177
+ mqtt_config = CORE.config[CONF_MQTT]
178
+ options.append((f"MQTT ({mqtt_config[CONF_BROKER]})", "MQTT"))
179
+
180
+ if has_api():
181
+ if has_resolvable_address():
182
+ options.append((f"Over The Air ({CORE.address})", CORE.address))
183
+ if has_mqtt_ip_lookup():
184
+ options.append(("Over The Air (MQTT IP lookup)", "MQTTIP"))
185
+
186
+ elif purpose == Purpose.UPLOADING and has_ota():
187
+ if has_resolvable_address():
188
+ options.append((f"Over The Air ({CORE.address})", CORE.address))
189
+ if has_mqtt_ip_lookup():
190
+ options.append(("Over The Air (MQTT IP lookup)", "MQTTIP"))
157
191
 
158
192
  if check_default is not None and check_default in [opt[1] for opt in options]:
159
193
  return [check_default]
160
194
  return [choose_prompt(options, purpose=purpose)]
161
195
 
162
196
 
163
- def mqtt_logging_enabled(mqtt_config):
197
+ def has_mqtt_logging() -> bool:
198
+ """Check if MQTT logging is available."""
199
+ if CONF_MQTT not in CORE.config:
200
+ return False
201
+
202
+ mqtt_config = CORE.config[CONF_MQTT]
203
+
204
+ # enabled by default
205
+ if CONF_LOG_TOPIC not in mqtt_config:
206
+ return True
207
+
164
208
  log_topic = mqtt_config[CONF_LOG_TOPIC]
165
209
  if log_topic is None:
166
210
  return False
211
+
167
212
  if CONF_TOPIC not in log_topic:
168
213
  return False
169
- return log_topic.get(CONF_LEVEL, None) != "NONE"
170
214
 
215
+ return log_topic[CONF_LEVEL] != "NONE"
216
+
217
+
218
+ def has_mqtt() -> bool:
219
+ """Check if MQTT is available."""
220
+ return CONF_MQTT in CORE.config
221
+
222
+
223
+ def has_api() -> bool:
224
+ """Check if API is available."""
225
+ return CONF_API in CORE.config
226
+
227
+
228
+ def has_ota() -> bool:
229
+ """Check if OTA is available."""
230
+ return CONF_OTA in CORE.config
171
231
 
172
- def has_mqtt_logging() -> bool:
173
- """Check if MQTT logging is available."""
174
- return (mqtt_config := CORE.config.get(CONF_MQTT)) and mqtt_logging_enabled(
175
- mqtt_config
176
- )
232
+
233
+ def has_mqtt_ip_lookup() -> bool:
234
+ """Check if MQTT is available and IP lookup is supported."""
235
+ if CONF_MQTT not in CORE.config:
236
+ return False
237
+ # Default Enabled
238
+ if CONF_DISCOVER_IP not in CORE.config[CONF_MQTT]:
239
+ return True
240
+ return CORE.config[CONF_MQTT][CONF_DISCOVER_IP]
241
+
242
+
243
+ def has_mdns() -> bool:
244
+ """Check if MDNS is available."""
245
+ return CONF_MDNS not in CORE.config or not CORE.config[CONF_MDNS][CONF_DISABLED]
246
+
247
+
248
+ def has_non_ip_address() -> bool:
249
+ """Check if CORE.address is set and is not an IP address."""
250
+ return CORE.address is not None and not is_ip_address(CORE.address)
251
+
252
+
253
+ def has_ip_address() -> bool:
254
+ """Check if CORE.address is a valid IP address."""
255
+ return CORE.address is not None and is_ip_address(CORE.address)
256
+
257
+
258
+ def has_resolvable_address() -> bool:
259
+ """Check if CORE.address is resolvable (via mDNS or is an IP address)."""
260
+ return has_mdns() or has_ip_address()
261
+
262
+
263
+ def mqtt_get_ip(config: ConfigType, username: str, password: str, client_id: str):
264
+ from esphome import mqtt
265
+
266
+ return mqtt.get_esphome_device_ip(config, username, password, client_id)
267
+
268
+
269
+ _PORT_TO_PORT_TYPE = {
270
+ "MQTT": "MQTT",
271
+ "MQTTIP": "MQTTIP",
272
+ }
177
273
 
178
274
 
179
275
  def get_port_type(port: str) -> str:
180
276
  if port.startswith("/") or port.startswith("COM"):
181
277
  return "SERIAL"
182
- if port == "MQTT":
183
- return "MQTT"
184
- return "NETWORK"
278
+ return _PORT_TO_PORT_TYPE.get(port, "NETWORK")
185
279
 
186
280
 
187
281
  def run_miniterm(config: ConfigType, port: str, args) -> int:
@@ -226,7 +320,9 @@ def run_miniterm(config: ConfigType, port: str, args) -> int:
226
320
  .replace(b"\n", b"")
227
321
  .decode("utf8", "backslashreplace")
228
322
  )
229
- time_str = datetime.now().time().strftime("[%H:%M:%S]")
323
+ time_ = datetime.now()
324
+ nanoseconds = time_.microsecond // 1000
325
+ time_str = f"[{time_.hour:02}:{time_.minute:02}:{time_.second:02}.{nanoseconds:03}]"
230
326
  safe_print(parser.parse_line(line, time_str))
231
327
 
232
328
  backtrace_state = platformio_api.process_stacktrace(
@@ -437,23 +533,9 @@ def upload_program(
437
533
  password = ota_conf.get(CONF_PASSWORD, "")
438
534
  binary = args.file if getattr(args, "file", None) is not None else CORE.firmware_bin
439
535
 
440
- # Check if we should use MQTT for address resolution
441
- # This happens when no device was specified, or the current host is "MQTT"/"OTA"
442
- if (
443
- CONF_MQTT in config # pylint: disable=too-many-boolean-expressions
444
- and (not devices or host in ("MQTT", "OTA"))
445
- and (
446
- ((config[CONF_MDNS][CONF_DISABLED]) and not is_ip_address(CORE.address))
447
- or get_port_type(host) == "MQTT"
448
- )
449
- ):
450
- from esphome import mqtt
451
-
452
- devices = [
453
- mqtt.get_esphome_device_ip(
454
- config, args.username, args.password, args.client_id
455
- )
456
- ]
536
+ # MQTT address resolution
537
+ if get_port_type(host) in ("MQTT", "MQTTIP"):
538
+ devices = mqtt_get_ip(config, args.username, args.password, args.client_id)
457
539
 
458
540
  return espota2.run_ota(devices, remote_port, password, binary)
459
541
 
@@ -474,20 +556,28 @@ def show_logs(config: ConfigType, args: ArgsProtocol, devices: list[str]) -> int
474
556
  if get_port_type(port) == "SERIAL":
475
557
  check_permissions(port)
476
558
  return run_miniterm(config, port, args)
477
- if get_port_type(port) == "NETWORK" and "api" in config:
478
- addresses_to_use = devices
479
- if config[CONF_MDNS][CONF_DISABLED] and CONF_MQTT in config:
480
- from esphome import mqtt
481
559
 
482
- mqtt_address = mqtt.get_esphome_device_ip(
560
+ port_type = get_port_type(port)
561
+
562
+ # Check if we should use API for logging
563
+ if has_api():
564
+ addresses_to_use: list[str] | None = None
565
+
566
+ if port_type == "NETWORK" and (has_mdns() or is_ip_address(port)):
567
+ addresses_to_use = devices
568
+ elif port_type in ("NETWORK", "MQTT", "MQTTIP") and has_mqtt_ip_lookup():
569
+ # Only use MQTT IP lookup if the first condition didn't match
570
+ # (for MQTT/MQTTIP types, or for NETWORK when mdns/ip check fails)
571
+ addresses_to_use = mqtt_get_ip(
483
572
  config, args.username, args.password, args.client_id
484
- )[0]
485
- addresses_to_use = [mqtt_address]
573
+ )
574
+
575
+ if addresses_to_use is not None:
576
+ from esphome.components.api.client import run_logs
486
577
 
487
- from esphome.components.api.client import run_logs
578
+ return run_logs(config, addresses_to_use)
488
579
 
489
- return run_logs(config, addresses_to_use)
490
- if get_port_type(port) in ("NETWORK", "MQTT") and "mqtt" in config:
580
+ if port_type in ("NETWORK", "MQTT") and has_mqtt_logging():
491
581
  from esphome import mqtt
492
582
 
493
583
  return mqtt.show_logs(
@@ -553,10 +643,7 @@ def command_upload(args: ArgsProtocol, config: ConfigType) -> int | None:
553
643
  devices = choose_upload_log_host(
554
644
  default=args.device,
555
645
  check_default=None,
556
- show_ota=True,
557
- show_mqtt=False,
558
- show_api=False,
559
- purpose="uploading",
646
+ purpose=Purpose.UPLOADING,
560
647
  )
561
648
 
562
649
  exit_code, _ = upload_program(config, args, devices)
@@ -581,10 +668,7 @@ def command_logs(args: ArgsProtocol, config: ConfigType) -> int | None:
581
668
  devices = choose_upload_log_host(
582
669
  default=args.device,
583
670
  check_default=None,
584
- show_ota=False,
585
- show_mqtt=True,
586
- show_api=True,
587
- purpose="logging",
671
+ purpose=Purpose.LOGGING,
588
672
  )
589
673
  return show_logs(config, args, devices)
590
674
 
@@ -610,10 +694,7 @@ def command_run(args: ArgsProtocol, config: ConfigType) -> int | None:
610
694
  devices = choose_upload_log_host(
611
695
  default=args.device,
612
696
  check_default=None,
613
- show_ota=True,
614
- show_mqtt=False,
615
- show_api=True,
616
- purpose="uploading",
697
+ purpose=Purpose.UPLOADING,
617
698
  )
618
699
 
619
700
  exit_code, successful_device = upload_program(config, args, devices)
@@ -630,10 +711,7 @@ def command_run(args: ArgsProtocol, config: ConfigType) -> int | None:
630
711
  devices = choose_upload_log_host(
631
712
  default=successful_device,
632
713
  check_default=successful_device,
633
- show_ota=False,
634
- show_mqtt=True,
635
- show_api=True,
636
- purpose="logging",
714
+ purpose=Purpose.LOGGING,
637
715
  )
638
716
  return show_logs(config, args, devices)
639
717
 
@@ -11,15 +11,8 @@ from esphome.components.esp32.const import (
11
11
  VARIANT_ESP32S2,
12
12
  VARIANT_ESP32S3,
13
13
  )
14
- from esphome.config_helpers import filter_source_files_from_platform
15
14
  import esphome.config_validation as cv
16
- from esphome.const import (
17
- CONF_ANALOG,
18
- CONF_INPUT,
19
- CONF_NUMBER,
20
- PLATFORM_ESP8266,
21
- PlatformFramework,
22
- )
15
+ from esphome.const import CONF_ANALOG, CONF_INPUT, CONF_NUMBER, PLATFORM_ESP8266
23
16
  from esphome.core import CORE
24
17
 
25
18
  CODEOWNERS = ["@esphome/core"]
@@ -273,21 +266,3 @@ def validate_adc_pin(value):
273
266
  )(value)
274
267
 
275
268
  raise NotImplementedError
276
-
277
-
278
- FILTER_SOURCE_FILES = filter_source_files_from_platform(
279
- {
280
- "adc_sensor_esp32.cpp": {
281
- PlatformFramework.ESP32_ARDUINO,
282
- PlatformFramework.ESP32_IDF,
283
- },
284
- "adc_sensor_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
285
- "adc_sensor_rp2040.cpp": {PlatformFramework.RP2040_ARDUINO},
286
- "adc_sensor_libretiny.cpp": {
287
- PlatformFramework.BK72XX_ARDUINO,
288
- PlatformFramework.RTL87XX_ARDUINO,
289
- PlatformFramework.LN882X_ARDUINO,
290
- },
291
- "adc_sensor_zephyr.cpp": {PlatformFramework.NRF52_ZEPHYR},
292
- }
293
- )
@@ -9,6 +9,7 @@ from esphome.components.zephyr import (
9
9
  zephyr_add_prj_conf,
10
10
  zephyr_add_user,
11
11
  )
12
+ from esphome.config_helpers import filter_source_files_from_platform
12
13
  import esphome.config_validation as cv
13
14
  from esphome.const import (
14
15
  CONF_ATTENUATION,
@@ -20,6 +21,7 @@ from esphome.const import (
20
21
  PLATFORM_NRF52,
21
22
  STATE_CLASS_MEASUREMENT,
22
23
  UNIT_VOLT,
24
+ PlatformFramework,
23
25
  )
24
26
  from esphome.core import CORE
25
27
 
@@ -174,3 +176,21 @@ async def to_code(config):
174
176
  }};
175
177
  """
176
178
  )
179
+
180
+
181
+ FILTER_SOURCE_FILES = filter_source_files_from_platform(
182
+ {
183
+ "adc_sensor_esp32.cpp": {
184
+ PlatformFramework.ESP32_ARDUINO,
185
+ PlatformFramework.ESP32_IDF,
186
+ },
187
+ "adc_sensor_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
188
+ "adc_sensor_rp2040.cpp": {PlatformFramework.RP2040_ARDUINO},
189
+ "adc_sensor_libretiny.cpp": {
190
+ PlatformFramework.BK72XX_ARDUINO,
191
+ PlatformFramework.RTL87XX_ARDUINO,
192
+ PlatformFramework.LN882X_ARDUINO,
193
+ },
194
+ "adc_sensor_zephyr.cpp": {PlatformFramework.NRF52_ZEPHYR},
195
+ }
196
+ )
@@ -113,7 +113,7 @@ void ADE7880::update() {
113
113
  if (this->channel_a_ != nullptr) {
114
114
  auto *chan = this->channel_a_;
115
115
  this->update_sensor_from_s24zp_register16_(chan->current, AIRMS, [](float val) { return val / 100000.0f; });
116
- this->update_sensor_from_s24zp_register16_(chan->voltage, BVRMS, [](float val) { return val / 10000.0f; });
116
+ this->update_sensor_from_s24zp_register16_(chan->voltage, AVRMS, [](float val) { return val / 10000.0f; });
117
117
  this->update_sensor_from_s24zp_register16_(chan->active_power, AWATT, [](float val) { return val / 100.0f; });
118
118
  this->update_sensor_from_s24zp_register16_(chan->apparent_power, AVA, [](float val) { return val / 100.0f; });
119
119
  this->update_sensor_from_s16_register16_(chan->power_factor, APF,
@@ -42,6 +42,8 @@ static constexpr uint8_t MAX_PING_RETRIES = 60;
42
42
  static constexpr uint16_t PING_RETRY_INTERVAL = 1000;
43
43
  static constexpr uint32_t KEEPALIVE_DISCONNECT_TIMEOUT = (KEEPALIVE_TIMEOUT_MS * 5) / 2;
44
44
 
45
+ static constexpr auto ESPHOME_VERSION_REF = StringRef::from_lit(ESPHOME_VERSION);
46
+
45
47
  static const char *const TAG = "api.connection";
46
48
  #ifdef USE_CAMERA
47
49
  static const int CAMERA_STOP_STREAM = 5000;
@@ -1081,12 +1083,6 @@ void APIConnection::on_get_time_response(const GetTimeResponse &value) {
1081
1083
  }
1082
1084
  #endif
1083
1085
 
1084
- bool APIConnection::send_get_time_response(const GetTimeRequest &msg) {
1085
- GetTimeResponse resp;
1086
- resp.epoch_seconds = ::time(nullptr);
1087
- return this->send_message(resp, GetTimeResponse::MESSAGE_TYPE);
1088
- }
1089
-
1090
1086
  #ifdef USE_BLUETOOTH_PROXY
1091
1087
  void APIConnection::subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) {
1092
1088
  bluetooth_proxy::global_bluetooth_proxy->subscribe_api_connection(this, msg.flags);
@@ -1376,9 +1372,8 @@ bool APIConnection::send_hello_response(const HelloRequest &msg) {
1376
1372
  HelloResponse resp;
1377
1373
  resp.api_version_major = 1;
1378
1374
  resp.api_version_minor = 12;
1379
- // Temporary string for concatenation - will be valid during send_message call
1380
- std::string server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
1381
- resp.set_server_info(StringRef(server_info));
1375
+ // Send only the version string - the client only logs this for debugging and doesn't use it otherwise
1376
+ resp.set_server_info(ESPHOME_VERSION_REF);
1382
1377
  resp.set_name(StringRef(App.get_name()));
1383
1378
 
1384
1379
  #ifdef USE_API_PASSWORD
@@ -1425,8 +1420,6 @@ bool APIConnection::send_device_info_response(const DeviceInfoRequest &msg) {
1425
1420
  std::string mac_address = get_mac_address_pretty();
1426
1421
  resp.set_mac_address(StringRef(mac_address));
1427
1422
 
1428
- // Compile-time StringRef constants
1429
- static constexpr auto ESPHOME_VERSION_REF = StringRef::from_lit(ESPHOME_VERSION);
1430
1423
  resp.set_esphome_version(ESPHOME_VERSION_REF);
1431
1424
 
1432
1425
  resp.set_compilation_time(App.get_compilation_time_ref());
@@ -219,7 +219,6 @@ class APIConnection final : public APIServerConnection {
219
219
  #ifdef USE_API_HOMEASSISTANT_STATES
220
220
  void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) override;
221
221
  #endif
222
- bool send_get_time_response(const GetTimeRequest &msg) override;
223
222
  #ifdef USE_API_SERVICES
224
223
  void execute_service(const ExecuteServiceRequest &msg) override;
225
224
  #endif
@@ -921,14 +921,6 @@ bool GetTimeResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
921
921
  }
922
922
  return true;
923
923
  }
924
- void GetTimeResponse::encode(ProtoWriteBuffer buffer) const {
925
- buffer.encode_fixed32(1, this->epoch_seconds);
926
- buffer.encode_string(2, this->timezone_ref_);
927
- }
928
- void GetTimeResponse::calculate_size(ProtoSize &size) const {
929
- size.add_fixed32(1, this->epoch_seconds);
930
- size.add_length(1, this->timezone_ref_.size());
931
- }
932
924
  #ifdef USE_API_SERVICES
933
925
  void ListEntitiesServicesArgument::encode(ProtoWriteBuffer buffer) const {
934
926
  buffer.encode_string(1, this->name_ref_);
@@ -1180,10 +1180,6 @@ class GetTimeResponse final : public ProtoDecodableMessage {
1180
1180
  #endif
1181
1181
  uint32_t epoch_seconds{0};
1182
1182
  std::string timezone{};
1183
- StringRef timezone_ref_{};
1184
- void set_timezone(const StringRef &ref) { this->timezone_ref_ = ref; }
1185
- void encode(ProtoWriteBuffer buffer) const override;
1186
- void calculate_size(ProtoSize &size) const override;
1187
1183
  #ifdef HAS_PROTO_MESSAGE_DUMP
1188
1184
  void dump_to(std::string &out) const override;
1189
1185
  #endif
@@ -1113,13 +1113,7 @@ void GetTimeRequest::dump_to(std::string &out) const { out.append("GetTimeReques
1113
1113
  void GetTimeResponse::dump_to(std::string &out) const {
1114
1114
  MessageDumpHelper helper(out, "GetTimeResponse");
1115
1115
  dump_field(out, "epoch_seconds", this->epoch_seconds);
1116
- out.append(" timezone: ");
1117
- if (!this->timezone_ref_.empty()) {
1118
- out.append("'").append(this->timezone_ref_.c_str()).append("'");
1119
- } else {
1120
- out.append("'").append(this->timezone).append("'");
1121
- }
1122
- out.append("\n");
1116
+ dump_field(out, "timezone", this->timezone);
1123
1117
  }
1124
1118
  #ifdef USE_API_SERVICES
1125
1119
  void ListEntitiesServicesArgument::dump_to(std::string &out) const {
@@ -160,15 +160,6 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
160
160
  break;
161
161
  }
162
162
  #endif
163
- case GetTimeRequest::MESSAGE_TYPE: {
164
- GetTimeRequest msg;
165
- // Empty message: no decode needed
166
- #ifdef HAS_PROTO_MESSAGE_DUMP
167
- ESP_LOGVV(TAG, "on_get_time_request: %s", msg.dump().c_str());
168
- #endif
169
- this->on_get_time_request(msg);
170
- break;
171
- }
172
163
  case GetTimeResponse::MESSAGE_TYPE: {
173
164
  GetTimeResponse msg;
174
165
  msg.decode(msg_data, msg_size);
@@ -656,11 +647,6 @@ void APIServerConnection::on_subscribe_home_assistant_states_request(const Subsc
656
647
  }
657
648
  }
658
649
  #endif
659
- void APIServerConnection::on_get_time_request(const GetTimeRequest &msg) {
660
- if (this->check_connection_setup_() && !this->send_get_time_response(msg)) {
661
- this->on_fatal_error();
662
- }
663
- }
664
650
  #ifdef USE_API_SERVICES
665
651
  void APIServerConnection::on_execute_service_request(const ExecuteServiceRequest &msg) {
666
652
  if (this->check_authenticated_()) {
@@ -71,7 +71,7 @@ class APIServerConnectionBase : public ProtoService {
71
71
  #ifdef USE_API_HOMEASSISTANT_STATES
72
72
  virtual void on_home_assistant_state_response(const HomeAssistantStateResponse &value){};
73
73
  #endif
74
- virtual void on_get_time_request(const GetTimeRequest &value){};
74
+
75
75
  virtual void on_get_time_response(const GetTimeResponse &value){};
76
76
 
77
77
  #ifdef USE_API_SERVICES
@@ -226,7 +226,6 @@ class APIServerConnection : public APIServerConnectionBase {
226
226
  #ifdef USE_API_HOMEASSISTANT_STATES
227
227
  virtual void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) = 0;
228
228
  #endif
229
- virtual bool send_get_time_response(const GetTimeRequest &msg) = 0;
230
229
  #ifdef USE_API_SERVICES
231
230
  virtual void execute_service(const ExecuteServiceRequest &msg) = 0;
232
231
  #endif
@@ -348,7 +347,6 @@ class APIServerConnection : public APIServerConnectionBase {
348
347
  #ifdef USE_API_HOMEASSISTANT_STATES
349
348
  void on_subscribe_home_assistant_states_request(const SubscribeHomeAssistantStatesRequest &msg) override;
350
349
  #endif
351
- void on_get_time_request(const GetTimeRequest &msg) override;
352
350
  #ifdef USE_API_SERVICES
353
351
  void on_execute_service_request(const ExecuteServiceRequest &msg) override;
354
352
  #endif
@@ -62,9 +62,11 @@ async def async_run_logs(config: dict[str, Any], addresses: list[str]) -> None:
62
62
  time_ = datetime.now()
63
63
  message: bytes = msg.message
64
64
  text = message.decode("utf8", "backslashreplace")
65
- for parsed_msg in parse_log_message(
66
- text, f"[{time_.hour:02}:{time_.minute:02}:{time_.second:02}]"
67
- ):
65
+ nanoseconds = time_.microsecond // 1000
66
+ timestamp = (
67
+ f"[{time_.hour:02}:{time_.minute:02}:{time_.second:02}.{nanoseconds:03}]"
68
+ )
69
+ for parsed_msg in parse_log_message(text, timestamp):
68
70
  print(parsed_msg.replace("\033", "\\033") if dashboard else parsed_msg)
69
71
 
70
72
  stop = await async_run(cli, on_log, name=name)
@@ -130,7 +130,9 @@ class BluetoothProxy final : public esp32_ble_tracker::ESPBTDeviceListener, publ
130
130
 
131
131
  std::string get_bluetooth_mac_address_pretty() {
132
132
  const uint8_t *mac = esp_bt_dev_get_address();
133
- return str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
133
+ char buf[18];
134
+ format_mac_addr_upper(mac, buf);
135
+ return std::string(buf);
134
136
  }
135
137
 
136
138
  protected: