Projet : arcadien/tinySensor — firmware AVR bas-consommation pour capteurs d'environnement sans fil (ATtiny84a, 433 MHz, protocoles Oregon v3 / Lacrosse WS7000 / X10).
Auditeur : Claude (modèle opus 4.7) — revue statique
Date : 19 avril 2026 — mise à jour 19 juin 2026 (voir §1bis)
Périmètre : ensemble du dépôt au commit aa53a83 (branche master) — code firmware (src/, lib/, include/), tests (test/), projet Atmel Studio legacy (TinySensor/), outillage (scripts/, shared/), web builder (web/), hardware (hardware/), CI (.github/workflows/), Docker/devcontainer.
TinySensor est un projet firmware embarqué mature sur le plan fonctionnel (protocoles radio testés, HAL propre, tests unitaires natifs avec Unity, portage PlatformIO). Le code "cœur" (lib/oregon, lib/LacrosseWS7000, lib/x10, HAL) est propre, bien abstrait, testé. La dette se concentre dans trois zones qui pèsent sur la maintenabilité et le risque opérationnel :
D'abord, un secret Coveralls est committé en clair dans .coveralls.yml — il doit être révoqué immédiatement. Ensuite, la CI ne compile aucun firmware AVR (seul l'environnement natif est testé), donc un refactor peut casser silencieusement les builds de production S_02..S_05. Enfin, un second arbre source (TinySensor/, projet Atmel Studio legacy) duplique le code firmware et contient des binaires de build versionnés ; il est une source de divergence certaine et gonfle l'historique git.
Au-delà de ces trois points, la configuration per-device vit sous forme de blocs presque identiques dans platformio.ini (7 environnements avec copier-coller), les dépendances tirent toutes vers des forks personnels non épinglés, l'image Docker php:7.4-apache est EOL (novembre 2022), et plusieurs scripts d'outillage contiennent des chemins absolus spécifiques à l'auteur. L'ensemble est traitable en ~3 sprints d'un développeur à temps partiel, avec les gains de risque concentrés sur les deux premières semaines.
Chiffres clés : 3 779 lignes de code+tests sur ~20 fichiers. 8 suites de tests Unity natives. 1 workflow GitHub Actions (build + test native uniquement). 6 envs PlatformIO pour cibles physiques distinctes. 1 secret exposé. 2 dépendances critiques EOL.
Cette section suit l'évolution de la dette au fil des corrections apportées. Chaque entrée indique l'item résolu, la date, le(s) fichier(s) touché(s) et l'impact sur le score global.
Fichier modifié : .github/workflows/main.yml
Trois items du top-20 traités en une seule PR :
- T1 (36) — CI compile maintenant toutes les cibles AVR. Le workflow a été scindé en deux jobs :
test-native(inchangé) etbuild-avravec matrice[S_02, S_03, S_04, S_05, robot, devmodule, SOLAR_TEST].fail-fast: falsepour isoler les pannes par env. → Résolu. - D2 (30) — Actions et Python mis à jour.
checkout@v4,cache@v4,setup-python@v5, Python3.12(remplace 3.9 EOL). Clé de cache désormais invalidée surhashFiles('platformio.ini'). → Résolu. - I4 (20) — Artefacts firmware publiés. Chaque build AVR upload
firmware.hex+firmware.elfviaactions/upload-artifact@v4, rétention 30 j. Addresse la partie "artefact téléchargeable" d'I4 ; la partie "release automation sur tag" reste à faire. → Partiellement résolu.
Également : déclenchement étendu aux pull requests (auparavant : on: push seul), et cache configuré avec fallback via restore-keys.
Impact global : score cumulé réduit de 86 points (36 + 30 + 20). Top-20 recomposé au §4.
Fichier modifié : .gitignore
- I7 (20) — Ligne 1 buggée
Debug/ Release/(un seul pattern littéral avec espace) supprimée. Fichier réorganisé en blocs commentés. Ajout des patrons*.o,*.d,*.hex,*.eep,*.lss,*.map,*.srec(*.elfétait déjà là). Préservation des fins de ligne CRLF. → Résolu. - I1 (25) — Audit-revisité.
git ls-files TinySensor/Debug/retourne vide : aucun artefact n'était réellement tracké (les.o/.hex/.elfsur disque proviennent d'une compilation locale Atmel Studio non committée). Legit rm --cachedprévu par le plan est un no-op. Le nouveau.gitignoreempêche toute régression :git check-ignoreconfirme que chaque fichier deTinySensor/Debug/match la règleDebug/. → Résolu (par prévention ; l'audit initial surestimait l'item).
Impact cumulé 2026-04-19 (toutes entrées confondues) : 131 points (86 + 25 + 20).
Branche : fix/magi-review-findings — revue indépendante par trois agents MAGI (Gaspard, Melchior, Balthazar) ayant voté REJECT 2/3 sur des bugs firmware, suivie d'une session de corrections.
Nouveaux bugs firmware identifiés par MAGI (non présents dans l'audit initial) :
- M1 —
PRR &= ~_BV(PRTIM1/PRADC)logique inversée dansUseLessPowerAsPossible()(lib/hal/Attiny84aHal.cpp). Dans le registre PRR, mettre un bit à 1 éteint le périphérique ;&= ~l'allumait (Timer1 et ADC restaient actifs en permanence). Corrigé en|=. Score rétroactif : (3+3)×5 = 30. → Résolu. - M2 —
SetChannel()sans validation de bornes (lib/oregon/Oregon_v3.cpp). Channel > 3 décalait des bits dans les nibbles de l'ID capteur, corrompant silencieusementmessage[2]. Guard ajouté. Score rétroactif : (3+3)×5 = 30. → Résolu. - M3 —
message[]variable globale de fichier, non membre de classe (lib/oregon/Oregon_v3.cpp). Singleton accidentel : deux instancesOregonV3auraient partagé le même buffer. Déplacé en membre privé. Score rétroactif : (2+2)×4 = 16. → Résolu.
Items de l'audit résolus dans cette PR :
- C4 (20) — Dead-code
if (int(count) != count)dansOregonV3::Sum. Héritage d'une implémentation internet oùcountétaitfloat; avecuint8_t, la branche est toujours fausse. Supprimée. → Résolu. - C7 (18) + C10 (15) — Duplication massive
platformio.ini. Introduction de[env:avr_base]+extends; suppression duUSE_BMP280=1en double dansenv:S_03. → Résolu. - D9 (25) — Pas de Dependabot. Fichier
.github/dependabot.ymlajouté : mises à jour hebdomadaires pourgithub-actions, mensuelles pourdockeretpip. → Résolu. - I4 (12) — Release automation sur tag (partie restante). Job
releaseajouté au workflow : se déclenche surv*, télécharge tous les artefacts firmware et publie une GitHub Release avec notes auto-générées. → Résolu (complètement). - D8/Doc7 (10) — Badge Travis mort. Remplacé par le badge GitHub Actions dans
README.md. → Résolu.
Impact 2026-06-16 : 176 points résolus (M1:30 + M2:30 + M3:16 + C4:20 + C7:18 + C10:15 + D9:25 + I4:12 + D8:10).
Impact cumulé toutes dates : 307 points (131 + 176).
-
C1 (35) — Token Coveralls révoqué et sorti du repo. Le token
K1UMmvKnmugffPWriB48kR274KXcAuvuKprésent dans.coveralls.ymla été révoqué côté coveralls.io et remplacé par un secret GitHub ActionsCOVERALLS_REPO_TOKEN. → Résolu. -
D1 (36) + A4 (15) + D6 (12) —
web/supprimé. Décision : le firmware builder web n'a jamais été finalisé ni déployé. Suppression des deux fichiers (web/build.php,web/index.html). Élimine d'un coup l'image Docker PHP 7.4 EOL, la vulnérabilitéshell_exec, et jQuery 1.12.4. → Résolu (D1, A4, D6). -
A1 — Requalifié (risque accepté).
TinySensor/n'est pas du code mort : il est conservé intentionnellement pour le workflow de debug/flash Atmel Studio (debugWIRE/JTAG), non remplaçable par PlatformIO. Score abaissé de 32 → 20, catégorie "risque de divergence à surveiller". Mitigations recommandées : commentaires croisés dans les deuxmain.cpp+ step CIdiffen warn-only. → Requalifié, non supprimé. -
C2 (30) — Macro
OREGON_DELAY_USmorte supprimée. La macro n'était jamais appelée (Oregon utilise_hal->Delay512Us()/Delay1024Us()directement) et référençait une méthode inexistante. Supprimée deTestHal.h. → Résolu. -
C15 (15) —
overrideajouté sur les stubs de délai deTestHal.Delay400Us,Delay1024Us,Delay512Usn'avaient pasoverride; dérive de signature désormais détectable à la compilation. → Résolu. -
C3 (20) —
Init()orphelin supprimé. Fonction librevoid Init(void)en bas deAttiny84aHal.cpp, hors de la classe, jamais appelée — shadow silencieux deAttiny84aHal::Init. Supprimée. → Résolu. -
C11 (15) — Branche morte
SetPressuresupprimée.if (pressure < 200) pressure = 200;était immédiatement écrasé par le clamp à 850 ; supprimé. → Résolu. -
D5 (20) —
avrdude.confsorti du repo. Le fichier (534 KB) provient du toolchain PlatformIO (~/.platformio/packages/tool-avrdude/) ; supprimé avecgit rm. → Résolu. -
I3 — Requalifié. Audit revisité : le ZIP KiCAD n'était pas tracké git (sur disque uniquement) ;
*.zipdéjà couvert par.gitignore. Non-issue, comme I1. → Résolu (par prévention). -
I2 (25) — Chemins absolus paramétrés.
Makefile:PIO ?= $(HOME)/.platformio/penv/bin/pio,TARGET ?= S_03,cpremplacecopy.scripts/flash_tinySensor:PIO_HOMEetPROJECT_DIRavec défauts portables (${HOME}/.platformioet$(dirname $0)/..). → Résolu. -
D3 (24) + D4 (24) — Dépendances PlatformIO épinglées sur SHA. Les 5 dépendances (BH1750, tiny-i2c, Unity, avr-ds18b20, SparkFun_BME280) épinglées sur leur commit HEAD courant dans
platformio.ini. Reproductibilité garantie, risque supply-chain éliminé. → Résolu. -
Doc1 (20) —
docs/environments.mdcréé. ConventionS_*= numéro sur le PCB, guide de calibrationINTERNAL_1v1par carte, table boards physiques + envs spéciaux (robot,devmodule,SOLAR_TEST), seuils batterie par chimie, procédure d'ajout d'une nouvelle carte. → Résolu.
Impact 2026-06-18 : 291 points résolus (C1:35 + D1:36 + A4:15 + D6:12 + C2:30 + C15:15 + C3:20 + C11:15 + D5:20 + I2:25 + D3:24 + D4:24 + Doc1:20).
Impact cumulé toutes dates : 598 points (307 + 291).
Le projet est passé sous Requirement-Based Development (RBD) via le plugin Claude Code arcadien/rbd@0.12.0. Cela comprend :
.rbd/config.yml— ID formatFUNC/TECH/CONF/PLAT-DOMAIN-NNN, framework Unity/C++, linterclang-format.clang-format— style Google, 2 espaces, 80 colonnes,SortIncludes: false- Baseline clang-format appliquée sur tous les
.cpp/.hexistants (37 fichiers) CLAUDE.mdmis à jour avec la section RBD (commit prefix obligatoire,// @req {id}, etc.)- Pre-push hook
~/.claude/hooks/rbd-pre-push-check.shinstallé
Analyse architecturale complète (docs/analysis-2026-06-18.md) suivie de 8 vagues de requirement-analyst agents en parallèle. 67 exigences validées et committées :
| Fichier | Domaines | Nb exigences |
|---|---|---|
requirements/functional.md |
FUNC-OREGON, LACROSSE, X10, BATTERY, SENSOR, ANALOG | 37 |
requirements/technical.md |
TECH-HAL, FILTER, CONVERT, SERIAL, X10 | 14 |
requirements/configuration.md |
CONF-BUILD | 11 |
requirements/platform.md |
PLAT-POWER | 5 |
| Total | 67 |
docs/architecture.md enrichi d'une table de traçabilité complète (67 lignes Requirement → Component).
-
V1 —
x10rfcontournait le HAL pour tous les timings : 5 fonctions statiques locales (x10_preamble_high, etc.) appelaient_delay_us()directement, violantTECH-HAL-001. Cycle RBD complet : TECH-X10-001 (5 nouvelles méthodesHal:DelayX10PreambleHigh8960 µs,DelayX10PreambleLow4500 µs,DelayX10BitShort560 µs,DelayX10BitLong1120 µs,DelayX10Gap40 000 µs) + TECH-X10-002 (x10rf remplacé — bloc#if defined(AVR) _delay_ussupprimé, 5 appels_hal->DelayX10*()substitués). 14 nouveaux tests Unity. → Résolu. Note : C6 (SoftSerial) reste ouvert — même pattern, traitement séparé. -
V2 —
#include <AnalogFilter.h>mort dansAttiny84aHal.cpp: inclus ligne 2, jamais référencé —AdcReadutilisait des variables locales. Supprimé. → Résolu. -
V3 —
BH1750absent dedocs/architecture.md: ajouté au diagramme Mermaid et à la table des responsabilités. → Résolu. -
V4 —
ds18b20absent dedocs/architecture.md: idem. → Résolu.
- DevContainer : Node.js 20 LTS +
@anthropic-ai/claude-codeajoutés à.devcontainer/Dockerfile(installation système via NodeSource). Claude Code désormais disponible aprèsRebuild Container.
- C5 (20) —
main.cppaccédait directement aux registres AVR pour DS18B20 (ds18b20convert(&PORTA, &DDRA, &PINA, …)). Cycle RBD complet : TECH-SENSOR-001 validé, 4 tests Unity natifs (test/test_ds18b20/), classeinclude/Ds18b20.hcréée suivant exactement le patronBMx280(sections#if defined(AVR)/#elsestub, constructeurHal*).main.cppréduit àds18b20sensor.Convert()+ds18b20sensor.Read()— aucune référence résiduelle àPORTA/DDRA/PINA. → Résolu.
Impact 2026-06-19 : 20 points résolus (C5:20). Score cumulé : 618 points (598 + 20).
Chaque item identifié est scoré selon la formule du framework tech-debt :
Priorité = (Impact + Risque) × (6 − Effort)
- Impact (1–5) : dans quelle mesure cela ralentit l'équipe ou dégrade la qualité ?
- Risque (1–5) : que se passe-t-il si on ne corrige pas ?
- Effort (1–5) : coût de la correction (1 = trivial, 5 = gros chantier).
Le plus haut score théorique est 50 ((5+5)×(6−1)). Je classe les items en quatre bandes :
| Bande | Score | Traitement |
|---|---|---|
| P0 — Critique | ≥ 30 | À traiter sous 1–2 semaines |
| P1 — Élevé | 20–29 | Sprint courant ou suivant |
| P2 — Moyen | 12–19 | Backlog qualité à dérouler sur un trimestre |
| P3 — Faible | < 12 | Opportuniste, quand on touche la zone |
| ID | Item | Localisation | Impact | Risque | Effort | Priorité |
|---|---|---|---|---|---|---|
repo_token: K1UMmvKnmugffPWriB48kR274KXcAuvuK)COVERALLS_REPO_TOKEN) |
.coveralls.yml |
2 | 5 | 1 | ||
TestHal référence un OREGON_DELAY_US(x) TestHal.Delay(x) qui n'existe pas._hal->Delay512Us()/Delay1024Us() directement ; macro morte supprimée) |
lib/hal/TestHal.h:74 |
3 | 3 | 1 | ||
void Init(void) orpheline en bas de Attiny84aHal.cpp, hors de la classe, jamais appelée. |
lib/hal/Attiny84aHal.cpp:199-203 |
2 | 2 | 1 | ||
OregonV3::Sum : if (int(count) != count) est toujours faux pour un uint8_t.float count) |
lib/oregon/Oregon_v3.cpp:82 |
2 | 2 | 1 | ||
main.cpp fait des accès registres directs (ds18b20convert(&PORTA, &DDRA, &PINA, (1 << 3), nullptr)), contournant le HAL.Ds18b20 créée dans include/Ds18b20.h — même patron que BMx280 ; main.cpp appelle ds18b20sensor.Convert() / ds18b20sensor.Read(), plus aucune référence à PORTA/DDRA/PINA ; TECH-SENSOR-001 + 4 tests Unity) |
src/main.cpp:116,120 |
3 | 2 | 2 | ||
| C6 | SoftSerial utilise _delay_us() directement au lieu du HAL → impossible à tester en natif et rompt le contrat d'abstraction. |
lib/softSerial/SoftSerial.cpp:3-6,16,24,32,36 |
3 | 2 | 2 | 20 |
platformio.ini : S_02, S_03, S_04, S_05, robot, devmodule, SOLAR_TEST partagent 80 % de leurs build_flags.[env:avr_base] + extends ; default_envs pour exclure la base des builds) |
platformio.ini |
4 | 2 | 3 | ||
| C8 | Magic numbers non documentés : PRESSURE_SCALING_VALUE = 795, MAX_ROLLING_CODE_VALUE = 0xA5 (non utilisée), SYNC_NIBBLE = 0x0A (non utilisée), timings X10 (PREAMBLE_LOW = 4500, etc.) sans référence datasheet. |
lib/oregon/Oregon_v3.cpp, lib/x10/x10rf.cpp |
2 | 2 | 2 | 16 |
| C9 | dec16ToHex déborde silencieusement pour input > 9999 (le test conversionToolsTest.cpp le prouve avec 10000 → 0xA000 marqué en commentaire "overflow"). Pas de assert ni de clamp. |
lib/utils/src/conversionTools.cpp:5-22 |
2 | 2 | 2 | 16 |
USE_BMP280=1 déclaré deux fois dans env:S_03 (lignes 88 et 90) — copier-coller résiduel.extends a éliminé le doublon) |
platformio.ini:88,90 |
2 | 1 | 1 | ||
LacrosseWS7000::SetPressure : if (pressure < 200) pressure = 200; est immédiatement écrasé par if (pressure < 850) pressure = 850;. |
lib/LacrosseWS7000/LacrosseWS7000.cpp:24-25 |
1 | 2 | 1 | ||
| C12 | Macro BITREAD redéfinie dans 4 fichiers (Oregon_v3.cpp, LacrosseWS7000.cpp, x10rf.cpp, x10rf.h) avec des variantes (bitRead, BITREAD). |
(multiple) | 2 | 1 | 2 | 12 |
| C13 | HAL "leaky" : méthodes nommées RadioGoHigh/Low, SerialGoHigh/Low — pilotage sémantique d'IO, pas une vraie abstraction de bus radio. Un port sur un MCU sans GPIO configurable de la même façon obligera à retoucher le HAL. |
lib/hal/Hal.h |
3 | 2 | 4 | 10 |
| C14 | TODO isolé : // TODO: tests for other modes |
test/test_x10/x10LibTest.cpp:130 |
2 | 2 | 3 | 12 |
TestHal::Delay400Us/Delay1024Us/Delay512Us manquent override.override ajouté sur les trois méthodes) |
lib/hal/TestHal.h:41-44 |
2 | 1 | 1 | ||
PRR &= ~_BV(PRTIM1/PRADC) logique inversée dans UseLessPowerAsPossible() : les périphériques restaient actifs (consommation inutile sur batterie).|=) |
lib/hal/Attiny84aHal.cpp |
3 | 3 | 1 | ||
OregonV3::SetChannel() sans validation de bornes : channel > 3 corrompt silencieusement message[2] en écrasant les nibbles ID capteur.if (channel < 1 || channel > 3) return; ajouté) |
lib/oregon/Oregon_v3.cpp |
3 | 3 | 1 | ||
message[] variable globale de fichier dans Oregon_v3.cpp — singleton accidentel : deux instances OregonV3 auraient partagé le même buffer.uint8_t message[MESSAGE_SIZE_IN_BYTES]) |
lib/oregon/Oregon_v3.cpp/.h |
2 | 2 | 2 |
| ID | Item | Impact | Risque | Effort | Priorité |
|---|---|---|---|---|---|
| A1 | Arbre source dupliqué — risque accepté : TinySensor/ (projet Atmel Studio) est conservé intentionnellement pour le workflow de debug pas-à-pas et de flashage via debugWIRE/JTAG, que PlatformIO ne remplace pas complètement. Contient main.cpp, bh1750.cpp/h, TinyI2CMaster.cpp/h + third_party/. Risque résiduel : divergence silencieuse si un fix appliqué dans src/ n'est pas reporté dans TinySensor/main.cpp. Mitigations recommandées : (1) commentaire croisé dans les deux main.cpp pointant l'un vers l'autre, (2) step CI diff -u src/main.cpp TinySensor/main.cpp en mode warn-only pour rendre la divergence visible. |
2 | 3 | 2 | 20 |
| A2 | Pas d'interface commune EnvironmentEncoder : main.cpp dispatche Oregon vs Lacrosse avec des #if defined(USE_OREGON)/USE_LACROSSE répétés 4× dans la même fonction. Ajouter un 3e protocole coûtera un passage dans toute la main(). |
3 | 2 | 3 | 15 |
| A3 | Le bloc BH1750 dans main.cpp:155-168 instancie en ligne un LacrosseWS7000 lightEncoder(&hal) — logique capteur mélangée avec logique de transmission. |
3 | 2 | 2 | 20 |
web/build.php) : shell_exec sans sanitisation des inputs.web/ ; builder jamais finalisé, jamais utilisé en production — web/build.php + web/index.html supprimés) |
2 | 3 | 3 | ||
| A5 | Configuration 100 % build-time : chaque capteur physique = un env PIO + une recompilation. Pas de config runtime, donc aucune mise à jour terrain sans reflashage manuel. Architecture acceptable pour un hobby / production très petite série ; limitante si on veut scaler. | 3 | 2 | 4 | 10 |
| A6 | HAL ATmega328p absent malgré mention README. Branche feat/328p_hal existe mais non mergée — code parallèle qui va dériver. |
2 | 1 | 4 | 6 |
| ID | Item | Impact | Risque | Effort | Priorité |
|---|---|---|---|---|---|
pio test -e native_debug. Un refactor peut casser S_02..SOLAR_TEST sans alerte. Le projet "prod" n'est jamais vérifié. |
5 | 4 | 2 | ||
| T2 | Pas de rapport de couverture actif. .coveralls.yml existe (et est compromis, cf. C1), mais aucune étape CI ne génère/upload la couverture. |
2 | 1 | 2 | 12 |
| T3 | Pas de test pour le wrapper BMx280 (le fichier d'en-tête expose GetTemperature/GetHumidity/GetPressure, aucun test ne vérifie les passerelles). |
3 | 2 | 3 | 15 |
| T4 | Pas de test pour SoftSerial — blocage lié à C6 (dépendance à _delay_us). |
2 | 2 | 2 | 16 |
| T5 | Pas de test HW-in-the-loop ni Simavr-based exécuté en CI, malgré la présence de [env:SOLAR_TEST] configuré pour simavr. Infrastructure prête mais non exploitée. |
3 | 3 | 4 | 12 |
| T6 | Les tests de timings Oregon/Lacrosse valident une chaîne de caractères d'ordres ("LDH PLD" = 1, "HDL PHD" = 0) via TestHal.Orders. C'est élégant mais ne vérifie pas les timings réels ni l'interop avec RTL_433/RFLink que le README cite comme référence. |
3 | 3 | 4 | 12 |
| T7 | test_busses/bussesTest.cpp ne teste qu'un booléen I2CIsConfigured après Init() — valeur de régression nulle. |
2 | 1 | 2 | 12 |
| ID | Item | Impact | Risque | Effort | Priorité |
|---|---|---|---|---|---|
php:7.4-apache EOL depuis novembre 2022. Utilisée comme base du firmware builder web.web/ — plus de Dockerfile PHP dans le repo) |
4 | 5 | 2 | ||
actions/checkout@v3, actions/cache@v3, actions/setup-python@v4. Python 3.9 utilisé — EOL octobre 2025 (nous sommes en avril 2026). |
3 | 3 | 1 | ||
platformio.ini) |
4 | 4 | 3 | ||
bh1750 épinglé sur la branche feat/attiny_support au lieu d'un SHA.6d06b87) |
3 | 3 | 2 | ||
avrdude.conf (534 KB) commité dans le repo.git rm avrdude.conf ; vient du toolchain PlatformIO, pas de la source) |
2 | 2 | 1 | ||
web/build.php charge jQuery 1.12.4 depuis CDN (sortie 2016, EOL).web/) |
1 | 2 | 2 | ||
| D7 | Copies tierces vendored dans TinySensor/third_party/ (BMX, I2C, X10) figées, risque de divergence vs. upstream. |
2 | 2 | 2 | 16 |
api.travis-ci.org) — service fermé aux OSS non payants depuis 2020. Badge cassé = signal négatif pour les contributeurs.README.md) |
1 | 1 | 1 | ||
.github/dependabot.yml : hebdomadaire pour github-actions, mensuel pour docker + pip) |
2 | 3 | 1 |
| ID | Item | Impact | Risque | Effort | Priorité |
|---|---|---|---|---|---|
S_02..S_05 non documentée.docs/environments.md créé : convention de nommage PCB, guide de calibration INTERNAL_1v1, table des boards physiques et envs spéciaux, seuils batterie) |
3 | 2 | 2 | ||
| Doc2 | Pas de guide d'onboarding (stack requise, setup local, premier build). Le README est orienté utilisateur/hardware, pas contributeur. | 3 | 2 | 2 | 20 |
| Doc3 | Workflow de flashage non documenté : scripts/flash_tinySensor + waitForUpload supposent une organisation NAS spécifique (/var/services/homes/aurelien/…). |
2 | 2 | 2 | 16 |
| Doc4 | Spécifications Oregon et Lacrosse référencées en commentaires ("A copy of the document should be provided along the implementation") mais les docs PDF ne sont pas au repo. Lien externe ou fichier embarqué requis. | 2 | 2 | 2 | 16 |
| Doc5 | Absent : CONTRIBUTING.md, SECURITY.md (surtout pertinent vu C1), CODE_OF_CONDUCT.md, CHANGELOG.md. |
2 | 1 | 2 | 12 |
| Doc6 | Hardware : pas de BOM consolidé, pas de guide d'assemblage dans doc/ (seulement 3 images : boardv2.png, boardv2_copper.png, schematic.png). |
2 | 1 | 3 | 9 |
README.md) |
1 | 1 | 1 |
| ID | Item | Impact | Risque | Effort | Priorité |
|---|---|---|---|---|---|
TinySensor/Debug/ : .o, .d, .elf, .hex, .lss, .map, .srec.TinySensor/Debug/ désormais couvert par .gitignore). |
3 | 2 | 1 | ||
Makefile et scripts/flash_tinySensor.PIO ?= $(HOME)/.platformio/penv/bin/pio, TARGET ?= S_03 dans Makefile ; PIO_HOME et PROJECT_DIR avec défauts ${HOME}/.platformio et $(dirname $0)/.. dans le script) |
3 | 2 | 1 | ||
tinySensorv1-2025-05-01_183922.zip).*.zip déjà couvert par .gitignore) |
2 | 2 | 1 | ||
.hex téléchargeable).release ajouté sur v* tags : télécharge tous les artefacts et publie une GitHub Release avec notes auto-générées — complète la résolution partielle du 2026-04-19) |
2 | 1 | 2 | ||
| I5 | CI single-runner, single-python, single-env. Pas de matrice pour tester différentes versions d'outillage. | 3 | 2 | 2 | 20 |
| I6 | Pas de pre-commit ni de .editorconfig. clang-format est installé dans le devcontainer mais non appliqué automatiquement (le commit 68cefb8 chore: clang-format laisse penser à une passe manuelle ponctuelle). |
2 | 1 | 2 | 12 |
.gitignore minimaliste (12 lignes) : n'exclut pas Debug/ (d'où I1), pas *.o, *.d, *.hex au root. |
2 | 2 | 1 | ||
| I8 | Pas de release / tag git visible sur les 30 derniers commits. Versioning absent. | 2 | 1 | 2 | 12 |
Les items barrés ont été traités depuis la publication initiale (cf. §1bis). Ils restent listés pour traçabilité de l'effort consenti.
| Rang | ID | Item | Cat. | Score |
|---|---|---|---|---|
| — | Test | |||
| — | Dep | |||
| — | Code | |||
| — | TinySensor/ |
Archi | ||
| — | Dep | |||
| — | OREGON_DELAY_US réfère une méthode inexistante |
Code | ||
| — | UseLessPowerAsPossible() |
Code | ||
| — | SetChannel() sans validation de bornes |
Code | ||
| — | Dep | |||
| — | Debug/) |
Infra | ||
| — | Infra | |||
| — | Dep | |||
| — | bh1750 épinglé sur une branche au lieu d'un tag/SHA |
Dep | ||
| — | Init() orphelin dans Attiny84aHal.cpp |
Code | ||
| — | if (int(count) != count) dans Sum |
Code | ||
| 8 | C5 | main.cpp accède aux registres sans passer par le HAL |
Code | 20 |
| 8 | C6 | SoftSerial utilise _delay_us directement (non testable) |
Code | 20 |
| 8 | A3 | Logique BH1750 mélangée dans main.cpp |
Archi | 20 |
| — | avrdude.conf (534 KB) commité |
Dep | ||
| — | S_0x non documentés (tribal knowledge) |
Doc | ||
| 8 | Doc2 | Pas de guide d'onboarding | Doc | 20 |
| — | Infra | |||
| 8 | I5 | Matrice CI inexistante | Infra | 20 |
| — | .gitignore minimaliste |
Infra | ||
| — | message[] variable globale partagée entre instances |
Code | ||
| — | platformio.ini |
Code | ||
| — | USE_BMP280=1 en double dans env:S_03 |
Code | ||
| — | Infra | |||
| — | Dep |
Plan dimensionné pour 1 développeur à ~20 % de son temps. Chaque phase s'intercale avec du travail feature ; aucune ne bloque les autres.
Un seul item, non négociable : révoquer le token Coveralls (C1). Révoquer côté coveralls.io, supprimer le token du fichier, le déplacer dans un secret GitHub Actions COVERALLS_REPO_TOKEN, et adapter le workflow. Même si le repo est public et que l'expo a déjà eu lieu, la rotation est obligatoire.
Objectif : ne plus pouvoir casser le firmware de prod sans le voir dans la CI, et remettre l'outillage au goût du jour.
Actions, par ordre de valeur :
T1 — Ajouter la compilation AVR à la CI. Étendre✅ Fait 2026-04-19 (matrice sur 7 envs,.github/workflows/main.ymlavec une matrice qui faitpio run -e S_02 -e S_03 -e S_04 -e S_05 -e robot -e devmoduleen plus dupio test -e native_debug. Coût : 30 min.fail-fast: false).D2 — Mettre à jour les Actions :✅ Fait 2026-04-19.checkout@v4,cache@v4,setup-python@v5, Python3.12. Coût : 15 min.I1, I7 — Nettoyer les artefacts versionnés. Ajouter à✅ Fait 2026-04-19 (cf. §1bis ;.gitignore:Debug/,Release/,*.o,*.d,*.elf,*.hex(root seulement),*.lss,*.map,*.srec,TinySensor/Debug/. Puisgit rm -r --cached TinySensor/Debug/et commit.git rm --cacheds'est révélé no-op, aucun artefact n'était réellement tracké).- I2 — Paramétrer les scripts. Remplacer les chemins absolus du
Makefileet descripts/flash_tinySensorpar des variables d'environnement (PIO_HOME,PROJECT_DIR). Documenter dans le README. Coût : 1 h. - D9 — Activer Dependabot (
.github/dependabot.yml) pourgithub-actions,docker,pip(le python utilisé dans les scripts). Coût : 10 min. - D8 + Doc7 — Retirer le badge Travis, ajouter le badge GitHub Actions. Coût : 5 min.
- I4 (partie restante) — Release automation sur tag : workflow
on: push: tags: ['v*']qui rejoue la matrice et publie les.hex/.elfen GitHub Release. Coût : 1 h. Déplacé ici depuis la phase 4 car le socle artefacts est désormais en place.
Livrable de fin de phase : CI verte sur toutes les cibles AVR + natif (atteint), plus aucune modification ne peut casser silencieusement un firmware de production (atteint), artefacts téléchargeables par build (atteint), et releases taguées automatiques (à faire).
Objectif : une seule source de vérité pour chaque fichier, dépendances reproductibles.
- A1 — Décision sur
TinySensor/(legacy Atmel Studio). Deux options :- (a) Supprimer intégralement le dossier. C'est ce que je recommande : le projet PlatformIO couvre tout l'usage, Atmel Studio n'est plus maintenu (Microchip Studio 7.0 également en fin de support). Coût : 10 min + audit de ce qui serait perdu.
- (b) Le conserver en tant que branche ou submodule séparé, hors de
master. Action : ouvrir une PR "remove legacy Atmel Studio tree" avec une fenêtre de confirmation d'une semaine.
- D3, D4 — Épingler les dépendances PlatformIO. Passer de
url.git#branchàurl.git#<SHA>(ou mieux, créer des tagsv1.0.0sur chaque fork et utiliser#v1.0.0). Coût : 1 h. - D5 — Sortir
avrdude.confdu repo. La config vient du paquettool-avrdudede PlatformIO ; documenter dans le README et ajouter au.gitignore. Coût : 15 min. - I3 — Supprimer le backup ZIP KiCAD. L'historique git suffit. Coût : 5 min.
- D1 — Migrer le Dockerfile de
php:7.4-apacheversphp:8.3-apache(ou plus récent). Tester le build. Coût : 2 h + test.
Livrable : un seul arbre source, deps reproductibles, image Docker à jour.
Objectif : éliminer la dette de code identifiée, renforcer les tests.
Quick wins (1 h chacun) :
- C2 — Corriger la macro
OREGON_DELAY_USdansTestHal.h. - C3 — Supprimer la fonction libre
Init()orpheline. - C4 — Supprimer le
ifmort dansOregonV3::Sum. - C10 — Dédupliquer
USE_BMP280=1dansenv:S_03. - C11 — Retirer le
if (pressure < 200)mort. - C15 — Ajouter
overridesur toutes les méthodes virtuelles deTestHal.
Refactorings moyens (1 jour chacun) :
- C5 + A3 — Encapsuler les accès DS18B20 et BH1750 derrière des classes capteurs (
Ds18b20Sensor,Bh1750Sensor) utilisant le HAL. Alignerait sur le patternBMx280. - C6 + T4 — Refactorer
SoftSerialpour passer toutes les temporisations par le HAL (hal->DelayBitPeriod()ou similaire). Ajouter un test natif deSoftSerialqui vérifie la séquence deSerialGoHigh/Lowpour un caractère connu. - C7 — Dédupliquer
platformio.ini: utiliser[env:base_avr]héritée par[env:S_02], etc. (feature native de PlatformIO viaextends = env:base_avr). Coût : 2 h + test. - C12 — Centraliser
BITREADdanslib/utils/include/bitops.het supprimer les redéfinitions. - T3 — Ajouter un test unitaire pour
BMx280en mode non-AVR (vérifie que les stubs renvoient 0 sans crash). - C8 — Documenter les magic numbers (commentaire avec référence datasheet + lien).
- A2 — Introduire une interface
IEnvironmentEncoderpartagée parOregonV3etLacrosseWS7000, injectée dansmain(). Simplifie l'ajout de futurs protocoles. - A4 — Statuer sur le sort de
web/: (a) le finir (formulaire + sanitisation) ou (b) le supprimer et documenter un builder local. Je recommande (b) vu l'état. - Doc1, Doc2 — Écrire
docs/environments.md(quel env pour quelle carte physique) etdocs/CONTRIBUTING.md(stack, premier build, architecture HAL/encoders). - Doc5 — Créer
SECURITY.md(processus de report) etCHANGELOG.md(tenir à jour sur les prochaines releases). - I5 — Matrice d'outillage : étendre la matrice existante à plusieurs Pythons (
3.11,3.12,3.13) et/ou plusieurs versions de PlatformIO Core. (La partie release automation d'I4 a été remontée en Phase 1.) - T5, T6 — Élever la barre des tests : intégrer
simavrdans la CI pour au moins un env (SOLAR_TESTest prêt), et ajouter un test d'intégration qui fait passer la trame Oregon au décodeur RTL_433 (binaire installable en CI) pour valider l'interop réelle. - A5 — Évaluation : runtime config via EEPROM ? Pertinent seulement si on vise plus de 5 unités en production. Ne pas faire avant d'en avoir le besoin.
Pour équilibrer, voici les forces du projet à ne pas casser lors des refactorings :
Le HAL est bien pensé (Hal.h → Attiny84aHal / TestHal_) : abstraction claire, méthode template (ComputeVccMv, ConvertAnalogValueToMv) dans la classe de base, substituable pour les tests. C'est le patron à généraliser.
Les encodeurs protocolaires sont testés et déterministes : OregonV3 et LacrosseWS7000 sont vérifiés via une trace d'ordres HAL (Orders.push_back('H')), ce qui permet d'asserter la séquence de bits sans matériel. Approche élégante.
Les commentaires inline dans les encodeurs documentent le format de trame (structure des nibbles, bits de battery status, checksum) — précieux pour un domaine où les specs sont rares.
Le Dockerfile devcontainer est complet et autosuffisant pour onboarder un nouveau développeur — le point d'entrée technique est clair.
Les commits suivent une convention (feat:, fix:, chore:, hardware:, optim:) — base pour semver automatique quand les releases seront outillées (phase 4).
| Métrique | Valeur |
|---|---|
| Lignes de code (lib + src + include) | 1 543 |
| Lignes de tests | 1 835 |
| Ratio tests/code | 1,19 |
Fichiers .cpp/.h audités (hors legacy) |
19 |
| TODO/FIXME/HACK restants | 1 |
| Environnements PlatformIO | 8 (1 natif + 7 AVR) |
| Dépendances externes | 5 (toutes forks perso) |
| Workflows CI | 1 (2 jobs : native + matrice AVR 7 envs, maj 2026-04-19) |
| Secrets exposés | 0 (C1 révoqué) |
Les éléments suivants ont été vus mais ne justifient pas d'action immédiate :
- Qualité du KiCAD (hardware) : hors compétence d'une revue de code. À confier à un reviewer hardware.
- Choix du langage (C++ sur ATtiny) : adapté au contexte mémoire/ressources. Pas de dette.
- Format
floatpour la température (Oregon_v3.cpp) : acceptable vu la place disponible ; à reconsidérer seulement si la taille flash devient critique.
# Phase 1 — vérifier que la CI couvre toutes les cibles AVR
pio run -e S_02 -e S_03 -e S_04 -e S_05 -e robot -e devmodule -e SOLAR_TEST
# Phase 2 — purger l'arbre legacy (après décision)
git rm -r TinySensor/
git rm avrdude.conf
git rm hardware/tinysensor/tinySensorv1-backups/
# Phase 3 — dédupliquer platformio.ini avec extends
# [env:base_avr]
# platform = atmelavr
# board = attiny84
# framework = arduino
# board_build.f_cpu = 1000000L
# board_build.mcu = attiny84a
# build_type = release
# [env:S_02]
# extends = env:base_avr
# build_flags = -DUSE_OREGON -DOREGON_RCODE=0x20 …Fin du rapport. Auteur : Claude. Date : 19 avril 2026. Ce rapport reflète l'état du dépôt au commit aa53a83. Les scores sont indicatifs et doivent être recalibrés selon la capacité équipe et les priorités produit.