openadr

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2026 License: MIT Imports: 9 Imported by: 0

README

go-openadr — OpenADR 3 for Go

Go Reference CI

A Go implementation of OpenADR 3, the demand-response protocol between utilities or aggregators and the energy resources of their customers. It provides both sides of the REST API:

  • client: a VEN client and a Business Logic client for any OpenADR 3.1 VTN;
  • server: a VTN as an embeddable http.Handler;
  • openadr (the module root): the domain model both share.

Status: pre-release. OpenADR 3.1.0 only. All 45 operations of the specification are implemented in the VTN, with OAuth2 client credentials or JSON Web Tokens, scopes, object ownership, targeting, and notifications by webhook and by MQTT. The API may still change. The clients are tested against the OpenLEADR VTN, MQTT notifications included, and the VTN with the ElaadNL client; webhooks, and the VTN's side of MQTT, are so far tested between this module's own two sides only. See INTEROP.md for the evidence, docs/CONFORMANCE.md for exactly what is covered and PLAN.md for what comes next.

Out of scope: OpenADR 2.x, dispatch or optimization logic, integrations with physical resources (Modbus, OPC UA, ...), a web UI and a CLI. The library implements the protocol; what to do with a price or a load-shed request is the application's business.

go-openadr vs OpenLEADR and the ElaadNL client

go-openadr is tested against two other open-source implementations of OpenADR 3 (see INTEROP.md): the OpenLEADR VTN and client library, and the ElaadNL openadr3-client. Both are good software, and each does things this module does not. The table shows where the three differ, so that you can pick the right one, and where this module still has to catch up.

Capability otfabric/go-openadr OpenLEADR openleadr-rs ElaadNL openadr3-client
Language Go Rust Python
License MIT Apache-2.0 or MIT Apache-2.0
VTN (server) ✅ embeddable http.Handler ✅ standalone service —
VEN client ✅ ✅ ✅
Business Logic client ✅ ✅ same client ✅
OpenADR 3.1.0 ✅ ✅ ✅
OpenADR 3.0.1 — planned — ✅
Programs, events, reports, VENs, resources ✅ ✅ ✅
Subscriptions ✅ — ✅
Webhook notifications ✅ sender and receiver — — not documented
MQTT notifications ✅ publisher and subscriber ¹ ✅ ✅ client, optional extra
MQTT topic operations (12) ✅ ✅ 11, none for subscriptions ✅
WebSocket notifications (not in the specification) — ✅ —
OAuth2 client credentials, token caching and renewal ✅ ✅ ✅
Token endpoint discovery (/auth/server) ✅ ✅ ✅
Built-in token service for the VTN ✅ in memory, for tests and small setups ✅ users in the database n/a
JSON Web Tokens from an external identity provider ✅ static keys and JWKS ✅ n/a
VTN without authentication — — not documented ✅ anonymous client
Targeting with target hiding ✅ ✅ n/a
Persistent storage ✅ journal file ² ✅ PostgreSQL n/a
Storage behind an interface (bring your own) ✅ prepared, PostgreSQL only n/a
Resource groups (proposed for OpenADR 3.2) — ✅ ✅
mDNS discovery of local VTNs — ✅ —
Response compression — ✅ —
Typed, validated models ✅ ✅ ✅ pydantic
Extra validation by plugin — — ✅
Event intervals as tables — — ✅ pandas, optional
Cancellation and deadlines per call ✅ context.Context ✅ async — timeouts
Structured logging ✅ log/slog, opt-in ✅ ✅
Dependencies none (standard library) many crates; PostgreSQL to run several packages
Run against the OpenADR Alliance test suite — ✅ 166 of 168 applicable, by its authors — not documented
Cross-tested against other implementations in CI ✅ against both — not documented — not documented

¹ The MQTT client is this module's own (MQTT 3.1.1, QoS 1). The subscriber is tested on Mosquitto with the notifications OpenLEADR publishes; the publisher has met this module's test broker only.

² One process, all objects in memory, every change appended to a file. Not a database: for a large VTN, implement storage.Store on one. A SQL store is planned.

✅ = available · — = not available or not documented · n/a = does not apply to a client library. For openleadr-rs v0.2.7 and openadr3-client 2.4.0, the versions go-openadr is tested against, from their public sources and documentation as of October 2026. If you spot an inaccuracy, please open an issue and we will correct it.

Choose go-openadr if you want both sides of the protocol in one Go module without dependencies, a VTN you embed in your own service with your own identity provider and store, or webhook notifications.

Choose OpenLEADR if you want a VTN to deploy as it is, backed by PostgreSQL, that its authors have run against the Alliance's test suite, or if you need resource groups or mDNS today.

Choose the ElaadNL client if you write a VEN or Business Logic in Python, or need OpenADR 3.0.1.

Install

go get github.com/otfabric/go-openadr

Go 1.23 or later. No dependencies outside the standard library.

A VEN

ven, err := client.NewVEN(client.Config{
    BaseURL:     "https://vtn.example.com/openadr3",
    Credentials: &client.Credentials{ClientID: id, ClientSecret: secret},
})
if err != nil {
    return err
}

events, err := ven.Events(ctx, client.EventQuery{ProgramID: programID, ActiveOnly: true})
if err != nil {
    return err
}
for _, event := range events {
    for _, interval := range event.Intervals {
        for _, payload := range interval.Payloads {
            if price, ok := payload.Values[0].Number(); ok && payload.Type == "PRICE" {
                fmt.Println(interval.ID, price)
            }
        }
    }
}

_, err = ven.CreateReport(ctx, openadr.Report{
    EventID:    events[0].ID,
    ClientName: "site-42",
    Resources: []openadr.ReportResource{{
        ResourceName: "main-meter",
        Intervals: []openadr.Interval{{ID: 0, Payloads: []openadr.ValuesMap{
            {Type: "USAGE", Values: []openadr.Value{openadr.Number(1.8)}},
        }}},
    }},
})

The client discovers the token endpoint from the VTN (GET /auth/server), obtains a token, keeps it until shortly before it expires, and fetches a new one when the VTN answers 401. client.BL is the same for the Business Logic side: it creates programs and events, provisions VENs and their targets, and reads reports.

Errors from the VTN are *openadr.Error values and match sentinels:

if errors.Is(err, openadr.ErrNotFound) { ... }

A VTN

vtn, err := server.New(server.Config{
    Store:     storage.NewMemory(),
    Validator: validator,              // resolves a bearer token to a client ID and scopes
    TokenURL:  "https://idp.example.com/oauth/token",
})
if err != nil {
    return err
}
http.Handle("/openadr3/", http.StripPrefix("/openadr3", vtn))

The server does not bundle an identity provider: it takes an auth.Validator. For tests and small deployments, auth.Issuer is an in-memory client-credentials token service that is both the /auth/token handler and the validator, and auth.JWTValidator validates the JSON Web Tokens of an identity provider, with static keys or its key set (JWKS). storage.OpenFile is a store that survives a restart. TokenURL is what GET /auth/server tells clients and has to be an absolute URL.

examples/quickstart runs a VTN, a Business Logic client and a VEN through the program → event → report workflow in one process:

go run ./examples/quickstart

examples/vtn is a standalone VTN to point other clients at.

Notifications

A client that would rather be told than poll subscribes with a webhook:

http.Handle("/openadr", &webhook.Handler{
    BearerToken: hookToken, // made up for this subscription
    Notify: func(ctx context.Context, n openadr.Notification) error {
        if event, ok := n.Object.(openadr.Event); ok {
            // n.Operation is CREATE, UPDATE or DELETE
        }
        return nil
    },
})

_, err = ven.CreateSubscription(ctx, openadr.Subscription{
    ClientName: "site-42",
    ObjectOperations: []openadr.ObjectOperation{{
        Objects:     []openadr.ObjectType{openadr.ObjectEvent},
        Operations:  []openadr.Operation{openadr.OperationCreate, openadr.OperationUpdate},
        CallbackURL: "https://site-42.example.com/openadr",
        BearerToken: hookToken,
    }},
})

The VTN verifies the callback URL before it accepts the subscription, so the handler has to be reachable first. A VTN serves subscriptions when it is given a sender:

sender := webhook.NewSender(webhook.SenderConfig{})
defer sender.Close(ctx)
vtn, err := server.New(server.Config{ /* ... */ Webhooks: sender})

Delivery is at least once and not durable: a client that must not miss a change still polls now and then. examples/notifications runs both sides.

A VTN with an MQTT broker publishes the same notifications there (server.Config.MQTT with a mqtt.Publisher), and a client asks the VTN for the broker and for its topics and subscribes:

notifiers, err := ven.Notifiers(ctx)                              // where the broker is
topics, err := ven.MQTTTopics(ctx, client.EventsForVEN(venID))    // what this VEN may hear
sub, err := mqtt.NewSubscriber(mqtt.SubscriberConfig{
    Broker: mqtt.Broker{URL: notifiers.MQTT.URIs[0]},
    Topics: []string{topics.All},
    Notify: func(ctx context.Context, topic string, n openadr.Notification) { /* ... */ },
})

The broker is yours to run, and its access control decides who can read which topic: see SECURITY.md.

Things to know

  • Concurrency. Clients and the server are safe for concurrent use.
  • Timeouts. Every client call takes a context that bounds the whole call, including a token request it may trigger. The default HTTP client has a 30 second timeout; pass your own http.Client for TLS settings, proxies or other limits.
  • Paging. A VTN returns at most 50 objects per search. client.Each iterates over a whole result.
  • Values. JSON does not distinguish integers from other numbers, so payload numbers are float64.
  • Validation. Objects are checked against the schema before they are sent; a violation is an *openadr.ValidationError and no request is made. Payload types, units and other enumerations of the specification are plain strings and are not restricted, so private values work.
  • Logging. The library is silent. The server logs internal errors, and the webhook sender and the MQTT publisher and subscriber failed deliveries and lost connections, to the slog.Logger each is given, if any.

Documentation

  • API.md: the public API by package, and the behaviour that signatures do not show.
  • ERRORS.md: every error a caller can get, and how to tell them apart.
  • INTEROP.md: what has been tested against which other implementation, and how to repeat it.
  • docs/CONFORMANCE.md: operation coverage, and how the VTN reads the parts of the specification that leave room.
  • ARCHITECTURE.md: packages, the version strategy, and the storage and authentication boundaries.
  • SECURITY.md: reporting a vulnerability, and what to know before deploying.
  • RELEASE.md: release notes. PLAN.md: roadmap and status. CONTRIBUTING.md: how to change things.

The reference implementations it is tested against, and a conformance suite that asserts the specification, come from a separate repository, otfabric/openadr-interop, which shares no code with this one.

Development

make check    # format, lint, vet, vulnerability scan, tests with -race, coverage, examples
make fuzz     # the parser fuzz targets
make e2e      # this module's clients against this module's VTN, every feature
make interop  # against the OpenLEADR and ElaadNL reference images (needs Docker, see INTEROP.md)

License

MIT, see LICENSE.

Documentation

Overview

Package openadr defines the domain model of OpenADR 3: programs, events, reports, VENs, resources and the value types they are built from.

The types in this package are independent of any one protocol revision's JSON representation. Encoding and decoding for a specific revision (3.1.0 today) is an internal concern of the client and server packages, so the structures here carry no JSON tags and are not meant to be marshalled directly.

Entry points:

  • package client: VEN and Business Logic clients for a VTN.
  • package server: an embeddable VTN http.Handler.
  • package auth: bearer-token validation and OAuth2 scopes.

OpenADR 2.x is out of scope, as are dispatch algorithms and integrations with physical energy resources.

Index

Constants

View Source
const (
	MQTTAnonymous   = "ANONYMOUS"
	MQTTBearerToken = "OAUTH2_BEARER_TOKEN"
	MQTTCertificate = "CERTIFICATE"
)

MQTT authentication methods defined by OpenADR 3.1.0.

View Source
const AggregatedReport = "AGGREGATED_REPORT"

AggregatedReport is the resource name of an aggregated report.

Variables

View Source
var (
	ErrBadRequest   = errors.New("openadr: bad request")
	ErrUnauthorized = errors.New("openadr: unauthorized")
	ErrForbidden    = errors.New("openadr: forbidden")
	ErrNotFound     = errors.New("openadr: not found")
	ErrConflict     = errors.New("openadr: conflict")
)

Categories of failure reported by a VTN. An *Error matches the one for its HTTP status through errors.Is. The storage layer of the server returns ErrNotFound and ErrConflict directly.

View Source
var Infinite = Duration{Years: 9999}

Infinite is P9999Y, which the specification uses to mean "indefinitely".

Functions

func ValidID

func ValidID(id string) bool

ValidID reports whether id is a well-formed object ID: 1 to 128 characters of letters, digits, '_' and '-'.

Types

type Duration

type Duration struct {
	Negative bool
	Years    int64
	Months   int64
	Weeks    int64
	Days     int64
	Hours    int64
	Minutes  int64
	Seconds  float64
}

Duration is an ISO 8601 duration as OpenADR uses it, for example PT1H or P1DT12H. Years and months are kept as written because their length depends on the date they are applied to; use AddTo for calendar arithmetic and TimeDuration when the duration has no such components.

The format allows either days or weeks, not both; String writes weeks only when Days is zero.

func DurationOf

func DurationOf(td time.Duration) Duration

DurationOf converts a time.Duration, using hours, minutes and seconds only.

func ParseDuration

func ParseDuration(s string) (Duration, error)

ParseDuration parses an ISO 8601 duration in the form the OpenADR 3 schema accepts.

func (Duration) AddTo

func (d Duration) AddTo(t time.Time) time.Time

AddTo returns t moved by the duration, applying years, months and days on the calendar in t's location.

func (Duration) IsInfinite

func (d Duration) IsInfinite() bool

IsInfinite reports whether the duration is P9999Y.

func (Duration) IsZero

func (d Duration) IsZero() bool

IsZero reports whether the duration has no length.

func (Duration) String

func (d Duration) String() string

String returns the ISO 8601 form. The zero Duration is "PT0S".

func (Duration) TimeDuration

func (d Duration) TimeDuration() (time.Duration, bool)

TimeDuration converts to a time.Duration, taking a day as 24 hours. It reports false when the duration has years or months, whose length is not fixed, or does not fit in a time.Duration.

type Error

type Error struct {
	// Method and Path identify the request.
	Method string
	Path   string
	// StatusCode is the HTTP status of the response.
	StatusCode int
	Problem    Problem
}

Error is a non-success response from a VTN. Problem is zero when the response body was not a problem object.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Is

func (e *Error) Is(target error) bool

Is matches the category sentinel for the response's status code.

type Event

type Event struct {
	Metadata

	// ProgramID is the program the event belongs to.
	ProgramID string
	Name      string
	// Duration optionally bounds the event; it may be used to loop intervals.
	Duration *Duration
	// Priority orders events; a lower number is a higher priority.
	Priority           *int
	Targets            []string
	ReportDescriptors  []ReportDescriptor
	PayloadDescriptors []EventPayloadDescriptor
	// IntervalPeriod sets the default start and duration of Intervals.
	IntervalPeriod *IntervalPeriod
	Intervals      []Interval
}

Event communicates a demand-response request to VENs.

func (Event) Validate

func (e Event) Validate() error

Validate checks the client-provided properties against the schema. It does not look at Metadata.

type EventPayloadDescriptor

type EventPayloadDescriptor struct {
	PayloadType string
	Units       string
	Currency    string
}

EventPayloadDescriptor gives context, such as units and currency, to event payloads of one type.

type Interval

type Interval struct {
	ID             int32
	IntervalPeriod *IntervalPeriod
	Payloads       []ValuesMap
}

Interval is a temporal window with payloads. ID is chosen by the client that creates the interval and is not a sequence number.

type IntervalPeriod

type IntervalPeriod struct {
	Start    *time.Time
	Duration *Duration
	// RandomizeStart is the range of a client-applied offset to Start.
	RandomizeStart *Duration
}

IntervalPeriod defines the temporal aspects of one or more intervals.

The specification gives two values a special meaning: a Start in year 1 may mean "now", and a Duration of P9999Y may mean "indefinitely"; see Duration.IsInfinite.

type MQTTAuthentication

type MQTTAuthentication struct {
	// Method is MQTTAnonymous, MQTTBearerToken or MQTTCertificate.
	Method string
	// Username goes with MQTTBearerToken: the user name to present, with
	// the client's OAuth2 token as the password. The value "{clientID}"
	// stands for the client's own ID.
	Username string
	// CACert, ClientCert and ClientKey go with MQTTCertificate, in PEM.
	CACert     string
	ClientCert string
	ClientKey  string
}

MQTTAuthentication says how a client authenticates with the broker.

type MQTTBinding

type MQTTBinding struct {
	// URIs are the addresses of the broker, such as mqtts://broker.example.
	URIs []string
	// Serialization is the format of the messages; always "JSON" so far.
	Serialization  string
	Authentication MQTTAuthentication
}

MQTTBinding is what a client needs to receive notifications by MQTT.

type Metadata

type Metadata struct {
	ID       string
	Created  time.Time
	Modified time.Time
}

Metadata is assigned by the VTN when an object is created or modified. A VTN ignores these fields in create and update requests, so callers leave them zero when building an object to send.

type Notification

type Notification struct {
	ObjectType ObjectType
	Operation  Operation
	// Object is the object the operation happened to, as the subscriber
	// may see it: a Program, Event, Report, Subscription, VEN or Resource
	// value, according to ObjectType.
	Object any
	// Targets are the targets of the object that the subscriber may see.
	Targets []string
}

Notification is what a VTN sends to a webhook.

type Notifiers

type Notifiers struct {
	// Webhook says the VTN serves subscriptions with callback URLs.
	Webhook bool
	// MQTT describes the VTN's MQTT broker; nil when it has none.
	MQTT *MQTTBinding
}

Notifiers says how a VTN notifies its clients: the answer to GET /notifiers.

type ObjectOperation

type ObjectOperation struct {
	Objects    []ObjectType
	Operations []Operation
	// CallbackURL is the webhook. It has to use https, and the VTN checks
	// that it answers before it accepts the subscription.
	CallbackURL string
	// BearerToken, when set, is sent by the VTN with every notification so
	// that the webhook can tell the VTN from anyone else.
	BearerToken string
}

ObjectOperation selects operations on kinds of objects and names the webhook that is to be told of them.

type ObjectType

type ObjectType string

ObjectType names a kind of object addressable through the API.

const (
	ObjectProgram      ObjectType = "PROGRAM"
	ObjectEvent        ObjectType = "EVENT"
	ObjectReport       ObjectType = "REPORT"
	ObjectSubscription ObjectType = "SUBSCRIPTION"
	ObjectVEN          ObjectType = "VEN"
	ObjectResource     ObjectType = "RESOURCE"
)

Object types defined by OpenADR 3.1.0.

type Operation

type Operation string

Operation is something that happens to an object and that a client can subscribe to.

const (
	OperationCreate Operation = "CREATE"
	OperationRead   Operation = "READ"
	OperationUpdate Operation = "UPDATE"
	OperationDelete Operation = "DELETE"
)

Operations defined by OpenADR 3.1.0. A VTN notifies of CREATE, UPDATE and DELETE; READ is in the schema and is never notified of by this module.

type PayloadDescriptor

type PayloadDescriptor interface {
	// contains filtered or unexported methods
}

PayloadDescriptor is an EventPayloadDescriptor or a ReportPayloadDescriptor.

type Point

type Point struct {
	X, Y float64
}

Point is a pair of numbers, typically a point on a two dimensional grid.

type Problem

type Problem struct {
	Type     string
	Title    string
	Status   int
	Detail   string
	Instance string
}

Problem is the error body a VTN returns with a 4xx or 5xx response.

type Program

type Program struct {
	Metadata

	// Name identifies the program and is unique within a VTN.
	Name string
	// IntervalPeriod is the temporal span of the program.
	IntervalPeriod *IntervalPeriod
	// Descriptions link to human or machine readable descriptions.
	Descriptions []ProgramDescription
	// PayloadDescriptors give context to the payloads of the program's
	// events and reports. Each element is an EventPayloadDescriptor or a
	// ReportPayloadDescriptor.
	PayloadDescriptors []PayloadDescriptor
	Attributes         []ValuesMap
	// Targets restrict which VENs may read the program. A VTN only shows a
	// VEN the targets that VEN asked for.
	Targets []string
}

Program is a demand-response program or tariff.

func (Program) Validate

func (p Program) Validate() error

Validate checks the client-provided properties against the schema. It does not look at Metadata.

type ProgramDescription

type ProgramDescription struct {
	URL string
}

ProgramDescription links to a description of a program.

type Report

type Report struct {
	Metadata

	// ClientID is written by the VTN from the creating client's token.
	ClientID string
	// EventID is the event the report is associated with.
	EventID string
	// ClientName is chosen by the reporting client.
	ClientName         string
	Name               string
	PayloadDescriptors []ReportPayloadDescriptor
	Resources          []ReportResource
}

Report carries data from a VEN in response to an event.

func (Report) Validate

func (r Report) Validate() error

Validate checks the client-provided properties against the schema. It does not look at Metadata or ClientID, which the VTN writes.

type ReportDescriptor

type ReportDescriptor struct {
	PayloadType string
	ReadingType string
	Units       string
	Targets     []string
	// Aggregate asks for one result over all targeted resources.
	Aggregate bool
	// StartInterval is the interval on which to report; -1 is the end of
	// the last interval.
	StartInterval int32
	// NumIntervals is the number of intervals to include; -1 is all.
	NumIntervals int32
	// Historical reports on the intervals before StartInterval, as opposed
	// to those after it.
	Historical bool
	// Frequency is the number of intervals between reports; -1 is the same
	// as NumIntervals.
	Frequency int32
	// Repeat is the number of reports to generate; -1 is indefinitely.
	Repeat          int32
	ReportIntervals ReportIntervals
}

ReportDescriptor requests a report from a VEN. NewReportDescriptor returns one holding the defaults of the specification; the zero value does not.

func NewReportDescriptor

func NewReportDescriptor(payloadType string) ReportDescriptor

NewReportDescriptor returns a descriptor for payloadType with every other field at the default the specification defines for it.

type ReportIntervals

type ReportIntervals string

ReportIntervals says which intervals a requested report covers.

const (
	ReportIntervalsIntervals    ReportIntervals = "INTERVALS"
	ReportIntervalsSubIntervals ReportIntervals = "SUB_INTERVALS"
	ReportIntervalsOpen         ReportIntervals = "OPEN_INTERVALS"
)

Report interval options defined by OpenADR 3.1.0.

type ReportPayloadDescriptor

type ReportPayloadDescriptor struct {
	PayloadType string
	ReadingType string
	Units       string
	Accuracy    *float64
	// Confidence is a percentage, 0 to 100.
	Confidence *int
}

ReportPayloadDescriptor gives context, such as units and data quality, to report payloads of one type.

type ReportResource

type ReportResource struct {
	ResourceName   string
	IntervalPeriod *IntervalPeriod
	Intervals      []Interval
}

ReportResource is the report data of one resource. A ResourceName of AggregatedReport denotes data aggregated over several resources.

type Resource

type Resource struct {
	Metadata

	ClientID string
	// VENID is the VEN the resource belongs to.
	VENID string
	// Name is unique within its VEN.
	Name       string
	Attributes []ValuesMap
	// Targets are granted by Business Logic; see VEN.Targets.
	Targets []string
}

Resource is a resource of a VEN, such as a device or a group of devices.

func (Resource) Validate

func (r Resource) Validate() error

Validate checks the client-provided properties against the schema. ClientID is not required here: whether it is depends on who sends the object.

type Subscription

type Subscription struct {
	Metadata

	// ClientID is written by the VTN from the creating client's token.
	ClientID string
	// ClientName is chosen by the subscribing client.
	ClientName string
	// ProgramID, when set, limits the subscription to that program, its
	// events and the reports on them.
	ProgramID string
	// ObjectOperations say what to notify of, and where.
	ObjectOperations []ObjectOperation
	// Targets are the targets the subscriber names, as in a search: see
	// the access rules for programs and events.
	Targets []string
}

Subscription asks a VTN to notify a client when objects are created, updated or deleted.

func (Subscription) Validate

func (s Subscription) Validate() error

Validate checks the client-provided properties against the schema. It does not look at Metadata or ClientID, which the VTN writes.

type Topics

type Topics struct {
	Create string
	Update string
	Delete string
	// All is a topic filter that matches the other three.
	All string
}

Topics are the MQTT topics on which a VTN publishes the operations on a set of objects. A field is empty where the VTN has no such topic: there is no Create for a single object, and All is optional.

type VEN

type VEN struct {
	Metadata

	// ClientID ties the VEN to the client credentials it authenticates with.
	// Business Logic supplies it; for a VEN-created object the VTN writes it
	// from the token.
	ClientID string
	// Name is unique within a VTN.
	Name       string
	Attributes []ValuesMap
	// Targets are granted by Business Logic and decide which targeted
	// programs and events the VEN may read. Only Business Logic may set them.
	Targets []string
}

VEN is a virtual end node known to the VTN.

func (VEN) Validate

func (v VEN) Validate() error

Validate checks the client-provided properties against the schema. ClientID is not required here: whether it is depends on who sends the object.

type ValidationError

type ValidationError struct {
	// Field is the path of the property in the JSON naming of the
	// specification, such as "intervals[0].payloads[1].type".
	Field  string
	Reason string
}

ValidationError reports a property that violates the OpenADR schema. It is returned by the Validate methods, by the clients before a request is sent, and by the wire codecs for malformed messages.

func (*ValidationError) Error

func (e *ValidationError) Error() string

type Value

type Value struct {
	// contains filtered or unexported fields
}

Value is one data point of a ValuesMap: a number, a string, a boolean or a Point. The zero Value is invalid. Values are comparable with ==.

JSON does not distinguish integers from other numbers, so both are held as a float64; integers beyond 2^53 lose precision.

func Bool

func Bool(b bool) Value

Bool returns a boolean Value.

func Number

func Number(n float64) Value

Number returns a numeric Value.

func PointValue

func PointValue(x, y float64) Value

PointValue returns a Value holding the point (x, y).

func String

func String(s string) Value

String returns a string Value.

func (Value) Bool

func (v Value) Bool() (bool, bool)

Bool returns the boolean held and whether the Value is a boolean.

func (Value) Kind

func (v Value) Kind() ValueKind

Kind reports what the Value holds; it is 0 for the zero Value.

func (Value) Number

func (v Value) Number() (float64, bool)

Number returns the number held and whether the Value is a number.

func (Value) Point

func (v Value) Point() (Point, bool)

Point returns the point held and whether the Value is a point.

func (Value) String

func (v Value) String() string

String formats the Value for diagnostics.

func (Value) Text

func (v Value) Text() (string, bool)

Text returns the string held and whether the Value is a string.

type ValueKind

type ValueKind uint8

ValueKind is the JSON type of a Value.

const (
	KindNumber ValueKind = iota + 1
	KindString
	KindBool
	KindPoint
)

Kinds of value a ValuesMap may hold.

func (ValueKind) String

func (k ValueKind) String() string

type ValuesMap

type ValuesMap struct {
	Type   string
	Values []Value
}

ValuesMap is a list of values together with a type that says what they are, such as "PRICE". Type is one of the strings enumerated in the specification or a privately defined one; this package does not restrict it.

type Version

type Version string

Version identifies a revision of the OpenADR 3 specification.

const (
	// Version310 is OpenADR 3.1.0 (document 20250807-X).
	Version310 Version = "3.1.0"
)

Supported protocol revisions.

Directories

Path Synopsis
Package auth holds what the VTN needs to authenticate and authorize a request: the identity behind a bearer token and the OAuth2 scopes of OpenADR 3.
Package auth holds what the VTN needs to authenticate and authorize a request: the identity behind a bearer token and the OAuth2 scopes of OpenADR 3.
Package client holds the two clients of a VTN: VEN, for a virtual end node, and BL, for the Business Logic of a utility or aggregator.
Package client holds the two clients of a VTN: VEN, for a virtual end node, and BL, for the Business Logic of a utility or aggregator.
Package e2e holds end-to-end tests of go-openadr against itself: the clients of this module against the VTN of this module, over real HTTPS connections on loopback, with the token service, the stores, the webhook sender and handler, and the MQTT publisher and subscriber that the module ships.
Package e2e holds end-to-end tests of go-openadr against itself: the clients of this module against the VTN of this module, over real HTTPS connections on loopback, with the token service, the stores, the webhook sender and handler, and the MQTT publisher and subscriber that the module ships.
examples
notifications command
Notifications shows a VEN that is told of new events instead of polling for them: it runs a webhook, subscribes to events at the VTN, and the VTN calls the webhook when Business Logic publishes one.
Notifications shows a VEN that is told of new events instead of polling for them: it runs a webhook, subscribes to events at the VTN, and the VTN calls the webhook when Business Logic publishes one.
quickstart command
Quickstart runs the basic OpenADR 3 workflow in one process: Business Logic creates a program and an event on a VTN, a VEN discovers them and sends a report, and Business Logic reads the report.
Quickstart runs the basic OpenADR 3 workflow in one process: Business Logic creates a program and an event on a VTN, a VEN discovers them and sends a report, and Business Logic reads the report.
vtn command
Vtn runs a standalone VTN with its own token endpoint, for trying out clients and for interoperability tests.
Vtn runs a standalone VTN with its own token endpoint, for trying out clients and for interoperability tests.
internal
mqtt
Package mqtt is a client for MQTT 3.1.1 (OASIS standard, also ISO/IEC 20922), with what the MQTT binding of OpenADR notifications needs: publishing and subscribing at QoS 1 over TCP or TLS, with a clean session.
Package mqtt is a client for MQTT 3.1.1 (OASIS standard, also ISO/IEC 20922), with what the MQTT binding of OpenADR notifications needs: publishing and subscribing at QoS 1 over TCP or TLS, with a clean session.
mqtttest
Package mqtttest is a small MQTT 3.1.1 broker for the tests and examples of this module: enough of a broker to carry notifications between a publisher and subscribers in one process.
Package mqtttest is a small MQTT 3.1.1 broker for the tests and examples of this module: enough of a broker to carry notifications between a publisher and subscribers in one process.
wire
Package wire defines what a protocol revision has to provide to the client and server: the JSON form of each object.
Package wire defines what a protocol revision has to provide to the client and server: the JSON form of each object.
wire/v310
Package v310 is the JSON representation of OpenADR 3.1.0, following the schemas of the specification's OpenAPI document (20250807-X).
Package v310 is the JSON representation of OpenADR 3.1.0, following the schemas of the specification's OpenAPI document (20250807-X).
Package interop holds tests that run this module's clients against VTNs implemented by others.
Package interop holds tests that run this module's clients against VTNs implemented by others.
notification
mqtt
Package mqtt is the MQTT binding of OpenADR 3 notifications, for both sides: Publisher sends a VTN's notifications to a broker, and Subscriber receives them in a client.
Package mqtt is the MQTT binding of OpenADR 3 notifications, for both sides: Publisher sends a VTN's notifications to a broker, and Subscriber receives them in a client.
webhook
Package webhook is the webhook binding of OpenADR 3 notifications, for both sides: Sender delivers a VTN's notifications to the callback URLs of its subscriptions, and Handler receives them in a client.
Package webhook is the webhook binding of OpenADR 3 notifications, for both sides: Sender delivers a VTN's notifications to the callback URLs of its subscriptions, and Handler receives them in a client.
Package server is an OpenADR 3.1.0 VTN as an http.Handler.
Package server is an OpenADR 3.1.0 VTN as an http.Handler.
storage
Package storage is the persistence boundary of the VTN.
Package storage is the persistence boundary of the VTN.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL