SunSpec Modbus is not a wire protocol of its own. It is a set of standard information models that distributed energy resources expose, and their mapping into Modbus registers: inverters, meters, batteries, string combiners and more. A device starts its map with the SunS marker at a base address, followed by a chain of models, each identified by a number (for example 103 for a three-phase inverter). Values carry scale factors, so a raw register becomes watts, volts or amps only after decoding.
What Modbus defines, and what SunSpec adds
| Modbus defines | SunSpec Modbus adds |
|---|---|
| Function codes to read and write coils and 16-bit registers | Which registers hold which value: standard models with named, typed points |
| Addressing by unit ID and register number, with no meaning attached | A SunS marker at a known base address, then a chain of models a client can walk |
| Framing for TCP, TLS, RTU and ASCII | Data types across registers (int32, float32, strings, enums, bitfields) and “not implemented” values |
| Exceptions when a request fails | Scale factors and units, so a raw register becomes watts, volts or amps |
| Optional device identification (FC 43) as free-form vendor strings | Common model, nameplate, settings, DER controls and curves, laid out the same way on every compliant device |
A SunSpec client is a Modbus client that knows the models. go-sunspec builds on go-modbus for that reason: go-modbus moves registers over the wire, go-sunspec turns them into models and back.
Where you meet it
- Solar inverters and hybrid inverters
- Battery storage systems and their energy management
- Revenue and production meters on DER sites
Quickstart
From the command line
sunspecctl is a single binary for Linux, macOS and Windows. Download it from GitHub Releases, then:
# Is this a SunSpec device, and at which base address?sunspecctl detect --url tcp://192.168.1.100:502
# Which SunSpec models does it implement?sunspecctl models --url tcp://192.168.1.100:502
# Copy the device into a file, and serve that copy as a simulated devicesunspecctl capture --url tcp://192.168.1.100:502 -o device.jsonsunspecctl serve --file device.json --url tcp://127.0.0.1:1502modbusctl client sunspec probe gives a quick check from the Modbus CLI too.
In a window
SunSpec Explorer shows every model a device exposes, fully decoded, and polls, records and exports it without ever writing to the device. Run it as a desktop application on macOS, Windows or Linux, or as a daemon on a gateway with the same interface in your browser. Download it from GitHub Releases.
From Go
go get github.com/otfabric/go-sunspecDiscover the device and print the scaled points of a three-phase inverter model (abridged from the go-sunspec README):
client, _ := modbus.New(modbus.Config{URL: "tcp://192.168.1.100:502"})if err := client.Open(); err != nil { log.Fatal(err)}defer client.Close()
device, err := sunspec.Discover(ctx, client, &sunspec.DiscoverOptions{UnitID: 1})if err != nil { log.Fatal(err) // errors.Is(err, sunspec.ErrNotSunSpec) when the device is not SunSpec}
inverter, err := device.ReadModelByID(ctx, 103) // three-phase inverterif err != nil { log.Fatal(err)}for _, p := range inverter.Group.Points { if p.Implemented && p.ScaledValue != nil { fmt.Printf("%s = %g %s\n", p.Name, *p.ScaledValue, p.Units) }}The same model definitions work the other way round: sunspec.NewServer builds a device from point values by name and serves it through go-modbus, as a simulator for an EMS or SCADA integration, or as the SunSpec interface of your own equipment. See Serving a device.
What go-sunspec supports
| Discovery | Finds the SunS marker at common base addresses and walks the model chain |
| Models | 112 built in: inverters, meters, nameplate and settings, multiple MPPT, DER (701–715), storage (801–809), environmental sensors, string combiners |
| Decoding | Every SunSpec point type, scale factors applied, unimplemented points flagged, enums and bitfields by name |
| Unknown models | Discovered and returned with raw registers |
| Changed devices | A model whose header no longer matches discovery is reported as ErrModelChanged, never decoded with a stale layout |
| Serving | A SunSpec device in memory, built from point values by name, served through go-modbus over TCP or TLS; accepts client writes to writable points and live updates |
| Encoding | EncodeModel builds a model’s registers from point values, the inverse of DecodeModel |
| Transports | Every go-modbus transport: TCP, RTU, ASCII, TLS, UDP and serial bridges |
| Go version | 1.23 or later, with go-modbus v1.5.0 or later |
Specifications
The SunSpec Alliance publishes the SunSpec Information Model and SunSpec Modbus specifications and the machine-readable model definitions in sunspec/models, from which go-sunspec generates its 112 built-in models. The SunSpec Alliance also runs product certification; OT Fabric does not claim SunSpec certification for any of its projects.