Files
L'électron rare 80cfa134a6 feat(firmware): 48V pack class for 13s packs
Add a Kconfig voltage-class choice (BMU_PACK_CLASS: 24V default /
48V) plus an sdkconfig.defaults.48v overlay, implementing lot 4 of
the 48V design note.

48V class defaults: min 44600 mV (3.43 V/cell, same fleet policy
as 24V), max 55200 mV (charger CV 54.6 V + 600 mV margin),
imbalance 2000 mV (x13/7), VRM SOC window 44600-53500 mV.

Blocking fixes found while implementing:
- bmu_protection: plausibility guard rejected any reading above
  35 V as an I2C glitch -> class macro BMU_V_PLAUSIBLE_MAX_MV.
- bmu_ina237: BOVL/BUVL hardwired 30000/24000 -> programmed from
  runtime thresholds (NVS/Kconfig) at init; log real values.
- bmu_ble control + display steppers: hardcoded 20-30/25-35 V
  setting bounds rejected any 48V config -> class-derived macros
  BMU_VMIN/VMAX_SET_FLOOR/CEIL_MV in bmu_config.h.
- bmu_ui_detail: chart autoscale seeds 35000/15000 broke above
  35 V -> neutral 65535/0.
- bmu_ble_victron: SOC window hardcoded 24.0/28.8 -> reads the
  VRM Kconfig (class fallback when VRM disabled).
- legacy firmware/src/config.h: BATTERY_PACK_CLASS_48V ifdef.

Validated: idf.py build green for both classes (esp32s3, isolated
sdkconfig; 48V generates 44600/55200/2000), no new warnings in
touched files, legacy sim-host tests 13/13 pass. NVS erase needed
when reflashing a board that has 24V thresholds persisted.
2026-07-07 16:05:43 +02:00

2.6 KiB

ESP-IDF Firmware (Production)

ESP-IDF 5.4 firmware pour ESP32-S3-BOX-3, 25 composants modulaires, LVGL display, NimBLE, MQTT, OTA.

Build & Flash

source ~/esp/esp-idf/export.sh
idf.py build                              # ~30-60s incremental
idf.py -p /dev/cu.usbmodem* flash monitor # flash + serial
idf.py menuconfig                          # configure sdkconfig

# Variante 48V (packs 13s, hardware BMU-v2-48v) — overlay Kconfig :
idf.py -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.48v" build
# (supprimer sdkconfig existant + erase NVS si seuils 24V déjà persistés)

Classe de tension : choix Kconfig BMU_PACK_CLASS (24V défaut / 48V). Fixe les défauts des seuils (44600/55200 mV en 48V), les bornes de réglage BLE/écran, le garde de plausibilité INA237 et la fenêtre SOC VRM.

Erase NVS (si config corrompue ou override sdkconfig) :

python3 -m esptool --chip esp32s3 -p /dev/cu.usbmodem* erase_region 0x9000 0x6000

Boot Sequence (14 étapes)

NVS → SPIFFS → Display → WiFi → BLE → FAT → SNTP → I2C scan → topology → protection → cloud → web → VE.Direct → OTA

Architecture clé

  • bmu_protection : state machine 5 états (CONNECTED/DISCONNECTED/RECONNECTING/ERROR/LOCKED), lock après 5 reconnexions
  • bmu_balancer : soft-balancing duty-cycling (3 ON / 2 OFF) + R_int opportuniste
  • bmu_ble : NimBLE, 4 services GATT (battery/system/control/Victron SmartShunt), bmu_ble_set_nb_ina() post-scan I2C
  • bmu_influx + _store : InfluxDB line-protocol + persistence offline FAT/SD (rotation 512KB)
  • bmu_mqtt : ESP-MQTT auth user/password (NVS override possible)
  • bmu_display : LVGL tabview, swipe detail, pack info line, R_int column
  • bmu_storage : NVS, FAT (/fatfs), SPIFFS (/spiffs), SD (/sdcard SPI PMOD2)

Offline Data Persistence

Si WiFi/InfluxDB down, télémétrie persistée :

  • Primary : /fatfs/influx/current.lp → rotation rotated.lp à 512KB (max 1MB)
  • Fallback : /sdcard/influx/
  • Replay automatique au reconnect WiFi (cloud_telemetry_task, 10s)

Safety

  • I2C : tout passe par bmu_i2c_lock() / bmu_i2c_unlock()
  • bmu_protection skip les batteries où bmu_balancer_is_off() (évite incrémentation nb_switch)
  • Tâches (priorités réelles du code) : protection (prio 8), balancer (prio 3), hotplug (prio 3), cloud (prio 2), ah_task (prio 1), display (esp_timer)

Anti-Patterns

  • Ne pas lire s_nb_ina figé — utiliser prot->nb_ina dynamique post-scan
  • Ne pas oublier d'ajouter un nouveau composant aux REQUIRES de main/CMakeLists.txt
  • Ne pas appeler ble_gap_adv_set_fields() sans name — macOS/iOS perd la pub