Skip to content

produce merged binaries with injected wifi creds for web flashable firmware files#690

Merged
tavdog merged 5 commits intomainfrom
inject_merge
Jan 15, 2026
Merged

produce merged binaries with injected wifi creds for web flashable firmware files#690
tavdog merged 5 commits intomainfrom
inject_merge

Conversation

@tavdog
Copy link
Member

@tavdog tavdog commented Jan 14, 2026

Produce merged firmware files with injected firmware for initial webflash and later OTA capable device. Also change the firmware instructions to use webflashers instead of espflasher app

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @tavdog, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the user experience for initial device setup by enabling the generation of web-flashable firmware files that come pre-configured with WiFi credentials. By producing "merged" binaries that include all necessary components (bootloader, partition table, and application), users can now flash their devices directly via web-based tools at address 0x0, streamlining the setup process and reducing potential flashing complexities.

Highlights

  • Merged Firmware Binaries: Introduced the capability to generate "merged" firmware binaries, which include the bootloader, partition table, and application, making them suitable for direct flashing at address 0x0 using web-based tools.
  • Checksum Handling for Injected Data: Enhanced the firmware generation logic to accurately calculate and apply checksums when injecting WiFi credentials and other placeholders into the binary, ensuring data integrity.
  • Web Interface Updates: Updated the web interface for firmware generation, allowing users to choose between generating an OTA-only firmware or a full merged binary, and providing clear instructions for web-based flashing.
  • Firmware Version Adjustment: Adjusted the minFirmwareFeaturesVersion constant from v1.5.0 to v1.4.9.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the capability to generate merged, web-flashable firmware binaries with injected credentials. The changes include:

  • A new GenerateMerged function to create full firmware images.
  • An update to the firmware generation logic to use a more efficient checksum delta calculation.
  • UI changes to support selecting between OTA-only and full merged firmware generation, along with updated flashing instructions.

Overall, this is a great enhancement that simplifies the initial device flashing process for users. I've provided a couple of suggestions for improvement:

  • An efficiency improvement in GenerateMerged to avoid reading the entire firmware file into memory.
  • A small readability enhancement in the checksum calculation loop.

Comment on lines +136 to +146
mergedContent, err := os.ReadFile(mergedPath)
if err != nil {
return nil, fmt.Errorf("merged firmware file not found (needed for bootloader/partition): %s", mergedPath)
}

if len(mergedContent) < MergedAppOffset {
return nil, fmt.Errorf("merged firmware file too short to contain preamble")
}

// Extract the preamble (first 0x10000 bytes containing bootloader + partition table)
preamble := mergedContent[:MergedAppOffset]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation reads the entire merged firmware file into memory, even though only the first 0x10000 bytes (the preamble) are needed. This can be inefficient for large firmware files. You can optimize this by opening the file and reading only the required number of bytes using io.ReadFull.

Suggested change
mergedContent, err := os.ReadFile(mergedPath)
if err != nil {
return nil, fmt.Errorf("merged firmware file not found (needed for bootloader/partition): %s", mergedPath)
}
if len(mergedContent) < MergedAppOffset {
return nil, fmt.Errorf("merged firmware file too short to contain preamble")
}
// Extract the preamble (first 0x10000 bytes containing bootloader + partition table)
preamble := mergedContent[:MergedAppOffset]
mergedContent, err := os.Open(mergedPath)
if err != nil {
return nil, fmt.Errorf("merged firmware file not found (needed for bootloader/partition): %s", mergedPath)
}
defer mergedContent.Close()
// Extract the preamble (first 0x10000 bytes containing bootloader + partition table)
preamble := make([]byte, MergedAppOffset)
if _, err := io.ReadFull(mergedContent, preamble); err != nil {
return nil, fmt.Errorf("merged firmware file too short to contain preamble: %w", err)
}

Copy link
Member Author

@tavdog tavdog Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah this could be a good idea. gotta go to bed now though so can't test it.

@tavdog
Copy link
Member Author

tavdog commented Jan 15, 2026

I've tested the firmware generation for flash at 0x0, wifi portal triggered OTA and server triggered OTA. Seems to be working. Only issue I ran into was that the the merged files don't get downloaded if the firmware version is already up to date.

@@ -648,23 +648,10 @@ func (dt DeviceType) FirmwareFilename(swapColors bool) string {

func (dt DeviceType) MergedFilename(swapColors bool) string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentionally mapping Tidbyt Gen1+2 to the same file (as well as S3, S3-Wide, and the Matrix Portals)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, the merged bins bootloader and partitions don't change between gen1/gen2 or between any S3 target.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, the merged bins bootloader and partitions don't change between gen1/gen2 or between any S3 target.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see that you're only taking the bootloader and partition table from there and then add the patched app. I assumed that you're patching the app partition contained in the merged bin, in which case they would need to be device-specific.

@tavdog tavdog merged commit e56dcbd into main Jan 15, 2026
11 checks passed
@IngmarStein IngmarStein deleted the inject_merge branch January 17, 2026 21:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants