Skip to content

Move localization to ESPHome compile-time substitutions#58

Merged
edwardtfn merged 15 commits intomainfrom
v9999.99.9
Mar 22, 2026
Merged

Move localization to ESPHome compile-time substitutions#58
edwardtfn merged 15 commits intomainfrom
v9999.99.9

Conversation

@edwardtfn
Copy link
Copy Markdown
Owner

@edwardtfn edwardtfn commented Mar 21, 2026

Summary

Moves language selection and all UI strings from the Blueprint (runtime, Jinja) to ESPHome firmware (compile-time substitutions). Only the strings for the selected language are compiled into the firmware — no locale table is loaded at runtime.

Changes

ESPHome

  • Add esphome/nspanel_esphome_localization.yaml with full locale table for 54 languages
  • Add language substitution (default: en) with validation and fallback
  • Add render_date script to nspanel_esphome_datetime.yaml — reusable date rendering with localized weekday/month names, used by home page and weather pages
  • Replace all mui_* globals receiving values via Blueprint mem calls with compile-time string literals from ${LOCALIZATION[LANG].*}
  • Remove mui_bytes_per_char, mui_please_confirm, mui_unavailable, mui_meridiem_am, mui_meridiem_pm globals and their action_component_text/action_component_val handlers
  • Remove mui_alarm parameter from page_alarm API action
  • Add SENTINEL_UNAVAILABLE, SENTINEL_UNKNOWN, SENTINEL_NO_NAME substitutions for Blueprint-side placeholder strings

Blueprint

  • Remove language selector !input
  • Remove full mui locale table
  • Remove all component_text calls sending locale strings via page: mem
  • Update page_alarm call to remove mui_alarm parameter
  • Send sentinel strings (__unavailable__, __unknown__, __no_name__) where needed

Docs

  • Add docs/localization.md with language code table and font support notes
  • Update docs/blueprint.md — language section now points to ESPHome substitution
  • Update docs/install.md — add language: substitution to all YAML examples
  • Update docs/migration_from_blackymas.md — language migration note and FAQ entry

⚠️ Breaking Change

This release requires a coordinated update of both ESPHome firmware and Blueprint.

Users must also add language: xx to their ESPHome substitutions block before flashing.
Without it, the panel will default to English regardless of the previous Blueprint language setting.

See docs/localization.md for the full list of supported language codes.

Supported Languages

Code Language
af Afrikaans
ar Arabic
bg Bulgarian
bn Bengali
bs Bosnian
ca Catalan
cs Czech
cy Welsh
da Danish
de German
el Greek
en English (default)
es Spanish
et Estonian
eu Basque
fa Persian (Farsi)
fi Finnish
fr French
gl Galician
he Hebrew
hi Hindi
hr Croatian
hu Hungarian
id Indonesian
is Icelandic
it Italian
ja Japanese
jv Javanese
ko Korean
lt Lithuanian
lv Latvian
mk Macedonian
ms Malay
nb Norwegian Bokmål
nl Dutch
pa Punjabi (Gurmukhi)
pl Polish
pt Portuguese
ro Romanian
ru Russian
sk Slovak
sl Slovenian
sq Albanian
sr Serbian
sv Swedish
sw Swahili
ta Tamil
th Thai
tr Turkish
uk Ukrainian
ur Urdu
vi Vietnamese
zh-cn Chinese (Simplified)
zh-tw Chinese (Traditional)

Summary by CodeRabbit

  • New Features

    • Full localization support via a language substitution (defaults to English) and a new localization guide.
  • Documentation

    • Install, migration, add‑on, blueprint and API docs updated to show language substitution examples and tightened table formatting.
  • User-facing changes

    • UI strings and button labels now use shared language substitutions; improved date/time rendering and weather/day display; refined text wrapping and updated boot display stage behavior.
  • Chores

    • Raised compatibility thresholds; adjusted UI text scope to local; increased QR code max text size.

## Summary

Moves language selection and all UI strings from the Blueprint (runtime, Jinja) to ESPHome
firmware (compile-time substitutions). Only the strings for the selected language are compiled
into the firmware — no locale table is loaded at runtime.

## Changes

### ESPHome
- Add `esphome/nspanel_esphome_localization.yaml` with full locale table for 54 languages
- Add `language` substitution (default: `en`) with validation and fallback
- Add `render_date` script to `nspanel_esphome_datetime.yaml` — reusable date rendering
  with localized weekday/month names, used by home page and weather pages
- Replace all `mui_*` globals receiving values via Blueprint `mem` calls with compile-time
  string literals from `${LOCALIZATION[LANG].*}`
- Remove `mui_bytes_per_char`, `mui_please_confirm`, `mui_unavailable`, `mui_meridiem_am`,
  `mui_meridiem_pm` globals and their `action_component_text`/`action_component_val` handlers
- Remove `mui_alarm` parameter from `page_alarm` API action
- Add `SENTINEL_UNAVAILABLE`, `SENTINEL_UNKNOWN`, `SENTINEL_NO_NAME` substitutions for
  Blueprint-side placeholder strings

### Blueprint
- Remove language selector `!input`
- Remove full `mui` locale table
- Remove all `component_text` calls sending locale strings via `page: mem`
- Update `page_alarm` call to remove `mui_alarm` parameter
- Send sentinel strings (`__unavailable__`, `__unknown__`, `__no_name__`) where needed

### Docs
- Add `docs/localization.md` with language code table and font support notes
- Update `docs/blueprint.md` — language section now points to ESPHome substitution
- Update `docs/install.md` — add `language:` substitution to all YAML examples
- Update `docs/migration_from_blackymas.md` — language migration note and FAQ entry

## ⚠️ Breaking Change

This release requires a **coordinated update** of both ESPHome firmware and Blueprint.

Users must also add `language: xx` to their ESPHome `substitutions` block before flashing.
Without it, the panel will default to English regardless of the previous Blueprint language setting.

See [docs/localization.md](docs/localization.md) for the full list of supported language codes.

## Supported Languages (54)

`af` `ar` `bg` `bn` `bs` `ca` `cs` `cy` `da` `de` `el` `en` `es` `et` `eu` `fa` `fi` `fr`
`gl` `he` `hi` `hr` `hu` `id` `is` `it` `ja` `jv` `ko` `lt` `lv` `mk` `ms` `nb` `nl` `pa`
`pl` `pt` `ro` `ru` `sk` `sl` `sq` `sr` `sv` `sw` `ta` `th` `tr` `uk` `ur` `vi` `zh-cn` `zh-tw`
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 21, 2026

📝 Walkthrough

Walkthrough

Adds compile-time localization via an ESPHome substitutions.language (default en), moves many runtime-localized strings to compile-time substitutions, introduces localization docs, restructures date/time rendering and weather scripts, removes several persisted globals, adjusts boot/display init ordering, updates HMI attributes, and bumps blueprint/TFT/HMI version thresholds.

Changes

Cohort / File(s) Summary
Localization docs & examples
docs/localization.md, docs/blueprint.md, docs/addon_climate.md, docs/addon_upload_tft.md, docs/customization.md, docs/install.md, docs/migration_from_blackymas.md
Added docs/localization.md; added substitutions: language: en to example YAMLs; updated blueprint guidance and table formatting to reflect language substitution usage.
API docs
docs/api.md
Removed documented mui_alarm parameter and its Home Assistant example from page_alarm; minor table/phrasing formatting edits.
Localization core & substitutions
esphome/nspanel_esphome_localization.yaml, esphome/nspanel_esphome_version.yaml
Default language set to en; added LANG_BYTES_PER_CHAR, LANG_ALARM_*, sentinel constants (SENTINEL_*); bumped min_blueprint_version 9→10 and min_tft_version 10→11.
API preprocessing & sentinel handling
esphome/nspanel_esphome_api.yaml
Removed mui_unavailable persistent global; api component_text now copies and replaces sentinel tokens with localized strings before calling action_component_text.
Datetime & date rendering
esphome/nspanel_esphome_datetime.yaml
Added persisted mui_date_format/mui_time_format and defaults; removed meridiem globals; added restartable render_date script; updated refresh_datetime to use render_date and a token-replace helper.
Pages — alarm / confirm / climate / settings / weather / cover
esphome/nspanel_esphome_page_alarm.yaml, esphome/nspanel_esphome_page_confirm.yaml, esphome/nspanel_esphome_page_climate.yaml, esphome/nspanel_esphome_page_settings.yaml, esphome/nspanel_esphome_page_weather.yaml, esphome/nspanel_esphome_page_cover.yaml
Removed per-call mui_alarm and mui_please_confirm persisted strings; replaced button labels and wrapText byte-widths with compile-time ${LANG_ALARM_*} and ${LANG_BYTES_PER_CHAR}; removed cover page scripts; added weather page scripts and lifecycle hooks invoking render_date.
Bytes-per-char migration
esphome/nspanel_esphome_hw_display.yaml, esphome/nspanel_esphome_page_buttons.yaml, esphome/nspanel_esphome_page_media_player.yaml, esphome/nspanel_esphome_page_notification.yaml
Removed bytes_per_char substitution/global and replaced id(mui_bytes_per_char) references with ${LANG_BYTES_PER_CHAR} in wrapText calls.
Home page cleanup
esphome/nspanel_esphome_page_home.yaml
Removed persisted time/meridiem globals (functionality migrated to datetime/render_date logic).
Boot / display init
esphome/nspanel_esphome_boot.yaml
Reordered boot progress steps; switched to script.execute/wait; added explicit display-settings stage that sends Nextion brightness/dim/sleep and sets wakeup_page_id.
HMI updates (version, QR, scope)
hmi/dev/.../boot.txt, hmi/dev/.../qrcode.txt, hmi/dev/.../settings.txt
Bumped HMI version Text attribute 10→11 across variants; increased QR Max. Text Size 70→78; changed several Text component Scope attributes from globallocal.

Sequence Diagram(s)

sequenceDiagram
    participant HA as Home Assistant
    participant API as esphome API (component_text)
    participant Pre as Preprocessor (lambda)
    participant Local as Localization substitutions
    participant HMI as HMI/display script

    HA->>API: call component_text(txt)
    API->>Pre: forward txt
    Pre->>Local: lookup SENTINEL or LOCALIZATION[LANG]
    Local-->>Pre: replaced txt_str
    Pre->>API: execute action_component_text with txt_str
    API->>HMI: update display component text
    HMI-->>HA: ack/update visual
Loading
sequenceDiagram
    participant Page as Page controller (page_weather)
    participant Render as render_date script
    participant Local as Localization substitutions
    participant Display as HMI/display component

    Page->>Render: execute(component="home.date", timestamp)
    Render->>Local: substitute %A/%a/%B/%b tokens from LOCALIZATION[LANG]
    Local-->>Render: formatted tokens
    Render->>Display: set component text (rendered date)
    Display-->>Page: done
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰
I nibble constants, swap runtime for compile,
Substitutions hum and labels wear new style.
render_date hops, weekdays learn to rhyme,
Globals curl up — localization in good time.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly describes the main change: moving localization to compile-time substitutions in ESPHome. This aligns with the primary objective of the PR and is specific and actionable.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v9999.99.9

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can disable the changed files summary in the walkthrough.

Disable the reviews.changed_files_summary setting to disable the changed files summary in the walkthrough.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/addon_climate.md (1)

82-82: ⚠️ Potential issue | 🟠 Major

Fix markdown table pipe style to unblock CI.

Line 82 has spacing before a pipe that violates MD060 (table-column-style) and currently fails validation.

Proposed fix
-temp_min|Optional|Number representing a temperature in the selected unit|*cool: `15` (°C) or `60` (°F)*<br>*heat: `7` (°C) or `45` (°F)*<br>*dual: `7` (°C) or `45` (°F)* |The minimum temperature the climate device can reach. Used to set the range of the frontend gauge.
+temp_min|Optional|Number representing a temperature in the selected unit|*cool: `15` (°C) or `60` (°F)*<br>*heat: `7` (°C) or `45` (°F)*<br>*dual: `7` (°C) or `45` (°F)*|The minimum temperature the climate device can reach. Used to set the range of the frontend gauge.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/addon_climate.md` at line 82, The table row for the "temp_min" field has
stray spaces before pipe characters which violates MD060; edit the markdown row
containing "temp_min" so all pipe separators are flush (no spaces immediately
before '|'), ensuring the columns use consistent pipe style (e.g., change
"temp_min | Optional | ..." to "temp_min|Optional|..."). Keep the cell content
unchanged other than removing the extra spaces around the pipes so the table
validates.
🧹 Nitpick comments (3)
esphome/nspanel_esphome_api.yaml (1)

75-82: Consider using else if chain for clarity and minor efficiency.

The sentinel replacement logic uses three independent if statements. Since txt_str can only match one sentinel value at a time, an else if chain would be slightly clearer about the mutually exclusive nature and avoid unnecessary string comparisons.

♻️ Suggested optimization
             std::string txt_str = std::string(txt);
-            if (txt_str == "${SENTINEL_UNAVAILABLE}") txt_str = "${LOCALIZATION[LANG].unavailable}";
-            if (txt_str == "${SENTINEL_UNKNOWN}") txt_str = "${LOCALIZATION[LANG].unknown}";
-            if (txt_str == "${SENTINEL_NO_NAME}") txt_str = "${LOCALIZATION[LANG].no_name}";
+            if (txt_str == "${SENTINEL_UNAVAILABLE}") {
+              txt_str = "${LOCALIZATION[LANG].unavailable}";
+            } else if (txt_str == "${SENTINEL_UNKNOWN}") {
+              txt_str = "${LOCALIZATION[LANG].unknown}";
+            } else if (txt_str == "${SENTINEL_NO_NAME}") {
+              txt_str = "${LOCALIZATION[LANG].no_name}";
+            }
             action_component_text->execute(
               page.c_str(),
               id.c_str(),
               txt_str.c_str()
             );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@esphome/nspanel_esphome_api.yaml` around lines 75 - 82, The
sentinel-replacement block that sets txt_str currently uses three independent if
checks (txt_str == "${SENTINEL_UNAVAILABLE}", "${SENTINEL_UNKNOWN}",
"${SENTINEL_NO_NAME}"); change these to an if / else if / else if chain so only
the first matching sentinel triggers replacement (leave the replacement strings
using LOCALIZATION[LANG] and the subsequent call to
action_component_text->execute(page.c_str(), id.c_str(), txt_str.c_str())
unchanged), preserving behavior but avoiding redundant comparisons.
docs/migration_from_blackymas.md (1)

126-126: Inconsistent quoting in table.

The language row uses single quotes ('language') while other rows use backticks for code formatting. This should be consistent with the rest of the table.

📝 Suggested fix
-| 'language' | Selected via Blueprint dropdown | Set as `language: xx` substitution in ESPHome YAML - see [Localization](localization.md) |
+| `language` | Selected via Blueprint dropdown | Set as `language: xx` substitution in ESPHome YAML - see [Localization](localization.md) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/migration_from_blackymas.md` at line 126, The table row is inconsistent:
change the single-quoted cell 'language' to use backticks like the other rows
(i.e., replace 'language' with `language`) so the code formatting matches the
rest of the table; update the same table line containing the string 'language'
to use backtick quoting.
docs/localization.md (1)

92-93: Add newline at end of file.

The file is missing a trailing newline after the last line. Per coding guidelines, files should end with a newline character.

📝 Suggested fix
 If your language is not listed, please [open a feature request](https://github.com/edwardtfn/NSPanel-Easy/issues/new)
 and it will be added in a future release.
+
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/localization.md` around lines 92 - 93, The file ending with the line "If
your language is not listed, please [open a feature
request](https://github.com/edwardtfn/NSPanel-Easy/issues/new) and it will be
added in a future release." is missing a trailing newline; open the file
containing that exact sentence and add a single newline character at the end of
the file so the file ends with a newline (ensure your editor or pre-commit
trims/retains trailing newline correctly).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@esphome/nspanel_esphome_datetime.yaml`:
- Around line 169-178: The replace_token helper only replaces the first
occurrence of a token in date_str; update the lambda used around
id(mui_date_format) so it repeatedly finds and replaces all occurrences (e.g.,
loop while str.find(token) != npos and replace each found instance) for each
call (tokens "%A", "%a", "%B", "%b") so formats like "%A %d (%A)" or "%b / %b"
are fully expanded.

In `@esphome/nspanel_esphome_page_weather.yaml`:
- Around line 63-69: The timestamp calculation currently adds page_index *
${SECONDS_PER_DAY} to the current epoch which can cross DST boundaries; instead
compute a stable local-day anchor at local noon and add page_index days to that
anchor. Locate the code around PAGE_WEATHER01_ID and SECONDS_PER_DAY where
timestamp is set (uses id(time_provider).now().timestamp), convert the current
instant to local date/time, build an anchor timestamp for that local date at
12:00 (noon) and then compute timestamp = anchor_noon + (page_index *
${SECONDS_PER_DAY}); keep the rest of the logic (page_index bounds check and
logging) unchanged.

In `@hmi/dev/nspanel_CJK_eu_code/boot.txt`:
- Line 63: Update the boot variant's min_tft_version by changing the "Text      
: 10" entry in hmi/dev/nspanel_easy_landscape/boot.txt to "Text          : 11"
so it matches the other updated variants and passes the version compatibility
check.

---

Outside diff comments:
In `@docs/addon_climate.md`:
- Line 82: The table row for the "temp_min" field has stray spaces before pipe
characters which violates MD060; edit the markdown row containing "temp_min" so
all pipe separators are flush (no spaces immediately before '|'), ensuring the
columns use consistent pipe style (e.g., change "temp_min | Optional | ..." to
"temp_min|Optional|..."). Keep the cell content unchanged other than removing
the extra spaces around the pipes so the table validates.

---

Nitpick comments:
In `@docs/localization.md`:
- Around line 92-93: The file ending with the line "If your language is not
listed, please [open a feature
request](https://github.com/edwardtfn/NSPanel-Easy/issues/new) and it will be
added in a future release." is missing a trailing newline; open the file
containing that exact sentence and add a single newline character at the end of
the file so the file ends with a newline (ensure your editor or pre-commit
trims/retains trailing newline correctly).

In `@docs/migration_from_blackymas.md`:
- Line 126: The table row is inconsistent: change the single-quoted cell
'language' to use backticks like the other rows (i.e., replace 'language' with
`language`) so the code formatting matches the rest of the table; update the
same table line containing the string 'language' to use backtick quoting.

In `@esphome/nspanel_esphome_api.yaml`:
- Around line 75-82: The sentinel-replacement block that sets txt_str currently
uses three independent if checks (txt_str == "${SENTINEL_UNAVAILABLE}",
"${SENTINEL_UNKNOWN}", "${SENTINEL_NO_NAME}"); change these to an if / else if /
else if chain so only the first matching sentinel triggers replacement (leave
the replacement strings using LOCALIZATION[LANG] and the subsequent call to
action_component_text->execute(page.c_str(), id.c_str(), txt_str.c_str())
unchanged), preserving behavior but avoiding redundant comparisons.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1ec2f139-c741-408e-93da-51be8498c62c

📥 Commits

Reviewing files that changed from the base of the PR and between dc6c18f and fb45784.

📒 Files selected for processing (54)
  • docs/addon_climate.md
  • docs/addon_upload_tft.md
  • docs/api.md
  • docs/blueprint.md
  • docs/customization.md
  • docs/install.md
  • docs/localization.md
  • docs/migration_from_blackymas.md
  • esphome/nspanel_esphome_api.yaml
  • esphome/nspanel_esphome_datetime.yaml
  • esphome/nspanel_esphome_hw_display.yaml
  • esphome/nspanel_esphome_localization.yaml
  • esphome/nspanel_esphome_page_alarm.yaml
  • esphome/nspanel_esphome_page_buttons.yaml
  • esphome/nspanel_esphome_page_climate.yaml
  • esphome/nspanel_esphome_page_confirm.yaml
  • esphome/nspanel_esphome_page_cover.yaml
  • esphome/nspanel_esphome_page_home.yaml
  • esphome/nspanel_esphome_page_media_player.yaml
  • esphome/nspanel_esphome_page_notification.yaml
  • esphome/nspanel_esphome_page_settings.yaml
  • esphome/nspanel_esphome_page_weather.yaml
  • esphome/nspanel_esphome_version.yaml
  • hmi/dev/nspanel_CJK_eu_code/boot.txt
  • hmi/dev/nspanel_CJK_eu_code/qrcode.txt
  • hmi/dev/nspanel_CJK_eu_code/settings.txt
  • hmi/dev/nspanel_CJK_us_code/boot.txt
  • hmi/dev/nspanel_CJK_us_code/qrcode.txt
  • hmi/dev/nspanel_CJK_us_code/settings.txt
  • hmi/dev/nspanel_CJK_us_land_code/boot.txt
  • hmi/dev/nspanel_CJK_us_land_code/qrcode.txt
  • hmi/dev/nspanel_CJK_us_land_code/settings.txt
  • hmi/dev/nspanel_eu_code/boot.txt
  • hmi/dev/nspanel_eu_code/qrcode.txt
  • hmi/dev/nspanel_eu_code/settings.txt
  • hmi/dev/nspanel_us_code/boot.txt
  • hmi/dev/nspanel_us_code/qrcode.txt
  • hmi/dev/nspanel_us_code/settings.txt
  • hmi/dev/nspanel_us_land_code/boot.txt
  • hmi/dev/nspanel_us_land_code/qrcode.txt
  • hmi/dev/nspanel_us_land_code/settings.txt
  • hmi/nspanel_CJK_eu.HMI
  • hmi/nspanel_CJK_eu.tft
  • hmi/nspanel_CJK_us.HMI
  • hmi/nspanel_CJK_us.tft
  • hmi/nspanel_CJK_us_land.HMI
  • hmi/nspanel_CJK_us_land.tft
  • hmi/nspanel_eu.HMI
  • hmi/nspanel_eu.tft
  • hmi/nspanel_us.HMI
  • hmi/nspanel_us.tft
  • hmi/nspanel_us_land.HMI
  • hmi/nspanel_us_land.tft
  • nspanel_easy_blueprint.yaml
💤 Files with no reviewable changes (4)
  • docs/api.md
  • esphome/nspanel_esphome_hw_display.yaml
  • esphome/nspanel_esphome_page_cover.yaml
  • esphome/nspanel_esphome_page_home.yaml

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/addon_climate.md`:
- Line 82: The table row for the "temp_min" column contains an unescaped pipe
inside the cell text ("device | can reach") which splits the row into an extra
column and triggers MD056; update the "temp_min" table cell to escape the pipe
(e.g., replace "device | can reach" with "device \| can reach") or wrap that
phrase in code/backticks so the pipe is treated as literal, ensuring the row
remains the intended number of columns and the table renders correctly.
- Around line 72-89: The table in the PR uses non-compact pipe spacing which
triggers MD060; update the table rows to use compact pipe spacing (single space
around pipes) so the header/separator and all data rows are consistent —
specifically modify the header row "| Key | Required | Supported values |
Default | Description |", the separator row currently formatted as "| :-  | :-: 
| :-:              | :-:     | :-          |" to a compact form like "| :- | :-:
| :-: | :-: | :- |", and normalize every data row (including the "~temp_step~"
deprecated row and rows containing multi-line defaults like temp_min/temp_max)
to have single spaces around pipes and no extra internal spacing so markdownlint
MD060 passes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c32969ae-af25-461d-bd58-78a26d547320

📥 Commits

Reviewing files that changed from the base of the PR and between fb45784 and 77e10fb.

📒 Files selected for processing (3)
  • docs/addon_climate.md
  • docs/api.md
  • docs/blueprint.md
✅ Files skipped from review due to trivial changes (1)
  • docs/blueprint.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/api.md

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
esphome/nspanel_esphome_datetime.yaml (1)

74-112: ⚠️ Potential issue | 🟡 Minor

Handle repeated time tokens the same way as repeated date tokens.

mui_time_format is user-editable, but %-H, %-I, and %p are each processed only once here. Formats like %-I:%M (%-I) or %p %I:%M %p will still leave a raw/untranslated token in the rendered output, and the home.time path still keeps leading whitespace when %p is used as a prefix. Please switch these to the same looped replacement strategy you already use in render_date, and trim both ends after stripping %p for home.time.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@esphome/nspanel_esphome_datetime.yaml` around lines 74 - 112, The code only
replaces %-H, %-I and %p once, causing leftover tokens for repeated occurrences;
update the replacement logic in the blocks using time_format_str (and its copies
time_format_str_sleep and time_format_str_home) to repeatedly replace all
occurrences of "%-H" and "%-I" and to replace all "%p" instances the same way
render_date does (i.e., loop until find returns npos), and after
removing/replacing "%p" for time_format_str_home and the final home.time text
trim both leading and trailing whitespace before calling
disp1->set_component_text("home.meridiem", ...); reference symbols:
time_format_str, time_format_str_sleep, time_format_str_home, "%-H", "%-I",
"%p", render_date, home.time, home.meridiem.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@esphome/nspanel_esphome_datetime.yaml`:
- Around line 74-112: The code only replaces %-H, %-I and %p once, causing
leftover tokens for repeated occurrences; update the replacement logic in the
blocks using time_format_str (and its copies time_format_str_sleep and
time_format_str_home) to repeatedly replace all occurrences of "%-H" and "%-I"
and to replace all "%p" instances the same way render_date does (i.e., loop
until find returns npos), and after removing/replacing "%p" for
time_format_str_home and the final home.time text trim both leading and trailing
whitespace before calling disp1->set_component_text("home.meridiem", ...);
reference symbols: time_format_str, time_format_str_sleep, time_format_str_home,
"%-H", "%-I", "%p", render_date, home.time, home.meridiem.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8db41b6c-9355-4f4b-8c6d-ddf08a2652c3

📥 Commits

Reviewing files that changed from the base of the PR and between 023ecb7 and 045400f.

📒 Files selected for processing (7)
  • docs/migration_from_blackymas.md
  • esphome/nspanel_esphome_api.yaml
  • esphome/nspanel_esphome_datetime.yaml
  • esphome/nspanel_esphome_page_weather.yaml
  • hmi/dev/nspanel_easy_landscape/boot.txt
  • hmi/nspanel_easy_landscape.hmi
  • hmi/nspanel_easy_landscape.tft
✅ Files skipped from review due to trivial changes (3)
  • hmi/dev/nspanel_easy_landscape/boot.txt
  • docs/migration_from_blackymas.md
  • esphome/nspanel_esphome_page_weather.yaml

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@esphome/nspanel_esphome_boot.yaml`:
- Around line 153-160: The lambda in boot_nextion emits step 5 before
boot_progress is initialized, causing the progress bar to jump; remove the
boot_progress->execute(5) call from the lambda (the block that contains
boot_log, disp1->send_command_printf(...), and
get_page_id(wakeup_page_name->current_option())) and instead invoke
boot_progress->execute(5) from the caller after the boot script (boot) has reset
progress to 0; locate the call by looking for the boot_nextion lambda and the
boot_progress symbol and move the step update into the caller immediately after
the initial progress reset.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 01c99351-4a41-4331-800a-40ac7891ffd8

📥 Commits

Reviewing files that changed from the base of the PR and between 045400f and e95c1bb.

📒 Files selected for processing (4)
  • esphome/nspanel_esphome_boot.yaml
  • esphome/nspanel_esphome_datetime.yaml
  • esphome/nspanel_esphome_page_settings.yaml
  • nspanel_easy_blueprint.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • esphome/nspanel_esphome_datetime.yaml

@edwardtfn
Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 22, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@edwardtfn
Copy link
Copy Markdown
Owner Author

@coderabbitai resume

@edwardtfn edwardtfn enabled auto-merge March 22, 2026 07:34
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
esphome/nspanel_esphome_datetime.yaml (1)

170-178: Consider extracting duplicated replace_token helper.

The replace_token lambda is defined identically in both refresh_datetime (lines 76-84) and render_date (lines 170-178). While functional, this duplication increases maintenance burden.

You could define a reusable C++ helper function in a shared location or accept the duplication given the lambdas are self-contained.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@esphome/nspanel_esphome_datetime.yaml` around lines 170 - 178, The duplicated
replace_token lambda used in refresh_datetime and render_date should be
extracted into a single helper function to avoid duplication; create a
free/static helper like replace_token(std::string& str, const char* token, const
char* value) (or put it in the appropriate namespace) and replace both lambda
definitions in refresh_datetime and render_date with calls to that helper,
keeping the same behavior (find/replace loop using strlen and pos advancement)
so callers remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@esphome/nspanel_esphome_datetime.yaml`:
- Around line 170-178: The duplicated replace_token lambda used in
refresh_datetime and render_date should be extracted into a single helper
function to avoid duplication; create a free/static helper like
replace_token(std::string& str, const char* token, const char* value) (or put it
in the appropriate namespace) and replace both lambda definitions in
refresh_datetime and render_date with calls to that helper, keeping the same
behavior (find/replace loop using strlen and pos advancement) so callers remain
unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ceaeff20-db51-4d2f-8193-1d0352f169b5

📥 Commits

Reviewing files that changed from the base of the PR and between 045400f and e9e5292.

📒 Files selected for processing (4)
  • esphome/nspanel_esphome_boot.yaml
  • esphome/nspanel_esphome_datetime.yaml
  • esphome/nspanel_esphome_page_settings.yaml
  • nspanel_easy_blueprint.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • esphome/nspanel_esphome_page_settings.yaml

@edwardtfn edwardtfn merged commit aa0ebb6 into main Mar 22, 2026
32 checks passed
@edwardtfn edwardtfn deleted the v9999.99.9 branch March 22, 2026 07:35
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 22, 2026

✅ Actions performed

Reviews resumed.

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.

1 participant