IEEE 2030.5, the Smart Energy Profile 2.0, is how a utility or an aggregator talks to distributed energy resources (DER): solar inverters, batteries, EV chargers, smart meters and the gateways in front of them. A server, run by the utility or the aggregator, holds resources such as DER programs, controls, tariffs and metering; each device is a client that polls them over HTTPS, or subscribes to be notified, and follows links from one root, the DeviceCapability. There are no passwords: a device is its certificate, named by the LFDI and SFDI derived from its fingerprint, and every connection is mutual TLS.
What a device receives are events: “limit export to 1.5 kW from 14:00 for 30 minutes”, a price for the next hour, a message for the display. Each belongs to a program with a primacy, and the device schedules them itself, resolves conflicts, applies a default control when no event does, and answers with Responses: received, started, completed, superseded.
Where you meet it
- California: Rule 21 makes IEEE 2030.5 the default protocol between utilities and smart inverters, through the Common Smart Inverter Profile (CSIP), certified by SunSpec
- Australia: distributors use CSIP-AUS for dynamic connections, where a solar or battery site receives its dynamic operating envelope: export and import limits that change through the day with the capacity of the local network
- Elsewhere: IEEE 1547-2018 names it as one of the interfaces of a grid-connected inverter, next to SunSpec Modbus and DNP3; aggregators of batteries, home energy systems and EV chargers speak it towards the utility
Quickstart
From the command line
Download ieee20305ctl from GitHub Releases. It brings its own test PKI and a seeded test server, so you can start without a utility:
# A CA, a server certificate and a device certificateieee20305ctl cert generate --out pki --devices 1
# A server with an example DER program, in one terminalieee20305ctl server generate-config | sed 's#cert: device.crt#cert: pki/device-1.pem#' > seed.yamlieee20305ctl server start --listen 127.0.0.1:8443 --cert pki/server.pem --key pki/server.key \ --ca pki/ca.pem --config seed.yaml --control-socket /tmp/ieee20305.sockand act as the device in another:
export IEEE20305CTL_URL=https://127.0.0.1:8443/dcapexport IEEE20305CTL_CERT=pki/device-1.pem IEEE20305CTL_KEY=pki/device-1.key IEEE20305CTL_CA=pki/ca.pem
# Register, and check the PIN the device was given out of bandieee20305ctl client register --pin 111115
# What does the server ask of this device?ieee20305ctl client programsieee20305ctl client controls
# Run a device that schedules and answers every eventieee20305ctl client run --pin 111115The same commands reach a real server: --ccm8 for servers that offer only the CCM_8 cipher suite, and --profile csipaus for an Australian one.
From Go
go get github.com/otfabric/go-ieee20305A device: a client with its certificate, and an agent that registers, checks the PIN and applies the DER controls of its programs (abridged from the go-ieee20305 README):
c, err := client.New(client.Config{ Server: "https://utility.example/dcap", HTTPClient: client.NewHTTPClient(device, roots), // the device's certificate, the server's CA})if err != nil { log.Fatal(err)}a, err := agent.New(agent.Config{ Client: c, Identity: client.IdentityOf(device.Leaf), PIN: 111115, // given to the device out of band VerifyPIN: true, OnDERControl: func(ctx context.Context, t schedule.Transition) error { log.Printf("control %s: %v", t.Event.MRID, t.To) // apply or release it return nil },})if err != nil { log.Fatal(err)}defer a.Close()if err := a.Run(ctx); err != nil && ctx.Err() == nil { log.Fatal(err)}And the other side, a server as an http.Handler with an operator’s API to provision devices and publish programs and controls:
srv, err := server.New(server.Config{})a := srv.Admin()_, err = a.ProvisionDevice(ctx, server.DeviceSpec{LFDI: lfdi, Register: true, PIN: 111115})program, err := a.Create(ctx, "/derp", &ieee20305.DERProgram{Primacy: 1}, "")_, err = a.Create(ctx, program+"/derc", control, "")hs := &http.Server{Addr: ":8443", Handler: srv, TLSConfig: security.ServerTLSConfig(serverCert, deviceCAs)}log.Fatal(hs.ListenAndServeTLS("", ""))What go-ieee20305 and ieee20305ctl support
| Roles | Client, a device agent on the client, and server (an embeddable http.Handler with an operator API) |
| Function sets | Every resource of the IEEE 2030.5 WADL: registration, DER programs, controls, default controls and curves, demand response, pricing, messaging, prepayment, billing, metering mirrors, flow reservation, files, log events, Responses, subscriptions and notifications |
| Editions and profiles | IEEE 2030.5-2018 and 2023, CSIP and CSIP-AUS v1.3, with types generated from the official schemas |
| Security | Mutual TLS 1.2, LFDI and SFDI, certificates with a HardwareModuleName, and the CCM_8 cipher suite in the separate module tlsccm |
| Discovery | DNS-SD (_smartenergy._tcp) |
| Dependencies | None outside the Go standard library in the core module |