Documentation
¶
Overview ¶
Package ocpp holds what the OCPP versions and both roles of go-ocpp share: the protocol versions and their WebSocket subprotocols, the contracts between the layers (Peer, Caller, Dispatcher), CALLERRORs and their codes, the sentinel errors, and the observability hooks.
The roles are in package client (Charging Station) and package server (CSMS); the OCPP-J frame codec is in package ocppj. The typed messages of the version packages ocpp16, ocpp201 and ocpp21 are designed in ARCHITECTURE.md and are not implemented yet: until then, requests and responses are raw JSON.
Documentation:
- ARCHITECTURE.md: layers, packages, the engine, both roles
- REQUIREMENTS.md: what the library must do
- SPECIFICATIONS.md: the OCA editions and errata it follows
- IMPLEMENTATION_PLAN.md: phases and their gates
- ERRORS.md: error semantics
Index ¶
- Variables
- func AfterResponse(ctx context.Context, f func()) bool
- func Ptr[T any](v T) *T
- type CallError
- type CallInfo
- type Caller
- type CloseError
- type ConnInfo
- type Direction
- type Dispatcher
- type DispatcherFunc
- type ErrorCode
- type FrameObserver
- type Interceptor
- type Metrics
- type NopMetrics
- func (NopMetrics) OnCallDone(ConnInfo, string, time.Duration, error)
- func (NopMetrics) OnCallHandled(ConnInfo, string, time.Duration, error)
- func (NopMetrics) OnConnect(ConnInfo)
- func (NopMetrics) OnConnectFailed(ConnInfo, error)
- func (NopMetrics) OnDisconnect(ConnInfo, error)
- func (NopMetrics) OnProtocolError(ConnInfo, error)
- func (NopMetrics) OnReconnectAttempt(ConnInfo, int)
- type Peer
- type Role
- type SendDispatcher
- type Sender
- type State
- type ValidationError
- type Version
Constants ¶
This section is empty.
Variables ¶
var ( // ErrClosed is returned by operations on a client, server or session // after Close. ErrClosed = errors.New("ocpp: closed") // ErrNotConnected is returned by a call on a client that has no open // connection, including while it reconnects. Nothing is queued. ErrNotConnected = errors.New("ocpp: not connected") // ErrConnectFailed is returned when a client cannot open a connection: // the dial, the TLS handshake, the WebSocket handshake or the // subprotocol negotiation failed. ErrConnectFailed = errors.New("ocpp: connect failed") // ErrConnectionLost is returned to calls that were pending or queued // when the connection broke. ErrConnectionLost = errors.New("ocpp: connection lost") // ErrTimeout is returned when no response to a CALL arrived in time. ErrTimeout = errors.New("ocpp: timeout") // ErrBusy is returned when the queue of calls waiting to be sent is // full. OCPP allows one outstanding CALL per direction. ErrBusy = errors.New("ocpp: busy") // ErrWrongDirection is returned when an action is sent by a role that // the specification does not let send it. ErrWrongDirection = errors.New("ocpp: action not sent in this direction") // ErrUnsupportedVersion is returned when no common OCPP version can be // negotiated, or when a version is used that was not configured. ErrUnsupportedVersion = errors.New("ocpp: unsupported version") // ErrProtocol is returned when the peer violates the OCPP-J framing. ErrProtocol = errors.New("ocpp: protocol error") // ErrInvalidOption is returned by constructors given an invalid option. ErrInvalidOption = errors.New("ocpp: invalid option") // ErrHandlerPanic is reported through Metrics.OnCallHandled when a // handler panicked. The panic is recovered, logged with its stack, and // the CALL answered with InternalError. ErrHandlerPanic = errors.New("ocpp: handler panic") )
Sentinel errors shared by the client, the server and the version packages. They are usually wrapped with detail; test for them with errors.Is. ERRORS.md describes when each is returned.
var ErrInvalidMessage = errors.New("ocpp: invalid message")
ErrInvalidMessage is wrapped by every *ValidationError: a payload that does not conform to the JSON schema of its action.
var ErrUnexpectedResponse = errors.New("ocpp: unexpected response")
ErrUnexpectedResponse is reported through Metrics.OnProtocolError for a CALLRESULT or CALLERROR that matches no pending CALL: a late response after a timeout, a duplicate, or an unknown message ID.
Functions ¶
func AfterResponse ¶
AfterResponse registers f to run once the response to the CALL being handled is on its way: for what a handler must do after answering, such as sending the NotifyReport messages after accepting GetBaseReport, the FirmwareStatusNotifications after accepting UpdateFirmware, or the triggered message after TriggerMessage. ctx must be the context the handler received; f runs on a goroutine of its own, after the response (CALLRESULT or CALLERROR) has been queued ahead of any CALL f sends. It reports false, and f does not run, when ctx is not a handler's context (a SEND handler's included: a SEND has no response).
Types ¶
type CallError ¶
type CallError struct {
Code ErrorCode
Description string
// Details is a JSON object, or nil for {}.
Details json.RawMessage
}
CallError is a CALLERROR: the peer's answer that it could not process a CALL. A call returns it as the error (test with errors.As), and a handler returns it to answer with a CALLERROR of its choosing.
A CALLERROR is not a business rejection. A BootNotification answered with status Rejected is a successful call.
func NewCallError ¶
NewCallError returns a CallError with the given code and description.
type CallInfo ¶
type CallInfo struct {
ConnInfo
Action string
MessageID string
Direction Direction // Outgoing: a call this end sends; Incoming: one it handles
}
CallInfo describes one CALL, for interceptors.
type Caller ¶
Caller sends a CALL and waits for its result.
req is marshalled with encoding/json; a json.RawMessage is sent as is. The result payload is unmarshalled into resp, which must be a pointer (a *json.RawMessage receives the payload unchanged) or nil to discard it. A CALLERROR is returned as a *CallError.
type CloseError ¶
type CloseError struct {
Code int // RFC 6455 §7.4 status code, e.g. 1000
Reason string // the peer's reason text, often empty
}
CloseError says how the peer closed the connection, when it sent a WebSocket close frame. The error of a lost connection (Session.Err, the session handler, Metrics.OnDisconnect, the client's state handler) wraps it next to ErrConnectionLost:
var ce *ocpp.CloseError
if errors.As(err, &ce) && ce.Normal() { /* the peer closed on purpose */ }
func (*CloseError) Normal ¶
func (e *CloseError) Normal() bool
Normal reports whether the peer closed on purpose: status 1000 (normal closure) or 1001 (going away, e.g. a reboot or a server shutting down).
type ConnInfo ¶
type ConnInfo struct {
StationID string
Version Version // zero before the handshake completes
Role Role // the local role
SessionID string // random, unique per connection; for correlating logs
}
ConnInfo identifies a connection in callbacks.
type Dispatcher ¶
type Dispatcher interface {
Dispatch(ctx context.Context, p Peer, action string, payload json.RawMessage) (json.RawMessage, error)
}
Dispatcher handles the CALLs that arrive on a connection of one OCPP version. The version packages build dispatchers from typed handlers; DispatcherFunc handles raw payloads.
Dispatch returns the CALLRESULT payload, or an error: a *CallError is sent as is, any other error as an InternalError whose description does not reveal the error text.
type DispatcherFunc ¶
type DispatcherFunc func(ctx context.Context, p Peer, action string, payload json.RawMessage) (json.RawMessage, error)
DispatcherFunc adapts a function to a Dispatcher.
func (DispatcherFunc) Dispatch ¶
func (f DispatcherFunc) Dispatch(ctx context.Context, p Peer, action string, payload json.RawMessage) (json.RawMessage, error)
Dispatch calls f.
type ErrorCode ¶
type ErrorCode string
ErrorCode is the error code of a CALLERROR (and, in OCPP 2.1, of a CALLRESULTERROR). Which codes a version allows is defined by package ocppj (ocppj.ValidErrorCode).
const ( NotImplemented ErrorCode = "NotImplemented" NotSupported ErrorCode = "NotSupported" InternalError ErrorCode = "InternalError" ProtocolError ErrorCode = "ProtocolError" SecurityError ErrorCode = "SecurityError" PropertyConstraintViolation ErrorCode = "PropertyConstraintViolation" TypeConstraintViolation ErrorCode = "TypeConstraintViolation" GenericError ErrorCode = "GenericError" // FormationViolation is the 1.6 name of the code 2.x calls FormatViolation. FormationViolation ErrorCode = "FormationViolation" // FormatViolation is OCPP 2.x only. See FormationViolation. FormatViolation ErrorCode = "FormatViolation" // OccurenceConstraintViolation is the OCPP 1.6 spelling, with one "r", // as the 1.6 specification writes it. OccurenceConstraintViolation ErrorCode = "OccurenceConstraintViolation" // OccurrenceConstraintViolation is the OCPP 2.x spelling. OccurrenceConstraintViolation ErrorCode = "OccurrenceConstraintViolation" // MessageTypeNotSupported is OCPP 2.x only. MessageTypeNotSupported ErrorCode = "MessageTypeNotSupported" // RpcFrameworkError is OCPP 2.x only. RpcFrameworkError ErrorCode = "RpcFrameworkError" //nolint:revive // the name the specification uses )
The CALLERROR error codes of OCPP-J 1.6 §4.2.3 and OCPP 2.0.1/2.1 Part 4 §4.3. Most codes exist in every version. Where the versions differ, the constant's comment says so.
type FrameObserver ¶
FrameObserver sees every OCPP-J frame sent or received, as raw JSON. It runs synchronously on the connection's reader or writer, so it must not block, and it must not retain or modify frame.
type Interceptor ¶
Interceptor wraps an outgoing call (client and server option WithCallInterceptor) or the handling of an incoming one (WithHandlerInterceptor). It must call next exactly once, with ctx or a context derived from it, and return its error or an error of its own. This is where tracing spans start and end.
type Metrics ¶
type Metrics interface {
// OnConnect is called when a connection opens.
OnConnect(info ConnInfo)
// OnConnectFailed is called when a client's dial or a server's
// handshake fails. info.Version is zero.
OnConnectFailed(info ConnInfo, err error)
// OnDisconnect is called when an open connection ends; err is nil after
// a local Close.
OnDisconnect(info ConnInfo, err error)
// OnReconnectAttempt is called before a client redials.
OnReconnectAttempt(info ConnInfo, attempt int)
// OnCallDone is called when an outgoing CALL ends, with its round trip
// time and nil, a *CallError, ErrTimeout or another error.
OnCallDone(info ConnInfo, action string, d time.Duration, err error)
// OnCallHandled is called when an incoming CALL has been answered, with
// the handler's duration and its error.
OnCallHandled(info ConnInfo, action string, d time.Duration, err error)
// OnProtocolError is called for a frame that violates OCPP-J, and for a
// response that matches no pending CALL (late or unknown).
OnProtocolError(info ConnInfo, err error)
}
Metrics receives events for metrics. Callbacks are synchronous and must be safe for concurrent use and must not block.
Every callback gets the station identity in ConnInfo. Whether it becomes a metric label is the implementation's choice; labelling by station gives one series per station.
Embed NopMetrics so that an implementation keeps compiling when callbacks are added.
type NopMetrics ¶
type NopMetrics struct{}
NopMetrics implements Metrics and does nothing.
func (NopMetrics) OnCallDone ¶
OnCallDone does nothing.
func (NopMetrics) OnCallHandled ¶
OnCallHandled does nothing.
func (NopMetrics) OnConnectFailed ¶
func (NopMetrics) OnConnectFailed(ConnInfo, error)
OnConnectFailed does nothing.
func (NopMetrics) OnDisconnect ¶
func (NopMetrics) OnDisconnect(ConnInfo, error)
OnDisconnect does nothing.
func (NopMetrics) OnProtocolError ¶
func (NopMetrics) OnProtocolError(ConnInfo, error)
OnProtocolError does nothing.
func (NopMetrics) OnReconnectAttempt ¶
func (NopMetrics) OnReconnectAttempt(ConnInfo, int)
OnReconnectAttempt does nothing.
type Peer ¶
type Peer interface {
// ID returns the charging station identity of the connection, on both
// ends: the client's own identity, or the identity of the station a
// server session belongs to.
ID() string
// Version returns the OCPP version negotiated for the connection.
Version() Version
Caller
}
Peer is the other end of one connection, as a handler sees it: the station's identity, the negotiated version, and a way to send it CALLs.
type Role ¶
type Role uint8
Role is one of the two OCPP roles.
The roles. OCPP 1.6 calls them Charge Point and Central System.
type SendDispatcher ¶
type SendDispatcher interface {
DispatchSend(ctx context.Context, p Peer, action string, payload json.RawMessage) error
}
SendDispatcher is implemented by a Dispatcher that also handles incoming SEND messages (OCPP 2.1). They are never answered, so DispatchSend returns only an error, which is logged.
type Sender ¶
Sender sends a SEND (OCPP 2.1): a message that is never answered and may be sent while a CALL is outstanding (2.1 Part 4 §4.1.1, §4.2.4). The client and server sessions implement it.
type State ¶
type State uint8
State is the state of a client's connection.
type ValidationError ¶
type ValidationError struct {
// Code is the CALLERROR code that fits the violation, spelt as the
// connection's version spells it: FormationViolation/FormatViolation
// for structure, OccurenceConstraintViolation/OccurrenceConstraintViolation
// for a missing field or a wrong number of elements,
// TypeConstraintViolation for a value of the wrong type, and
// PropertyConstraintViolation for a value outside its constraints.
Code ErrorCode
// Field is the path of the offending field, e.g.
// "meterValue[0].sampledValue[1].measurand"; empty for the payload.
Field string
// Reason says what is wrong.
Reason string
}
ValidationError says why a payload does not conform to the schema of its action. The version packages return it for requests and responses they refuse, outgoing and incoming. An incoming CALL that fails validation is answered with a CALLERROR carrying Code.
func (*ValidationError) CallError ¶
func (e *ValidationError) CallError() *CallError
CallError returns the CALLERROR that answers a CALL failing validation.
func (*ValidationError) Unwrap ¶
func (e *ValidationError) Unwrap() error
Unwrap returns ErrInvalidMessage.
type Version ¶
type Version uint8
Version is an OCPP protocol version that go-ocpp implements over JSON and WebSocket (OCPP-J). The zero value is not a valid version.
const ( V16 Version = iota + 1 // OCPP 1.6J, with the Security Whitepaper extensions V201 // OCPP 2.0.1 V21 // OCPP 2.1 )
The versions in scope. OCPP 1.6 SOAP and versions before 1.6 are not supported. SPECIFICATIONS.md lists the editions and errata followed.
func ParseSubprotocol ¶
ParseSubprotocol returns the version a WebSocket subprotocol selects. The comparison is exact: RFC 6455 subprotocol tokens are case-sensitive.
func ParseVersion ¶
ParseVersion parses a version as String writes it.
func (Version) String ¶
String returns the version as the specifications write it: "1.6", "2.0.1" or "2.1". An invalid version is written as "Version(n)".
func (Version) Subprotocol ¶
Subprotocol returns the WebSocket subprotocol that selects v during the opening handshake ("ocpp1.6", "ocpp2.0.1" or "ocpp2.1"). It returns "" for an invalid version.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package client is the Charging Station role of OCPP (OCPP 1.6: Charge Point): it connects to a CSMS, sends CALLs to it and answers the CALLs the CSMS sends.
|
Package client is the Charging Station role of OCPP (OCPP 1.6: Charge Point): it connects to a CSMS, sends CALLs to it and answers the CALLs the CSMS sends. |
|
Package e2e tests this module's client against this module's server over real WebSocket connections: every version, CALLs in both directions, authentication, TLS, session replacement, reconnection, limits and many concurrent stations.
|
Package e2e tests this module's client against this module's server over real WebSocket connections: every version, CALLs in both directions, authentication, TLS, session replacement, reconnection, limits and many concurrent stations. |
|
examples
|
|
|
csms
command
Command csms is a small CSMS that serves OCPP 1.6, 2.0.1 and 2.1 on one endpoint.
|
Command csms is a small CSMS that serves OCPP 1.6, 2.0.1 and 2.1 on one endpoint. |
|
device-model
command
Command device-model shows device model management, OCPP 2.0.1 (default) or 2.1 (-version 2.1), with a CSMS and a charging station in one process:
|
Command device-model shows device model management, OCPP 2.0.1 (default) or 2.1 (-version 2.1), with a CSMS and a charging station in one process: |
|
observability
command
Command observability shows the hooks go-ocpp offers for logs, metrics and tracing, with a CSMS and a Charging Station in one process: a JSON slog logger, an ocpp.Metrics implementation that counts, and call and handler interceptors that time every CALL (where a tracer would start and end its spans).
|
Command observability shows the hooks go-ocpp offers for logs, metrics and tracing, with a CSMS and a Charging Station in one process: a JSON slog logger, an ocpp.Metrics implementation that counts, and call and handler interceptors that time every CALL (where a tracer would start and end its spans). |
|
ocpp16
command
Command ocpp16 runs an OCPP 1.6J Central System and Charge Point in one process, over TLS with Basic authentication (security profile 2).
|
Command ocpp16 runs an OCPP 1.6J Central System and Charge Point in one process, over TLS with Basic authentication (security profile 2). |
|
ocpp201
command
Command ocpp201 runs an OCPP 2.0.1 CSMS and Charging Station in one process, over TLS with Basic authentication (security profile 2) and WebSocket compression.
|
Command ocpp201 runs an OCPP 2.0.1 CSMS and Charging Station in one process, over TLS with Basic authentication (security profile 2) and WebSocket compression. |
|
ocpp21
command
Command ocpp21 runs an OCPP 2.1 CSMS and Charging Station in one process.
|
Command ocpp21 runs an OCPP 2.1 CSMS and Charging Station in one process. |
|
remote-management
command
Command remote-management shows the remote operations of an OCPP 2.0.1 CSMS on a charging station, in one process:
|
Command remote-management shows the remote operations of an OCPP 2.0.1 CSMS on a charging station, in one process: |
|
security-profiles
command
Command security-profiles runs one OCPP 2.0.1 CSMS that accepts the three OCPP security profiles, and stations that connect with each:
|
Command security-profiles runs one OCPP 2.0.1 CSMS that accepts the three OCPP security profiles, and stations that connect with each: |
|
smart-charging
command
Command smart-charging shows smart charging between a CSMS and a charging station in one process, on OCPP 2.0.1 (default) or 1.6 (-version 1.6):
|
Command smart-charging shows smart charging between a CSMS and a charging station in one process, on OCPP 2.0.1 (default) or 1.6 (-version 1.6): |
|
station-simulator
command
Command station-simulator is a charging station simulator for testing a CSMS, on OCPP 1.6, 2.0.1 or 2.1.
|
Command station-simulator is a charging station simulator for testing a CSMS, on OCPP 1.6, 2.0.1 or 2.1. |
|
vendor-extensions
command
Command vendor-extensions shows the ways OCPP leaves room for vendor-specific data, on OCPP 1.6, 2.0.1 and 2.1, with one CSMS and one station per version in one process:
|
Command vendor-extensions shows the ways OCPP leaves room for vendor-specific data, on OCPP 1.6, 2.0.1 and 2.1, with one CSMS and one station per version in one process: |
|
internal
|
|
|
after
Package after carries the functions a handler registers with ocpp.AfterResponse from the handler's context to the engine, which runs them once the handler's result is queued.
|
Package after carries the functions a handler registers with ocpp.AfterResponse from the handler's context to the engine, which runs them once the handler's result is queued. |
|
engine
Package engine is the OCPP-J RPC endpoint that the client and the server share: one Endpoint per WebSocket connection, whichever side opened it (ARCHITECTURE.md, "The engine"; ADR 0004).
|
Package engine is the OCPP-J RPC endpoint that the client and the server share: one Endpoint per WebSocket connection, whichever side opened it (ARCHITECTURE.md, "The engine"; ADR 0004). |
|
gen
command
Command gen generates the message types, validation, call functions, handler interfaces, dispatchers and coverage manifest of a version package from the OCA JSON schemas (ADR 0003).
|
Command gen generates the message types, validation, call functions, handler interfaces, dispatchers and coverage manifest of a version package from the OCA JSON schemas (ADR 0003). |
|
schematest
Package schematest checks a generated version package against the OCA JSON schemas and an independent JSON Schema validator (github.com/santhosh-tekuri/jsonschema), as ADR 0003 requires.
|
Package schematest checks a generated version package against the OCA JSON schemas and an independent JSON Schema validator (github.com/santhosh-tekuri/jsonschema), as ADR 0003 requires. |
|
specsync
command
Command specsync refreshes schemas/ from the Open Charge Alliance: it finds the newest editions, errata and appendices on the OCA download page, downloads them, writes the JSON schemas they contain into schemas/ (as they are; ADR 0007), and records what it fetched in schemas/UPSTREAM.json and the checksums in schemas/SHA256SUMS.
|
Command specsync refreshes schemas/ from the Open Charge Alliance: it finds the newest editions, errata and appendices on the OCA download page, downloads them, writes the JSON schemas they contain into schemas/ (as they are; ADR 0007), and records what it fetched in schemas/UPSTREAM.json and the checksums in schemas/SHA256SUMS. |
|
transport
Package transport is the WebSocket underneath the engine (ADR 0002): text messages in and out, a close with a status code, and the negotiated subprotocol.
|
Package transport is the WebSocket underneath the engine (ADR 0002): text messages in and out, a close with a status code, and the negotiated subprotocol. |
|
wire
Package wire is the runtime of the generated version packages (ocpp16, ocpp201, ocpp21): strict decoding, validation errors with the error codes of a version, and the checks around a typed call.
|
Package wire is the runtime of the generated version packages (ocpp16, ocpp201, ocpp21): strict decoding, validation errors with the error codes of a version, and the checks around a typed call. |
|
Package ocpp16 is OCPP 1.6J, with the extensions of the OCPP 1.6 Security Whitepaper Edition 4: a type for every request and response, validation against the OCA JSON schemas, a call function per action, and the handler interfaces and dispatchers of both roles.
|
Package ocpp16 is OCPP 1.6J, with the extensions of the OCPP 1.6 Security Whitepaper Edition 4: a type for every request and response, validation against the OCA JSON schemas, a call function per action, and the handler interfaces and dispatchers of both roles. |
|
Package ocpp201 is OCPP 2.0.1 (Edition 4): a type for every request and response, validation against the OCA JSON schemas, a call function per action, and the handler interfaces and dispatchers of both roles.
|
Package ocpp201 is OCPP 2.0.1 (Edition 4): a type for every request and response, validation against the OCA JSON schemas, a call function per action, and the handler interfaces and dispatchers of both roles. |
|
Package ocpp21 is OCPP 2.1 (Edition 2): a type for every request and response, validation against the OCA JSON schemas, a call function per action, and the handler interfaces and dispatchers of both roles.
|
Package ocpp21 is OCPP 2.1 (Edition 2): a type for every request and response, validation against the OCA JSON schemas, a call function per action, and the handler interfaces and dispatchers of both roles. |
|
Package ocppcert computes the certificate identifiers OCPP messages carry: CertificateHashData, which GetInstalledCertificateIds, DeleteCertificate, GetCertificateStatus and the 1.6 Security Whitepaper messages use to name a certificate without sending it.
|
Package ocppcert computes the certificate identifiers OCPP messages carry: CertificateHashData, which GetInstalledCertificateIds, DeleteCertificate, GetCertificateStatus and the 1.6 Security Whitepaper messages use to name a certificate without sending it. |
|
Package ocppj is the OCPP-J RPC frame codec: the JSON arrays that carry OCPP messages over WebSocket.
|
Package ocppj is the OCPP-J RPC frame codec: the JSON arrays that carry OCPP messages over WebSocket. |
|
Package ocpptest helps applications test their OCPP handlers against a real go-ocpp peer over a WebSocket on the loopback interface, the way net/http/httptest helps test HTTP handlers.
|
Package ocpptest helps applications test their OCPP handlers against a real go-ocpp peer over a WebSocket on the loopback interface, the way net/http/httptest helps test HTTP handlers. |
|
Package server is the CSMS role of OCPP (OCPP 1.6: Central System): it accepts charging stations' connections, answers their CALLs and sends CALLs to them.
|
Package server is the CSMS role of OCPP (OCPP 1.6: Central System): it accepts charging stations' connections, answers their CALLs and sends CALLs to them. |