A daemon that do modbus with the sunspec standard and publishes to MQTT with home assistant discovery.
  • Go 83.9%
  • Nix 11.6%
  • Makefile 3.7%
  • Shell 0.8%
Find a file
Simon Gate 016a7270df
All checks were successful
CI / test (push) Successful in 1m13s
release v0.2.1
2026-06-30 21:19:44 +02:00
.forgejo/workflows add cicd 2026-06-27 22:36:50 +02:00
cmd/sunspecd fix linting errors 2026-06-27 22:47:50 +02:00
internal fix linting errors 2026-06-27 22:47:50 +02:00
nix improve modbus connection handling 2026-06-27 16:25:32 +02:00
packaging rename project ha-sunspec 2026-06-25 18:59:54 +02:00
.gitignore update modbus module to latest version 2026-06-27 16:31:22 +02:00
AGENTS.md rename project ha-sunspec 2026-06-25 18:59:54 +02:00
flake.lock add nixos module 2026-06-25 20:58:31 +02:00
flake.nix release v0.2.1 2026-06-30 21:19:44 +02:00
go.mod update modbus module to latest version 2026-06-27 16:31:22 +02:00
go.sum update modbus module to latest version 2026-06-27 16:31:22 +02:00
Makefile rename project ha-sunspec 2026-06-25 18:59:54 +02:00
README.md add nixos module 2026-06-25 20:58:31 +02:00
sunspecd.service rename project ha-sunspec 2026-06-25 18:59:54 +02:00

ha-sunspec

ha-sunspec is a read-only SunSpec-over-Modbus TCP telemetry daemon. It probes a SunSpec device, derives device metadata where possible, logs readings locally when MQTT is disabled, and optionally publishes Home Assistant MQTT discovery, state, and availability payloads.

Commands

Probe a device and print discovered SunSpec information:

sunspecd probe --modbus-host 192.168.1.50

Run the daemon without MQTT:

sunspecd run --modbus-host 192.168.1.50

Run the daemon with MQTT:

sunspecd run \
  --modbus-host 192.168.1.50 \
  --mqtt-host mqtt.local \
  --poll-interval 30s

Discovery

At startup, run and probe scan for the SunSpec layout, read the model list, read common model 1 when available, and select the telemetry model automatically.

Auto-selected telemetry model priority:

  1. 113 three-phase float inverter model
  2. 103 three-phase integer plus scale-factor inverter model

Explicit values override discovery for:

  • --sunspec-base-offset
  • --sunspec-model-id
  • --device-name
  • --device-manufacturer
  • --device-model
  • --device-identifier

Defaults

Setting Default
Modbus port 502
Modbus unit ID 1
SunSpec base offset 0 auto-discover
SunSpec model ID 0 auto-discover
Poll interval 30s
MQTT broker disabled; set MQTT_HOST to enable MQTT
MQTT client ID sunspecd
MQTT discovery prefix homeassistant
Device identity auto-discover from SunSpec common model 1
Metrics address :9332
Log level info

--modbus-host or MODBUS_HOST is required. If --mqtt-host or MQTT_HOST is empty, readings are written to the application log instead of MQTT.

Configuration

Flags override environment variables.

Flag Environment Description
--modbus-host MODBUS_HOST SunSpec Modbus TCP host.
--modbus-port MODBUS_PORT SunSpec Modbus TCP port.
--modbus-unit-id MODBUS_UNIT_ID Modbus unit ID.
--sunspec-base-offset SUNSPEC_BASE_OFFSET SunSpec base/layout offset. 0 enables auto-discovery.
--sunspec-model-id SUNSPEC_MODEL_ID SunSpec telemetry model ID. 0 enables auto-discovery.
--poll-interval POLL_INTERVAL Poll interval as a Go duration, for example 30s or 1m.
--mqtt-host MQTT_HOST MQTT broker host. Leave empty to log readings instead of publishing MQTT.
--mqtt-port MQTT_PORT MQTT broker port.
--mqtt-user MQTT_USER MQTT username.
--mqtt-pass MQTT_PASS MQTT password.
--mqtt-client-id MQTT_CLIENT_ID MQTT client ID.
--mqtt-prefix MQTT_PREFIX Optional prefix prepended to all MQTT topics.
--mqtt-discovery-prefix MQTT_DISCOVERY_PREFIX Home Assistant discovery prefix.
--mqtt-connect-timeout MQTT_CONNECT_TIMEOUT MQTT connect timeout.
--mqtt-publish-timeout MQTT_PUBLISH_TIMEOUT MQTT publish timeout.
--device-name DEVICE_NAME Home Assistant device name. Empty uses SunSpec common model metadata.
--device-manufacturer DEVICE_MANUFACTURER Home Assistant device manufacturer. Empty uses SunSpec common model metadata.
--device-model DEVICE_MODEL Home Assistant device model. Empty uses SunSpec common model metadata.
--device-identifier DEVICE_IDENTIFIER Stable Home Assistant device identifier. Empty uses SunSpec common model metadata.
--metrics-address METRICS_ADDRESS Prometheus listen address.
--log-level LOG_LEVEL debug, info, warn, or error.

MQTT Topics

State topics are retained and use the device identifier and SunSpec point ID:

<mqtt-prefix>/<device-identifier>/sensor/<point-id>/state

Availability is retained at:

<mqtt-prefix>/<device-identifier>/availability

Home Assistant discovery payloads are retained at:

<mqtt-prefix>/<mqtt-discovery-prefix>/sensor/<device-identifier>_<point-id>/config

When --mqtt-prefix is empty, the leading prefix segment is omitted.

Published sensor points include AC current, voltage, power, frequency, energy, DC current, DC voltage, DC power, temperature, status, and event diagnostics from SunSpec inverter models 113 and 103.

No MQTT command topics are published in this version.

Build And Run

go test ./...
go vet ./...
go run ./cmd/sunspecd --help
go run ./cmd/sunspecd probe --help
make build-amd64

Run locally:

MODBUS_HOST=192.168.1.50 MQTT_HOST=mqtt.local go run ./cmd/sunspecd run

Install

Build a package and install it on the target host:

make build-amd64
sudo tar -xzf dist/ha-sunspec-amd64.tar.gz -C /tmp
sudo /tmp/ha-sunspec/install.sh

Install the systemd unit:

sudo cp sunspecd.service /etc/systemd/system/sunspecd.service
sudo systemctl daemon-reload
sudo systemctl enable --now sunspecd.service

Edit environment values in /etc/systemd/system/sunspecd.service or add a systemd drop-in before starting the service.

NixOS Module

The flake exports a package and NixOS module for use from another flake:

{
  inputs.ha-sunspec.url = "github:your-org/ha-sunspec";

  outputs = {nixpkgs, ha-sunspec, ...}: {
    nixosConfigurations.my-host = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        ha-sunspec.nixosModules.default
        {
          services.ha-sunspec = {
            enable = true;
            modbus.host = "192.168.1.50";
            mqtt.host = "mqtt.local";
            mqtt.passwordFile = "/run/secrets/ha-sunspec-mqtt-password";
          };
        }
      ];
    };
  };
}

Set services.ha-sunspec.mqtt.host = null or omit it to log readings instead of publishing MQTT. Use services.ha-sunspec.mqtt.passwordFile for the MQTT password; the module loads it with systemd LoadCredential and exports it as MQTT_PASS only at service runtime.