Files
L'électron rare bbb2102166
CI / firmware-native (push) Successful in 1m10s
qa-cicd-environments / qa-kxkm-s3-build (push) Successful in 5m28s
qa-cicd-environments / qa-sim-host (push) Successful in 1m38s
qa-cicd-environments / qa-kxkm-s3-memory-budget (push) Successful in 18m36s
docs: add French translation of README
Context: the project README is written in English while the client
(KompleX KapharnaüM) and field technicians are French-speaking.

Approach: full translation of README.md into README.fr.md, keeping
tables, badges, code blocks and anchors identical.

Changes:
- Add README.fr.md (complete French translation)
- Cross-link to the English version at the top of the file

Impact: French-speaking users get first-class documentation without
diverging from the English source of truth.
2026-07-04 12:58:53 +02:00

16 KiB
Raw Permalink Blame History

PCB BMU

KXKM Batterie Parallelator

Battery Management Unit pour packs 24-30V en parallèle
Jusqu'à 32 batteries · ESP32-S3 · BLE + MQTT + InfluxDB · App iOS compagnon

CI QA ESP-IDF Licence Tests

🇬🇧 English version: README.md


Vue d'ensemble

Le KXKM Batterie Parallelator est une Battery Management Unit (BMU) embarquée qui met en parallèle, en toute sécurité, plusieurs packs de batteries (24-30V) pour des installations scéniques hors réseau. Chaque batterie est surveillée individuellement (tension, courant, température) et peut être déconnectée en quelques microsecondes via des interrupteurs MOSFET.

Conçu par L'Electron Rare pour KompleX KapharnaüM (Villeurbanne, France) — une compagnie d'arts vivants qui déploie de la scénographie numérique dans l'espace public, sans alimentation secteur.

Fonctionnalités clés

Fonctionnalité Description
Protection par batterie Détection sous/sur-tension, surintensité, déséquilibre
Reconnexion automatique Backoff exponentiel avec verrouillage permanent après 5 défauts
Équilibrage doux (soft-balancing) Duty-cycling avec mesure opportuniste de R_int
Intégration Victron Instant Readout BLE + émulation GATT SmartShunt + scanner de périphériques
Interface tactile Écran LVGL 320x240 avec grille batteries, SOH, graphiques
App iOS compagnon Supervision temps réel en BLE, cache hors-ligne, accès par rôles
Télémétrie cloud MQTT + InfluxDB + Grafana avec persistance hors-ligne
Mises à jour OTA Double partition avec rollback automatique

Démarrage rapide

# Firmware ESP-IDF (production)
cd firmware-idf
source ~/esp/esp-idf/export.sh
idf.py build
idf.py -p /dev/cu.usbmodem* flash monitor

# PlatformIO (Arduino legacy)
pio run -e kxkm-s3-16MB --target upload

# Lancer tous les tests (aucun matériel requis)
pio test -e sim-host          # 13 tests PlatformIO
cd firmware-idf && idf.py build  # 13 tests host ESP-IDF

# Stack cloud (serveur kxkm-ai)
cd kxkm-api && cp .env.example .env && docker compose up -d

Architecture

                          ┌──────────────────────────┐
                          │    ESP32-S3-BOX-3         │
                          │    Écran LVGL 320x240     │
                          │    NimBLE + WiFi          │
                          └─────────┬────────────────┘
                                    │ I2C 50kHz
                    ┌───────────────┼───────────────┐
                    │               │               │
              ┌─────▼─────┐  ┌─────▼─────┐  ┌─────▼─────┐
              │ TCA9535    │  │ TCA9535   │  │  ...×8    │
              │ 4× MOSFET  │  │ 4× LED   │  │           │
              └─────┬─────┘  └───────────┘  └───────────┘
                    │
              ┌─────▼─────┐
              │ INA237 ×4  │  ← par TCA (tension + courant)
              └───────────┘

    ┌──────────────────────────────────────────────────────┐
    │                    Stack Cloud                        │
    │  BMU ──MQTT──► Mosquitto ──► Telegraf ──► InfluxDB   │
    │                                              │       │
    │  iPhone ◄──BLE──► BMU    Grafana ◄───────────┘       │
    │  iPhone ◄──REST──► FastAPI ◄─────────────────┘       │
    └──────────────────────────────────────────────────────┘

Composants firmware (ESP-IDF, 25 modules)

Composant Rôle
bmu_protection Machine à états : 5 états, 5 critères, verrouillage permanent
bmu_balancer Soft-balancing par duty-cycling + mesure R_int
bmu_ina237 16× moniteurs de puissance INA237 (shunt 2mΩ)
bmu_tca9535 8× expanders GPIO (interrupteurs + LEDs)
bmu_ble NimBLE 4 services GATT + Victron SmartShunt
bmu_ble_victron Victron Instant Readout (advertising chiffré AES-CTR)
bmu_ble_victron_scan Scanner BLE central pour périphériques Victron
bmu_display LVGL : grille batteries, infos pack, SOH, graphiques, swipe
bmu_influx + _store Client InfluxDB + persistance hors-ligne FAT/SD
bmu_mqtt ESP-MQTT avec identifiants d'authentification
bmu_vedirect Parseur UART Victron VE.Direct (chargeur solaire)
bmu_rint Mesure de résistance interne par impulsion
bmu_web HTTP + WebSocket avec auth par token + rate limiting
bmu_config Config runtime NVS + clés périphériques Victron
bmu_storage NVS, FAT, SPIFFS, carte SD, USB MSC
bmu_ota Mise à jour firmware OTA avec rollback

Logique de protection

Nb_switch < 5   →  Reconnexion immédiate dès que la condition disparaît
Nb_switch == 5  →  Délai de 10 secondes avant reconnexion
Nb_switch > 5   →  Verrouillage permanent (LED rouge clignotante) jusqu'au redémarrage
Seuil Défaut Configurable
Tension min 24 000 mV via Kconfig + NVS
Tension max 30 000 mV via Kconfig + NVS
Courant max 10 000 mA via Kconfig + NVS
Déséquilibre 1 000 mV via Kconfig + NVS
Délai de reconnexion 10 000 ms via Kconfig
Limite de commutations 5 via Kconfig

Comportement des LEDs

État LED
Connectée Vert fixe
Déconnectée Rouge fixe
Erreur Rouge clignotant (~1 Hz)
Verrouillée Rouge fixe

App iOS compagnon

KXKM BMU — SwiftUI + CoreBluetooth

Fonctionnalité Transport
Tableau de bord batteries temps réel BLE (poll 2s)
Détail batterie + graphique de tension BLE
Interrupteur ON/OFF + reset BLE (selon rôle)
Config protection (pas de 0,025 V/A) BLE
Config WiFi de la BMU BLE
Journal d'audit + filtrage SQLDelight local
Mode hors-ligne avec indicateur de cache Bascule automatique
Tableau de bord SOH + R_int BLE + REST
Scan des périphériques Victron BLE passif

3 rôles : Admin (complet), Technicien (contrôle), Observateur (lecture seule) — PIN + Face ID.

Code : iosApp/ (Xcode, CoreBluetooth) + kxkm-bmu-app/ (module Kotlin partagé KMP)


Intégration BLE Victron

La BMU interagit avec l'écosystème Victron via trois mécanismes :

Mécanisme Direction Protocole
Instant Readout BMU → VictronConnect Advertising chiffré AES-CTR (PID 0xA389)
GATT SmartShunt BMU → tout client BLE 9 caractéristiques en lecture seule (V, I, SOC, Ah, TTG, T, alarme)
Scanner de périphériques Périphériques Victron → BMU Scan BLE passif, déchiffrement AES, cache 8 périphériques

Types d'enregistrements Victron supportés : Solar (0x01), Battery (0x02), Inverter (0x03), DC-DC (0x04).


Infrastructure cloud

Stack Docker sur le serveur kxkm-ai :

Service Port Rôle
Mosquitto 1883, 9001 Broker MQTT (authentifié)
InfluxDB 2.7 8086 Stockage séries temporelles (org=kxkm, bucket=bmu)
Telegraf - Passerelle MQTT → InfluxDB
FastAPI 8400 API REST (sync, historique, audit)
Grafana 11 3001 3 tableaux de bord (live, flotte, solaire)

Installation : cp .env.example .env — renseigner tous les secrets (clé API, token InfluxDB, identifiants MQTT, mot de passe Grafana, origines CORS). Tous les secrets passent par des variables d'environnement ${...}, chmod 600 .env.

Résilience hors-ligne : quand le WiFi/InfluxDB est injoignable, la télémétrie est persistée en flash FAT interne (/fatfs/influx/) avec rotation sur 2 fichiers (512 Ko chacun). Rejeu automatique à la reconnexion.


Tests

26 tests au total — aucun matériel requis.

PlatformIO sim-host (13 tests)

pio test -e sim-host
Suite Tests Couvre
test_protection 10 Machine à états V/I/déséquilibre/verrouillage
test_battery_route_validation - Bornes d'index + vérifications d'état
test_influx_buffer_codec - Encodage line-protocol InfluxDB
test_web_mutation_rate_limit 3 Fenêtre glissante + multi-IP
test_web_route_security 9 Token en temps constant + Bearer
test_ws_auth_flow 7 Auth combinée + rate limit
test_mqtt_influx_codec 3 JSON MQTT + parsing des topics
test_emulation_bench - Benchmark d'émulation

Tests host ESP-IDF (13 tests)

cd firmware-idf && idf.py build
Suite Tests Couvre
test_protection 13 Machine à états complète (ESP-IDF)
test_victron_gatt 8 Encodage GATT (V, SOC, alarme, TTG, T)
test_victron_scan 5 Parsing des trames, expiration, MAC, CID
test_ble_victron - Encodage des trames batterie/solaire
test_vedirect_parser - Parsing des trames VE.Direct
test_rint - Calcul de R_int
test_config_labels - Gestion des étiquettes batterie
test_vrm_topics - Génération des topics VRM

Pipelines CI/CD

Pipeline Déclencheur Gate
ci.yml push/PR 13 tests sim-host au vert
sim-host-tests.yml push/PR + build S3 + RAM ≤75% + Flash ≤85%
esp-idf-ci.yml push/PR + tests host ESP-IDF + flash ≤85% des 2 Mo OTA

Occupation flash actuelle : 81 % (1,69 Mo / 2 Mo de partition OTA) — 19 % de marge.


Audit de sécurité

Tous les constats résolus au 2026-04-07.

Phase 1 — Migration (mars 2026) : 7/7 résolus
ID Constat Statut
CRIT-001 Appels de fonctions obsolètes
CRIT-002 Variable globale Nb_INA non fiable
CRIT-003 Accès I2C sans mutex
CRIT-004 Initialisation de mutex manquante
HIGH-005 Race condition WebSocket V/I
HIGH-006 Race condition reconnect_time
HIGH-007 Globales non initialisées
Phase 2 — Audit approfondi (mars-avril 2026) : 13/13 résolus
ID Sévérité Constat Correctif
CRIT-A Critique Incohérence d'unités mV/V ESP-IDF : mV partout
CRIT-B Critique Déséquilibre comparé à la config au lieu du max de flotte bmu_protection
CRIT-C Critique Deadlock dans le switch web bmu_web
CRIT-D Critique Routes non authentifiées bmu_web_security
HIGH-1 Haute Surintensité négative ignorée Facteur bidirectionnel
HIGH-2 Haute WebSocket non authentifié Token sur la première trame
HIGH-3 Haute XSS dans /log Vérification null cJSON
HIGH-4 Haute MQTT en clair Auth Mosquitto + .env
HIGH-5 Haute Changement de vitesse I2C non protégé I2CLockGuard
HIGH-7 Haute battery_voltages[] public state_mutex
HIGH-8 Haute Crash de la tâche Influx si la SD échoue Repli influx_store
MED-1 Moyenne Pas de verrouillage permanent (F08) BMU_STATE_LOCKED
MED-010 Moyenne Harmonisation mV/V mV partout
Audit infrastructure (avril 2026) : 5/5 résolus
Constat Correctif
Accès anonyme Mosquitto Auth + fichier de mots de passe
Secrets en dur dans docker-compose Tout via .env (chmod 600)
Token InfluxDB par défaut Régénéré (44 caractères aléatoires)
CORS allow_origins=["*"] Restreint via variable d'environnement
Perte de données hors-ligne Persistance FAT/SD + rejeu

Matériel

Révisions du PCB

Version Statut Fichiers
BMU v1 Fabriquée hardware/PCB/
BMU v2 Prête pour production (ERC 0, BOM 107) hardware/pcb-bmu-v2/

Circuits intégrés clés

CI Boîtier Rôle Adresse I2C
INA237 VSSOP-10 Moniteur de puissance (V/I/P) 0x40-0x4F (16 max)
TCA9535 TSSOP-24 Expander GPIO (interrupteurs + LEDs) 0x20-0x27 (8 max)
ISO1540 SOIC-8 Isolateur I2C galvanique -
IRF4905 D2PAK MOSFET canal P (55V, 74A) -

Cartographie I2C

TCA_0 (0x20) → INA 0x40-0x43 → Batteries 1-4
TCA_1 (0x21) → INA 0x44-0x47 → Batteries 5-8
TCA_2 (0x22) → INA 0x48-0x4B → Batteries 9-12
TCA_3 (0x23) → INA 0x4C-0x4F → Batteries 13-16

Contrainte topologique : Nb_TCA × 4 == Nb_INA — toute incohérence déclenche le fail-safe (tout OFF).


Structure du projet

KXKM_Batterie_Parallelator/
├── firmware-idf/          # Firmware ESP-IDF 5.4 (25 composants)
│   ├── components/        # Composants ESP-IDF modulaires
│   ├── main/              # Point d'entrée app_main
│   └── test/              # Tests host Unity (13 suites)
├── firmware/              # Firmware PlatformIO/Arduino legacy
│   ├── src/               # Modules source
│   ├── test/              # Tests sim-host (8 suites, 13 tests)
│   └── lib/INA237/        # Fork local du driver INA237
├── iosApp/                # App iOS SwiftUI (CoreBluetooth)
├── kxkm-bmu-app/          # Module Kotlin partagé KMP
│   └── shared/            # Logique métier multiplateforme
├── kxkm-api/              # Stack Docker (Mosquitto, InfluxDB, FastAPI, Grafana)
├── hardware/              # Schémas KiCad + Gerbers (v1 + v2)
├── specs/                 # Gates Kill_LIFE (S0-S3)
├── docs/                  # Specs, plans, gouvernance, recherche
├── grafana/dashboards/    # 3 dashboards Grafana JSON
└── scripts/               # CI, QA, pipeline ML

À propos de KompleX KapharnaüM

KompleX KapharnaüM est une compagnie d'arts vivants basée à Villeurbanne (Lyon, France), active depuis plus de 20 ans dans les arts de rue, le spectacle vivant et la création numérique. La compagnie développe sa propre plateforme matérielle embarquée (K32, à base d'ESP32) et maintient des outils open source sur GitHub.


Licence

GNU General Public License v3.0


Construit avec ESP-IDF, LVGL, NimBLE, SwiftUI, FastAPI, InfluxDB et Grafana.
Développé par L'Electron Rare pour KompleX KapharnaüM