Skip to content

Move user-facing strings and QR URLs into config.yml - #545

Open
joelhawksley wants to merge 9 commits into
usetrmnl:mainfrom
timeframe:localization-config
Open

Move user-facing strings and QR URLs into config.yml#545
joelhawksley wants to merge 9 commits into
usetrmnl:mainfrom
timeframe:localization-config

Conversation

@joelhawksley

@joelhawksley joelhawksley commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Moves the firmware's user-facing display text and the on-screen QR code URLs into a single config.yml, generated into headers at build time. Defaults reproduce the stock TRMNL strings and URLs exactly, so an unmodified config.yml builds identical firmware.

This makes the firmware straightforward to localize the firmware without editing C++, such as for device deployments using Terminus, etc.

How it works

scripts/generate_branding.py runs as a PlatformIO pre-build script and emits:

  • include/branding.h — string / URL #define macros.
  • src/wifi_connect_qr.h, src/wifi_failed_qr.h — 66×66 G5 QR bitmaps (same format bbep.loadG5Image already consumes, so no display code changes).

Notes

  • include/branding.h and the QR headers are generated; added to .clang-format-ignore alongside the existing generated headers.
  • Captive-portal web page text is intentionally out of scope here for now.
  • Wired the pre-build script into the shipping envs (trmnl, trmnl_4clr, TRMNL_X, TRMNL_X_E1003, seeed_reTerminal_E1001/E1002, WAVESHARE_397).

Testing

Builds succeed for trmnl (OG), seeed_reTerminal_E1001, and TRMNL_X_E1003 (X-class), with the generator running as a pre-build step. The QR bitmaps were verified to round-trip to the encoder's QR matrix. clang-format passes.

Add a build-time generator (scripts/generate_branding.py) that reads
config.yml and emits include/branding.h (BRAND_STR_* / URL macros) and the
on-screen QR bitmaps (src/wifi_connect_qr.h, wifi_failed_qr.h) for the
configured URLs. All user-facing display strings in display.cpp now come
from these macros instead of inline literals.

Defaults reproduce the stock TRMNL strings and URLs exactly, so an
unmodified config.yml produces identical firmware. The generator runs as a
PlatformIO pre-build script; QR regeneration needs the optional 'segno'
package and falls back to the committed bitmaps when it is absent.
Install segno on demand in the branding generator instead of skipping QR
regeneration when it is absent, and declare it in scripts/requirements.txt.
@joelhawksley
joelhawksley marked this pull request as ready for review August 8, 2026 01:11
@schrockwell schrockwell added the refactor Code cleanup only label Aug 10, 2026
Localization outputs are build artifacts and customization is confined to a
single git-ignored overlay, so a white-label fork never edits a tracked file
and pulling upstream never conflicts.

- generate_branding.py deep-merges an optional config.local.yml over config.yml.
- Stop tracking the generated headers (branding.h, wifi_connect_qr.h,
  wifi_failed_qr.h); they are regenerated at build time and git-ignored.
- Add config.local.yml.example and document the override flow in config.yml.
- CI: generate headers before build/test, and add a branding-config job that
  proves an override changes output without dirtying any tracked file.

Defaults still reproduce the stock TRMNL strings/URLs byte-identically.
Extend the config-driven, git-ignored-artifact model to the captive portal and
the e-paper logos so a white-label fork customizes them without editing tracked
files.

- generate_branding.py now also generates lib/wificaptive/src/WifiCaptivePage.h
  from the portal HTML/SVG, applying optional strings.portal_* / accent_color
  overrides. With no overrides it gzips the raw source, so the page content is
  unchanged (line endings normalize to LF). WifiCaptivePage.h is now a
  git-ignored build artifact; the manual portal/convert.py is removed.
- Optional images.* config converts 1-bit PNGs to git-ignored *.local.h logo
  sidecars (pillow auto-installed on demand). The committed stock logo headers
  include them via __has_include, so stock builds are unchanged and need no
  pillow, while custom logos never modify a tracked file.
- config.yml / config.local.yml.example document portal + image overrides.
- CI branding-config job also verifies a portal_title override changes the
  generated page without dirtying tracked files.
…lder

- Portal HTML now uses {{accent_color}} placeholders (default #F86527), so the
  captive-portal accent is themable via branding.accent_color. Stock output is
  byte-identical after substitution.
- wifi.ap_ssid_prefix drives the setup hotspot SSID via a git-ignored
  lib/wificaptive/src/wifi_ssid.local.h sidecar that WifiCaptive.h includes with
  a "TRMNL" fallback, so the library needs no access to include/branding.h.
- strings.portal_api_placeholder rebrands the custom-server input hint.
- config.yml documents the new keys; defaults reproduce stock verbatim.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor Code cleanup only

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants