Skip to main content

FranklinWH Cloud Client

Tests

A Python client library for interacting with FranklinWH energy storage systems via the cloud API.

📦 Package: franklinwh-cloud — pip install franklinwh-cloud | import: from franklinwh_cloud import Client

📊 Fork of richo/franklinwh-python — see FORK_ANALYSIS.md for a detailed comparison of additions (60+ API methods, 45+ sensor fields, TOU scheduling, power control, and more).

🔒 API Citizenship: See API_CLIENT_GUIDE.md for rate limiting strategies, client identity headers, and how to prepare for authentication changes.

⚠️ Disclaimer: This library is unofficial and not endorsed by FranklinWH. It interfaces with a proprietary Cloud API designed exclusively for the official FranklinWH mobile app and authorised installer portal — not for third-party use. It is provided "AS IS" for educational and informational purposes only, with no warranty of fitness for any purpose. Use at your own risk. See the full disclaimer for details.

✨ Features

  • Authentication: Automatic token management and refresh, homeowner + installer account types
  • Real-time Data: Battery status, solar production, grid usage, home loads
  • Mode Control: Switch between operating modes (Time-of-Use, Self-Consumption, Emergency Backup)
  • TOU Schedules: Manage Time-of-Use scheduling with multi-season, weekday/weekend support
  • Energy History: Day, week, month, year, year-to-date and lifetime kWh, plus 5-minute power, exported as a table, JSON or CSV, with a field dictionary describing every column (guide)
  • Device Info: Gateway details, network status, device inventory, BMS cell-level data
  • Performance Monitoring: API call metrics, response timing (min/avg/max), error rates, and CloudFront edge tracking
  • CloudFront Edge Tracking: Automatic PoP location monitoring, failover detection, cache hit rates, and distribution ID tracking
  • Client Identity: Honest identification headers for responsible API citizenship
  • Rate Limiting: Opt-in client-side throttling with per-minute/hour/daily budgets
  • Stale Data Cache: Per-endpoint TTL caching for graceful degradation when the cloud is slow or unavailable
  • Modular Architecture: Domain-specific mixins (stats, modes, TOU, storm, power, devices, account)
  • CLI Tool: Subcommand-based CLI with fetch for arbitrary endpoint access, debug tracing, JSON output

🔧 Technical Highlights

Capability Implementation
HTTP/2 All API calls use httpx with http2=True — multiplexed requests, header compression, persistent connections
CloudFront Monitoring Tracks PoP edge location, cache hit rate, distribution IDs, and failover transitions in real-time
Configurable Base URL Client(fetcher, gw, url_base=...) — ready for FranklinWH DNS migration (energy. → api.)
Dual Account Types LOGIN_TYPE_USER (0) and LOGIN_TYPE_INSTALLER (1) constants for homeowner and installer login
Stale-While-Revalidate Per-endpoint TTL cache returns last-known-good data during API outages
Modbus Mode Constants Bidirectional CLOUD_TO_MODBUS_MODE / MODBUS_TO_CLOUD_MODE mapping for Modbus TCP integration
70+ API Endpoints Comprehensive coverage across TOU scheduling, power control, BMS, storm, smart circuits, compliance

📦 Installation

From a wheel (for downstream projects like FEM)

python -m build                                   # in a checkout of the release tag
pip install dist/franklinwh_cloud-<version>-py3-none-any.whl

From source (editable, for development)

git clone https://github.com/david2069/franklinwh-cloud.git
cd franklinwh-cloud
python3 -m venv venv
source venv/bin/activate
pip install -e .

With test dependencies

pip install -e ".[test]"

From GitHub (direct)

# Latest (tracks main branch)
pip install git+https://github.com/david2069/franklinwh-cloud.git@main

# Pinned release (recommended for production / Docker)
pip install git+https://github.com/david2069/franklinwh-cloud.git@v0.4.10

🏷️ Versions & Releases

  • Releases are listed on the GitHub Releases page; CHANGELOG.md has every version's changes.
  • Pin a tag (@vX.Y.Z) in anything you deploy. @main moves.
  • main holds released code. Work happens on feat/* branches and reaches users only through a tagged release.
  • Versioning is SemVer (pre-1.0): patch releases are fixes only, minor releases add features.
  • Release process: .agents/policies/release_policy.md.

⚙️ Configuration

Create franklinwh.ini with your credentials:

[energy.franklinwh.com]
email = your.email@example.com
password = your_password

[gateways.enabled]
serialno = YOUR_GATEWAY_SERIAL

Security Note: The .ini file is in .gitignore to protect your credentials.

Alternatively, set environment variables:

export FRANKLIN_USERNAME="your.email@example.com"
export FRANKLIN_PASSWORD="your_password"
export FRANKLIN_GATEWAY="YOUR_GATEWAY_SERIAL"

🚀 Quick Start

Authentication Methods

The franklinwh-cloud library supports two distinct initialization architectures.

1. Preferred Method (Legacy Facade)

The easiest way to jump in and begin querying your battery. This wrapper handles standard username/password authentication, naturally locates your gateway serial, and binds the connection for you. Recommended for all standard scripts and basic automations.

import asyncio
from franklinwh_cloud import FranklinWHCloud

async def main():
    client = FranklinWHCloud("user@email.com", "my_password")
    await client.login()
    await client.select_gateway()

    stats = await client.get_stats()
    print(f"Battery: {stats.current.battery_soc}%")
    print(f"Solar: {stats.current.solar_production} kW")
    print(f"Mode: {stats.current.work_mode_desc}")

asyncio.run(main())

2. Advanced / Future-Proof Method (Decoupled Client)

The Decoupled Client architecture separates the Authentication Engine from the Core API Dispatcher.

Future-Proofing: This method should be utilized when the existing legacy authentication method is no longer supported by FranklinWH Cloud API, and new token-based mechanisms (such as API Tokens, OAuth2, or JWT) become mandatory.

This method is also recommended for long-running services (like Home Assistant) that need to securely persist JWT tokens across reboots without storing plaintext passwords on disk.

import asyncio
from franklinwh_cloud.client import Client
from franklinwh_cloud.auth import TokenAuth

async def main():
    # Inject a pre-authenticated OAuth/JWT token directly
    fetcher = TokenAuth("jwt_token_string") 
    client = Client(fetcher, "10060006A02F241XXXX")

    stats = await client.get_stats()
    print(f"Battery: {stats.current.battery_soc}%")

asyncio.run(main())

CLI Tool

# System overview — power, SOC, batteries, weather, grid, metrics
franklinwh-cli status

# Device discovery — 3 verbosity tiers
franklinwh-cli discover          # High-level: site, aGate, flags, state
franklinwh-cli discover -v       # Verbose: + firmware, warranty, relays, accessories
franklinwh-cli discover -vv      # Pedantic: + full firmware, NEM, PTO date
franklinwh-cli discover --json   # Full JSON export

# Operating mode
franklinwh-cli mode
franklinwh-cli mode --set tou --soc 20

# TOU schedule inspection
franklinwh-cli tou --dispatch

# Energy history — table, JSON or CSV (see docs/cli-energy.md)
franklinwh-cli energy --period month --date 2026-09-01 --format csv -o sep.csv
franklinwh-cli energy --period ytd
franklinwh-cli energy --period day --interval 5min --format csv
franklinwh-cli energy --describe        # what every column means (no login)

# Direct API passthrough (33 methods available)
franklinwh-cli raw help
franklinwh-cli raw get_power_info
franklinwh-cli raw get_bms_info AP_SERIAL_NUMBER

# API metrics
franklinwh-cli metrics

# Real-time battery monitor (auto-refresh dashboard)
franklinwh-cli monitor              # full dashboard, 30s refresh, Ctrl+C to exit
franklinwh-cli monitor -i 10        # refresh every 10 seconds
franklinwh-cli monitor -d 5         # run for 5 minutes then stop
franklinwh-cli monitor --compact    # single-line mode (no screen clearing)
franklinwh-cli monitor --json       # JSON stream per interval

Output modes:

franklinwh-cli status --json    # JSON output
franklinwh-cli status --no-color  # disable ANSI colours

Debug & tracing:

franklinwh-cli status -v          # API call summaries
franklinwh-cli status -vv         # + request/response headers
franklinwh-cli status -vvv        # + full raw JSON payloads
franklinwh-cli tou --trace tou    # only TOU mixin debug (46 log points!)
franklinwh-cli status --trace all # everything
franklinwh-cli status --api-trace # per-call timing
franklinwh-cli status -vv --log-file debug.log

DEBUG logs from franklinwh_cloud mask the login token (***) and gateway serials (last 4). The HTTP libraries underneath log on their own: httpx at INFO writes request URLs (with gatewayId=), and httpcore/hpack at DEBUG write the loginToken header. Keep those at WARNING when you turn on DEBUG for the root logger:

for name in ("httpx", "httpcore", "hpack"):
    logging.getLogger(name).setLevel(logging.WARNING)

🏗️ Architecture

graph TB
    CLI["franklinwh-cli"] --> Client
    FEM["FEM / HA Addon"] --> Client
    Scripts["Python Scripts"] --> Client

    subgraph "franklinwh_cloud"
        Client["Client<br/>(composes all mixins)"]
        Client --> API["api.py<br/>HTTP transport, auth"]
        API --> RL["RateLimiter"]
        API --> ET["EdgeTracker<br/>CloudFront PoP"]
        API --> SC["StaleDataCache"]
        
        Client --> Discover["mixins/discover.py"]
        Client --> Stats["mixins/stats.py"]
        Client --> Modes["mixins/modes.py"]
        Client --> TOU["mixins/tou.py"]
        Client --> Power["mixins/power.py"]
        Client --> Devices["mixins/devices.py"]
        Client --> Storm["mixins/storm.py"]
        Client --> Account["mixins/account.py"]
    end

    API --> CF["CloudFront CDN"]
    CF --> FW["FranklinWH Cloud"]
    FW -->|"FranklinWH Official Client<br/>(sendMqtt format)"| aGate[aGate]

    MB["franklinwh_modbus"] -->|"Modbus TCP<br/>(SunSpec/Raw)"| Net["Network<br/>(LAN / WiFi / Remote)"]
    Net -->|port 502| aGate

    aGate --> aPower[aPower Batteries]
    aGate --> PV[Solar PV]
    aGate --> SmC[Smart Circuits]

    style CLI fill:#22c55e,color:#fff
    style Client fill:#3b82f6,color:#fff
    style ET fill:#eab308,color:#000
    style FW fill:#7c3aed,color:#fff
    style MB fill:#d97706,color:#fff
    style Net fill:#6b7280,color:#fff
    style aGate fill:#059669,color:#fff

Terminology Disambiguation: sendMqtt vs True MQTT
Throughout this project, you will see references to sendMqtt payload wrappers. Please note that the FranklinWH Cloud API executes these commands exclusively over standard HTTPS REST endpoints (e.g., POST /hes-gateway/manage/sendMqtt). This library does not establish a true, continuous MQTT TCP/WebSocket local connection to the aGate broker. The term sendMqtt is merely FranklinWH's internal naming convention for the HTTP-encapsulated JSON wrapper they use to tunnel polling requests from the Cloud down to the physical hardware.

franklinwh_cloud/
├── client.py            # Client class (inherits all mixins)
├── models.py            # Stats, Current, Totals, GridStatus dataclasses
├── api.py               # HTTP transport, auth, session management
├── exceptions.py        # Custom exception hierarchy
├── metrics.py           # ClientMetrics — API call instrumentation
├── discovery.py         # DeviceSnapshot dataclass
├── const/               # Operating modes, TOU, device constants
│   ├── modes.py, tou.py, devices.py, device_catalog.json
├── mixins/              # Domain-specific API method groups (8 modules)
│   ├── discover.py      # client.discover() — 3-tier device survey
│   ├── stats.py         # get_stats, get_runtime_data, get_power_by_day
│   ├── modes.py         # get_mode, set_mode, get_mode_info
│   ├── tou.py           # TOU schedule CRUD + dispatch details
│   ├── storm.py         # weather, storm hedge settings
│   ├── power.py         # grid status, PCS settings, power control
│   ├── devices.py       # device info, BMS, composite info
│   └── account.py       # site info, notifications, alarms, warranty
├── cli.py               # CLI entry point
├── cli_output.py        # Terminal rendering + colour utilities
└── cli_commands/        # CLI subcommand modules
    ├── status.py        # Power flow, SOC, mode, weather, grid
    ├── discover.py      # Device discovery — 3 tiers, system readiness
    ├── monitor.py       # Real-time dashboard (full/compact/JSON)
    ├── metrics.py       # API probe + CloudFront edge data
    ├── bms.py           # Battery Management System inspection
    ├── diag.py          # System diagnostics report
    ├── tou.py           # TOU schedule with dispatch details
    ├── mode.py          # Operating mode get/set
    └── raw.py           # Direct API method calls

📖 Documentation

Document Description
API_CLIENT_GUIDE.md Rate limiting, CloudFront edge tracking, metrics, monitor usage
docs/CLI_COMMAND_REFERENCE.md Every CLI command and option on one page, with examples
docs/TEST_QUICK_REFERENCE.md Running the checks safely: offline, live, results, docs build
docs/cli-energy.md energy command: kWh/kW history as CSV/JSON, and the field dictionary for every energy array
franklinwh_openapi.json Unofficial Swagger v3 schema mapped from 123+ raw HTTP .har intercepts
FORK_ANALYSIS.md Detailed comparison with upstream richo/franklinwh-python
HISTORY.md Project timeline from fork to independence
UPSTREAM_STRATEGY.md Contributing back to upstream — the trust ladder
CHANGELOG.md Version history and release notes
CONTRIBUTING.md Development setup, code standards, PR process
ISSUES.md How to report bugs and request features

🧪 Testing

# Unit tests only — offline, no credentials, safe to run any time
pytest -m "not live" -q

# Live API tests (requires franklinwh.ini or env vars)
pytest -m live -v

# Record results for traceability (AP-11)
./tests/run_and_record.sh CLI-refactor
cat tests/results/test_history.log

⚠️ Live tests act on your real system. -m live authenticates against the real cloud, and tests/test_live_mode.py issues real set_mode() writes that change your aGate's operating mode. Plain pytest with no -m filter includes them. Never run live tests unattended. See .agents/policies/live_test_protocol.md.

📚 API Reference

Client Methods

Domain Key Methods
Discovery discover(tier=1) → DeviceSnapshot — site, aGate, batteries, flags, accessories, warranty
Stats get_stats(), get_runtime_data(), get_power_by_day(date), get_power_details(type, date)
Modes get_mode(), set_mode(mode, soc), get_mode_info()
TOU get_tou_info(type), set_tou(schedule), get_gateway_tou_list(), get_tou_dispatch_detail()
Tariff get_utility_companies(), get_tariff_list(), get_tariff_detail(), apply_tariff_template()
Storm get_weather(), get_storm_settings(), get_storm_list()
Power get_grid_status(), get_power_control_settings(), get_power_info()
Devices get_device_info(), get_bms_info(serial), get_device_composite_info()
Account siteinfo(), get_warranty_info(), get_alarm_codes_list(), get_notification_settings()
Metrics get_metrics() → {total_api_calls, avg_response_time_s, calls_by_method, errors, ...}

Data Structures

stats.current.battery_soc          # Battery State of Charge (%)
stats.current.solar_production     # Solar production (kW)
stats.current.grid_use             # Grid usage (kW, negative = export)
stats.current.home_load            # Home consumption (kW)
stats.current.work_mode_desc       # Operating mode name
stats.current.grid_status          # GridStatus enum (NORMAL/DOWN/OFF)
stats.totals.solar                 # Daily solar production (kWh)
stats.totals.grid_import           # Daily grid import (kWh)
stats.totals.home_use              # Daily home consumption (kWh)

🗺️ Roadmap

Installer Account Support (CLI-only, read-only)

The FranklinWH Cloud API supports installer accounts — these are privileged accounts used by solar installers to manage fleets of customer aGate gateways. The login endpoint (appUserOrInstallerLogin) supports both account types via a type parameter: 0 = app user, 1 = installer.

Already implemented:

  • LOGIN_TYPE_USER = 0 and LOGIN_TYPE_INSTALLER = 1 constants
  • login_type parameter on TokenFetcher, login(), and _login()
  • Configurable url_base on Client for future DNS changes

Planned scope:

  • CLI --installer flag to authenticate as an installer
  • discover command to list all customer gateways in the installer's fleet
  • status command with --gateway SN to view any customer's system
  • Read-only only — no write operations (mode changes, TOU updates) via installer CLI
  • Per-gateway selection required (no fleet-wide operations)

Usage:

from franklinwh_cloud.client import TokenFetcher, LOGIN_TYPE_INSTALLER

# Installer login
fetcher = TokenFetcher("installer@company.com", "password", login_type=LOGIN_TYPE_INSTALLER)
client = Client(fetcher, "CUSTOMER_GATEWAY_SN")
info = await client.siteinfo()  # returns installerId, userTypes, roles, etc.

⚠️ Installer accounts can access and modify multiple customer sites. This library intentionally limits installer support to read-only CLI operations as a matter of responsible API citizenship. Developers who fork this library assume their own responsibility for write operations.

🤝 Contributing

See CONTRIBUTING.md for development setup, code standards, API citizenship requirements, and pull request process.

See ISSUES.md for how to report bugs and request features.

📝 License

🔒 Telemetry & Privacy

This project strictly enforces opt-in telemetry to understand community usage patterns through Scarf and PostHog when actively configured. Because the gateway holds sensitive credentials and hardware mapping, we mathematically never log PII, serial numbers, IP addresses, or gateway configurations.

See the explicitly audited Telemetry & Privacy Policy for full compliance details on PyPI and Home Assistant integrations.


MIT License with Additional Terms — see LICENSE for details.

The Additional Terms address the specific risks of interacting with undocumented energy equipment APIs. You must read and understand the LICENSE before using this software.

🙏 Acknowledgments

  • FranklinWH - For innovative energy storage systems
  • richo - Original library foundation
  • This project was developed with AI assistance (Claude, Gemini)

⚖️ Disclaimer

UNOFFICIAL SOFTWARE — NOT AFFILIATED WITH FRANKLINWH

By using this software, you confirm that you have read and understood the LICENSE and its Additional Terms.

This software is provided AS-IS, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. Use entirely at your own risk.

This library interacts with FranklinWH's undocumented cloud API, which may change, break, or become unavailable without notice. The authors accept no liability for service interruptions, data loss, equipment damage, or any other consequences arising from the use of this software.

MIT License — see LICENSE for details.

This disclaimer is also logged once at startup by the library for audit trail purposes.

Metadata

Release files for franklinwh-cloud 0.6.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for franklinwh-cloud 0.6.4
File Size Uploaded Provenance
franklinwh_cloud-0.6.4.tar.gz 429.4 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for franklinwh-cloud 0.6.4
File Interpreter ABI Platform
franklinwh_cloud-0.6.4-py3-none-any.whl Python 3 none any Details

Total release size: 749.1 kB

Release files / franklinwh_cloud-0.6.4.tar.gz

Download URL franklinwh_cloud-0.6.4.tar.gz
Size 429.4 kB
Tags Source
SHA-256 checksum
How to use checksums
a32382d888e3335574ba65f4ef87d9ea983222b18c9cc77cda50083123c757ff
BLAKE2b-256 checksum
How to use checksums
fa5ec20006556ab73c8e4c184222247003634fa465c7b056f2ffc1e7ee404355
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

Release files / franklinwh_cloud-0.6.4-py3-none-any.whl

Download URL franklinwh_cloud-0.6.4-py3-none-any.whl
Size 319.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
827deaed23ab332cf09dc288dd7803303c1c9061c9f2c0df5a82e5af30959895
BLAKE2b-256 checksum
How to use checksums
484d97450fbdec04c5176b2f09e774fae92ef1f9f7108e505d5d4c0def653c3b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

Security for franklinwh-cloud 0.6.4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for franklinwh_cloud-0.6.4.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page