

Plts monitoring controller
Integrated to PLTSMonitoring_PWA
- Size
- 140 × 100 mm
- Copper layers
- 2
- Thickness
- 1.6 mm
- Parts
- 152
- Nets
- 120
- Pads
- 490
- Tracks, vias
- 2,023, 367
- Pours
- 17
- Routed
- Yes
- KiCad
- KiCad 9.0 (file 20241229)
- Created
- 2 Sep 2026
- Updated
- 22 Sep 2026
Overview
Plts monitoring controller is an open-source printed circuit board by desvandi, from the desvandi/PLTSMonitoring_Firmware-Backend repository on GitHub. It is a 2-layer board of 140 × 100 mm with 152 parts on 120 nets, routed with 2,023 tracks and 367 vias.
It is built around the ESP32-WROOM-32E, MAX3485CSA+T and ACS712ELCTR-30A-T, with the CP2102N-A02-GQFN24, AP2112K-3.3 and DS3231SN# among its other parts. Its parts include 34 resistors, 27 capacitors, 8 ICs, 6 diodes and 6 transistors. It belongs with the ESP32 boards of this library.
Main components
12ESP32-WROOM-32E
SMD,18x25.5mmSMD,18x25.5mm WiFi Modules ROHSEspressif SystemsWiFi ModulesMAX3485CSA+T
SO-80℃~+70℃ 1 1 10Mbps 2.2mA 32 3V~3.6V Half-Duplex Transceiver SO-8 RS-485 / RS-422 ICs ROHSMaxim Integrated (Analog Devices)RS-485 / RS-422 ICsACS712ELCTR-30A-T
SOIC-8-40℃~+85℃ 1.2mΩ 2.1kVrms 30A 50kHz 5V 5us 66mV/A Support SOIC-8 Current Sensors ROHSALLEGROCurrent SensorsCP2102N-A02-GQFN24
QFN-24-EP(4x4)-40℃~+85℃@(Ta) 1.3uA 13.7mA 3V~3.6V USB 2.0 USB to UART QFN-24-EP(4x4) USB Converters ROHSSilicon LabsUSB ConvertersAP2112K-3.3
SOT253.3V 600mA CMOS Low Dropout Linear Regulator with EnableDiodes IncorporatedUncategorisedDS3231SN#
SOIC-16-300mil-40℃~+85℃ 100nA 2.3V~5.5V 200uA Built-in I2C Temperature compensation、Backup power management and battery charging、Programmable clock output、Alarm function Yes SOIC-16-300mil Real Time Clocks ROHSMaxim Integrated (Analog Devices)Real Time ClocksSMAJ5.0A
DO-214AC(SMA)-65℃~+150℃ 400W@10/1000us 43.5A 5V 7V 800uA 9.2V TVS Unidirectional DO-214AC(SMA) ESD and Surge Protection (TVS/ESD) ROHSMDDESD And Surge Protection (TVS/ESD)BSS138
SOT-23-55℃~+150℃ 1 N-channel 1.1Ω@10V、1.2Ω@4.5V 1.2V 1.7nC@10V 17.5pF 340mA 350mW 50V 6.5pF N-Channel SOT-23 MOSFETs ROHShongjiachengMOSFETsS8050
SOT-23-55℃~+150℃ 1 NPN 100MHz 100nA 120 25V 300mW 500mA 5V 600mV NPN SOT-23 Bipolar (BJT) ROHShongjiachengBipolar (BJT)AO3400A
SOT-23-55℃~+150℃ 1 N-channel 1.45V 1.4W 30V 48mΩ@2.5V 5.7A 50pF 630pF 75pF 7nC@10V N-Channel SOT-23 MOSFETs ROHSAlpha & Omega SemiconductorMOSFETsBAV199
SOT-231 Pair Series Connection 1.25V@150mA 160mA 4A 5nA@75V 85V SOT-23 Diodes - General Purpose ROHSNexperiaDiodes - General PurposeCDSOT23-T24CAN
SOT-2317pF 2 24V 250W@8/20us 32V 5.5A@8/20us 50V 80nA Bidirectional IEC 61000-4-2、IEC 61000-4-5、IEC 61000-4-4 SOT-23 ESD and Surge Protection (TVS/ESD) ROHSTECH PUBLICESD And Surge Protection (TVS/ESD)
README
README.mdPLTS Monitoring — Firmware, Backend GAS, & Toolkit
Firmware Version: v1.9.3 · Backend GAS: WAVE-7+ · License: MIT Status: Development (v1.9.x INA219 dynamic gain switching — hardware acceptance pending; v1.9.3 menutup REL-03/REL-04: build kini reproducible) Repositori kembar (PWA frontend): desvandi/PLTSMonitoring_PWA
Daftar Isi
- Gambaran Proyek
- Arsitektur Sistem
- Struktur Repositori
- Hardware Requirements
- Firmware v1.9.x — INA219 Dynamic Gain Switching
- Panduan Deployment Lengkap
- Konfigurasi Firmware
- Backend Google Apps Script
- CI/CD Pipeline
- Release Engineering
- Hardware Acceptance
- Testing
- Troubleshooting
- Changelog
1. Gambaran Proyek
Proyek ini adalah sistem monitoring PLTS (Pembangkit Listrik Tenaga Surya) berbasis ESP32 untuk baterai 48V LiFePO4. Sistem mencakup telemetri lengkap (tegangan, arus, daya, SOC, suhu, BMS), alarm real-time, kontrol relay 8-channel, OTA update dengan signature verification, dan push notification.
Dua Subsistem
| Subsistem | Fungsi | Komponen |
|---|---|---|
| PLTS Monitor (dasbor) | Telemetri → Google Apps Script → PWA Next.js; realtime MQTT opsional | firmware/, firmware-generic/, code.gs/, scripts/ |
| Push-Alarm MonitorIoT | Alarm sensor via Web Push terenkripsi (VAPID + aes128gcm) | push-alarm/ |
Prinsip Inti
- Never fabricate certainty — setiap pengukuran membawa
value/unit/quality/source/timestamp; sensor gagal →null(bukan0) - Fail-closed — production build menolak konfigurasi tanpa signature/CA/allowlist
- Immutable releases — setiap release ditandatangani GPG + Ed25519, provenance binding machine-verifiable
2. Arsitektur Sistem
┌─────────────────────────────────────────────────────────────┐
│ ESP32-WROOM-32 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ INA219 │ │ ADC GPIO │ │ SHT31 │ │ PCF8574 │ │
│ │ (Arus) │ │ (Tegang) │ │ (Suhu) │ │ (Relay) │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ I²C │ ADC │ I²C │ I²C │
│ ┌────┴─────────────┴─────────────┴─────────────┴────┐ │
│ │ Firmware v1.9.3 │ │
│ │ • Dynamic PGA Switching (±80mV / ±160mV) │ │
│ │ • Voltage Divider 190kΩ/10kΩ (20:1) │ │
│ │ • 8-Channel Relay Controller (E-WAVE) │ │
│ │ • Reproducible Build (deterministic identity) │ │
│ │ • OTA Manager (Ed25519 + SHA-256) │ │
│ │ • MQTT TLS / HTTPS telemetry │ │
│ └───────────────────┬──────────────────────────────┘ │
│ │ │
└──────────────────────┼────────────────────────────────────┘
│
┌────────┴────────┐
│ WiFi / MQTT │
└────────┬────────┘
│Topologi Operasi
| Topologi | Transport | Backend | Use Case |
|---|---|---|---|
| A (Dasbor) | HTTPS POST | Google Apps Script + Google Sheets | Standby/standalone tanpa internet real-time |
| B (Realtime) | MQTT TLS | Broker MQTT + PWA subscribe | Real-time dashboard dengan live updates |
3. Struktur Repositori
PLTSMonitoring_Firmware-Backend/
├── firmware/ # Modular production firmware (v1.9.3)
│ ├── Core/ # Config.h, Types.h, Globals.h, Common.h
│ ├── Drivers/ # INA219, ADC, SHT31, ACS712, PCF8574, RTC
│ ├── Services/ # OtaManager, RelayController, AlarmRegistry, dll
│ ├── Network/ # MQTT transport, telemetry publisher, OTA handler
│ ├── Web/ # HTTP server, REST handlers (status, OTA, config, dll)
│ ├── Storage/ # NVS config store, filesystem
│ ├── Utils/ # Crypto (Ed25519), CRC, I2C recovery, JSON
│ ├── AI/ # GasAdvisor (HMAC-signed AI insights)
│ ├── Comm/ # BMS protocols (CAN, Modbus RTU/TCP)
│ ├── firmware_v1.ino # Main entry point
│ ├── platformio.ini # Build configs: development, staging, production
│ └── partitions_ota_1mb5.csv # OTA partition table
│
├── firmware-generic/ # Generic firmware (ESP Web Tools flashing)
│ ├── src/
│ │ └── plts_firmware_v1.ino # Single-file firmware (same features, simpler build)
│ ├── manifest.json # ESP Web Tools manifest (v1.9.3)
│ ├── platformio.ini
│ └── bin/ # CI-built binaries (gitignored)
│
├── code.gs/ # Google Apps Script backend
│ └── Code.gs # doPost handler, telemetry ingest, HMAC, OTA dispatch4. Hardware Requirements
Komponen Utama
| Komponen | Spesifikasi | Fungsi |
|---|---|---|
| ESP32-WROOM-32 | Dual-core 240MHz, 4MB Flash, WiFi+BT | Mikrokontroler utama |
| INA219 | I²C 0x40, shunt 100A/75mV (R=0.75mΩ) | Pengukuran arus baterai (1A–150A) |
| Shunt Resistor | 100A/75mV (0.75mΩ) | Low-side current sensing |
| Voltage Divider | R1=190kΩ, R2=10kΩ (ratio 20:1) + 0.1µF cap | Pembacaan tegangan baterai 42–57.5V via ADC |
| SHT31 | I²C, ±0.3°C, ±2%RH | Suhu + kelembaban ambient |
| PCF8574 | I²C expander 8-bit | 8-channel relay control |
| Relay Module | 8-channel, active-LOW optocoupler | Kontrol beban PLTS |
| Emergency Relay | Active-LOW, normally-closed E-stop | Safety cutoff (hardware-level) |
| ACS712-30A (opsional) | ADC GPIO35 | Arus AC inverter |
| PZEM-004T (opsional) | Modbus RTU | Meter AC presisi |
Wiring INA219 (Low-Side Sensing)
Baterai (+) ──────────────────────────────────────── Beban (+)
│
[Divider]
R1=190kΩ
│
Baterai (−) ──────┬──────────────────────┬───── ADC GPIO34
│ │
[Shunt 100A] R2=10kΩ
75mV, 0.75mΩ │
│ [0.1µF]
├──── INA219 Vin+ │
│ │
└──── INA219 Vin− │
│ │
GND ────────────────────┘Penting: R100 (0.1Ω) bawaan modul INA219 wajib dicopot. Gunakan shunt eksternal 100A/75mV. INA219 dipasang low-side (jalur GND) karena Vbus bisa 57.5V > 26V max INA219.
Pin Assignment
| GPIO | Fungsi | Modul |
|---|---|---|
| 21 | I²C SDA | INA219, SHT31, PCF8574 |
| 22 | I²C SCL | INA219, SHT31, PCF8574 |
| 34 | ADC1 CH6 | Voltage divider (input-only, WiFi-safe) |
| 35 | ADC1 CH7 | ACS712 AC current (opsional) |
| 0 | BOOT button | Factory reset trigger |
| 2 | Built-in LED | Status indicator |
5. Firmware v1.9.x — INA219 Dynamic Gain Switching
Masalah
Rentang arus PLTS sangat lebar: 1A (standby) hingga 150A (beban puncak). Single PGA range INA219 tidak bisa cover keduanya:
- ±80mV: saturasi di ~106A (150A × 0.75mΩ = 112.5mV > 80mV)
- ±160mV: resolusi buruk di arus standby 1–2A
Solusi: Dynamic PGA Switching
Firmware v1.9.2+ (termasuk v1.9.3) secara otomatis beralih PGA berdasarkan besaran arus:
| Mode | Register | PGA Range | Max Current | Resolusi |
|---|---|---|---|---|
| Standby | 0x0FFF | ±80mV (gain /2) | 106A | 10µV/bit (0.013A) |
| Peak | 0x17FF | ±160mV (gain /4) | 213A | 10µV/bit |
Hysteresis
|I| < 90A → ±80mV (high-resolution standby)
|I| ≥ 100A → ±160mV (peak load, no saturation)Gap 10A mencegah chattering saat beban hover di sekitar threshold.
INA219 Config Register (TI Datasheet SBOS448G)
Bit 15 : RST (1 = reset)
Bit 14 : RESERVED (must be 0)
Bit 13 : BRNG (0 = 16V FSR, 1 = 32V FSR)
Bits 12:11: PG (00=±40mV, 01=±80mV, 10=±160mV, 11=±320mV)
Bits 10:7 : BADC (4-bit, 1111 = 12-bit/128-sample/68ms)
Bits 6:3 : SADC (4-bit, 1111 = 12-bit/128-sample/68ms)
Bits 2:0 : MODE (111 = shunt+bus continuous)Safety Features
- Register readback verification — setiap PGA switch diverifikasi via I²C readback
- Sample discard — sample pertama setelah PGA switch dibuang (settling time 68ms)
- Saturation detection — di ±80mV mode, jika shunt > 78mV → emergency switch ke ±160mV
- pga_mode telemetry — field
bat.pgaMode("80mV"/"160mV") dikirim ke backend + PWA
Verifikasi Register
python3 scripts/decode_ina219_config.py 0x0FFF 0x17FF
python3 scripts/test_ina219_config_registers.py6. Panduan Deployment Lengkap
Prasyarat
- PlatformIO Core 6.1.18+ (
pip install platformio) - Python 3.11+ (untuk scripts)
- Git dengan GPG signing configured
- Google Account (untuk Apps Script + Sheets)
- Vercel Account (untuk PWA deployment — lihat repo PWA)
Langkah 1: Clone Repositori
git clone https://github.com/desvandi/PLTSMonitoring_Firmware-Backend.git
cd PLTSMonitoring_Firmware-BackendLangkah 2: Build Firmware
Opsi A: Modular Production (Recommended)
cd firmware
# Set production secrets (WAJIB sebelum build production)
export MQTT_BROKER_HOST="your-broker.example.com"
export MQTT_BROKER_PORT="8883"
export MQTT_USERNAME="plts-device"
export MQTT_PASSWORD="your-password"
export MQTT_ROOT_CA="$(cat roots.pem)"
export OTA_ED25519_PUBLIC_KEY_HEX="your-64-hex-char-public-key"
export OTA_HTTPS_ROOT_CA="$(cat ota-ca.pem)"
# Build
pio run -e production
# Output: .pio/build/production/firmware.binOpsi B: Development (tanpa secrets)
cd firmware
pio run -e developmentOpsi C: Generic (ESP Web Tools browser flashing)
cd firmware-generic
pio run -e esp32dev
# Output: bin/plts_firmware_v1.9.3.binLangkah 3: Sign Firmware (Ed25519)
# Generate keypair (sekali saja)
python3 scripts/sign_firmware.py --gen-keys
# Output: firmware_signing_private.pem + firmware_signing_public.pem
# Sign binary
python3 scripts/sign_firmware.py --sign .pio/build/production/firmware.bin
# Output: firmware.bin.sig (128 hex chars = 64 bytes Ed25519)
# Verify
python3 scripts/sign_firmware.py --verify firmware.bin.sig firmware.binLangkah 4: Flash ke ESP32
Via USB (PlatformIO)
cd firmware
pio run -e production -t upload
# Monitor:
pio device monitor -b 115200Via ESP Web Tools (Browser)
- Host
firmware-generic/bin/di web server (GitHub Pages, Vercel, dll) - Buka PWA → Setup → "Install Firmware" button
- Browser akan flash via Web Serial API
Langkah 5: Deploy Backend Google Apps Script
- Buka script.google.com → New Project
- Copy seluruh isi
code.gs/Code.gske editor - Buat Google Sheet baru, copy ID dari URL
- Di Apps Script, jalankan
setupMasterTemplate()(Run → function) - Set
AUTH_TOKENdi Config sheet (minimal 16 karakter, tidak boleh "CHANGE_ME") - Deploy → New Deployment → Web App
- Execute as: Me
- Who has access: Anyone
- Copy Web App URL → simpan untuk konfigurasi PWA
Langkah 6: Generate OTA Signing Keys
# Generate Ed25519 keypair untuk OTA
python3 scripts/sign_firmware.py --gen-keys
# Public key hex (untuk firmware Config.h / OTA_ED25519_PUBLIC_KEY_HEX)
xxd -p -c 64 firmware_signing_public.pem | head -1
# Atau:
python3 -c "
from cryptography.hazmat.primitives import serialization
key = open('firmware_signing_public.pem','rb').read()
pub = serialization.load_pem_public_key(key)
raw = pub.public_bytes(serialization.Encoding.Raw, serialization.PublicFormat.Raw)
print(raw.hex())
"Langkah 7: Konfigurasi ESP32 (via PWA)
- Buka PWA di browser (deploy dari repo PWA)
- Hubungkan ke WiFi AP ESP32 ("PLTS-Setup-XXXX")
- PWA akan redirect ke setup page
- Isi: WiFi SSID+password, GAS URL, AUTH_TOKEN, MQTT broker (opsional)
- Submit → ESP32 reboot → connect ke WiFi
Langkah 8: Verifikasi
- Buka Serial Monitor:
pio device monitor -b 115200 - Verifikasi log INA219:
text [INA219 0x40] config readback OK: 0x0FFF (BRNG=0 16V, PGA=1 ±80mV, BADC=15, SADC=15, MODE=7) [INA219 0x40] init: shunt=0.7500 mΩ, cal=0x..., sign=-1.0, pga=80mV - Buka PWA → verifikasi telemetri muncul
- Cek Google Sheet → data telemetri masuk
7. Konfigurasi Firmware
Environment Variables (Production Build)
| Variable | Wajib | Description |
|---|---|---|
MQTT_BROKER_HOST | Ya | MQTT broker hostname |
MQTT_BROKER_PORT | Ya | MQTT port (8883 untuk TLS) |
MQTT_USERNAME | Ya | MQTT username |
MQTT_PASSWORD | Ya | MQTT password |
MQTT_ROOT_CA | Ya | PEM-encoded Root CA untuk TLS |
OTA_ED25519_PUBLIC_KEY_HEX | Ya | 64 hex char Ed25519 public key |
OTA_HTTPS_ROOT_CA | Ya | PEM Root CA untuk HTTPS OTA download |
Runtime Config (via PWA / NVS)
| Config | Default | Description |
|---|---|---|
deviceName | "PLTS-XXXX" | Nama device |
siteName | "Site" | Nama lokasi |
idleCurrentThreshold | 0.5A | Deadband arus idle |
cfgBmsProtocol | "auto" | Protokol BMS (auto/CAN/Modbus) |
INA219 Constants (firmware/Core/Config.h)
static constexpr float INA219_SHUNT_OHM = 0.00075f; // 0.75 mΩ
static constexpr float INA219_PGA_SWITCH_UP_A = 100.0f; // switch to 160mV
static constexpr float INA219_PGA_SWITCH_DOWN_A = 90.0f; // switch back to 80mV
static constexpr uint16_t INA219_CONFIG_PGA_80MV = 0x0FFF; // ±80mV, 12b/128s, cont
static constexpr uint16_t INA219_CONFIG_PGA_160MV = 0x17FF; // ±160mV, 12b/128s, contVoltage Divider Constants
static constexpr float DIVIDER_R1 = 190000.0f; // 190 kΩ
static constexpr float DIVIDER_R2 = 10000.0f; // 10 kΩ
static constexpr float DIVIDER_RATIO = 20.0f; // (R1+R2)/R2
static constexpr float ADC_FINE_TUNE = 1.000000f; // kalibrasi multimeter8. Backend Google Apps Script
Struktur code.gs/Code.gs
| Function | Fungsi |
|---|---|
doPost(e) | Entry point — parse JSON, HMAC auth, route action |
recordTelemetry_(body, deviceKey) | Simpan telemetri ke Google Sheets |
latestTelemetry_(deviceKey) | Baca telemetri terbaru |
otaGetManifest_(deviceKey) | Serve OTA manifest ke device |
otaPublish_(body, deviceKey) | Publish OTA command ke device |
emergencyCommand_(body, deviceKey) | Dispatch emergency command |
setupMasterTemplate() | Inisialisasi sheets + config (run sekali) |
Google Sheets Schema
| Column | Field | Type |
|---|---|---|
| 0 | timestamp | DateTime (server) |
| 1 | device_key | String |
| 2 | sequence | Integer |
| 3 | event_time | DateTime (device) |
| 5 | v_bat | Float |
| 6 | i_bat_dc | Float |
| 7 | p_bat_dc | Float |
| 8 | soc | Float |
| ... | ... | ... |
| 39 | ina219_pga_mode | String ("80mV"/"160mV"/"") |
HMAC Authentication
Authorization: HMAC <deviceKey>:<base64(HMAC-SHA256(authToken, canonicalString))>9. CI/CD Pipeline
Workflow: .github/workflows/build-firmware.yml
push/PR to main → [test] → [build-staging] → [build-generic-tree] → [build-production]
↓
[release-gate]
↓
[verify-tag-signature] (tag push only)
↓
[verify-hardware-acceptance] (tag push only)
↓
[release-publish] (tag push only)Jobs
| Job | Trigger | Fungsi |
|---|---|---|
| Python tests | All pushes | 30+ unit/property/contract tests |
| Build staging | All pushes | PlatformIO staging env |
| Build generic | All pushes | PlatformIO generic tree |
| Build production | All pushes | PlatformIO production env (signed) |
| Reproducible build 2x | All pushes | REL-04: build A vs clean build B — SHA harus byte-identical (modular + generic) |
| Release gate | All pushes | Strict invariant check |
| Verify tag signature | Tag push (v*) | GPG tag + authorized signer verification |
| Verify HW acceptance | Tag push (v*) | Hardware acceptance JSON gate |
| Release publish | Tag push (v*) | Create GitHub Release with 20+ assets (requires reproducible-build PASS) |
Branch Protection
main: PR required, 0 approvals, 4 required status checks- Tags
v*: deletion + non-fast-forward + creation blocked
10. Release Engineering
Release Chain
source → build → sign (Ed25519) → gate → tag-verify (GPG) → hw-verify → releaseGPG Tag Signing
# Generate GPG key (RSA 4096)
gpg --full-generate-key
# Configure git
git config --global user.signingkey <KEY_ID>
git config --global tag.gpgsign true
# Sign release tag
git tag -s -a v1.9.2 -m "Release v1.9.2 — INA219 dynamic gain (canonical fix)"Provenance Binding
Setiap release menyertakan provenance-binding.json yang mengikat:
tag → signed tag object → release commit → source commit
→ hardware-tested binary SHA → released binary SHA
→ GitHub Release → PWA canonical release identityRelease Assets (20 files)
| Asset | Description |
|---|---|
modular-firmware.bin | Modular production firmware (signed) |
modular-firmware.bin.sig | Ed25519 signature |
modular-firmware.bin.sha256 | SHA-256 hash |
modular-release.json | Release metadata |
modular-provenance.json | Build provenance |
modular-manifest-canonical.json | Schema 2.0 OTA manifest |
generic-*.bin | Generic tree binaries |
hardware-acceptance.json | Physical test evidence |
provenance-binding.json | Explicit provenance chain |
11. Hardware Acceptance
General Hardware Acceptance (v1.8.0+)
Protocol 11-criteria: boot, sensors, alarms, OTA REST, OTA MQTT, rollback, emergency relay, config persistence, security, 24h soak, factory reset.
python3 scripts/verify_hardware_acceptance.py \
--version 1.8.0 \
--source-commit <SHA> \
--release-json modular-release.json \
--hw-dir docs/hardware-acceptanceINA219 Hardware Acceptance (v1.9.2/v1.9.3)
Protocol 12-criteria khusus INA219: config readback, low/mid/peak current accuracy, PGA transitions, hysteresis, current sign, voltage divider, power calculation, telemetry pga_mode. Gunakan v1.9.3.md untuk release line v1.9.3 (measurement chain identik dengan v1.9.2; bukti SHA kini byte-exact karena build reproducible).
python3 scripts/verify_ina219_hardware_acceptance.py \
--version 1.9.3 \
--source-commit <SHA> \
--release-json modular-release.json \
--hw-dir docs/hardware-acceptanceOTA Physical Test (v1.8.0+)
Protocol 16-criteria: PWA → GitHub Release → download → SHA verify → upload → device flash → reboot → version check → relay safe state → rollback.
python3 scripts/verify_ota_evidence.py \
--version 1.8.0 \
--canonical-release-json modular-release.json \
--ota-dir docs/ota-physical-test12. Testing
Run All Tests
# Python unit + property tests
python3 scripts/test_ina219_config_registers.py
python3 scripts/test_version_identity.py
python3 scripts/test_voltage_calibration.py
python3 scripts/test_soc_calculation.py
python3 scripts/test_emergency_firmware_logic.py
# ... 30+ test scripts
# JavaScript tests
node scripts/test_wave1_integration.js
node scripts/test_wave2_data_honesty.js
node scripts/test_gas_contract.jsKey Test Scripts
| Script | Fungsi |
|---|---|
test_ina219_config_registers.py | Verifikasi PGA register constants per datasheet |
test_version_identity.py | Version parity antara modular + generic + manifest |
test_wave12_contract_regression.py | Cross-layer contract regression |
test_ed25519_interop.py | Ed25519 signature interop (Python ↔ firmware) |
release_gate.py | Master release gate (strict mode) |
13. Troubleshooting
INA219: "config MISMATCH" di Serial Monitor
Penyebab: I²C write gagal atau register constant salah.
Fix:
- Cek wiring I²C (SDA=GPIO21, SCL=GPIO22, pull-up 4.7kΩ)
- Verifikasi constant:
python3 scripts/test_ina219_config_registers.py - Jika constant benar tapi readback gagal → ganti modul INA219
INA219: Arus terbaca 0A / NaN
Penyebab: R100 bawaan modul belum dicopot, atau shunt belum terpasang.
Fix:
- Lepas R100 (0.1Ω) dari modul INA219
- Pasang shunt 100A/75mV di jalur GND
- Verifikasi: VIN+ dan VIN− terhubung ke baut shunt
Voltage Divider: Tegangan tidak akurat
Penyebab: Toleransi resistor ±5% → error hingga ±2V di 57.5V.
Fix:
- Ukur tegangan aktual dengan multimeter
- Hitung
ADC_FINE_TUNE = tegangan_aktual / tegangan_PWA - Update di
Config.h:static constexpr float ADC_FINE_TUNE = 1.004016f; - Rebuild + reflash
OTA: "signature header missing (PRODUCTION)"
Penyebab: PWA tidak mengirim header X-Signature.
Fix: Update PWA ke versi terbaru (commit 9c8510a+) yang mengirim X-Expected-SHA256, X-Signature, X-Firmware-Version.
MQTT: "TLS connection failed"
Penyebab: Root CA tidak ter-set atau broker tidak support TLS.
Fix:
- Set
MQTT_ROOT_CAenvironment variable sebelum build - Verifikasi broker menggunakan port 8883 (TLS) atau 8884 (TLS+auth)
- Test:
openssl s_client -connect broker:8883 -showcerts
14. Changelog
v1.9.3 (Current)
- Reproducible build (REL-03/REL-04 CLOSED) —
FIRMWARE_BUILD_DATEtidak lagi__DATE__/__TIME__(wall-clock); kini diturunkan dariSOURCE_DATE_EPOCH(timestamp commit HEAD git) viafirmware/scripts/set_build_date.py. Dua build dari source yang sama = SHA-256 identik. - CI job
reproducible-build— build 2× (modular production + generic) dari clean tree, compare SHA;release-publishkini mewajibkan job ini (release tak bisa dipublish tanpa bukti determinisme). - buildDate semantics —
/api/versionbuildDatekini melaporkan tanggal SOURCE commit (identitas provenance), bukan wall-clock kompilasi. - HW acceptance v1.9.3 protocol — template
docs/hardware-acceptance/v1.9.3.template.json(12 kriteria sama dengan v1.9.2; evidencefirmwareSha256kini byte-exact vs released binary). - Version parity — 1.9.3 di modular (Config.h) + generic (plts_firmware_v1.ino + manifest.json) + mirror PWA (
public/firmware/manifest.json). - Tidak ada perubahan measurement chain — INA219 PGA 0x0FFF/0x17FF, hysteresis 90A/100A, voltage divider 190k/10k, pga_mode telemetry: semuanya identik dengan v1.9.2.
v1.9.2
- INA219 dynamic gain switching — PGA ±80mV/±160mV dengan hysteresis 90A/100A
- Canonical register fix — constants 0x0FFF/0x17FF per TI datasheet SBOS448G
- Register readback verification — setiap PGA switch diverifikasi via I²C readback
- Sample discard — sample pertama setelah PGA switch dibuang (settling time)
- Voltage divider 190kΩ/10kΩ (20:1 ratio) untuk tegangan baterai 42–57.5V
- pga_mode telemetry — field
bat.pgaMode("80mV"/"160mV") di JSON payload - CURRENT_SPIKE_REJECT_A raised 120A → 160A (software ceiling, NOT hardware rating)
- Mandatory measurement evidence — 17 field observed wajib diisi di HW acceptance
v1.8.0
- 8-channel relay integration via PCF8574 I²C expander
- RelayController with safety supervisor (maxOnTime, minOnTime, antiChatter)
- 5-state lockout (NORMAL→TRIPPED→ACKNOWLEDGED→CLEARED→ARMED)
- Interlock engine (mutual exclusion + dead time)
- E-WAVE safety cascade (trip → all relay channels OFF)
- REST API:
/api/relays,/api/relays/{id}/{on|off|pulse},/api/relays/all_off - PWA relay control view with 3-tier state model
v1.7.x
- OTA boot-health fix (
esp_ota_mark_app_valid_cancel_rollback) - Mixed-fleet manifest target self-check
- PZEM-004T real AC meter support
- Emergency relay + E-stop sense
- 2nd ACS712 channel (genset→inverter)
- Cross-layer contract regression tests (WAVE 7-13)
v1.6.x
- External BMS/inverter comm (CAN, Modbus RTU/TCP)
- SOC provenance (BMS_DIRECT | SHUNT_COULOMB | OCV_ESTIMATED)
- Transaction journal for command dedup
- I²C bus recovery (NOISE-3)
License
MIT — see LICENSE
Kontak
- GitHub Issues: github.com/desvandi/PLTSMonitoring_Firmware-Backend/issues
- PWA Repo: github.com/desvandi/PLTSMonitoring_PWA
Parts
152| Qty | Value | Footprint | References |
|---|---|---|---|
| 13 | 100nF 25V X7R | C_0603_1608Metric | C20, C21, C34, C35, C40, C41, C44, C65, C66, C70, C75, C81, C82 |
| 5 | 10k 1% | R_0603_1608Metric | R30, R31, R45, R78, R82 |
| 4 | 10k | R_0603_1608Metric | R80, R81, R87, R88 |
| 4 | 4.7k 1% | R_0603_1608Metric | R40, R41, R79, R84 |
| 4 | MountingHole_3.2mm_M3 | MountingHole_3.2mm_M3 | H1, H2, H3, H4 |
| 4 | SMAJ5.0A | D_SMA | D22, D23, D24, D25 |
| 3 | 10uF 16V X5R | C_0805_2012Metric | C60, C62, C80 |
| 3 | 15k 1% | R_0603_1608Metric | R32, R33, R83 |
| 3 | BSS138 | SOT-23 | Q21, Q22, Q23 |
| 3 | Fiducial_1mm_Mask2mm | Fiducial_1mm_Mask2mm | FID1, FID2, FID3 |
| 2 | 100k 1% | R_0603_1608Metric | R71, R77 |
| 2 | 100nF 50V X7R | C_0805_2012Metric | C61, C63 |
| 2 | 10nF 50V X7R | C_0603_1608Metric | C30, C31 |
| 2 | 120R 1% | R_0603_1608Metric | R48, R49 |
| 2 | 49.9k 1% 0805 | R_0603_1608Metric | R20a, R20b |
| 2 | 5.1k | R_0603_1608Metric | R85, R86 |
| 2 | 600R@100MHz | L_0805_2012Metric | FB2, FB50 |
| 2 | 680R 1% | R_0603_1608Metric | R51, R52 |
| 2 | ACS712ELCTR-30A-T | SOIC-8_3.9x4.9mm_P1.27mm | U4, U5 |
| 2 | DT-55-B01X-02 | TerminalBlock_Dinkle_DT-55-B01X-02_P10.00mm | J_ACS1, J_ACS2 |
| 2 | S8050 | SOT-23 | Q1, Q2 |
| 2 | TERM 120R | SolderJumper-2_P1.3mm_Open_Pad1.0x1.5mm | JP_CAN_TERM, JP_RS485_TERM |
| 1 | +3V3 | TestPoint_Pad_D2.0mm | TP_3V3 |
| 1 | +5V | TestPoint_Pad_D2.0mm | TP_5V |
| 1 | +5V_RELAY | TestPoint_Pad_D2.0mm | TP_5V_RELAY |
| 1 | 0.5A T 63V | Fuse_1206_3216Metric | F1 |
| 1 | 0.5A hold | Fuse_1812_4532Metric | F2 |
| 1 | 1.1A hold | Fuse_1812_4532Metric | F4 |
| 1 | 100R 1% | R_0603_1608Metric | R70 |
| 1 | 100nF 25V C0G | C_0603_1608Metric | C43 |
| 1 | 10uF 16V X5R | C_0603_1608Metric | C42 |
| 1 | 1A T 250VAC 5x20 | Fuseholder_Clip-5x20mm_Littelfuse_111_Inline_P20.00x5.00mm_D1.05mm_Horizontal | F3 |
| 1 | 1k | R_0603_1608Metric | R74 |
| 1 | 1k 1% | R_0603_1608Metric | R55 |
| 1 | 1uF 25V X7R | C_0603_1608Metric | C83 |
| 1 | 2.2k 1% | R_0603_1608Metric | R22 |
| 1 | 2.2uF 100V X7R | C_0603_1608Metric | C50 |
| 1 | 330R 1% | R_0603_1608Metric | R72 |
| 1 | 4.7uF 16V X5R | C_0603_1608Metric | C64 |
| 1 | 47k 1% | R_0603_1608Metric | R75 |
| 1 | 47uF 100V | CP_Elec_10x10.5 | C57 |
| 1 | 47uF 25V X5R | C_1210_3225Metric | C52 |
| 1 | 5.6k 1% | R_0603_1608Metric | R21 |
| 1 | 68k 1% | R_0603_1608Metric | R76 |
| 1 | ACS1_ADC | TestPoint_Pad_D2.0mm | TP_ACS1_ADC |
| 1 | ACS2_ADC | TestPoint_Pad_D2.0mm | TP_ACS2_ADC |
| 1 | AO3400A | SOT-23 | Q20 |
| 1 | AP2112K-3.3 | SOT-23-5 | U11 |
| 1 | BAT+ | TestPoint_Pad_D2.0mm | TP_BAT+ |
| 1 | BATT 45-54V | TerminalBlock_Phoenix_MKDS-1,5-2-5.08_1x02_P5.08mm_Horizontal | J_BAT |
| 1 | BAV199 | SOT-23 | D30 |
| 1 | BIAS A | SolderJumper-2_P1.3mm_Open_Pad1.0x1.5mm | JP_RS485_BIAS_A |
| 1 | BIAS B | SolderJumper-2_P1.3mm_Open_Pad1.0x1.5mm | JP_RS485_BIAS_B |
| 1 | BOOT | SW_PUSH_6mm | SW2 |
| 1 | CAN CANH/CANL/GND | TerminalBlock_Phoenix_MKDS-1,5-3-5.08_1x03_P5.08mm_Horizontal | J_CAN |
| 1 | CAN_H | TestPoint_Pad_D2.0mm | TP_CAN_H |
| 1 | CAN_L | TestPoint_Pad_D2.0mm | TP_CAN_L |
| 1 | CDSOT23-T24CAN | SOT-23 | D20 |
| 1 | CP2102N-A02-GQFN24 | HVQFN-24-1EP_4x4mm_P0.5mm_EP2.1x2.1mm | U2 |
| 1 | CR2032 3V | BatteryHolder_Keystone_106_1x20mm | BT1 |
| 1 | DS3231SN# | SOIC-16W_7.5x10.3mm_P1.27mm | U7 |
| 1 | E-STOP LOOP NC | TerminalBlock_Phoenix_MKDS-1,5-2-5.08_1x02_P5.08mm_Horizontal | J_ESTOP |
| 1 | EN | TestPoint_Pad_D2.0mm | TP_EN |
| 1 | ESP32-WROOM-32E | ESP32-WROOM-32E | U1 |
| 1 | EXPANSION 7-PIN 2,54 | PinHeader_1x07_P2.54mm_Vertical | J_EXP |
| 1 | E_STOP_SENSE | TestPoint_Pad_D2.0mm | TP_ESTOP |
| 1 | FL-2 100A/75mV | Shunt_FL2_100A | RSH1 |
| 1 | GCT USB4105-GF-A | USB_C_Receptacle_GCT_USB4105-xx-A_16P_TopMnt_Horizontal | J1 |
| 1 | HF115F-1/5V-H | Relay_HF115F_1 | K1 |
| 1 | I2C EXP 3V3/GND/SDA/SCL | PinHeader_1x04_P2.54mm_Vertical | J_I2C_EXP |
| 1 | INA219AIDCNR | SOT-23-8 | U3 |
| 1 | IO0 | TestPoint_Pad_D2.0mm | TP_IO0 |
| 1 | LM2596HVS 5V | Module_LM2596HVS | M1 |
| 1 | MAINS L/N 250VAC | TerminalBlock_Phoenix_MKDS-1,5-2-5.08_1x02_P5.08mm_Horizontal | J_PZEM_AC |
| 1 | MAX3485CSA+ | SOIC-8_3.9x4.9mm_P1.27mm | U8 |
| 1 | MOV 275VAC DNP | RV_Disc_D21.5mm_W5mm_P10mm | RV3 |
| 1 | NET-TIE AGND-PGND | NetTie-2_SMD_Pad0.5mm | NT1 |
| 1 | NET-TIE DGND-PGND (DIGITAL) | NetTie-2_SMD_Pad2.0mm | NT2 |
| 1 | NET-TIE PGND-BAT- (STAR) | NetTie-2_SMD_Pad2.0mm | NT0 |
| 1 | PC817 | DIP-4_W7.62mm | OPT1 |
The 128 most common of 152 parts.
Similar boards
- 2 layers77.5 × 107.9 mm

- 2 layers150.5 × 48 mm

Battery bus
hackclub/OnBoard
💡 Join 1,000 teenagers and make your first PCB with a $100 grant!
136 parts915 - 4 layers144 × 127 mm

Frothfet
hoeken/frothfet
Yarrboard load controller board with current sense, volt sense, fuses, and sender support.
394 parts14GPL-3.0 - 4 layers86 × 29.9 mm

Geiger probe
bartkepl/CanGeigerProbe
Polowa sonda promieniowania jonizującego z miniaturową lampą Geigera-Müllera, komunikująca się cyfrowo przez CAN 2.0B.
116 partsMIT - 4 layers76 × 29.9 mm

Gnss node
bartkepl/CanGnssNode
Polowy węzeł pozycyjny z modułem GNSS Quectel L76-L (GPS/GLONASS/Galileo/QZSS) i czujnikiem orientacji (akcelerometr + magnetometr), komunikujący się cyfrowo przez CAN 2.0B.
141 partsMIT - 2 layers60 × 47 mm

Astro driver
rudnik275/astronaut-lamp
Ночник «космонавт на луне» → нативное HomeKit-устройство на ESP32 + HAA: разбор родной платы, схема драйвера, конфиг, корпус
51 parts - 2 layers63 × 58 mm

OPNpool r5
cvonk/OPNpool
Integrates the functionality of a Pentair pool controller into the smart home using ESP32 SoC.
17 parts102 - 4 layers87.6 × 46.7 mm

Modbus to x
joachimda/modbus-to-x
ESP32 based hardware and firmware stack that bridges modbus RTU devices to modern network services.
58 parts5MIT
Questions
How big is the Plts monitoring controller PCB?
It measures 140 × 100 mm and has 2 copper layers, 1.6 mm thick.
What parts does the Plts monitoring controller use?
152 parts, built around the ESP32-WROOM-32E, MAX3485CSA+T, ACS712ELCTR-30A-T and CP2102N-A02-GQFN24. 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 Plts monitoring controller KiCad files?
From the desvandi/PLTSMonitoring_Firmware-Backend repository on GitHub, at the commit this page was made from: the board is pcb/plts-monitoring-controller.kicad_pcb and its schematic pcb/01_POWER.kicad_sch. PCBKit opens the board in the browser, with nothing to install.
Can I use the Plts monitoring controller design in my own project?
Its repository states no licence, so its author keeps all rights: ask desvandi before reusing the design.