Skip to content

fix: port standalone display safety to contribution staging - #24

Merged
flowcool merged 1 commit into
upstream/staging-v2r1from
upstream/standalone-safety
Oct 20, 2026
Merged

flowcool merged 1 commit into
upstream/staging-v2r1from
upstream/standalone-safety

Conversation

@flowcool

@flowcool flowcool commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

Behavior

Port the standalone safety follow-up requested in upstream PR29 (infra-3rr.58), already delivered on fork V2R1 in PR18. Missing and nonfinite readings show --; numeric readings stay raw while needles/icons clamp. Boot runs after display setup. A shared recovery timer bounds BUSY retries and reaches the emergency sleep action without another refresh.

Target: flowcool/Smart_Plant:upstream/staging-v2r1, base 4fccab1989a4c1f12022dadbbc34cc36ecdc04fc, source 408de7b. This does not publish to JGAguado or deploy firmware. Both normal and fault sleep retain explicit OTA image confirmation and native shutdown hooks. The 30.510s bound plus scheduling ends at the sleep action, not physical sleep.

Verification

  • python3 -B -m unittest discover -s tests -v: 49 tests pass, including actual renderer UBSan/extreme values and actual-YAML BUSY scenarios.
  • All 8 tracked YAML files parse. Strict Sphinx HTML build passes. git -c core.whitespace=cr-at-eol diff --check passes; existing RST CRLF is preserved.
  • Complete isolated ESPHome2026.9.0 ESP32-S2 standalone firmware build passes, config hash 0xadf7c688; local font/public image fixtures and synthetic credentials only. This proves compilation, not hardware behavior.
  • Rollback: revert this isolated PR on staging. No fleet/NAS/shared-builder/MQTT/HA action.

AI assistance

Codex ported the existing reviewed change. The author inspected the source, action ordering, compatibility guard, tests and line endings.

CodeRabbit review

Current-head review and required yaml-syntax must pass before merge. Record review/head in the delivery note. Owner: infra-3rr.64.

Summary by CodeRabbit

  • Améliorations

    • L’affichage de la batterie et des jauges gère désormais les valeurs absentes, invalides ou non finies avec des indicateurs clairs.
    • Les jauges et icônes restent dans leurs limites visuelles, tout en conservant la valeur mesurée pour l’étiquette.
    • La mise en veille attend désormais la confirmation de l’écran et tente une récupération en cas de blocage avant d’activer une veille de secours.
  • Documentation

    • Ajout d’informations sur la validation des valeurs, le fonctionnement de la mise en veille et la récupération après incident.

@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: 142e55a9-f247-4c7f-8adf-36e54c9f9db0
📥 Commits

Reviewing files that changed from the base of the PR and between 4fccab1 and 408de7b.

📒 Files selected for processing: 4
  • docs/source/files/configuration.yaml
  • docs/source/programming.rst
  • tests/display_automation.py
  • tests/test_standalone_display.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: 3
.claude/rules/esphome-yaml.md — auto-discovered
.claude/rules/nas-operations.md — auto-discovered
AGENTS.md — auto-discovered
📓 Path-based instructions: 3
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:

  • docs/source/files/configuration.yaml
Source excerpt: ESPHome's native guard (`>=2026.8.0`) confirms the app image on any orderly `deep_sleep.enter`, so a short measurement cycle is no longer misclassified as a failed OTA boot; `smart_plant_core.yaml` no longer calls `safe_mode...

📄 CodeRabbit inference engine (.claude/rules/nas-operations.md)

Files:

  • docs/source/files/configuration.yaml
Source excerpt: Parse changed YAML and run `git diff --check`; inspect both `git diff --numstat` and the semantic diff before committing.

📄 CodeRabbit inference engine (AGENTS.md)

Files:

  • docs/source/files/configuration.yaml
🪛 ast-grep (0.45.3)
tests/display_automation.py

[warning] 32-32: avoid deserializing untrusted YAML
Context: yaml.load((Path(root) / "docs/source/files/configuration.yaml").read_text(), PackageLoader)
Note: [CWE-502] Deserialization of Untrusted Data.

(yaml-load)

[warning] 36-36: avoid deserializing untrusted YAML
Context: yaml.load((packages / "smart_plant_core.yaml").read_text(), PackageLoader)
Note: [CWE-502] Deserialization of Untrusted Data.

(yaml-load)

[warning] 37-39: avoid deserializing untrusted YAML
Context: yaml.load(
(packages / f"smart_plant_profile_{profile}.yaml").read_text(), PackageLoader
)
Note: [CWE-502] Deserialization of Untrusted Data.

(yaml-load)

tests/test_standalone_display.py

[warning] 54-54: avoid deserializing untrusted YAML
Context: yaml.load(PUBLIC.read_text(), PackageLoader)
Note: [CWE-502] Deserialization of Untrusted Data.

(yaml-load)

[error] 62-63: Command coming from incoming request
Context: subprocess.run(["c++", "-std=c++20", "-fsanitize=undefined,float-cast-overflow",
"-fno-sanitize-recover=all", str(source), "-o", str(cls.executable)], check=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

[error] 68-68: Command coming from incoming request
Context: subprocess.run([str(self.executable), *args], check=True, text=True, capture_output=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

[warning] 127-127: avoid deserializing untrusted YAML
Context: yaml.load(PUBLIC.read_text(), PackageLoader)
Note: [CWE-502] Deserialization of Untrusted Data.

(yaml-load)

🪛 OpenGrep (1.30.1)
tests/display_automation.py

[ERROR] 32-32: yaml.load() without SafeLoader can execute arbitrary Python code. Use yaml.safe_load() or yaml.load(..., Loader=SafeLoader) instead.

(coderabbit.deserialization.python-yaml-unsafe-load)

[ERROR] 36-36: yaml.load() without SafeLoader can execute arbitrary Python code. Use yaml.safe_load() or yaml.load(..., Loader=SafeLoader) instead.

(coderabbit.deserialization.python-yaml-unsafe-load)

[ERROR] 37-39: yaml.load() without SafeLoader can execute arbitrary Python code. Use yaml.safe_load() or yaml.load(..., Loader=SafeLoader) instead.

(coderabbit.deserialization.python-yaml-unsafe-load)

tests/test_standalone_display.py

[ERROR] 54-54: yaml.load() without SafeLoader can execute arbitrary Python code. Use yaml.safe_load() or yaml.load(..., Loader=SafeLoader) instead.

(coderabbit.deserialization.python-yaml-unsafe-load)

[ERROR] 127-127: yaml.load() without SafeLoader can execute arbitrary Python code. Use yaml.safe_load() or yaml.load(..., Loader=SafeLoader) instead.

(coderabbit.deserialization.python-yaml-unsafe-load)

🪛 Ruff (0.16.9)
tests/display_automation.py

[error] 32-32: Probable use of unsafe loader PackageLoader with yaml.load. Allows instantiation of arbitrary objects. Consider yaml.safe_load.

(S506)

[error] 36-36: Probable use of unsafe loader PackageLoader with yaml.load. Allows instantiation of arbitrary objects. Consider yaml.safe_load.

(S506)

[error] 38-38: Probable use of unsafe loader PackageLoader with yaml.load. Allows instantiation of arbitrary objects. Consider yaml.safe_load.

(S506)

tests/test_standalone_display.py

[error] 54-54: Probable use of unsafe loader PackageLoader with yaml.load. Allows instantiation of arbitrary objects. Consider yaml.safe_load.

(S506)

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

(S603)

[error] 62-63: Starting a process with a partial executable path

(S607)

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

Add explicit value for parameter strict=

(B905)

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

(S603)

[error] 127-127: Probable use of unsafe loader PackageLoader with yaml.load. Allows instantiation of arbitrary objects. Consider yaml.safe_load.

(S506)

[warning] 170-170: Function definition does not bind loop variable cancel

(B023)

🔇 Additional comments: 6
docs/source/files/configuration.yaml: 3

9-13: LGTM!

Also applies to: 24-25, 201-202

222-238: LGTM!

Also applies to: 252-282

289-306: LGTM!

Also applies to: 315-341, 342-375, 376-409, 410-444, 445-476

tests/display_automation.py: 1

30-39: LGTM!

Also applies to: 70-71, 109-110, 130-130

tests/test_standalone_display.py: 1

1-181: LGTM!

docs/source/programming.rst: 1

64-76: LGTM!

Walkthrough

Le rendu vérifie les mesures avant conversion et borne les éléments graphiques sans modifier les valeurs affichées. Le cycle de veille surveille BUSY, tente une récupération avec RESET en cas d’échec, puis autorise ou force l’entrée en veille.

Changes

Rendu fiable et veille contrôlée

Layer / File(s) Summary
Rendu et validation autonome
docs/source/files/configuration.yaml, tests/display_automation.py, tests/test_standalone_display.py
Le rendu vérifie les mesures de batterie et de capteurs avant conversion. Les valeurs invalides affichent des espaces réservés. Les valeurs valides restent intactes dans les libellés, tandis que les aiguilles et l’icône sont bornées. Le mode autonome charge le YAML réel et les tests vérifient ces cas.
Stabilisation BUSY et mise en veille
docs/source/files/configuration.yaml, docs/source/programming.rst, tests/display_automation.py, tests/test_standalone_display.py
Le cycle de veille attend l’assertion puis la libération de BUSY. Si la stabilisation échoue, le flux tente une récupération, puis une réinitialisation et une veille forcée. Les tests vérifient les délais, les transitions et l’annulation des tâches lors d’un nouveau rafraîchissement. La documentation décrit les limites temporelles et le chemin de mise en veille.

Priority: ⬇️ Low

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant prepare_display_refresh
  participant settle_display
  participant BUSY_GPIO
  participant deep_sleep.enter
  prepare_display_refresh->>settle_display: prépare le suivi BUSY après le rafraîchissement
  settle_display->>BUSY_GPIO: attend l’assertion puis la libération
  BUSY_GPIO-->>settle_display: transmet l’état BUSY
  settle_display->>deep_sleep.enter: autorise la veille si BUSY est stable
Loading

Suggested reviewers: jgaguado

Merge Risk: ⚪ Minimal · up to 408de

This change makes the plant display show "--" for missing or invalid readings without corrupting gauges. It also adds a bounded, BUSY-aware sleep sequence with a reset-and-force-sleep fallback. Review found no remaining merge-blocking issues, and on-device behavior beyond the reported compile and test checks has not been shown here.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 2 files. (2 skipped: 2… 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 le changement principal : le portage des corrections de sécurité de l’affichage autonome vers la branche de staging.
Description check Passed La description couvre le comportement, la vérification, l’assistance IA et les exigences de revue CodeRabbit. Elle précise les résultats des tests, les limites de validation matérielle et la procédure…
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 et les exigences de revue CodeRabbit. Elle précise les résultats des tests, les limites de validation matérielle et la procédure de retour arrière. Les cases de suivi CodeRabbit et le lien de revue restent à compléter avant la fusion.

Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 2 files. (2 skipped: 2 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 veille près de l’écran,
Les aiguilles restent dans leurs bornes,
BUSY répond, le calme revient,
RESET pulse si l’écran s’attarde,
Puis le terrier dort jusqu’au matin.

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

@flowcool

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@flowcool
flowcool merged commit 79cc98c into upstream/staging-v2r1 Oct 20, 2026
2 checks passed
@flowcool
flowcool deleted the upstream/standalone-safety branch October 20, 2026 19:20
@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Pull request is closed.

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.

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