Skip to the content
4 layers193.5 × 105 mmBMU v1, the printed circuit board in 3D

Battery Management Unit for parallel 24-30V packs Up to 32 batteries ESP32-S3 BLE + MQTT + InfluxDB iOS companion app

Size
193.5 × 105 mm
Copper layers
4
Thickness
1.6 mm
Parts
143
Nets
105
Pads
438
Tracks, vias
1,042, 474
Pours
221
Routed
Yes
KiCad
KiCad 8.0 (file 20240108)
Created
27 Nov 2024
Updated
6 Nov 2026

Overview

BMU v1 is an open-source printed circuit board by KomplexKapharnaum, from the KomplexKapharnaum/KXKM_Batterie_Parallelator repository on GitHub, published under the GPL-3.0 licence. It is a 4-layer board of 193.5 × 105 mm with 143 parts on 105 nets, routed with 1,042 tracks and 474 vias.

It is built around the VPS8505, ISO1540DR-HXY and TCA9517ADGK, with the TCA9535PWR(UMW), 1N4148W and HOVB4026-5W-2MR-1% among its other parts. Its parts include 43 resistors, 24 diodes, 20 capacitors, 9 ICs and 5 connectors.

Main components

9

README

README.md

BMU v1 on the test bench with six battery packs

BMU v2 PCB (3D render)

KXKM Batterie Parallelator

Battery Management Unit for parallel 24-30V packs
Up to 32 batteries · ESP32-S3 · BLE + MQTT + InfluxDB · iOS companion app

CI QA ESP-IDF License Tests


Overview

The KXKM Batterie Parallelator is an embedded Battery Management Unit (BMU) that safely parallels multiple battery packs (24-30V) for off-grid stage installations. Each battery is individually monitored (voltage, current, temperature) and can be disconnected in microseconds via MOSFET switches.

Built by L'Electron Rare for KompleX KapharnaüM (Villeurbanne, France) — a live arts company deploying digital scenography in public spaces without grid power.

Key Features

FeatureDescription
Per-battery protectionUnder/over-voltage, over-current, imbalance detection
Auto-reconnectionExponential backoff with permanent lock after 5 faults
Soft-balancingDuty-cycling with opportunistic R_int measurement
Victron integrationBLE Instant Readout + GATT SmartShunt emulation + device scanner
Touchscreen UI320x240 LVGL display with battery grid, SOH, charts
iOS companion appBLE real-time monitoring, offline cache, role-based access
Cloud telemetryMQTT + InfluxDB + Grafana with offline persistence
OTA updatesDual-partition with automatic rollback

Quick Start

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

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

# Run all tests (no hardware needed)
pio test -e sim-host          # 13 PlatformIO tests
cd firmware-idf && idf.py build  # 13 ESP-IDF host tests

# Cloud stack (kxkm-ai server)
cd kxkm-api && cp .env.example .env && docker compose up -d

Architecture

text
                          ┌──────────────────────────┐
                          │    ESP32-S3-BOX-3         │
                          │    320x240 LVGL display   │
                          │    NimBLE + WiFi          │
                          └─────────┬────────────────┘
                                    │ I2C 50kHz
                    ┌───────────────┼───────────────┐
                    │               │               │
              ┌─────▼─────┐  ┌─────▼─────┐  ┌─────▼─────┐
              │ TCA9535    │  │ TCA9535   │  │  ...×8    │
              │ 4× MOSFET  │  │ 4× LED   │  │           │
              └─────┬─────┘  └───────────┘  └───────────┘
                    │
              ┌─────▼─────┐
              │ INA237 ×4  │  ← per TCA (voltage + current)
              └───────────┘

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

Firmware Components (ESP-IDF, 25 modules)

ComponentRole
bmu_protectionState machine: 5 states, 5 criteria, permanent lock
bmu_balancerSoft-balancing duty-cycling + R_int measurement
bmu_ina23716× INA237 power monitors (2mΩ shunt)
bmu_tca95358× GPIO expanders (switches + LEDs)
bmu_bleNimBLE 4 GATT services + Victron SmartShunt
bmu_ble_victronVictron Instant Readout (AES-CTR encrypted ads)
bmu_ble_victron_scanBLE central scanner for Victron devices
bmu_displayLVGL: battery grid, pack info, SOH, charts, swipe
bmu_influx + _storeInfluxDB client + offline FAT/SD persistence
bmu_mqttESP-MQTT with auth credentials
bmu_vedirectVictron VE.Direct UART parser (solar charger)
bmu_rintInternal resistance pulse measurement
bmu_webHTTP + WebSocket with token auth + rate limiting
bmu_configNVS runtime config + Victron device keys
bmu_storageNVS, FAT, SPIFFS, SD card, USB MSC
bmu_otaOTA firmware update with rollback

Protection Logic

text
Nb_switch < 5   →  Reconnect immediately when condition clears
Nb_switch == 5  →  10-second delay before reconnection
Nb_switch > 5   →  Permanent lock (blinking red LED) until reboot
ThresholdDefaultConfigurable
Min voltage24,000 mVvia Kconfig + NVS
Max voltage30,000 mVvia Kconfig + NVS
Max current10,000 mAvia Kconfig + NVS
Imbalance1,000 mVvia Kconfig + NVS
Reconnect delay10,000 msvia Kconfig
Switch limit5via Kconfig

LED Behavior

StateLED
ConnectedSolid green
DisconnectedSolid red
ErrorBlinking red (~1 Hz)
LockedSolid red

iOS Companion App

KXKM BMU — SwiftUI + CoreBluetooth

FeatureTransport
Real-time battery dashboardBLE (2s poll)
Battery detail + voltage chartBLE
Switch ON/OFF + resetBLE (role-gated)
Protection config (0.025V/A step)BLE
WiFi config for BMUBLE
Audit trail + filteringLocal SQLDelight
Offline mode with cache indicatorAuto-fallback
SOH dashboard + R_intBLE + REST
Victron device scanningBLE passive

3 roles: Admin (full), Technician (control), Viewer (read-only) — PIN + Face ID.

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


Victron BLE Integration

The BMU interacts with the Victron ecosystem via three mechanisms:

MechanismDirectionProtocol
Instant ReadoutBMU → VictronConnectAES-CTR encrypted advertising (PID 0xA389)
GATT SmartShuntBMU → any BLE client9 read-only characteristics (V, I, SOC, Ah, TTG, T, alarm)
Device ScannerVictron devices → BMUPassive BLE scan, AES decrypt, 8 device cache

Supported Victron record types: Solar (0x01), Battery (0x02), Inverter (0x03), DC-DC (0x04).


Cloud Infrastructure

Docker stack on kxkm-ai server:

ServicePortRole
Mosquitto1883, 9001MQTT broker (authenticated)
InfluxDB 2.78086Time-series storage (org=kxkm, bucket=bmu)
Telegraf-MQTT → InfluxDB bridge
FastAPI8400REST API (sync, history, audit)
Grafana 1130013 dashboards (live, fleet, solar)

Setup: cp .env.example .env — fill all secrets (API key, InfluxDB token, MQTT credentials, Grafana password, CORS origins). All secrets via ${...} env vars, chmod 600 .env.

Offline resilience: when WiFi/InfluxDB is unreachable, telemetry is persisted to internal FAT flash (/fatfs/influx/) with 2-file rotation (512KB each). Automatic replay on reconnection.


Testing

26 tests total — no hardware required.

PlatformIO sim-host (13 tests)

bash
pio test -e sim-host
SuiteTestsCovers
test_protection10V/I/imbalance/lock state machine
test_battery_route_validation-Index bounds + state checks
test_influx_buffer_codec-InfluxDB line-protocol encoding
test_web_mutation_rate_limit3Sliding window + multi-IP
test_web_route_security9Constant-time token + Bearer
test_ws_auth_flow7Combined auth + rate limit
test_mqtt_influx_codec3JSON MQTT + topic parsing
test_emulation_bench-Emulation benchmark

ESP-IDF Host Tests (13 tests)

bash
cd firmware-idf && idf.py build
SuiteTestsCovers
test_protection13Full state machine (ESP-IDF)
test_victron_gatt8GATT encoding (V, SOC, alarm, TTG, T)
test_victron_scan5Payload parsing, expiry, MAC, CID
test_ble_victron-Battery/solar payload encoding
test_vedirect_parser-VE.Direct frame parsing
test_rint-R_int calculation
test_config_labels-Battery label management
test_vrm_topics-VRM topic generation

CI/CD Pipelines

PipelineTriggerGate
ci.ymlpush/PRsim-host 13 tests pass
sim-host-tests.ymlpush/PR+ S3 build + RAM ≤75% + Flash ≤85%
esp-idf-ci.ymlpush/PR+ ESP-IDF host tests + flash ≤85% of 2MB OTA

Current flash usage: 81% (1.69 MB / 2 MB OTA partition) — 19% headroom.


Security Audit

All findings resolved as of 2026-04-07.

Phase 1 — Migration (March 2026): 7/7 resolved
IDFindingStatus
CRIT-001Obsolete function calls✅
CRIT-002Unreliable global Nb_INA✅
CRIT-003I2C access without mutex✅
CRIT-004Missing mutex init✅
HIGH-005WebSocket V/I race✅
HIGH-006reconnect_time race✅
HIGH-007Uninitialized globals✅
Phase 2 — Deep audit (March-April 2026): 13/13 resolved
IDSeverityFindingFix
CRIT-ACriticalmV/V unit mismatchESP-IDF: mV everywhere
CRIT-BCriticalImbalance vs config instead of fleet maxbmu_protection
CRIT-CCriticalDeadlock in web switchbmu_web
CRIT-DCriticalUnauthenticated routesbmu_web_security
HIGH-1HighNegative overcurrent ignoredBidirectional factor
HIGH-2HighUnauthenticated WebSocketToken on first frame
HIGH-3HighXSS in /logcJSON null check
HIGH-4HighMQTT plaintextMosquitto auth + .env
HIGH-5HighI2C speed change unguardedI2CLockGuard
HIGH-7HighPublic battery_voltages[]state_mutex
HIGH-8HighInflux task crash on SD failinflux_store fallback
MED-1MediumNo permanent lock (F08)BMU_STATE_LOCKED
MED-010MediummV/V harmonizationmV throughout
Infrastructure audit (April 2026): 5/5 resolved
FindingFix
Mosquitto anonymous accessAuth + password file
Hardcoded secrets in docker-composeAll via .env (chmod 600)
Default InfluxDB tokenRotated (44-char random)
CORS allow_origins=["*"]Restricted via env var
Offline data lossFAT/SD persistence + replay

Hardware

PCB Revisions

VersionStatusFiles
BMU v1Manufacturedhardware/PCB/
BMU v2Production-ready (ERC 0, BOM 107)hardware/pcb-bmu-v2/

Key ICs

ICPackageRoleI2C Address
INA237VSSOP-10Power monitor (V/I/P)0x40-0x4F (16 max)
TCA9535TSSOP-24GPIO expander (switches + LEDs)0x20-0x27 (8 max)
ISO1540SOIC-8Galvanic I2C isolator-
IRF4905D2PAKP-channel MOSFET (55V, 74A)-

I2C Mapping

text
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

Topology constraint: Nb_TCA × 4 == Nb_INA — mismatch triggers fail-safe (all OFF).


Project Structure

text
KXKM_Batterie_Parallelator/
├── firmware-idf/          # ESP-IDF 5.4 firmware (25 components)
│   ├── components/        # Modular ESP-IDF components
│   ├── main/              # app_main entry point
│   └── test/              # Unity host tests (13 suites)
├── firmware/              # Legacy PlatformIO/Arduino firmware
│   ├── src/               # Source modules
│   ├── test/              # sim-host tests (8 suites, 13 tests)
│   └── lib/INA237/        # Local INA237 driver fork
├── iosApp/                # iOS SwiftUI app (CoreBluetooth)
├── kxkm-bmu-app/          # KMP shared Kotlin module
│   └── shared/            # Cross-platform domain logic
├── kxkm-api/              # Docker stack (Mosquitto, InfluxDB, FastAPI, Grafana)
├── hardware/              # KiCad schematics + Gerbers (v1 + v2)
├── specs/                 # Kill_LIFE gates (S0-S3)
├── docs/                  # Specs, plans, governance, research
├── grafana/dashboards/    # 3 Grafana dashboard JSONs
└── scripts/               # CI, QA, ML pipeline

About KompleX KapharnaüM

KompleX KapharnaüM is a live arts company based in Villeurbanne (Lyon, France), active for 20+ years in street arts, live performance, and digital creation. The company develops its own embedded hardware platform (K32, ESP32-based) and maintains open-source tools on GitHub.


License

GNU General Public License v3.0


Built with ESP-IDF, LVGL, NimBLE, SwiftUI, FastAPI, InfluxDB, and Grafana.
Developed by L'Electron Rare for KompleX KapharnaüM

Parts

143
QtyValueFootprintReferences
19SolderJumper_3_OpenJumper:SolderJumper-3_P1.3mm_Open_RoundedPad1.0x1.5mm_NumberLabelsJP2, JP3, JP4, JP5, JP6, JP10, JP11, JP12, JP13, JP14, JP15, JP16, JP17, JP18, JP19, JP20 +3
100.1uFCapacitor_SMD:C_0805_2012MetricC2, C3, C4, C5, C6, C7, C8, C9, C10, C11
810RResistor_SMD:R_0603_1608MetricR3, R4, R10, R11, R17, R18, R37, R38
81N4148WDiode_SMD:D_SOD-523D2, D3, D6, D7, D10, D11, D14, D15
8330RResistor_SMD:R_0603_1608MetricR29, R30, R31, R32, R33, R34, R35, R36
8470RResistor_SMD:R_0603_1608MetricR2, R5, R9, R12, R16, R19, R23, R39
8MountingHole_PadMountingHole:MountingHole_5mm_PadH1, H2, H3, H4, H5, H6, H7, H8
5MountingHoleMountingHole:MountingHole_3.2mm_M3_DIN965H9, H10, H13, H13, H14
410kResistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_HorizontalR7, R14, R21, R41
4470RResistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_HorizontalR6, R13, R20, R40
4BLUELED_SMD:LED_0603_1608MetricD4, D8, D12, D16
4GREENLED_SMD:LED_0603_1608MetricD21, D23, D25, D27
4HOVB4026-5W-2MR-1%easyeda2kicad:RES-SMD_4P-L10.8-W6.7R1, R8, R46, R47
4INA237Package_SO:VSSOP-10_3x3mm_P0.5mmU1, U2, U3, U7
4IRFZ44NPBFPackage_TO_SOT_THT:TO-220-3_Horizontal_TabUpQ5, Q6, Q7, Q8
4REDLED_SMD:LED_0603_1608MetricD20, D22, D24, D26
310uFCapacitor_SMD:C_0805_2012MetricC14, C20, C21
31A/100VDiode_SMD:D_SMAD5, D18, D19
210uF/50VCapacitor_SMD:C_1206_3216MetricC15, C16
21KResistor_SMD:R_0603_1608MetricR26, R27
250RResistor_SMD:R_0603_1608MetricR24, R25
2MountingHole_PadMountingHole:MountingHole_3.2mm_M3_Pad_ViaH11, H12
2RJ45_Shieldedeasyeda2kicad:RJ45-TH_RC01061J1, J2
2Screw_Terminal_01x01easyeda2kicad:TH-8_L20.0-W16.0-P5.60_AMT0860001TA0000GJ11, J12
10,1uFCapacitor_SMD:C_0805_2012MetricC13
10.1uFCapacitor_SMD:C_0603_1608MetricC18
110KResistor_SMD:R_0603_1608MetricR28
110k/1%Resistor_SMD:R_0603_1608MetricR22
110uF,16VCapacitor_SMD:CP_Elec_8x10C1
11N4148WTDiode_SMD:D_SOD-523D9
11uFCapacitor_SMD:C_0805_2012MetricC12
120pFCapacitor_SMD:C_0603_1608MetricC19
122uH,1.5AInductor_SMD:L_Taiyo-Yuden_NR-50xxL1
152.3k/1%Resistor_SMD:R_0603_1608MetricR15
1Conn_01x02_PinConnector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_VerticalJ3
1ISO1540DRPackage_SO:SOIC-8_3.9x4.9mm_P1.27mmU5
1LOGOLOGOG***
1MCP16331T-E/CHPackage_TO_SOT_SMD:SOT-23-6U10
1SolderJumper_2_OpenJumper:SolderJumper-2_P1.3mm_Open_RoundedPad1.0x1.5mmJP1
1TCA9517ADGKeasyeda2kicad:VSSOP-8_L3.0-W3.0-P0.65-LS5.0-BLU4
1TCA9535PWRPackage_SO:TSSOP-24_4.4x7.8mm_P0.65mmU6
1VPS8505easyeda2kicad:SOT-23-6_L2.9-W1.6-P0.95-LS2.8-BRU8
1VPT85BB-01ATransformer_SMD:VP85BB-01ATR1

More from KomplexKapharnaum/KXKM_Batterie_Parallelator

6
  • 4 layers170 × 100 mmBMU v2, the printed circuit board in 3D

    BMU v2

    KomplexKapharnaum/KXKM_Batterie_Parallelator

    Battery Management Unit for parallel 24-30V packs Up to 32 batteries ESP32-S3 BLE + MQTT + InfluxDB iOS companion app

    142 partsGPL-3.0
  • 4 layers194.9 × 100 mmBMU v2, the printed circuit board in 3D

    BMU v2

    KomplexKapharnaum/KXKM_Batterie_Parallelator

    Battery Management Unit for parallel 24-30V packs Up to 32 batteries ESP32-S3 BLE + MQTT + InfluxDB iOS companion app

    140 partsGPL-3.0
  • 2 layers62.5 × 31 mmI2C repeter, the printed circuit board in 3D

    I2C repeter

    KomplexKapharnaum/KXKM_Batterie_Parallelator

    Battery Management Unit for parallel 24-30V packs Up to 32 batteries ESP32-S3 BLE + MQTT + InfluxDB iOS companion app

    28 partsGPL-3.0
  • 2 layers38 × 85.5 mmBMU switch mosfet, the printed circuit board in 3D

    BMU switch mosfet

    KomplexKapharnaum/KXKM_Batterie_Parallelator

    Battery Management Unit for parallel 24-30V packs Up to 32 batteries ESP32-S3 BLE + MQTT + InfluxDB iOS companion app

    22 partsGPL-3.0
  • 2 layers38 × 85.5 mmBMU switch mosfet, the printed circuit board in 3D

    BMU switch mosfet

    KomplexKapharnaum/KXKM_Batterie_Parallelator

    Battery Management Unit for parallel 24-30V packs Up to 32 batteries ESP32-S3 BLE + MQTT + InfluxDB iOS companion app

    22 partsGPL-3.0
  • 2 layersBMU switch mosfet, the printed circuit board in 3D

    BMU switch mosfet

    KomplexKapharnaum/KXKM_Batterie_Parallelator

    Battery Management Unit for parallel 24-30V packs Up to 32 batteries ESP32-S3 BLE + MQTT + InfluxDB iOS companion app

    18 partsGPL-3.0

Similar boards

  • 2 layers79 × 90 mmMHCI DMX, the printed circuit board in 3D

    MHCI DMX

    About-Time-Technologies/MHCI

    Modular Hardware Control Interface - Components for the Events Industry

    89 parts2
  • 4 layers100 × 176.5 mmElevation Pivot Daughter Board, the printed circuit board in 3D

    Elevation Pivot Daughter Board

    mauro-starspec/Elevation_Pivot_Daughter-Board

    KiCad 9 daughter board for the Starspec elevation/pivot controller.

    263 parts
  • 2 layers200 × 120 mmMainpcb, the printed circuit board in 3D

    Mainpcb

    bot-hoven/bot-hoven-electrical

    Electrical substem for Bot-Hoven. Includes KiCad files containing schematics and PCB designs for components in Bot-Hoven.

    82 parts
  • 2 layers44 × 72 mmIMU+Barometer logger, the printed circuit board in 3D

    IMU+Barometer logger

    Dhruv2212-star/9-axis-IMU-barometer-Data-logger-

    This project is a compact, battery-powered data logger designed to record motion and environmental data in a single device.

    59 parts
  • 2 layers63 × 34.5 mmE1201, the printed circuit board in 3D

    E1201

    Electro707/p1200_lcd_backpack

    My version of an LCD Backpack with some unique features

    54 partsGPL-3.0
  • 2 layers95 × 57 mmControesp hat, the printed circuit board in 3D

    Controesp hat

    gixxerPS/controesp-hat

    controllino like board for esp

    19 parts

Questions

How big is the BMU v1 PCB?

It measures 193.5 × 105 mm and has 4 copper layers, 1.6 mm thick.

What parts does the BMU v1 use?

143 parts, built around the VPS8505, ISO1540DR-HXY, TCA9517ADGK and TCA9535PWR(UMW). The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the BMU v1 KiCad files?

From the KomplexKapharnaum/KXKM_Batterie_Parallelator repository on GitHub, at the commit this page was made from: the board is hardware/PCB/BMU v1/BMU v1.kicad_pcb and its schematic hardware/PCB/BMU v1/BMU v1.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the BMU v1 design in my own project?

Its repository publishes it under the GPL-3.0 licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).