Monitoring Battery State via Meshtastic Telemetry
Meshtastic and MeshCore both include power telemetry features that allow a node to report its battery voltage and charge level over the mesh network. This page covers enabling these features, configuring voltage ADC pins for different hardware, interpreting voltage as state-of-charge for LiFePO4 batteries, setting low-battery alerts, and visualising data in Grafana.
Enabling Power Telemetry in Meshtastic
In Meshtastic firmware (2.x), power metrics are part of the Telemetry Module. To enable battery reporting:
Via Meshtastic Python CLI
# Install CLI: pip install meshtastic # Enable device metrics (includes battery level, voltage, uptime) meshtastic --set telemetry.device_update_interval 300 # Sets reporting interval to 300 seconds (5 minutes) # Verify telemetry module is enabled meshtastic --get telemetry
Via Meshtastic Web App or Mobile App
- Open the Meshtastic app and connect to your node.
- Navigate to Config → Module Config → Telemetry.
- Enable Device Metrics.
- Set the update interval (300 - 3600 seconds; use longer intervals for battery-powered nodes to reduce TX duty cycle).
- Save and reboot the node.
Once enabled, the node broadcasts a meshtastic.Telemetry protobuf packet on the default channel at the configured interval. The packet includes:
battery_level: Integer 0 - 100 (firmware-estimated SoC percentage)voltage: Float in volts (actual measured ADC voltage)channel_utilization: Float (% airtime used)air_util_tx: Float (TX airtime)
Voltage ADC Pin Configuration on Different Boards
Not all Meshtastic hardware platforms use the same pin or divider ratio for battery voltage measurement. The firmware auto-detects the board type from compile-time defines, but custom builds or off-label hardware may need manual configuration.
| Board | ADC Pin (GPIO) | Voltage Divider Ratio | Max Measurable Voltage | Notes |
|---|---|---|---|---|
| TTGO T-Beam v0.7 | GPIO35 | 1:2 (100 kΩ / 100 kΩ) | ~8.4 V | Measures raw LiPo voltage |
| TTGO T-Beam v1.1 (AXP192) | AXP192 PMIC register | Internal PMIC ADC | Reported via I²C | Reads VBAT register; very accurate |
| TTGO LoRa32 v2.1 | GPIO35 | 1:2 | ~8.4 V | Same as T-Beam v0.7 |
| Heltec WiFi LoRa 32 v3 | GPIO1 (ADC1_CH0) | 1:1 (no divider; up to 3.3 V input only) | 3.3 V max | Only suitable for direct 3.3 V LiPo via USB-C charging; not for 12 V systems |
| RAK WisBlock RAK4631 | GPIO5 (P0.05 / AIN3) | 1:2 via RAK5005-O base board | ~6 V | Reads via nRF52840 SAADC |
| Wispr / Custom ESP32 | User-defined GPIO | User-defined | User-defined | Set in platformio.ini or via power.adc_multiplier_override config key |
If the reported voltage seems incorrect, verify with a multimeter at the battery terminals. Then check power.adc_multiplier_override:
meshtastic --set power.adc_multiplier_override 2.0 # Multiplies the raw ADC reading by 2.0 (use for 1:2 divider boards)
Interpreting Voltage as State-of-Charge for LiFePO4
Meshtastic's built-in SoC estimation uses LiPo voltage thresholds (3.0 - 4.2 V per cell). For LiFePO4 packs, these thresholds are incorrect - LiFePO4 cells operate in the 2.5 - 3.65 V range. The firmware will report incorrect percentages unless you compensate.
LiFePO4 Single-Cell (3.2 V nominal) Voltage → SoC Table
| Resting OCV (V) | Approximate SoC (%) | Interpretation |
|---|---|---|
| 3.60 - 3.65 | 100% | Fully charged, absorb phase complete |
| 3.40 - 3.45 | 90% | High charge, float plateau |
| 3.30 - 3.35 | 70 - 80% | Mid-range - most of usable capacity here |
| 3.27 - 3.30 | 50% | Flat region - voltage barely distinguishable from 70% |
| 3.22 - 3.25 | 30% | Still flat; lower usable threshold approaching |
| 3.18 - 3.22 | 20% | Low battery - alert threshold |
| 3.10 - 3.18 | 10% | Critical - immediate recharge needed |
| < 3.10 | <5% | BMS will soon disconnect; node will shut down |
4S LiFePO4 Pack (12.8 V nominal) Voltage → SoC Table
| Pack Voltage (V) | SoC (%) |
|---|---|
| 14.4 - 14.6 | 100% (end of charge) |
| 13.6 - 13.8 | 90% |
| 13.2 - 13.4 | 70 - 80% |
| 13.0 - 13.2 | 50% |
| 12.8 - 13.0 | 30% |
| 12.4 - 12.8 | 20% |
| 12.0 - 12.4 | 10% |
| < 11.8 | <5% (BMS cutoff imminent) |
Setting Low-Battery Alerts in Meshtastic
Meshtastic does not natively send alert messages when battery drops below a threshold, but there are two approaches to implement this:
Approach 1 - Node-Red / MQTT Alert Pipeline
- Configure Meshtastic MQTT uplink:
meshtastic --set mqtt.enabled true --set mqtt.address YOUR_BROKER_IP - In Node-Red, subscribe to
msh/US/+/json/LongFast/#(adjust channel name as needed). - Filter for
msg.payload.decoded.telemetry.deviceMetrics.voltagebelow your LVD threshold. - Route low-voltage events to an alert node (email, PushOver, Telegram bot).
Approach 2 - Meshtastic Python Script (Autonomous Node)
import meshtastic
import meshtastic.serial_interface
from meshtastic.mesh_pb2 import MeshPacket
iface = meshtastic.serial_interface.SerialInterface()
LOW_VOLTAGE_THRESHOLD = 3.18 # V per cell for LiFePO4 (20% SoC)
def on_receive(packet, interface):
if "decoded" in packet and "telemetry" in packet["decoded"]:
m = packet["decoded"]["telemetry"].get("deviceMetrics", {})
voltage = m.get("voltage", 0)
node_id = packet["fromId"]
if voltage > 0 and voltage < LOW_VOLTAGE_THRESHOLD:
print(f"LOW BATTERY: Node {node_id} at {voltage:.2f} V")
# Send alert message on mesh
iface.sendText(f"⚠ Low battery: {node_id} {voltage:.2f}V", wantAck=False)
iface.localNode.setOwner("MonitorNode")
iface.addReceiveObserver(on_receive)
input("Press Enter to exit\n")
iface.close()
MeshCore Telemetry Equivalent
MeshCore uses a similar but distinct telemetry structure. Battery reporting in MeshCore is enabled via the telemetry section in the node YAML configuration file:
telemetry: enabled: true interval_s: 300 battery: adc_pin: 35 adc_vref: 3.3 divider_ratio: 2.0 low_voltage_alert: 3.18
MeshCore publishes telemetry packets to MQTT in JSON format. Grafana can consume these via the Grafana MQTT data source plugin or via InfluxDB (Node-Red → InfluxDB → Grafana).
Graphing Battery Data in Grafana
Architecture
Meshtastic Node │ (MQTT telemetry JSON) ▼ Mosquitto MQTT Broker │ ▼ Node-Red (parse JSON → extract voltage/SoC → write to InfluxDB) │ ▼ InfluxDB 2.x (time-series storage) │ ▼ Grafana (dashboards, alerts)
InfluxDB Line Protocol (Node-Red write node)
measurement: node_battery tags: node_id, node_name, location fields: voltage (float), battery_pct (int), soc_lifepo4 (float) timestamp: nanosecond UNIX timestamp from packet
Grafana Panel Configuration
- Battery voltage time series: Use a Time Series panel with threshold bands - green above 3.30 V, yellow 3.18 - 3.30 V, red below 3.18 V (per cell) or scale for your pack voltage.
- Multi-node SoC gauge: Use a Gauge panel per node with min=0, max=100, thresholds at 20% (red) and 40% (yellow).
- Grafana Alerting: Set an alert rule on
avg(voltage) < 3.18for any node, with a 15-minute evaluation window (to avoid false alarms from momentary load spikes). Route to PagerDuty, Slack, or email.
A complete Grafana dashboard JSON template for Meshtastic power monitoring is maintained in the Mesh America GitHub repository under monitoring/dashboards/meshtastic-power.json.
No comments to display
No comments to display