Skip to content

Latest commit

 

History

History
75 lines (56 loc) · 4 KB

File metadata and controls

75 lines (56 loc) · 4 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Fronius Gen24 Modbus TCP to MQTT bridge for Home Assistant. Reads inverter data via SunSpec Modbus TCP registers, publishes to MQTT with HA auto-discovery, and accepts commands from HA back to the inverter over Modbus.

Build & Run

# Run locally
pip install -r requirements.txt
cp .env.example .env  # edit with your inverter/broker IPs
python -m src

# Docker
docker compose up -d --build

# Logs
docker compose logs -f fronius-modbus

Architecture

src/
  config.py        - Env-var-based configuration (Config class)
  registers.py     - SunSpec model & register definitions (absolute 40xxx addresses)
  modbus_client.py - pymodbus wrapper: read/write registers, scale factor handling
  mqtt_client.py   - paho-mqtt wrapper: HA discovery, state publishing, command subscriptions
  greengrid.py     - Green Grid uniform command handler (SPEC §6): JSON command -> verified SunSpec-124 register sequences
  main.py          - Main loop: poll modbus -> publish MQTT, handle MQTT commands -> write modbus

Two command paths: the original fronius/command/<register> (raw register writes, used by HA) and the optional Green Grid uniform interface greengrid/inverter/<id>/command (high-level {mode, power_w, ttl_s} → verified register sequences, gated by GG_ENABLE). See README "Green Grid uniform command interface" and src/greengrid.py. Modbus I/O is serialized by a lock in modbus_client since the poll loop and the MQTT command callback run on different threads. Force-writes use FC16 (write_registers_fc16); FC06 is silently ignored by the storage model. Requires pymodbus 3.6.x (slave= kwarg).

Data flow:

  • Inverter → (Modbus TCP read) → modbus_client → scale factor applied → mqtt_client → MQTT broker → Home Assistant
  • Home Assistant → MQTT command topic → mqtt_clientmain.handle_commandmodbus_client → (Modbus TCP write) → Inverter

Key Design Decisions

  • Register addresses are absolute (40001-based, matching Fronius documentation). Fronius Gen24 uses raw Modbus addresses, so the pymodbus offset is computed via Register.address property (start - 1).
  • Scale factors are read once at startup, then refreshed every 60 poll cycles. Many are "auto-scaled" by the inverter and can change.
  • Two register maps: non-storage (MPPT with 2 PV modules) and storage (MPPT with 4 modules + storage model 124). Controlled by HAS_STORAGE env var.
  • MQTT topics: state at fronius/<model>/state (JSON), commands at fronius/command/<register_name> (single value).
  • HA Discovery: sensors for read-only registers, number/select entities for writable registers. Device grouping by inverter serial number.

SunSpec Models (from Fronius Excel register maps)

Model ID Addr Range Purpose
Common (1) 1 40003-40069 Device info (manufacturer, model, serial)
Inverter (10x) 101/103 40070-40121 AC/DC measurements, operating state
Nameplate (120) 120 40122-40149 Device ratings
Settings (121) 121 40150-40181 Configuration (read-only)
Status (122) 122 40182-40227 Connection status, lifetime energy
Controls (123) 123 40228-40253 Power limit, PF, VAR control (R/W)
MPPT (160) 160 40254-40303/40343 PV string data + battery channels
Storage (124) 124 40344-40369 Battery control (charge/discharge, SoC)

Writable Registers (Controls model 123)

Key controls: conn (connect/disconnect), w_max_lim_pct + w_max_lim_ena (power limiting), out_pf_set + out_pf_set_ena (power factor), var_max_pct + var_pct_ena (reactive power).

Writable Registers (Storage model 124)

Key controls: storage_ctrl_mode (bit 0=charge, bit 1=discharge), storage_out_w_rte / storage_in_w_rte (charge/discharge rate %), storage_min_rsv_pct (min battery reserve), storage_cha_gri_set (grid charging enable).