Skip to content

Commit f3cf107

Browse files
committed
feat(logging): Add collapsible output stages and ASCII progress bars
1 parent 0beee77 commit f3cf107

12 files changed

+361
-210
lines changed

docs/en/esptool/configuration-file.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ Complete list of configurable options:
9797
+------------------------------+-----------------------------------------------------------+----------+
9898
| erase_write_timeout_per_mb | Timeout (per megabyte) for erasing and writing data | 40 s |
9999
+------------------------------+-----------------------------------------------------------+----------+
100-
| mem_end_rom_timeout | Short timeout for ESP_MEM_END | 0.2 s |
100+
| mem_end_rom_timeout | Short timeout for MEM_END | 0.2 s |
101101
+------------------------------+-----------------------------------------------------------+----------+
102102
| serial_write_timeout | Timeout for serial port write | 10 s |
103103
+------------------------------+-----------------------------------------------------------+----------+

docs/en/esptool/scripting.rst

+19-11
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ Esptool allows redirecting output by implementing a custom logger class. This ca
295295
log_to_file = True
296296
log_file = "esptool.log"
297297
298-
def print(self, message, *args, **kwargs):
298+
def print(self, message="", *args, **kwargs):
299299
# Print to console
300300
print(f"[CustomLogger]: {message}", *args, **kwargs)
301301
# Optionally log to a file
@@ -312,14 +312,22 @@ Esptool allows redirecting output by implementing a custom logger class. This ca
312312
def error(self, message):
313313
self.print(message, file=sys.stderr)
314314
315-
def print_overwrite(self, message, last_line=False):
316-
# Overwriting not needed, print normally
317-
self.print(message)
318-
319-
def set_progress(self, percentage):
320-
# Progress updates not needed, pass
315+
def stage(self, finish=False):
316+
# Collapsible stages not needed in this example
321317
pass
322318
319+
def progress_bar(
320+
self,
321+
cur_iter,
322+
total_iters,
323+
prefix = "",
324+
suffix = "",
325+
bar_length: int = 30,
326+
):
327+
# Progress bars replaced with simple percentage output in this example
328+
percent = f"{100 * (cur_iter / float(total_iters)):.1f}"
329+
self.print(f"Finished: {percent}%")
330+
323331
# Replace the default logger with the custom logger
324332
log.set_logger(CustomLogger())
325333
@@ -334,11 +342,11 @@ To ensure compatibility with esptool, the custom logger should re-implement (or
334342
- ``note``: Logs informational messages.
335343
- ``warning``: Logs warning messages.
336344
- ``error``: Logs error messages.
337-
- ``print_overwrite``: Handles message overwriting (can be a simple ``print()`` if overwriting is not needed).
338-
- ``set_progress``: Handles percentage updates of long-running operations - ``write-flash``, ``read-flash``, and ``dump-mem`` (useful for GUI visualisation, e.g. as a progress bar).
345+
- ``stage``: Starts or ends a collapsible output stage.
346+
- ``progress_bar``: Displays a progress bar.
339347

340348
.. autoclass:: esptool.logger.EsptoolLogger
341-
:members: print, note, warning, error, print_overwrite, set_progress
349+
:members: print, note, warning, error, stage, progress_bar
342350
:member-order: bysource
343351

344-
These methods are essential for maintaining proper integration and behavior with esptool. Additionally, all calls to the logger should be made using ``log.print()`` (or the respective method, such as ``log.info()`` or ``log.warning()``) instead of the standard ``print()`` function to ensure the output is routed through the custom logger. This ensures consistency and allows the custom logger to handle all output appropriately. You can further customize this logger to fit your application's needs, such as integrating with GUI components or advanced logging frameworks.
352+
These methods are essential for maintaining proper integration and behavior with esptool. Additionally, all output printing should be made using ``log.print()`` (or the respective method, such as ``log.info()`` or ``log.warning()``) instead of the standard ``print()`` function to ensure the output is routed through the custom logger. This ensures consistency and allows the custom logger to handle all output appropriately. You can further customize this logger to fit your application's needs, such as integrating with GUI components or advanced logging frameworks.

esptool/__init__.py

+17-5
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ def check_flash_size(esp: ESPLoader, address: int, size: int) -> None:
278278
cls=Group,
279279
no_args_is_help=True,
280280
context_settings=dict(help_option_names=["-h", "--help"], max_content_width=120),
281-
help=f"esptool.py v{__version__} - Espressif chips ROM Bootloader Utility",
281+
help=f"esptool.py v{__version__} - Espressif SoCs flashing, debugging, "
282+
"and provisioning utility",
282283
)
283284
@click.option(
284285
"--chip",
@@ -376,6 +377,12 @@ def prepare_esp_object(ctx):
376377
# 1) Get the ESP object
377378
#######################
378379

380+
# Disable output stage collapsing, colors, and overwriting in trace mode
381+
if ctx.obj["trace"]:
382+
log._smart_features = False
383+
384+
log.stage()
385+
379386
if ctx.obj["before"] != "no_reset_no_sync":
380387
initial_baud = min(
381388
ESPLoader.ESP_ROM_BAUD, ctx.obj["baud"]
@@ -430,19 +437,23 @@ def prepare_esp_object(ctx):
430437
f"on any of the {len(ser_list)} available serial ports."
431438
)
432439

440+
log.stage(finish=True)
441+
log.print(f"Connected to {esp.CHIP_NAME} on {esp._port.port}:")
442+
433443
# 2) Print the chip info
434444
########################
435445

436446
if esp.secure_download_mode:
437447
log.print(f"Chip is {esp.CHIP_NAME} in Secure Download Mode")
438448
else:
439-
log.print(f"Chip is {esp.get_chip_description()}")
440-
log.print(f"Features: {', '.join(esp.get_chip_features())}")
441-
log.print(f"Crystal is {esp.get_crystal_freq()}MHz")
449+
log.print(f"{'Chip type:':<20}{esp.get_chip_description()}")
450+
log.print(f"{'Features:':<20}{', '.join(esp.get_chip_features())}")
451+
log.print(f"{'Crystal frequency:':<20}{esp.get_crystal_freq()}MHz")
442452
usb_mode = esp.get_usb_mode()
443453
if usb_mode is not None:
444-
log.print(f"USB mode: {usb_mode}")
454+
log.print(f"{'USB mode:':<20}{usb_mode}")
445455
read_mac(esp)
456+
log.print()
446457

447458
# 3) Upload the stub flasher
448459
############################
@@ -488,6 +499,7 @@ def teardown():
488499

489500
# 8) Reset the chip
490501
###################
502+
log.print()
491503
# Handle post-operation behaviour (reset or other)
492504
if ctx.obj["invoked_subcommand"] == "load-ram":
493505
# the ESP is now running the loaded image, so let it run

0 commit comments

Comments
 (0)