{"id":50063612,"url":"https://github.com/prodziekan-yt/esp-flasher-ui","last_synced_at":"2026-06-16T07:00:34.153Z","repository":{"id":359355109,"uuid":"1245715925","full_name":"prodziekan-yt/ESP-Flasher-UI","owner":"prodziekan-yt","description":"PyQt6 desktop GUI for flashing ESP32/8266 firmware via USB/Serial (serial-port discovery) or OTA (host detection via DNS + TCP probe on ports 6053/3232/8266, public-IP warning). Wraps esptool, espota and the full ESPHome workflow (config/compile/upload/run/logs/clean), console, tool checker, diagnostics, multilingual. ","archived":false,"fork":false,"pushed_at":"2026-05-21T20:38:23.000Z","size":227,"stargazers_count":2,"open_issues_count":6,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-21T22:09:19.690Z","etag":null,"topics":["esp32","esp8266","espflasher","esphome","espota","esptool","ui","wrapper"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/prodziekan-yt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-21T13:40:03.000Z","updated_at":"2026-05-21T20:38:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/prodziekan-yt/ESP-Flasher-UI","commit_stats":null,"previous_names":["prodziekan-yt/esp-flasher-ui"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/prodziekan-yt/ESP-Flasher-UI","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prodziekan-yt%2FESP-Flasher-UI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prodziekan-yt%2FESP-Flasher-UI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prodziekan-yt%2FESP-Flasher-UI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prodziekan-yt%2FESP-Flasher-UI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/prodziekan-yt","download_url":"https://codeload.github.com/prodziekan-yt/ESP-Flasher-UI/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prodziekan-yt%2FESP-Flasher-UI/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34393305,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["esp32","esp8266","espflasher","esphome","espota","esptool","ui","wrapper"],"created_at":"2026-05-21T21:00:54.503Z","updated_at":"2026-06-16T07:00:34.127Z","avatar_url":"https://github.com/prodziekan-yt.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u003cimg src=\"app/assets/esp-flasher-ui.svg\" alt=\"\" width=\"32\" height=\"32\" align=\"top\"\u003e ESP Flasher UI\n\nPyQt6 GUI for flashing ESP32 / ESP8266 modules via USB or OTA.\n\n\u003e **Easiest start:** grab the `full` AppImage from the [Releases page](../../releases). It bundles a relocatable CPython 3.12, PyQt6, `esphome`, `esptool` and `platformio` - self-contained, zero setup, no system Python required. Just `chmod +x` and run.\n\n\u003e **Architecture note:** under the hood ESP Flasher UI is a thin GUI wrapper - every flash / OTA / build / log action is delegated to `esptool`, `espota.py` or `esphome`. The `full` AppImage ships these CLIs. The `light` AppImage and source installs need them in `PATH` (e.g. `pip install -r requirements.txt` in a venv); without them the app starts but every action fails with \"tool not found\". Click **Diagnostic** after launch to verify - it prints both the environment snapshot and the tool checklist.\n\n\u003e **Target platform:** Linux (tested on Kubuntu 26.04).\n\n\u003e **Translations notice:** All language packs are machine-translated and may contain errors. Pull requests with corrections are welcome.\n\n---\n\n## Features\n\n- **Flash ESPHome tab** - full workflow: validate / compile / upload / run / logs / clean.\n- **Flash .BIN tab** - pick a raw firmware binary and push it to the device.\n- **Read flash tab** - USB-only flash dump to a local `.bin` (full backup, app-only or bootloader presets, custom offset + length, chip auto-detect).\n- **Erase flash tab** - rescue bricked modules with `esptool erase-flash` behind a confirmation checkbox that auto-unchecks after every click.\n- **Inspect .BIN tab** - offline parser for ESP firmware images: image + extended header, segment table with load addresses + resolved memory regions for ESP32 / S2 / S3 / C3 / C6 / H2 / P4, `esp_app_desc_t` metadata (project, version, build date, ESP-IDF, ELF SHA256), XOR checksum + appended SHA256 validation, strings-of-interest extractor (hostnames, URIs, IDF / ESPHome version markers). Switchable between **Plain** (text report) and **Interactive** (colour-coded hex dump; cursor resolves byte → region + segment + load address).\n- **Shared device selector** - USB/Serial or Network (OTA), used by all tabs.\n- **OTA detection** - DNS resolve + TCP probe on ESPHome ports (6053, 3232, 8266) with private/public IP classification.\n- **Known devices** - auto-discovers ESPHome manifests from `.esphome/storage/*.yaml.json`.\n- **Quick View/Edit side panel** - inline YAML viewer/editor docked to the right of the main window with syntax highlighting, an optional **Highlight spaces** toggle that overlays a `░` glyph on every space, find / find \u0026 replace, save / cancel; the window auto-resizes when the panel opens or closes.\n- **Bridge button** - forward a compiled `firmware.bin` from ESPHome tab to Flash .BIN tab.\n- **Console** - timestamped output, ANSI stripping, colour-coded log levels, `\u003e\u003e ` prefix on app-emitted lines so they stand out from raw `esptool` / `esphome` output, permission-denied hint for `/dev/tty*` access.\n- **Troubleshooting hints** - passive log scanner that flags ESPHome crashes (`Guru Meditation`, `task_wdt`, `abort()`), the \"took a long time for an operation\" warning, missing-ELF prompts when ESPHome cannot auto-decode a stack trace, and `VERY_VERBOSE` YAML pre-validation.\n- **Stack trace decoder** - modal dialog that resolves crash addresses via `addr2line` against a `firmware.elf` (auto-detects ESP32 / ESP8266 / RISC-V toolchains, ranks `firmware.elf` ahead of bootloader/partition ELFs).\n- **Reset ESP** - one-click hard reset of the connected USB device via DTR/RTS toggling (`esptool --no-stub chip-id`).\n- **Cancellable operations** - global **Stop** button cancels the running flash / compile / log / read / erase / reset subprocess without closing the window.\n- **Runtime language switcher** - language picker in the header re-translates the whole UI without restart.\n- **Diagnostic** - one-click environment dump (platform, cwd, serial ports, languages, current mode, firmware path, ESPHome project) plus the dependency checklist (Python, PyQt6, esptool, esphome, espota, pyserial, `dialout` group with stale-session detection).\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/screenshots/main-window.png\" alt=\"ESP Flasher UI main window - ESPHome tab with Quick View panel open, Highlight spaces enabled\" width=\"900\"\u003e\n\u003c/p\u003e\n\n---\n\n## Quick start\n\n### Option A: AppImage (no install required)\n\nGrab the latest AppImage from the [Releases page](../../releases). Each release ships with a relocatable CPython 3.12 interpreter embedded via [python-build-standalone](https://github.com/astral-sh/python-build-standalone), so no system Python is required - the AppImage runs on any modern Linux x86_64 distribution.\n\nTwo flavours are published:\n\n- `esp-flasher-ui-\u003cversion\u003e-light-x86_64.AppImage` - bundles CPython + PyQt6 + pyserial. Install `esphome` / `esptool` from your system pip; the GUI picks them up via `PATH`.\n- `esp-flasher-ui-\u003cversion\u003e-full-x86_64.AppImage` - bundles CPython + PyQt6 + pyserial + esphome + esptool + platformio. Fully self-contained: no system pip packages required.\n\n| Component | Light | Full | Source |\n|---|:---:|:---:|---|\n| CPython | `3.12.13` (pinned) | `3.12.13` (pinned) | `python-build-standalone` release `20260610` |\n| PyQt6 | `\u003e=6.11.0` | `\u003e=6.11.0` | pip |\n| pyserial | `\u003e=3.5` | `\u003e=3.5` | pip |\n| esptool | - (system `PATH`) | `\u003e=5.2.0` | pip |\n| esphome | - (system `PATH`) | `\u003e=2026.5.3` | pip |\n| platformio | - | bundled | transitive dependency of `esphome` |\n| `espota.py` | - (via `esphome`) | bundled | shim provided by the build script |\n| `addr2line` toolchains | system / user `~/.platformio` | user `~/.platformio` (populated on first compile) | not bundled - host-resolved at runtime |\n\n```bash\nchmod +x esp-flasher-ui-*-x86_64.AppImage\n./esp-flasher-ui-*-x86_64.AppImage\n```\n\nThe AppImage uses standard FUSE; on minimal systems pass `--appimage-extract-and-run` to bypass FUSE.\n\nEach release is smoke-tested in CI on Ubuntu 22.04 / 24.04 / 26.04 LTS, Debian 13 (Trixie), Fedora 43 and Arch Linux.\n\n### Option B: from source\n\n#### 1. System packages (Debian / Ubuntu)\n\n```bash\nsudo apt install -y python3 python3-venv python3-pip \\\n  libgl1 libegl1 libfontconfig1 \\\n  libxcb-cursor0 libxkbcommon-x11-0\n```\n\n#### 2. USB permissions\n\n```bash\nsudo usermod -aG dialout $USER\n# then LOG OUT and back in (full session restart required)\n```\n\n#### 3. Install\n\n```bash\ncd ESP-Flasher-UI\npython3 -m venv .venv\nsource .venv/bin/activate\npip install --upgrade pip\npip install -r requirements.txt\n```\n\n#### 4. Run\n\n```bash\nsource .venv/bin/activate\npython main.py\n```\n\nClick **Diagnostic** after launch - the bottom section lists every required tool with `[V]` or `[X]`.\n\n#### 5. Run tests (optional)\n\n```bash\nQT_QPA_PLATFORM=offscreen python build-tools/tests.py\n```\n\nHeadless offline test suite (441 checks) covering i18n integrity (37 packs, `_meta` consistency, placeholder consistency), workers, console classifier and `\u003e\u003e ` prefix, stack decoder with ELF prioritization, hint detection, Quick View/Edit panel, Read / Erase / Reset operations with their safety guards, the `.bin` parser (header / extended header / segments / `esp_app_desc_t` / checksum / SHA256 / region resolution) and the Inspect .BIN tab plain ↔ interactive toggle, and a GUI smoke test for every tab.\n\n---\n\n## Architecture\n\nESP Flasher UI is a thin wrapper - all flashing is delegated to external CLI tools:\n\n| UI action | Command | Tool |\n|-----------|---------|------|\n| Flash .BIN (USB) | `esptool --chip auto --port \u003cdev\u003e [--baud \u003crate\u003e] write-flash 0x0 \u003cfw.bin\u003e` | `esptool` |\n| Flash .BIN (OTA) | `espota.py -i \u003chost\u003e -f \u003cfw.bin\u003e [-a \u003cpassword\u003e]` | `esphome` (bundles `espota.py`) |\n| ESPHome workflow | `esphome {config\\|compile\\|upload\\|run\\|logs\\|clean} \u003cyaml\u003e [--device \u003cdev\u003e]` | `esphome` |\n| Read flash | `esptool --port \u003cdev\u003e [--baud \u003crate\u003e] read-flash \u003coffset\u003e \u003clength\\|ALL\u003e \u003cout.bin\u003e` | `esptool` |\n| Detect chip | `esptool --chip auto --port \u003cdev\u003e [--baud \u003crate\u003e] flash-id` | `esptool` |\n| Erase flash | `esptool --port \u003cdev\u003e [--baud \u003crate\u003e] erase-flash` | `esptool` |\n| Reset ESP | `esptool --port \u003cdev\u003e [--baud \u003crate\u003e] --no-stub chip-id` (DTR/RTS dance + hard reset on exit) | `esptool` |\n| OTA detection | DNS resolve + TCP probe on ports 6053 / 3232 / 8266 | - |\n| Inspect .BIN | offline parser - reads the file, walks `esp_image_header_t` + `esp_app_desc_t`, validates checksum + SHA256 | - (no external tool) |\n| Stack decoding | `\u003ctoolchain\u003e-addr2line -e firmware.elf -f -p -i -C \u003caddresses\u003e` | PlatformIO toolchain or system `addr2line` |\n\n---\n\n## Usage\n\n### USB/Serial flashing\n\n1. Plug in the ESP module, select **USB/Serial** mode.\n2. Pick the device from the dropdown (click **Refresh** if needed).\n3. Choose a baud rate. Defaults to `460800` (safe on all supported chips). Pick **Auto** to fall back to esptool's `115200` if a higher speed misbehaves on a bad cable / weak USB-UART bridge. Drop to `9600` or `57600` for long / noisy cables and flaky adapters.\n4. Choose a `.bin` file and click **Flash**.\n\nBaud rate guidance:\n\n| Speed | ESP8266 | ESP32 / S2 (external USB-UART) | ESP32-S3 / C3 / C6 (native USB-CDC) |\n|---|:---:|:---:|:---:|\n| 9600, 57600 (rescue) | V | V | V |\n| 115200, 230400, 460800 | V | V | V |\n| 921600 | usually V | V | V |\n| 1500000 | unreliable | works with quality bridge | V |\n| 2000000 | fail | sometimes | V |\n\n### OTA flashing\n\n1. Select **Network (OTA)** mode.\n2. Enter the device hostname or IP (e.g. `esp32.local` or `192.168.1.2`).\n3. Enter the OTA password (from `ota.password` in your ESPHome YAML).\n4. Optionally click **Detect device** to verify connectivity.\n5. Choose a `.bin` file and click **Flash**.\n\n### ESPHome workflow\n\n1. Set the **Project directory** (folder with your `.yaml` configs).\n2. Pick a **Known device** (auto-fills YAML path and OTA address) or browse for a YAML manually.\n3. Use the action buttons:\n\n| Action | Command | Needs device | Validate | Compile | Upload | Logs |\n|--------|---------|:---:|:---:|:---:|:---:|:---:|\n| **Validate** | `esphome config \u003cyaml\u003e` | no | V | - | - | - |\n| **Compile** | `esphome compile \u003cyaml\u003e` | no | V | V | - | - |\n| **Upload** | `esphome upload --device \u003cdev\u003e \u003cyaml\u003e` | yes | V | - | V | - |\n| **Run** | `esphome run --device \u003cdev\u003e \u003cyaml\u003e` | yes | V | V | V | V |\n| **Logs** | `esphome logs --device \u003cdev\u003e \u003cyaml\u003e` | yes | - | - | - | V |\n| **Clean** | `esphome clean \u003cyaml\u003e` | no | - | - | - | - |\n\n\u003e The last four columns show which sub-phases each action covers. `Validate` is run implicitly by `Compile`, `Upload` and `Run` (the YAML is always parsed before any build / flash). `Run` is the full pipeline: `Compile + Upload + Logs`, with validation included.\n\nAfter a successful compile, click **Send to Flash .BIN** to forward the built `firmware.bin` to the other tab. For the full pipeline in a single click, **Run** is the preferred path.\n\n### Quick View/Edit YAML\n\nA side panel docked to the right of the main window lets you view and edit the selected YAML without leaving the app.\n\n1. Select a project + YAML in the ESPHome tab (the **Quick View** button below **Browse** unlocks).\n2. Click **Quick View** - the window grows to make room for the panel and the YAML loads.\n3. Use **Find**, **Find \u0026 Replace**, **Save** or **Cancel** in the panel. Modifications mark the title with `*` and bring up a discard prompt when closing with unsaved changes.\n4. Click **Hide** (same button) to close - the window shrinks back to its previous width.\n\nYAML syntax (keys, strings, comments, booleans, numbers, anchors) is highlighted. The **Highlight spaces** checkbox at the bottom of the panel is off by default; when enabled it overlays a faint `░` glyph on every space so indentation is unambiguous - the underlying file is untouched, only the rendering changes.\n\n### Read flash (USB only)\n\nDump the device's SPI flash to a local `.bin` file.\n\n1. Open the **Read flash** tab and select a USB device.\n2. Pick a preset or set **Offset** and **Length** manually (accepts decimal or `0x...` hex). Leave **Length** empty for `ALL`.\n3. (Optional) Click **Detect chip** to verify chip + flash size before dumping.\n4. Click **Read flash** - progress streams in the console; the resulting `.bin` lands at the chosen path.\n\n| Preset | Offset | Length |\n|--------|-------:|-------:|\n| **Full backup** | `0x0` | `ALL` |\n| **Active app only** | `0x10000` | `0x200000` |\n| **Bootloader + partitions** | `0x0` | `0x10000` |\n\n### Erase flash (USB only - destructive)\n\nLast-resort rescue for bricked modules that no longer boot or accept new firmware.\n\n1. Open the **Erase flash** tab in USB mode.\n2. Read the warning - this wipes the entire SPI flash. Saved Wi-Fi credentials, calibration, NVS and user partitions are gone.\n3. Tick **I understand this will erase the flash...** - the red **Erase Flash** button activates.\n4. Click **Erase Flash**. The checkbox auto-unchecks immediately so a second device cannot be wiped by reflex.\n\nAfter erase, the device will not boot until you flash firmware again (use the Flash .BIN or Flash ESPHome tab).\n\n### Inspect .BIN (offline)\n\nDecode any ESP firmware image without a device attached. Accepts a freshly compiled `firmware.bin`, a Read-flash dump, bootloader / partition-table images, or any ESP-IDF / ESPHome app image.\n\n1. Open the **Inspect .BIN** tab.\n2. Click **Browse...**, pick a `.bin`, then **Parse**.\n3. Switch between view modes:\n   - **Plain** - text report: image header, segment table with resolved memory regions, `esp_app_desc_t` (project, version, build date, ESP-IDF, ELF SHA256), XOR checksum + appended SHA256 validation, deduplicated strings of interest.\n   - **Interactive** - colour-coded hex dump of the first 1 KB; each region (header / ext header / segment / `esp_app_desc_t` / SHA256 footer) gets its own tint. The detail strip resolves the byte under the cursor: file offset, byte value, region name, segment index + load address.\n\nThe parser tolerates corrupt / non-ESP input - bad files produce a best-effort report with warnings instead of a crash.\n\n### Reset ESP (USB only)\n\nThe **Reset ESP** button (left of **Diagnostics**, bottom action row) performs a hard reset of the connected USB device by toggling DTR/RTS through `esptool`. The chip enters bootloader mode briefly, then esptool releases RESET and the firmware boots normally.\n\n---\n\n## Languages\n\n37 language packs included. The language menu sorts Latin-script names first (diacritics-folded), then Greek, then Cyrillic.\n\n### Adding or fixing a language\n\n1. Copy `app/translations/en.json` to `app/translations/\u003ccode\u003e.json`.\n2. Set `_meta.code`, `_meta.name`, `_meta.native_name`.\n3. Translate the values (keep all keys and `{placeholder}` tokens intact).\n4. Restart the app - the new language appears automatically.\n\n---\n\n## Troubleshooting\n\n| Problem | Fix |\n|---------|-----|\n| `Permission denied: '/dev/ttyACM0'` | `sudo usermod -aG dialout $USER`, then **log out \u0026 back in** |\n| Diagnostic says \"IS in /etc/group but NOT in this process\" | Full session restart needed (not just a new terminal) |\n| `Could not load the Qt platform plugin \"xcb\"` | `sudo apt install libxcb-cursor0 libxkbcommon-x11-0` |\n| `ModuleNotFoundError: PyQt6` | Activate venv: `source .venv/bin/activate \u0026\u0026 pip install -r requirements.txt` |\n| OTA detection always fails | Verify device is on the same network; try `ping \u003chost\u003e`; check that ESPHome API/OTA is enabled in YAML |\n| `A fatal error occurred: Invalid head of packet` during USB flash | Lower the baud rate to `460800` or `230400`; some USB-UART bridges (CP2102, CH340) and ESP8266 boards can't sync at higher speeds. If still failing, drop to `57600` or `9600` for long or noisy cables |\n| OTA hostname resolves to a public IP (bold caption + console warning) | Avoid public TLDs in `hostname:` (e.g. `.world`, `.com`); use mDNS (`device.local`) or the LAN address directly |\n| First `esphome compile` is slow | Normal - PlatformIO downloads the toolchain (~150 MB) on first build |\n| Stack decoder reports \"no `addr2line` found\" | Compile the project at least once (populates PlatformIO toolchain under `~/.platformio/packages`) or install the GNU binutils `addr2line` |\n| Stack decoder says \"no addresses found\" | The pasted text must contain `0x` hex values - paste the full `Backtrace:` / crash dump, not just the summary line |\n| Module is bricked - no serial, no OTA, no boot | Open the **Erase flash** tab, tick the confirmation, click **Erase Flash**, then re-flash firmware from the Flash .BIN or Flash ESPHome tab |\n| **Read flash** / **Erase flash** / **Reset ESP** buttons greyed-out or \"USB only\" warning | Switch the shared device selector from **Network (OTA)** to **USB/Serial**; these operations require a direct serial connection |\n| Quick View/Edit button stays disabled | Select a YAML file first (the **Browse** button or a Known device entry); the **Quick View** toggle activates once a valid YAML path is set |\n| Need to tell which lines are app messages vs tool output | App-emitted lines (status, hints, operation start/finish) carry a `\u003e\u003e ` prefix after the timestamp; raw `esptool` / `esphome` / `espota` output has none |\n\n---\n\n## Author\n\n**Prodziekan**\n\n- Email: [prodziekan.yt@gmail.com](mailto:prodziekan.yt@gmail.com)\n- Website: [prodziekan-yt.github.io](https://prodziekan-yt.github.io)\n- YouTube: [youtube.com/@Prodziekan](https://www.youtube.com/@Prodziekan)\n\n---\n\n## License\n\nReleased under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprodziekan-yt%2Fesp-flasher-ui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprodziekan-yt%2Fesp-flasher-ui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprodziekan-yt%2Fesp-flasher-ui/lists"}