Skip to content

feat: add generic label geometry with explicit display scales - #31

Merged
flowcool merged 2 commits into
upstream/staging-v2r1from
upstream/generic-label-generator
Oct 20, 2026
Merged

flowcool merged 2 commits into
upstream/staging-v2r1from
upstream/generic-label-generator

Conversation

@flowcool

@flowcool flowcool commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

Behavior

Extract the reusable portion of fork PR #13. YAML input defines recommendation bands and optional display scales; the renderer emits a 1-bit 296x128 PNG plus matching substitutions. Correct the band endpoint to the actual 135-degree runtime start angle. Preserve staging defaults, exclude all real inventory/MAC/HA snapshots/artwork. Retain original JGAguado Label-maker MIT notice.

Target: flowcool/Smart_Plant:upstream/staging-v2r1. Sources 610cb60 and f788535, predecessor f426584. Open after the preceding contribution merges so this PR contains only its owned change. The upstream baseline is bcf373144b2d5c7e3a712fd02698e2e98e45aeed. No PR to JGAguado is authorized.

Verification

Four tests pass both with system libraries and pinned requirements Pillow 12.3.0, pycairo 1.29.1 and PyYAML 6.0.3. They execute the actual firmware gauge C++, compare default/custom scales and arc endpoints, reject invalid/unsupported inputs before output, and render twice byte-identically. The synthetic label was visually inspected.

Inspect the semantic diff and git -c core.whitespace=cr-at-eol diff --check; preserve existing line endings. All tracked YAML parses. Firmware fixtures use local fonts/public images and synthetic credentials, never devices or shared builders. Local compilation does not prove deployment.

Rollback: revert this isolated PR on staging. No automatic deployment, fleet/NAS/cache purge/MQTT/HA action.

AI assistance

Codex prepared the port or extraction. The author inspected the behavior, contribution boundary, actual-source tests, compatibility and diff. Existing staging OTA confirmation and native shutdown remain intact.

CodeRabbit review

Require current-head completed review and yaml-syntax before merge. Florent approved one manual review request per ignored PR for this series only. Documentation-only PRs use the standing docs gate. Record review/head/checks/merge in owner infra-3rr.71.

Three additional pinned ESPHome package-loader tests pass: generated scales after core win; reversed order and device-level overrides can replace them. The guide makes the required order and removal of conflicting local overrides explicit.

Summary by CodeRabbit

  • Nouvelles fonctionnalités

    • Ajout d’un générateur d’étiquettes monochromes de 296 × 128 pixels pour afficher des jauges de plantes.
    • Prise en charge de métriques configurables, d’échelles personnalisées et de bandes de recommandation.
    • Génération d’images PNG et de substitutions YAML compatibles avec ESPHome.
    • Ajout d’exemples de configuration et de validation des plages de mesures.
  • Documentation

    • Documentation ajoutée pour l’installation, l’utilisation, la configuration et les tests du générateur d’étiquettes.
    • Ajout des informations de licence du générateur d’étiquettes.
  • Tests

    • Ajout de tests couvrant le rendu, les échelles, les substitutions et les configurations invalides.

@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7007da51-472c-4f72-835c-12614e003f26
📥 Commits

Reviewing files that changed from the base of the PR and between 6901f24 and f788535.

📒 Files selected for processing: 11
  • .gitignore
  • examples/multi-device/README.md
  • examples/multi-device/label_maker/LICENSE.Label-maker.txt
  • examples/multi-device/label_maker/README.md
  • examples/multi-device/label_maker/example.yaml
  • examples/multi-device/label_maker/gauge-contract.yaml
  • examples/multi-device/label_maker/requirements.txt
  • scripts/smartplant_gauge_contract.py
  • scripts/smartplant_label_maker.py
  • tests/test_generic_labels.py
  • tests/test_label_packages.py

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review.

📜 Recent review details
🧰 Additional context used
📚 Code guidelines: 1
.claude/rules/esphome-yaml.md — auto-discovered
📓 Path-based instructions: 1
Source excerpt: `use_address` must be in the `wifi:` block of the device YAML, not only in `substitutions:` — the ESPHome CLI reads YAML without resolving packages.

📄 CodeRabbit inference engine (.claude/rules/esphome-yaml.md)

Files:

  • examples/multi-device/label_maker/example.yaml
  • examples/multi-device/label_maker/gauge-contract.yaml
🪛 ast-grep (0.45.3)
tests/test_generic_labels.py

[error] 42-43: Command coming from incoming request
Context: subprocess.run([str(self.executable), str(midpoint), "1", *map(str, metrics[metric]["scale"]),
"%.1f", *map(str, geometry["position"])], check=True, capture_output=True, text=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

[error] 59-60: Command coming from incoming request
Context: subprocess.run([str(self.executable), str(midpoint), "1", *map(str, metrics[metric]["scale"]),
"%.1f", *map(str, position)], check=True, capture_output=True, text=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

[error] 73-75: Command coming from incoming request
Context: subprocess.run([sys.executable, str(ROOT / "scripts/smartplant_label_maker.py"),
"--config", str(path / "input.yaml"), "--image", str(path / "label.png"),
"--substitutions", str(path / "display.yaml")], capture_output=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

[error] 85-85: Use of unsanitized data to create processes
Context: subprocess.run(command, check=True, capture_output=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(os-system-unsanitized-data)

[error] 85-85: Command coming from incoming request
Context: subprocess.run(command, check=True, capture_output=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

[error] 87-87: Use of unsanitized data to create processes
Context: subprocess.run(command, check=True, capture_output=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(os-system-unsanitized-data)

[error] 87-87: Command coming from incoming request
Context: subprocess.run(command, check=True, capture_output=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

🪛 Ruff (0.16.9)
tests/test_generic_labels.py

[warning] 33-33: zip() without an explicit strict= parameter

Add explicit value for parameter strict=

(B905)

[error] 42-42: subprocess call: check for execution of untrusted input

(S603)

[error] 59-59: subprocess call: check for execution of untrusted input

(S603)

[error] 73-73: subprocess call: check for execution of untrusted input

(S603)

[error] 85-85: subprocess call: check for execution of untrusted input

(S603)

[error] 87-87: subprocess call: check for execution of untrusted input

(S603)

🔇 Additional comments: 11
scripts/smartplant_gauge_contract.py: 1

1-56: LGTM!

examples/multi-device/label_maker/gauge-contract.yaml: 1

1-39: LGTM!

examples/multi-device/label_maker/example.yaml: 1

1-19: LGTM!

examples/multi-device/label_maker/requirements.txt: 1

1-3: LGTM!

examples/multi-device/label_maker/README.md: 1

1-58: LGTM!

examples/multi-device/README.md: 1

197-202: LGTM!

examples/multi-device/label_maker/LICENSE.Label-maker.txt: 1

1-21: LGTM!

.gitignore: 1

12-14: LGTM!

scripts/smartplant_label_maker.py: 1

1-141: LGTM!

tests/test_generic_labels.py: 1

1-97: LGTM!

tests/test_label_packages.py: 1

1-48: LGTM!

Walkthrough

Le dépôt ajoute un contrat de jauges configurable, un générateur d’étiquettes monochromes de 296 × 128 pixels et des substitutions d’échelle. Des exemples et des tests couvrent la validation des métriques, le rendu et l’ordre des paquets ESPHome.

Changes

Génération d’étiquettes

Layer / File(s) Summary
Contrat des jauges et configuration d’exemple
scripts/smartplant_gauge_contract.py, examples/multi-device/label_maker/*, examples/multi-device/README.md, .gitignore
Le contrat charge et valide quatre métriques, leurs échelles et leurs bandes. Les exemples, la documentation et les dépendances décrivent le générateur et ses entrées.
Validation et rendu de l’étiquette
scripts/smartplant_label_maker.py
Le script valide les plages, dessine les jauges et écrit une image monochrome ainsi que les substitutions d’échelle.
Tests du contrat, du rendu et des substitutions
tests/test_generic_labels.py, tests/test_label_packages.py
Les tests vérifient les échelles, les angles, les sorties de la CLI et l’ordre des paquets ESPHome.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant Main as smartplant_label_maker.main
  participant Contract as smartplant_gauge_contract.resolve_metrics
  participant Render as smartplant_label_maker.render_label
  participant Outputs as Fichiers générés
  CLI->>Main: Fournit les chemins de configuration et de sortie
  Main->>Contract: Valide les métriques configurées
  Main->>Render: Demande le rendu de l’étiquette
  Render->>Contract: Résout les métriques pour le rendu et les substitutions
  Render->>Outputs: Écrit l’image et les substitutions
Loading
Merge Risk: ⚪ Minimal · up to f7885

This change adds an optional label generator, example configuration, and tests. No concrete merge-blocking risk was identified.

Security architecture risk: 🔵 Low · up to f7885

The workflow generates local label files and display-scale values without adding device access or credential authority. Firmware adoption remains manual. The main limitation is that interrupted or concurrent generation can leave mismatched output files.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — Within the inspected implementation, configuration content can affect rendered text, bands and numeric display scales. Filesystem exposure is limited by the invoking process's permissions and caller-selected output paths. No device, tenant, credential or fleet authority is introduced by this execution path.

Trust Boundaries and Controls

  • observed — YAML is loaded with safe_load, then metric values are converted to validated numbers before fixed-key serialization with safe_dump. Configuration text is not forwarded as arbitrary ESPHome directives. The CLI also rejects resolved output-path equality and output paths equal to its input configuration.

Resilience and Maintainability Implications

  • inferred — Validation failures precede output publication, but later failures, interruption or concurrent invocations can leave a partial or mixed image/substitution pair because writes are sequential and uncoordinated. The checked downstream effect is display inconsistency after manual adoption; no security-control failure path was established.
Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 5.88% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 4 files. (7 skipped: 7… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed Le titre décrit clairement la modification principale : ajout d’une géométrie générique d’étiquette avec des échelles d’affichage explicites.
Description check Passed La description couvre le comportement, la vérification, l’assistance IA, les limites de portée et les contrôles CodeRabbit. Elle indique les tests exécutés et leurs résultats. Les champs Command, Expe…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

La description couvre le comportement, la vérification, l’assistance IA, les limites de portée et les contrôles CodeRabbit. Elle indique les tests exécutés et leurs résultats. Les champs Command, Expected result et Observed result ne sont pas présentés sous forme explicite, et la preuve de revue CodeRabbit avec URL et SHA reste absente, mais la description est globalement complète.

Full details: Docstring Coverage

Explanation

Docstring coverage is 5.88% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 4 files. (7 skipped: 7 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Un lapin règle les cadrans en douceur,
Quatre métriques prennent place sur l’écran.
L’aiguille suit l’angle calculé,
L’image noir et blanc sort du terrier.
Les substitutions rejoignent le YAML,
Et le lapin bondit, satisfait du résultat.

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

@flowcool

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

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.

@flowcool
flowcool merged commit fa7f1da into upstream/staging-v2r1 Oct 20, 2026
2 checks passed
@flowcool
flowcool deleted the upstream/generic-label-generator branch October 20, 2026 20:12
flowcool added a commit that referenced this pull request Oct 21, 2026
Bring bounded display recovery and safe rendering to the standalone example
flowcool added a commit that referenced this pull request Oct 21, 2026
…very

Drop the globals duplicated by the #31 merge. Let the parity test accept the
multi-device extensions (fault hook, counter, logs, MQTT status) and the
per-profile sleep_after_display. Bound the flow tests by each profile's
on_display_fault delay.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017fn1KdJJTY7LedVqZ7SxcA
flowcool added a commit that referenced this pull request Oct 21, 2026
…duction features (#34)

* feat: expose the running ESPHome version and native config hash

* feat: expose the filtered soil voltage without changing calibration

* fix: preserve raw gauge labels while clamping needles

* fix: recover the missing KiCad symbol library from schematic caches

* feat: add transport-independent low-battery protection

* fix: bound standalone display recovery and invalid rendering

* ci: add firmware tests workflow and CODEOWNERS

Run the unit tests and validate the standalone ESPHome configuration on
every PR. CODEOWNERS keeps hardware, documentation and repository
governance paths under maintainer review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: keep low-battery guide focused on user behavior

* docs: remove trailing empty line from battery guide

* fix: keep recovered KiCad symbol libraries LF on Windows

* fix: align core display recovery and support native tests without UBSan

* test: guard shared recovery parity and fresh timer budgets

* test: make battery display recorder format-security safe

* docs: keep recovery compatibility comments shared between entry points

* fix: make public examples self-contained upstream and validate both transports

* Limit test CI checkout credentials

* feat: add retained MQTT maintenance and storage modes

* test: adapt mode checks to merged soil diagnostics and portable libraries

* fix: reconcile maintenance/storage modes with the shared display recovery

Drop the globals duplicated by the #31 merge. Let the parity test accept the
multi-device extensions (fault hook, counter, logs, MQTT status) and the
per-profile sleep_after_display. Bound the flow tests by each profile's
on_display_fault delay.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017fn1KdJJTY7LedVqZ7SxcA

* feat: generate generic label bands from explicit scales and inputs

* ci: install pinned label renderer dependencies for unit tests

* docs: refresh project entry points and first-install guides

* docs: provide firmware-matched label input and clarify defaults

---------

Co-authored-by: J.G.Aguado <jon.garcia.aguado@gmail.com>
Co-authored-by: J.G.Aguado <jon-garcia@hotmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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