| 2.0.4.4 | — | archived | Factory firmware. Full flash dump backed up at C:\Users\dansc\xiaozhi_backup_full.bin. |
| 2.2.5 | 2026-04-05 | superseded | First custom build — board zhengchen-1.54tft-wifi-bitcraft, OTA URL set to this server, Chinese UI. OTA-flashed from 2.0.4.4. |
| 2.2.5 † | 2026-04-05 | running on device | English UI rebuild (Windows) — CONFIG_LANGUAGE_EN_US=y, fixed hardcoded Chinese high-temp label. |
| 2.2.6 | 2026-04-07 | crashes | First Linux build. Hangs after AudioCodec init — never reaches WiFi. Root cause: circular GetInstance() deadlock fixed in 2.2.8. |
| 2.2.7 | 2026-04-07 | crashes | Added http->SetTimeout(300000). Same deadlock crash as 2.2.6. |
| 2.2.8 | 2026-04-08 | superseded | Fixed GetInstance() deadlock: moved MediaPlayer::RegisterMcpTools() from constructor to AddCommonTools(). First working Linux build. |
| 2.2.9 | 2026-04-08 | superseded | Fixed media playback silent failure: stream_url_ cleared by StopPlayback() before StreamTask ran. |
| 2.2.10 | 2026-04-08 | superseded | Fixed ReadAll() deadlock for files >8 KB. Rewrote StreamTask to stream via Read() chunks into OggDemuxer. |
| 2.2.11 | 2026-04-08 | superseded | Fixed stack overflow: OggDemuxer moved to heap; task stack increased to 16 384 bytes. Audio confirmed working. |
| 2.2.12 | 2026-04-08 | superseded | Added MediaPlayer::Stop(). BOOT button stops media on tap. Used unsafe vTaskDelete — replaced in 2.2.13. |
| 2.2.13 | 2026-04-08 | regression | Atomic stop_requested_ flag. Added wait-for-idle loop — broke audio (output path torn down at idle). Rolled back in 2.2.14. |
| 2.2.14 | 2026-04-08 | superseded | Reverted wait-for-idle; audio works. Atomic stop flag retained. |
| 2.2.15 | 2026-04-08 | superseded | Added Flappy Bird game. Button not responding — BUTTON_SINGLE_CLICK debounce too slow. Fixed in 2.2.17. |
| 2.2.16 | 2026-04-08 | superseded | Attempted to suppress AI TTS via empty MCP return — insufficient (AI speaks regardless). Superseded by 2.2.18. |
| 2.2.17 | 2026-04-08 | superseded | Fixed Flappy Bird button: moved to BUTTON_PRESS_DOWN (fires immediately). AI speech suppressed after game/media launch. |
| 2.2.18 | 2026-04-08 | superseded | Fixed AI speech overlap: AbortSpeaking(kAbortReasonNone) cuts TTS at protocol level. BOOT button stop with press_consumed_ flag. Graceful game exit via lv_scr_load_anim. |
| 2.2.19 | 2026-04-08 | superseded | Flappy Bird: persistent "GAME OVER" overlay; long-press BOOT exits. Long-press WiFi config blocked during game. |
| 2.2.20 | 2026-04-08 | superseded | Added VideoPlayer module: .axv container (MJPEG + Opus), 4 MCP tools. Double-buffered JPEG decode to PSRAM. Test video (SMPTE bars) added. |
| 2.2.21–2.2.23 | 2026-04-09 | superseded | Details not documented. |
| 2.2.24 | 2026-04-09 | superseded | Baseline for this session — VideoPlayer functional. |
| 2.2.25 | 2026-04-10 | superseded | Fixed video running ~1.5× too fast: wake word acoustic feedback (speaker → mic) was triggering ResetDecoder() during playback, breaking audio backpressure. Fixed by disabling wake word detection during video and guarding ResetDecoder() calls in state machine. |
| 2.2.26 | 2026-04-10 | superseded | Added FlappyBird sound effects (flap/score/death via OGG assets). Added self.device.about MCP tool — fetches description from /esp32/xiaozhi/about and returns it to AI. Added public /esp32/xiaozhi/about.html page. |
| 2.2.27 | 2026-04-10 | superseded | Fixed generic media playback path so video items resolved by self.media.search are delegated to VideoPlayer instead of the audio-only OGG demuxer. |
| 2.2.28 | 2026-04-10 | superseded | Split video playback into separate reader and renderer tasks, added audio prebuffering, and started dropping stale video frames based on container timestamps instead of blocking audio. |
| 2.2.29 | 2026-04-10 | superseded | Ends active voice sessions when video starts and ignores late conversational events while media is active, preventing the AI from interrupting playback with retry speech. |
| 2.2.30 | 2026-04-10 | superseded | Removes per-frame JPEG output allocation/copy churn by decoding directly into reusable PSRAM framebuffers. Audio stayed solid; video remained decode-bound. |
| 2.2.31 | 2026-04-11 | superseded | Added playback-end diagnostics: HTTP read stalls, audio queue block time, late-frame stats, deeper audio buffering, and higher stream-reader priority. |
| 2.2.32 | 2026-04-11 | superseded | Streams playback telemetry live every 5 seconds during active video and surfaces the detailed diagnostics on this dashboard. Designed to distinguish stream transport stalls from local decode/render limits while playback is still running. |
| 2.2.33 | 2026-04-11 | regression | Introduced ranged video fetching and timeline resync, but startup failed before the first packet was delivered. Video items resolved correctly from the library, but playback exited after about 1.4 seconds with zero rendered frames. |
| 2.2.34 | 2026-04-11 | regression | Attempted a startup fallback to the legacy stream when the first Range request was ignored, but telemetry showed the same early-exit failure pattern as 2.2.33. The ranged transport remained broken on-device. |
| 2.2.35 | 2026-04-12 | superseded | Removed the ranged transport path and restored the known-good continuous HTTP streaming reader from 2.2.32 while keeping the live playback telemetry. This recovery build made video work again after the 2.2.33/2.2.34 transport regression. |
| 2.2.36 | 2026-04-12 | superseded | Expanded video telemetry into a full pipeline profile: startup latency, HTTP read timing, packet copy cost, queue overflow vs backlog drops, JPEG decode timing, frame-present timing, frame-age metrics, and explicit playback end reason. That data showed the renderer was oversleeping on far-future frames. |
| 2.2.37 | 2026-04-12 | superseded | Reworked video frame selection and pacing. The renderer now trims stale frames, selects the newest frame that is actually due, preserves future frames in the queue, and rechecks pacing in short intervals instead of sleeping on far-future frames. |
| 2.2.38 | 2026-04-12 | superseded | Added resumable video transport and new resume counters. Playback did attempt a resume after an early stream close, but the device’s range request was malformed and the server returned HTTP 416. |
| 2.2.39 | 2026-04-12 | superseded | Fixes the resume request formatting. The firmware now builds the Range header using a plain decimal string instead of printf-style formatting, which avoids malformed resume requests on the embedded libc build. |
| 2.2.40–2.2.74 | 2026-04–06 | superseded | Extensive video-pipeline iteration: ranged HTTP, sync_v1 batched transport, then full WebSocket streaming (media/ws/<id>) for video. Server-side pacing (_WS_LEAD_MS = 10000) keeps the device ~10 s ahead of audio_clock for jitter absorption. NVS-deferred end-of-playback summaries to avoid HttpClient lifecycle bugs. |
| 2.2.75–2.2.82 | 2026-06-03/04 | superseded | Patched managed-component tcp_receive and ssl_receive task priorities from 1 → 6 to stop them being starved by the video tasks. Coredump partition added to capture panics. Persistent telemetry WebSocket so per-event POSTs no longer instantiate HttpClient and trip the lifetime races. End-of-playback summary now sent via WS immediately (NVS only as fallback when WS isn't up). |
| 2.2.83–2.2.85 | 2026-06-04 | superseded | Restructured WS receive: dispatch happens inline on the receive task, eliminating the intermediate raw_queue whose auto-drop policy was silently discarding the OLDEST frames (the ones the renderer needed). Pinned video_stream/video_render to core 0/1 respectively. Pinned audio: opus_codec+audio_output+audio_input+audio_detection+audio_communication and both AFE-internal tasks to core 0. Dynamic ws_base_url via OTA response so server IP changes propagate without re-flash. Auto-OTA poll every 60 s when idle. |
| 2.2.86–2.2.87 | 2026-06-04 | superseded | Added per-core CPU stats to the playback summary (cpu_core0_busy_pct, cpu_core1_busy_pct, cpu_top_task_name, cpu_top_task_pct, cpu_top_task_core). Enabled CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y. Initial implementation reported since-boot stats; corrected to per-playback-window delta. Build-deploy verification: the script now hashes the version string out of the binary and aborts if it doesn't match CMakeLists.txt, after a 2.2.86 ship of the wrong binary caused a download-reboot loop. |
| 2.2.88 | 2026-06-04 | superseded | Big fix. The render task was spin-looping at 34 591 wakeups/sec when frames were not yet due. The "future_wait_us" branch did continue before reaching the vTaskDelay further down the loop body — sleep code unreachable. Result: core 1 sat at 100% even on 8 fps content, and LVGL got starved of CPU which is why visual playback didn't match the rendered-frame counter. Moved the delay inside the same branch as the continue. Core 1 dropped from 100% → 33% at 8 fps. |
| 2.2.89 | 2026-06-05 | superseded | Bumped kMaxQueuedVideoFrames 120 → 320 to cover the server's 10 s lead at 24 fps source rate. Verified 24 fps playback: R = 23.40 fps rendered (97.6% of 23.976 source), only 55 backlog drops over 137 s, 0 queue overflow, 0 audio underruns, core 1 at 81 %, core 0 at 27 %. Sustained ~245 KB/s network throughput. Top task taskLVGL at 43 % on core 1. |
| 2.3.00–2.3.07 | 2026-06 | superseded | Audio-path hardening (PSRAM task stacks, AFE VAD blocking, SendStartListening), VAD auto-stop + 60 s idle update poll, and the start of the DOOM (prboom) port under a gitignored components/ directory with the WAD in the assets partition. |
| 2.3.08–2.3.09 | 2026-06-22 | superseded | ESP coredump → boot-telemetry → erase; per-core CPU stats; ws_base_url NVS cache; audio tasks pinned to core 0; video sync-playback rework. 2.3.09 switched the device's hardcoded URLs (media search, telemetry, about) from https://www.danscodellaro.com to http://iot.danscodellaro.com (Cloudflare-bypass plaintext origin). |
| 2.3.10–2.3.12 | 2026-06-22 | superseded | Root-caused video + DOOM launch failures: PSRAM task stacks. The 32 KB video stream task and the DOOM engine task were created with internal-SRAM stacks, which silently fail once AFE audio + LVGL are loaded. Moved both to PSRAM via xTaskCreatePinnedToCoreWithCaps (+ vTaskDeleteWithCaps). Video confirmed playing on hardware; DOOM now launches. |
| 2.3.13–2.3.15 | 2026-06-22 | superseded | DOOM display fixes (horizontal-wrap LUT overflow, top-bar flicker, palette[255]), %zu logging fix (newlib-nano drops %z) → counters now print, and internal-SRAM relief during playback. |
| 2.3.16–2.3.17 | 2026-06-22 | superseded | DOOM exit-freeze deadlock fixed (cross-thread LVGL lock → lvgl_port_stop()/resume()); higher-quality video encode; DOOM SFX audio added from scratch (DMX lump parser + ≤8-channel mixer pushed to the codec) with a SetOutputKeepAlive fix so the power-save loop no longer mutes it. DOOM audio confirmed working by ear. |
| 2.3.18 | 2026-06-22 | current | Fixed two regressions: reverted the served video to baseline 4:2:0 JPEG (the device's esp_new_jpeg decoder rejects 4:4:4) and reordered DOOM start to take the display lock before lvgl_port_stop(), eliminating a post-DOOM main-task TWDT hang. Current shipping firmware: English voice chat (Bedrock claude-haiku via self-hosted backend), local media search + Simpsons video over WebSocket, Flappy Bird, and DOOM (attract mode, with SFX). |