Skip to content

FranklinWH Modbus

Unofficial Python library & CLI for controlling FranklinWH battery storage systems via Modbus TCP, optimized for the aGate gateway.

Related Project

For the FranklinWH Cloud API (non-Modbus), see franklinwh-cloud.


Overview

FranklinWH Modbus provides direct, vendor-agnostic local network control over your aGate via the Modbus TCP protocol. Because it communicates directly with the hardware on your LAN, it operates entirely offline, bypasses cloud limits, and offers near-instantaneous response times (≤50ms).

👉 Read the complete guide on What Modbus TCP is, its challenges, and how it compares to the Cloud API


FranklinWH Implementation Coverage

What the aGate X / aPower S system implements via Modbus TCP:

✅ Working

Function Model Details
Battery charge / discharge / standby M704 (WSetPct) Primary control mechanism — percentage of rated max
Battery SoC, SoH, DC power M713 / M714 M713.Sta unreliable (always 0) — state derived from M714.DCW
Battery lifetime energy M714 (DCWhInj / DCWhAbs) Cumulative charge and discharge (Wh)
AC grid power, voltage, frequency M701 Full implementation including per-phase data
Grid lifetime energy M701 (TotWhInj / TotWhAbs) Cumulative grid export and import (Wh)
Solar AC output power M502 (OutPw / OutWh) AC-coupled solar production and lifetime total
Grid protection trip curves M707–M710 Under/over voltage and frequency (read + write)
Volt-Var / Volt-Watt curves M705 / M706 Readable; writes untested
Frequency droop response M711 Readable; writes untested
Temperatures M701 (TmpAmb / TmpCab) Ambient and cabinet temperature

❌ Not Functional

Function Model Issue
DER heartbeat M715 (ControllerHb) Ignored by aGate — use software timeout instead
Hardware reversion timer M704 (WSetRvrtTms) Non-functional — software auto-revert used
DC battery voltage M714 (DCV) Register not populated
DC battery current M714 (DCA) Always returns 0 — calculate from P/V
Solar voltage / current M502 (OutV / InV) Not populated

⚠️ Requires SPAN Unlock

Function Register Without SPAN
Work mode switching Ext 15507 (OnGridMode) Read-only
Self-consumption reserve Ext 15508 Read-only
TOU reserve Ext 15509 Read-only (also mirrors 15508 — known defect)

Features

  • Modbus TCP — Direct register read/write via pymodbus + SunSpec 2.0
  • SunSpec Models — Models 1, 701–706, 713–715
  • FranklinWH Extensions — Registers 15507–15509 (OnGridMode, reserves)
  • CLI Toolfranklinwh_cli.py with charge, discharge, standby, healthcheck, and a live TUI monitor
  • Virtual Modes — Self-Consumption, Emergency Backup, TOU, Peak Shave, Manual
  • Safety Controls — SoC validation, alarm monitoring, conflict detection, auto-revert
  • Target SoC — Charge/discharge to specific SoC with auto-stop

Quick Start

git clone git@github.com:david2069/franklinwh-modbus.git
cd franklinwh-modbus
python3 -m venv venv && source venv/bin/activate
pip install -e ".[dev]"

CLI

CLI="python3 tools/franklinwh_cli.py -i YOUR_AGATE_IP"

$CLI --status                    # Compact status
$CLI --healthcheck               # System health check
$CLI --charge 3000               # Charge at 3000W
$CLI --discharge 2000            # Discharge at 2000W
$CLI --standby                   # Force battery idle
$CLI --charge 3000 --target-soc-auto 80 --loop  # Charge to 80%
$CLI --stop                      # Release control
$CLI --monitor                   # Interactive TUI dashboard

Library

from franklinwh_modbus import FranklinWHController, BatteryCommand

ctrl = FranklinWHController('YOUR_AGATE_IP')
ctrl.connect()

# Read battery status
status = ctrl.read_battery_status()
print(f"SoC: {status['soc']:.1f}%  State: {status['battery_state']}")

# Charge at 3000W with 1-hour auto-revert
cmd = BatteryCommand(power_watts=3000, mode='charge')
ctrl.send_command(cmd, duration_s=3600)

# Release control
ctrl.reset_control_state()
ctrl.disconnect()

SunSpec Model Support

Model Description Read Write Notes
1 Common
701 DER AC Measurements DERMode: Grid Following, Grid Forming, PV Clipped
702 DER DC Measurements
703 DER Capacity
704 DER AC Battery Control WSetPct/WSetEna confirmed working
713 DER Storage Capacity ⚠️ Sta always 0 (unreliable)
714 DER Storage Status DCW used for battery state derivation
715 DER Storage Controls LocRemCtl read-only, heartbeat non-functional

Documentation

Explore the sidebar for detailed guides on: