Skip to main content

Unofficial Python client library and CLI for FranklinWH energy storage systems via the Cloud API

Project description

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
  • 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 wheel (recommended for downstream projects like FEM)

pip install dist/franklinwh_cloud_client-0.3.0-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.3.0

โš™๏ธ 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

# 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

๐Ÿ—๏ธ 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
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 (no API credentials needed)
pytest -m "not live" -q

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

# All tests
pytest -v

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

Current coverage: 286 tests across all 8 domains

๐Ÿ“š 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

franklinwh_cloud-0.4.7.tar.gz (197.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

franklinwh_cloud-0.4.7-py3-none-any.whl (175.6 kB view details)

Uploaded Python 3

File details

Details for the file franklinwh_cloud-0.4.7.tar.gz.

File metadata

  • Download URL: franklinwh_cloud-0.4.7.tar.gz
  • Upload date:
  • Size: 197.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for franklinwh_cloud-0.4.7.tar.gz
Algorithm Hash digest
SHA256 fdab6abf900ee58aef7a0af7354b82f220ba69edfc3b4e256535dc690110cd3a
MD5 edc999c0a816d5226d7503647c5995fc
BLAKE2b-256 53ce3f499130f6858dcd2301e246b408d800acba08b4fc60d36ec477179b82db

See more details on using hashes here.

Provenance

The following attestation bundles were made for franklinwh_cloud-0.4.7.tar.gz:

Publisher: publish.yml on david2069/franklinwh-cloud

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file franklinwh_cloud-0.4.7-py3-none-any.whl.

File metadata

File hashes

Hashes for franklinwh_cloud-0.4.7-py3-none-any.whl
Algorithm Hash digest
SHA256 b56a43ca6aa4836b66e63de5f9dd68b2336198c8551d938d7ddd46d8784779af
MD5 0bb67dad50ece6d5169602f677ffce9a
BLAKE2b-256 f1e9bf62b6838f496e92b92cdcaa889ed3728aa949f93ff001e9e0c70fbc7c95

See more details on using hashes here.

Provenance

The following attestation bundles were made for franklinwh_cloud-0.4.7-py3-none-any.whl:

Publisher: publish.yml on david2069/franklinwh-cloud

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page