A type-safe Go implementation of the Open Charge Point Protocol (OCPP) 1.6 message set, with validated request/response structures for EV charge points (EVSE) and Central Systems (CSMS/backends).
This library implements OCPP (Open Charge Point Protocol) 1.6 message types with strict validation, following Go best practices and the official OCPP 1.6 specification. It is designed as a foundation for building OCPP-compliant charging station management systems and charge point implementations.
Status: Stable - v1.0.0 (28/28 OCPP 1.6 JSON messages implemented)
- API follows SemVer; see [CHANGELOG](CHANGELOG.md) for release notes.
- Public API is frozen for all v1.x releases; breaking changes will bump
MAJOR.
Search terms: OCPP 1.6, Open Charge Point Protocol, EVSE, CSMS, charge station backend, Authorize.req, BootNotification, MeterValues, RemoteStart, Charge Point, Central System.
- Type Safety - Constructor pattern with validation
(
New*()for types,Req()/Conf()for messages) - OCPP 1.6 Compliance - Strict adherence to protocol specification
- OCPP Naming - Uses
Req()/Conf()to match OCPP terminology (Authorize.req, Authorize.conf) - Immutable Types - Thread-safe by design with value receivers
- Comprehensive Testing - Unit tests and example tests with high coverage
- Zero Panics - All errors returned, never panicked
- Well Documented - Full godoc coverage and examples
The library covers the full OCPP 1.6 message surface, including:
- Authorize.req / .conf, BootNotification.req / .conf, Heartbeat.req / .conf
- StartTransaction.req / .conf, StopTransaction.req / .conf, StatusNotification
- MeterValues, ClearChargingProfile, SetChargingProfile, TriggerMessage
- RemoteStartTransaction, RemoteStopTransaction, ChangeAvailability, ChangeConfiguration, GetConfiguration, DataTransfer
- ReserveNow, CancelReservation, UnlockConnector, Reset, UpdateFirmware, GetDiagnostics, DiagnosticsStatusNotification, FirmwareStatusNotification
- SendLocalList, GetLocalListVersion, GetCompositeSchedule
go get github.com/aasanchez/ocpp16messages
Requirements: Go 1.24.6 or later (CI and go.mod aligned)
.
├── types/ # Core OCPP data types (shared across messages)
│ ├── cistring.go # CiString20/25/50/255/500 types
│ ├── datetime.go # RFC3339 DateTime with UTC normalization
│ ├── integer.go # Validated uint16 Integer type
│ ├── errors.go # Shared error constants and sentinels
│ ├── authorizationstatus.go # AuthorizationStatus enum
│ ├── idtoken.go # IdToken type
│ ├── idtaginfo.go # IdTagInfo type
│ ├── chargingprofilepurposetype.go # ChargingProfilePurposeType enum
│ ├── chargingrateunit.go # ChargingRateUnit enum
│ ├── chargingschedule.go # ChargingSchedule type
│ ├── chargingscheduleperiod.go # ChargingSchedulePeriod type
│ ├── metervalue.go # MeterValue and MeterValueInput types
│ ├── sampledvalue.go # SampledValue and SampledValueInput types
│ ├── measurand.go # Measurand enum
│ ├── readingcontext.go # ReadingContext enum
│ ├── valueformat.go # ValueFormat enum
│ ├── phase.go # Phase enum
│ ├── location.go # Location enum
│ ├── unitofmeasure.go # UnitOfMeasure enum
│ ├── doc.go # Package documentation
│ └── tests/ # Public API tests (black-box)
├── authorize/ # Authorize message
├── bootNotification/ # BootNotification message
├── cancelReservation/ # CancelReservation message
├── changeAvailability/ # ChangeAvailability message
├── changeConfiguration/ # ChangeConfiguration message
├── clearCache/ # ClearCache message
├── clearChargingProfile/ # ClearChargingProfile message
├── dataTransfer/ # DataTransfer message
├── diagnosticsStatusNotification/ # DiagnosticsStatusNotification message
├── firmwareStatusNotification/ # FirmwareStatusNotification message
├── getCompositeSchedule/ # GetCompositeSchedule message
├── getConfiguration/ # GetConfiguration message
├── getDiagnostics/ # GetDiagnostics message
├── getLocalListVersion/ # GetLocalListVersion message
├── heartbeat/ # Heartbeat message
├── meterValues/ # MeterValues message
├── remoteStartTransaction/ # RemoteStartTransaction message
├── remoteStopTransaction/ # RemoteStopTransaction message
├── reserveNow/ # ReserveNow message
├── reset/ # Reset message
├── sendLocalList/ # SendLocalList message
├── setChargingProfile/ # SetChargingProfile message
├── startTransaction/ # StartTransaction message
├── statusNotification/ # StatusNotification message
├── stopTransaction/ # StopTransaction message
├── triggerMessage/ # TriggerMessage message
├── unlockConnector/ # UnlockConnector message
├── updateFirmware/ # UpdateFirmware message
└── SECURITY.md # Security policy and vulnerability reporting
- Semantic Versioning: API surface follows SemVer starting with v1.0.0.
- Supported Go versions: >= 1.24 (aligned with go.mod and CI).
- Changelog: see CHANGELOG for releases and upgrade notes.
The library provides validated OCPP 1.6 data types:
import "github.com/aasanchez/ocpp16messages/types"
// CiString types (case-insensitive, ASCII printable, length-validated)
idTag, err := types.NewCiString20Type("RFID-ABC123")
if err != nil {
// Handle validation error (length > 20 or non-ASCII chars)
}
// DateTime (RFC3339, must be UTC)
timestamp, err := types.NewDateTime("2025-01-02T15:04:05Z")
if err != nil {
// Handle parsing error
}
// Integer (validated uint16)
retryCount, err := types.NewInteger(3)
if err != nil {
// Handle conversion/range error
}
Messages use OCPP terminology with Req() for requests and Conf() for responses:
import "github.com/aasanchez/ocpp16messages/authorize"
// Create an Authorize.req message using the ReqInput struct
// Validation happens automatically in the constructor
req, err := authorize.Req(authorize.ReqInput{
IdTag: "RFID-ABC123",
})
if err != nil {
// Handle validation error (empty, too long, or invalid characters)
}
// Access the validated IdTag
fmt.Println(req.IdTag.String()) // "RFID-ABC123"
import "github.com/aasanchez/ocpp16messages/clearChargingProfile"
// ClearChargingProfile.req with optional fields
id := 123
req, err := clearChargingProfile.Req(clearChargingProfile.ReqInput{
Id: &id,
ConnectorId: nil,
ChargingProfilePurpose: nil,
StackLevel: nil,
})
The ReqMessage type returned by Req() contains validated, typed fields
that are immutable and thread-safe.
- Go 1.24+
- golangci-lint
- staticcheck
- gci, gofumpt, golines (formatters)
# Install dependencies
go mod tidy
# Run tests
make test # Unit tests with coverage
make test-coverage # Generate HTML coverage report
make test-example # Run example tests (documentation tests)
make test-all # Run all test types
make test-race # Run race detector with -race (opt-in)
make test-fuzz # Run fuzzers in ./fuzz (short budget, opt-in)
make test-bench # Run benchmarks in ./benchmark (opt-in)
# Code quality
make lint # Run all linters (golangci-lint, go vet, staticcheck)
make format # Format code (gci, gofumpt, golines, gofmt)
# Documentation
make pkgsite # Start local documentation server at http://localhost:8080
- Nightly workflow runs
make test-all,make test-race,make test-fuzz, andmake test-benchto guard the opt-in suites.
Reports are generated in the reports/ directory:
reports/coverage.out- Coverage datareports/golangci-lint.txt- Lint results
| OCPP Type | Go Type | Validation |
|---|---|---|
| CiString20Type | types.CiString20Type |
Length <= 20, ASCII printable (32-126) |
| CiString25Type | types.CiString25Type |
Length <= 25, ASCII printable (32-126) |
| CiString50Type | types.CiString50Type |
Length <= 50, ASCII printable (32-126) |
| CiString255Type | types.CiString255Type |
Length <= 255, ASCII printable (32-126) |
| CiString500Type | types.CiString500Type |
Length <= 500, ASCII printable (32-126) |
| dateTime | types.DateTime |
RFC3339, UTC only |
| integer | types.Integer |
uint16 (0-65535) |
| OCPP Type | Go Type | Description |
|---|---|---|
| IdToken | types.IdToken |
RFID tag identifier (CiString20) |
| IdTagInfo | types.IdTagInfo |
Authorization info with status |
| AuthorizationStatus | types.AuthorizationStatus |
Accepted, Blocked, Expired, etc |
| OCPP Type | Go Type | Description |
|---|---|---|
| ChargingProfilePurposeType | types.ChargingProfilePurposeType |
TxDefaultProfile, TxProfile |
| ChargingRateUnit | types.ChargingRateUnit |
W or A |
| ChargingSchedule | types.ChargingSchedule |
Schedule with periods |
| ChargingSchedulePeriod | types.ChargingSchedulePeriod |
Start/limit/phases |
| OCPP Type | Go Type | Description |
|---|---|---|
| MeterValue | types.MeterValue |
Timestamp + SampledValue array |
| SampledValue | types.SampledValue |
Value + optional context/format/etc |
| Measurand | types.Measurand |
Energy, Power, Current, Voltage, etc |
| ReadingContext | types.ReadingContext |
Sample.Clock, Sample.Periodic, etc |
| ValueFormat | types.ValueFormat |
Raw or SignedData |
| Phase | types.Phase |
L1, L2, L3, N, L1-N, L2-N, L3-N |
| Location | types.Location |
Body, Cable, EV, Inlet, Outlet |
| UnitOfMeasure | types.UnitOfMeasure |
Wh, kWh, varh, kvarh, W, kW, VA, etc |
| Package | Type | Description |
|---|---|---|
bootNotification/types |
RegistrationStatus |
Accepted, Pending, Rejected |
cancelReservation/types |
CancelReservationStatus |
Accepted, Rejected |
changeAvailability/types |
AvailabilityType |
Inoperative, Operative |
changeAvailability/types |
AvailabilityStatus |
Accepted, Rejected, Scheduled |
changeConfiguration/types |
ConfigurationStatus |
Accepted, Rejected, etc |
clearCache/types |
ClearCacheStatus |
Accepted, Rejected |
clearChargingProfile/types |
ClearChargingProfileStatus |
Accepted, Unknown |
dataTransfer/types |
DataTransferStatus |
Accepted, Rejected, etc |
diagnosticsStatusNotification |
DiagnosticsStatus |
Idle, Uploaded, UploadFailed, etc |
firmwareStatusNotification |
FirmwareStatus |
Downloaded, Installing, etc |
getCompositeSchedule/types |
GetCompositeScheduleStatus |
Accepted, Rejected |
getConfiguration/types |
KeyValue |
Configuration key-value pair |
getLocalListVersion/types |
ListVersionNumber |
Local list version number |
remoteStartTransaction/types |
RemoteStartTransactionStatus |
Accepted, Rejected |
remoteStopTransaction/types |
RemoteStopTransactionStatus |
Accepted, Rejected |
reserveNow/types |
ReservationStatus |
Accepted, Faulted, Occupied, etc |
reset/types |
ResetType |
Hard, Soft |
reset/types |
ResetStatus |
Accepted, Rejected |
sendLocalList/types |
UpdateType |
Differential, Full |
sendLocalList/types |
UpdateStatus |
Accepted, Failed, etc |
sendLocalList/types |
AuthorizationData |
IdTag + IdTagInfo |
setChargingProfile/types |
ChargingProfile |
Complete charging profile |
setChargingProfile/types |
ChargingProfileKindType |
Absolute, Recurring, Relative |
setChargingProfile/types |
ChargingProfileStatus |
Accepted, Rejected, etc |
setChargingProfile/types |
RecurrencyKindType |
Daily, Weekly |
statusNotification/types |
ChargePointErrorCode |
ConnectorLockFailure, etc |
statusNotification/types |
ChargePointStatus |
Available, Charging, Faulted, etc |
stopTransaction/types |
StopReason |
EmergencyStop, EVDisconnected, etc |
triggerMessage/types |
MessageTrigger |
BootNotification, Heartbeat, etc |
triggerMessage/types |
TriggerMessageStatus |
Accepted, Rejected, NotImplemented |
unlockConnector/types |
UnlockStatus |
Unlocked, UnlockFailed, etc |
| Message | Request | Confirmation | Package |
|---|---|---|---|
| Authorize | Done | Done | authorize |
| BootNotification | Done | Done | bootNotification |
| CancelReservation | Done | Done | cancelReservation |
| ChangeAvailability | Done | Done | changeAvailability |
| ChangeConfiguration | Done | Done | changeConfiguration |
| ClearCache | Done | Done | clearCache |
| ClearChargingProfile | Done | Done | clearChargingProfile |
| DataTransfer | Done | Done | dataTransfer |
| DiagnosticsStatusNotification | Done | Done | diagnosticsStatusNotification |
| FirmwareStatusNotification | Done | Done | firmwareStatusNotification |
| GetCompositeSchedule | Done | Done | getCompositeSchedule |
| GetConfiguration | Done | Done | getConfiguration |
| GetDiagnostics | Done | Done | getDiagnostics |
| GetLocalListVersion | Done | Done | getLocalListVersion |
| Heartbeat | Done | Done | heartbeat |
| MeterValues | Done | Done | meterValues |
| RemoteStartTransaction | Done | Done | remoteStartTransaction |
| RemoteStopTransaction | Done | Done | remoteStopTransaction |
| ReserveNow | Done | Done | reserveNow |
| Reset | Done | Done | reset |
| SendLocalList | Done | Done | sendLocalList |
| SetChargingProfile | Done | Done | setChargingProfile |
| StartTransaction | Done | Done | startTransaction |
| StatusNotification | Done | Done | statusNotification |
| StopTransaction | Done | Done | stopTransaction |
| TriggerMessage | Done | Done | triggerMessage |
| UnlockConnector | Done | Done | unlockConnector |
| UpdateFirmware | Done | Done | updateFirmware |
- OCPP Naming - Messages use
Req()/Conf()to match OCPP terminology - Constructor Validation - All types require constructors that validate input
- Input Struct Pattern - Raw values passed via
ReqInput/ConfInputstructs, validated automatically - Immutability - Types use private fields and value receivers
- Error Accumulation - Constructors report all validation errors at once
using
errors.Join() - Error Wrapping - Context preserved via
fmt.Errorfwith%w - No Panics - Library never panics; all errors returned
- Thread Safety - Designed for safe concurrent use
- Go Conventions - Follows Effective Go guidelines
Security is critical for EV charging infrastructure. This library:
- Validates all input at construction time
- Prevents injection attacks via strict type constraints
- Provides clear error messages without exposing internals
- Uses immutable types to prevent tampering
- Is designed for safe concurrent use
Reporting vulnerabilities: See SECURITY.md for our security policy and responsible disclosure process.
We welcome contributions! Please:
- Follow Go best practices and Effective Go
- Add tests for all new functionality
- Ensure
make test-allpasses - Run
make lintandmake formatbefore committing - Document all exported types and functions
- Follow the existing code style
See CLAUDE.md for detailed development guidelines.
See LICENSE