Skip to content

Conversation

@prokoma
Copy link
Contributor

@prokoma prokoma commented Dec 3, 2024

I've cleaned the history and removed the code to pull ltchiptool from git. You need to make a release of ltchiptool first before merging this PR and also update the minimum required version in builder/main.py.

@prokoma prokoma force-pushed the ambz2-ota branch 2 times, most recently from 30af0a2 to 7082519 Compare December 17, 2024 16:35
@prokoma
Copy link
Contributor Author

prokoma commented Mar 29, 2025

Hi @fcol95,
OTA for rtl8720cf is not implemented yet in the official release. My solution works, but the code is not ideal and there are some open questions.

I've described steps how to install esphome with working OTA in #44 (comment) . You can skip step 0, because ltchiptool >= 4.11.5 already contains the mentioned fix.

@fcol95
Copy link

fcol95 commented Mar 29, 2025

@prokoma thanks for your quick reply, just had deleted my comment when stumbling on your open PR in ltchiptool repo and understanding a bit better the issue! thanks for the link to your custom solution!
I'll give it a go once I finish working on the component driver I need to do for the chip that interfaces with this rtl8720c in my device!

@fcol95
Copy link

fcol95 commented Mar 31, 2025

Just tested the OTA through esphome and your "source: https://github.com/prokoma/libretiny#55aacc8" framework, works quite well, thanks for the effort, would be glad to see that merged in the production release soon!

@MottiG
Copy link

MottiG commented Aug 10, 2025

Hi @prokoma,

Thanks for a great contribution! I wonder if there are any plans to merge this PR soon (given that #307 merged already)?

@DominicChm
Copy link

Just want to confirm this works perfectly for me in esphome once the latest libretiny commits are pulled in. Would love to see this in master!

@vitoralb
Copy link

vitoralb commented Sep 9, 2025

I have used this with a tuya smart weather station that uses WBR3 module and can confirm it works well. Thanks!!

@szupi-ipuzs
Copy link
Contributor

Hi @prokoma , could you please update your fork to include this commit from the original repo?
image

It cannot be compiled with the newest esphome without this change.

@kuba2k2
Copy link
Member

kuba2k2 commented Dec 8, 2025

Rebased on latest LibreTiny dev version.

@bdraco
Copy link
Contributor

bdraco commented Jan 13, 2026

confirmed working with ESPHome

[19:03:57.617][D][esphome.ota:334]: Progress: 91.3%
[19:03:58.945][D][esphome.ota:334]: Progress: 94.9%
[19:03:59.967][D][esphome.ota:334]: Progress: 99.4%
[19:04:00.188][I][esphome.ota:363]: Update complete
[19:04:00.194][W][component:379]: esphome.ota cleared Warning flag
[19:04:00.296][I][app:258]: Rebooting safely
[19:04:00.303][D][lt.preferences:141]: FDB data not changed; skipping 233825507  len=4
[19:04:00.310][D][lt.preferences:146]: Writing 1 items: 1 cached, 0 written, 0 failed
[19:04:00.314]trace task is needed to print trace log
[19:04:00.317]hci_uart_deinit: deinit call twice

[19:04:00.320]== Rtl8710c IoT Platform ==
[19:04:00.321]Chip VID: 5, Ver: 1
[19:04:00.323]ROM Version: v2.1

[19:04:00.345]== Boot Loader ==
[19:04:00.347]Jul 20 2022:18:22:42

[19:04:00.379]Boot Loader <==

[19:04:00.389]== RAM Start ==
[19:04:00.398]I [      0.000] LibreTiny v1.9.2 on bw15, compiled at Jan 12 2026 18:58:30, GCC 10.3.1 (-Os)
[19:04:00.404][I][logger:049]: Log initialized

Had to manually upload

ltchiptool flash write /Users/bdraco/esphome/.esphome/build/bw15-device/.pioenvs/bw15-device/image_flash_is.0x000000.bin -d /dev/cu.usbserial-0001 

Had to manually generate uf2

ltchiptool uf2 write -o firmware.uf2 -f rtl8720c -b bw15 image_firmware_is_ota.0x00C000.bin

but than esphome run bw15.yaml works

rtl87xx:
  board: bw15
  framework:
    version: 1.9.2
    source: https://github.com/prokoma/libretiny/archive/refs/heads/ambz2-ota.zip

edit: with patch it just works

diff --git a/builder/family/realtek-ambz2.py b/builder/family/realtek-ambz2.py
index f67d97b..144fa94 100644
--- a/builder/family/realtek-ambz2.py
+++ b/builder/family/realtek-ambz2.py
@@ -437,7 +437,6 @@ queue.BuildLibraries()
 image_part_table = "${BUILD_DIR}/image_part_table.${FLASH_PART_TABLE_OFFSET}.bin"
 image_bootloader = "${BUILD_DIR}/image_bootloader.${FLASH_BOOT_OFFSET}.bin"
 image_firmware_is = "${BUILD_DIR}/image_firmware_is.${FLASH_OTA1_OFFSET}.bin"
-image_firmware_is_ota = "${BUILD_DIR}/image_firmware_is_ota.${FLASH_OTA1_OFFSET}.bin"
 env.Replace(
     # linker command (dual .bin outputs)
     LINK='${LTCHIPTOOL} link2bin ${BOARD_JSON} "" ""',
@@ -445,8 +444,8 @@ env.Replace(
     UF2OTA=[
         # use unmodified image for flasher
         f"{image_firmware_is},{image_firmware_is}=flasher:ota1,ota2",
-        # use patched OTA image for device
-        f"{image_firmware_is_ota},{image_firmware_is_ota}=device:ota1,ota2",
+        # use same image for device OTA
+        f"{image_firmware_is},{image_firmware_is}=device:ota1,ota2",
         # having flashed an application image, update the bootloader and partition table (incl. keys)
         f"{image_bootloader},{image_bootloader}=flasher:boot,boot",
         f"{image_part_table},{image_part_table}=flasher:part_table,part_table",

This works with ESPHome dev

rtl87xx:
  board: bw15
  framework:
    version: 1.9.2
    source: https://github.com/bdraco/libretiny/archive/refs/heads/ambz2-ota.zip

@bdraco
Copy link
Contributor

bdraco commented Jan 13, 2026

I wanted to follow up on this PR. I understand you have broader plans for LibreTiny architecture, but I'd like to explain why merging this now would help the project.

I have a collection of BW15 boards (RTL8720CF) that I use as test targets. The problem: without OTA support, I can't include these boards in our release testing workflow. Flashing them requires manual intervention with ltchiptool, or using a fork which makes things brittle and more likely we end up skipping testing due to time constraints.

I've tried to get other RTL boards but obtaining them has proven difficult, and buying devices to guess which chip they have in them isn't a good plan either because they are even harder to debug and get serial logs on.

We had tons of WiFi and thread safety issues on LibreTiny in ESPHome that only just got fixed because I was able to obtain test boards and had a clear path to easily flash and iterate on that doesn't involve clamps and tiny wires and soldering things smaller than my eyes can see.

The practical result is that LibreTiny RTL code doesn't get tested during ESPHome releases. Bugs slip through or the platform falls behind because it's too painful to iterate on.

If this PR gets merged, I can add RTL8720CF to my manual test matrix. That means LibreTiny RTL code actually gets exercised during releases and we catch problems early instead of finding out later from users.

I get that it might not align perfectly with your future architecture plans, but working OTA with real testing seems better than untested code waiting for a rewrite.

Is there anything specific about the PR that concerns you, or something I can help with to get it over the line?

@kuba2k2
Copy link
Member

kuba2k2 commented Jan 13, 2026

Hi
I fully understand how difficult it can currently be to develop for these boards. I do have some sophisticated future plans, but as you mentioned, having something working would perhaps benefit users more.

The main issues were discussed over in ltchiptool's repository: libretiny-eu/ltchiptool#46
Among smaller things, it's mainly about the app ID counter and partition table/bootloader flashing. I'm not sure if they were sorted out already. I'm open for ideas anyway.

@bdraco
Copy link
Contributor

bdraco commented Jan 13, 2026

Thanks for being open to this. I spent some time today digging into how the RTL8720CF bootloader actually decides which image to boot, and I think I can address some of the concerns from the ltchiptool discussion.

From what I can tell, the bootloader doesn't actually use serial numbers for boot selection. It just checks if the first byte of each image is valid (not inverted). The serial numbers seem to be informational only. The SDK's own sys_update_ota_set_boot_fw_idx() uses the same byte inversion approach that prokoma implemented.

So the mechanism in this PR appears to be correct for the hardware. It's not a workaround, it's how Realtek designed it.

The main limitation is there's no automatic rollback if the new image is broken since the bootloader has no fallback mechanism. ESPHome's safe_mode catches most failures, but very early crashes would need UART recovery. That's a hardware limitation though, not something we can fix in software.

@kuba2k2
Copy link
Member

kuba2k2 commented Jan 14, 2026

Interesting. The Realtek documentation seems to disagree (after all, I must have gotten that serial number counter idea from somewhere) -- but that wouldn't be surprising at all.

It's worth noting that there are at least two different variants of the bootloader: stock Realtek (the one in SDK, the one LT has access to) and modified Tuya (with unknown modifications).

I'm not sure which one you're using on that BW15 (they can be reflashed), but it's entirely possible that they implement a different method for choosing the active application.

Serial numbers aside, there are some indications that one of the bootloaders could be using a bit flag value in the system partition (just like on AmebaZ).

So it appears we have three different possible checks:

  • serial number comparison
  • first byte of signature (or simply having an invalid signature?)
  • bit flag in system data
    ...and two bootloaders, without confirmation which checks are actually used on which bootloader.

We need to choose a solution that would work in both cases. There are commercial devices other than Tuya (for example TP-Link Tapo plugs), which, I assume, use the stock bootloader (or even something entirely different).

As for automatic rollback - yes, I know it's not possible, and it doesn't have to be. The feature is entirely useless without any bootloader-based bootloop checks, and it was added only to conform with Arduino's Update library. It should be dropped since there's no real use case for that.

@Cossid
Copy link
Collaborator

Cossid commented Jan 14, 2026

For reference/testing, https://github.com/divadiow/FlashDumps/tree/main/IoT/RTL8720CF has multiple full dumps, including the original BW15 firmware (expected Realtek bootloader), several Tuya firmwares (expected Tuya bootloader), and a handful of other firmwares (unknown bootloaders) for bootloader compatibility testing. Edit: this may not cover serparate ROMs, not sure how important that is.

@bdraco
Copy link
Contributor

bdraco commented Jan 19, 2026

I see I think requiring confirmation across all bootloader variants is effectively the same as "never merge." This PR has been open for over a year, and it took that long for someone like me (not even the original author) to stumble accross it and start pushing for it.

The reality is:

  • We can't obtain all the hardware variants, even if we could, new variants will appear
  • The byte inversion mechanism is what Realtek's own SDK uses internally
  • The current alternative is no OTA at all, which means no testing, which means bugs accumlate

I'd suggest we merge with documented limitations. Something like: "OTA tested on stock Realtek bootloader (BW15). Other bootloader variants (Tuya, etc.) are untested and may require UART recovery if OTA fails."

Users already need UART access for initial flashing anyway, so UART recovery for edge cases isn't a new burden. And if someone with a different bootloader variant reports issues, we can investigate then with actual hardware and logs rather than speculating about theoretical problems.

Perfect is the enemy of good here. Working OTA on known hardware is better than no OTA on any hardware.

@bdraco
Copy link
Contributor

bdraco commented Jan 19, 2026

Just to be clear, I fully agree the bootloader variance is a real risk. I’m not claiming this is universally safe, only that we merge a tested path with explicit limits, and iterate based on real reports rather than blocking indefinitely.

@kuba2k2
Copy link
Member

kuba2k2 commented Jan 23, 2026

Makes sense - I agree that this should be released.

Currently I'm not able to test whether this PR works - so I'll have to take your word for it. I know that many people have reported this to work just fine, so I'll trust that too.

I'm not sure about the encode_for_define() function, since it requires shell escaping - are you testing on Linux or Windows? Does it work on both systems?


Regarding the image_firmware_is_ota image - I see you're not using that in your branch. I believe this file is generated by a patched ltchiptool, and has a bit-flipped header byte. The C code has a function to un-flip that byte, appropriately.

I think it should be fine to leave this as-is - meaning that the OTA image will not have a bit-flipped byte at all, and will be "enabled" directly after writing. The C code will still have that if block, but it will essentially be a no-op.


Let me know if the proposed solution would work for you: merge #302 directly and leave libretiny-eu/ltchiptool#46 unmerged for now.

@bdraco
Copy link
Contributor

bdraco commented Jan 24, 2026

Opened #344 with a working version based on this PR.

Re: your questions -

The original encode_for_define() used shell escaping which wouldnt work on Windows. Fixed it by switching to C array initializer syntax ({0x12,0x34,...}) instead of escaped string literals. No shell escaping needed so it should work on all platforms now.

And yeah I'm not using the patched image, same firmware image for both flasher and device OTA. The enable/disable logic is still there but its basically a no-op since images are already enabled when written.

Retested with mutliple OTAs on ESPHome, working fine.

@kuba2k2
Copy link
Member

kuba2k2 commented Jan 24, 2026

Thanks, the PR #302 has been merged (in the form of #344). Realtek RTL8720CF OTA will be available in LibreTiny v1.10.0.

@kuba2k2 kuba2k2 added the enhancement New feature or request label Jan 24, 2026
@kuba2k2 kuba2k2 closed this Jan 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants