Monitoring Home Battery SOC with Grafana: OPNsense, Telegraf, and MQTT Bridge

Grafana connected to an OPNsense Telegraf plugin and an MQTT broker receiving data from a JBD or JK BMS gives you a real-time state-of-charge dashboard for your home battery that updates every 30 seconds. The entire stack runs on the OPNsense router itself — Telegraf as the metrics collector, Mosquitto as the MQTT broker bridging the battery BMS to the network, InfluxDB for time-series storage, and Grafana for visualization, all on the box that is already your firewall and always powered on. The 48V LiFePO4 battery that powers the network gear is the same battery whose SOC you are monitoring, which means the dashboard keeps reporting even during a grid outage, and the SOC curve during an outage is the most valuable data you will ever collect from the system.

The OPNsense Stack That Makes This Possible

OPNsense is a FreeBSD-based firewall with a plugin system that supports Telegraf natively. The Telegraf plugin does not require Docker, a separate VM, or a Raspberry Pi — it installs from the OPNsense plugin manager, reads system metrics (CPU, memory, network throughput, firewall states), and pushes them to an InfluxDB instance that can run on the same OPNsense box or on a separate network-attached storage device. Adding the MQTT input to Telegraf means the router becomes the bridge: the BMS publishes cell voltages and SOC via MQTT to a Mosquitto broker (also running on OPNsense), Telegraf subscribes to those MQTT topics and writes them to InfluxDB as time-series data, and Grafana queries InfluxDB to render the dashboard. No cloud services, no external dependencies — the whole stack is local and survives an internet outage because OPNsense, Mosquitto, InfluxDB, and Grafana all run on the same metal.

OPNsense router firewall rack-mounted in homelab server cabinet

Hardware That Bridges the BMS to the Network

The physical connection starts at the BMS UART port inside the battery enclosure. A JBD BMS has a 4-pin UART header (TX, RX, GND, VCC) that connects to an ESP32 development board via a logic-level converter — the BMS runs at 3.3V UART and the ESP32’s GPIO pins are 3.3V-tolerant, but the converter protects against voltage spikes from the BMS during cell balancing when the internal electronics can briefly pull the UART line to pack voltage if the BMS’s onboard regulator glitches. The ESP32 runs the open-source bms-to-mqtt firmware, which polls the BMS every 5 seconds for the full data packet (16 cell voltages, pack voltage, current, SOC, 4 temperature sensors, cycle count, protection status flags) and publishes each value to its own MQTT topic on the local Mosquitto broker.

The ESP32 connects to the same Wi-Fi SSID that OPNsense hosts, or via Ethernet if your ESP32 has an Ethernet shield. The Wi-Fi path is simpler — the ESP32 costs $5, draws under 1 watt, and connects to the network that the OPNsense router manages. If the Wi-Fi link drops during a grid outage because the access point rebooted, the ESP32 automatically reconnects when the AP comes back, and the data gap in InfluxDB is visible as a flat line on the Grafana dashboard — which is itself a diagnostic signal that something in the network path failed during the outage.

ESP32 microcontroller connected to JBD BMS board with UART wires
ComponentRuns OnPurpose
JBD/JK BMS with UART-to-USBBattery enclosurePublishes cell voltages, SOC, current, temperature
Mosquitto MQTT BrokerOPNsense (plugin or jail)Receives BMS data and relays to Telegraf
TelegrafOPNsense (plugin)Collects MQTT topics + system metrics into InfluxDB
InfluxDBOPNsense or NASTime-series database for all metrics
GrafanaOPNsense or separate hostDashboard visualization, alerting thresholds

MQTT Topics Your BMS Should Publish

The JBD BMS with an ESP32 running the “bms-to-mqtt” firmware publishes the following MQTT topics that form the dashboard data stream. Each topic updates every 5-30 seconds depending on BMS polling rate, and Telegraf’s MQTT consumer input plugin subscribes to all of them with a single configuration block:

battery/soc → 87.3 (state of charge percentage)
battery/voltage → 53.12 (pack voltage)
battery/current → -12.4 (negative = discharging, positive = charging)
battery/power → -658 (watts, calculated by BMS)
battery/cell_01_voltage → 3.321 (through cell_16_voltage)
battery/temp_01 → 28.5 (through temp_04, Celsius)
battery/cycles → 247 (total charge/discharge cycles)

Grafana’s InfluxDB data source queries these topics as time-series measurements. The most useful dashboard panels are SOC over time (line graph, 24-hour and 7-day views), individual cell voltage spread (to catch a weak cell before it drags the whole pack below the BMS cutoff), charge/discharge power (stacked area chart showing when the battery charged from solar and when it fed the house), and a stat panel showing current SOC, pack voltage, and estimated runtime at current load — which is calculated as (remaining watt-hours) divided by (current watts draw) displayed in hours and minutes. The cell voltage spread panel is the most valuable early-warning indicator in the entire dashboard — a single cell that drops to 2.8V while the other 15 are at 3.2V under load is a failing cell, and catching it on a dashboard is the difference between replacing a $50 cell and replacing a $200 BMS that welded its discharge MOSFETs shut trying to compensate.

Grafana dashboard showing LiFePO4 cell voltage spread chart with alert threshold

For the hardware side of a LiFePO4 system that produces this data — including cell selection, BMS wiring, and compression fixtures — the DIY LiFePO4 battery bank build guide on BatteryStorageHQ covers the electrical build that the monitoring stack here tracks.

Frequently Asked Questions

Can I monitor battery SOC from my OPNsense router?

Yes. Install the Telegraf plugin on OPNsense, configure the MQTT consumer input to subscribe to battery/soc and battery/voltage topics from your BMS, and write the data to InfluxDB. Grafana queries InfluxDB to render the SOC dashboard. The entire stack runs locally on the router without cloud services.

What BMS works with MQTT for home battery monitoring?

JBD (JiaBaida) and JK BMS models with UART output connect to an ESP32 running bms-to-mqtt firmware. The ESP32 reads the BMS via UART and publishes cell voltages, SOC, current, and temperature to MQTT topics. Total cost for the ESP32 plus firmware is under $10 per battery pack.

How often does the Grafana battery dashboard update?

The BMS publishes data every 5-30 seconds, Telegraf writes to InfluxDB on the same interval, and Grafana refreshes the dashboard on a configurable 10-60 second auto-refresh. The 30-second update granularity captures inrush current from inverter startup and reveals transient voltage sag under heavy load.

Can I set Grafana alerts for low battery SOC?

Yes. Grafana alerting rules trigger when SOC drops below a configurable threshold — typically 20% for LiFePO4. Configure notification channels for email, Discord, or Pushover. Set a second alert at 10% SOC as the critical threshold that means the inverter will shut down within minutes if load does not decrease.

Does this monitoring stack work during a power outage?

Yes. OPNsense, Mosquitto, InfluxDB, and Grafana all run on the router hardware, which is powered by the same 48V battery being monitored. The dashboard continues collecting and displaying data throughout an outage, and the SOC curve during discharge is the most valuable long-term data for sizing future battery expansions.

What Grafana dashboard panels are most useful for battery monitoring?

SOC over time (line graph with 24h and 7d views), individual cell voltage spread (detect weak cells), charge/discharge power (stacked area chart), and a stat panel showing current SOC with estimated runtime at current load in hours and minutes. Cell voltage spread is the most important early-warning metric in the entire pack.

Related Articles

Leave a Comment

Your email address will not be published. Required fields are marked *