A library for type-aware parsing, serialization and validation of OCPP 1.6, OCPP 2.0 and OCPP 2.1 messages
npm install typed-ocpptyped-ocppA library for fast, type-aware validation of OCPP 1.6, OCPP 2.0 and OCPP 2.1
messages, built against the official [JSON Schema][i2] documents published
by the [Open Charge Alliance][i1].
[i1]: https://openchargealliance.org
[i2]: https://json-schema.org
- typed-ocpp
- Table of Contents
- Usage
- OCPP16, OCPP20, OCPP21 namespaces
- validate()
- validateCall(), validateCallError() and validateCallResult()
- isCall(), isCallResult() and isCallError()
- checkCallResult()
- Types
- Primary types
- Types for specific messages
- The CheckedCallResult type
- Utility enums
- Message types SEND and CALLRESULTERROR in OCPP 2.1
- Utility types for OCPP 1.6
- Utility types for OCPP 2.0
- Utility types for OCPP 2.1
- ChargingManager class
- JSON Schema(s)
- Building and testing
- License
This library exports all functions and typings related to OCPP 1.6,
OCPP 2.0 and OCPP 2.1 under, respectively, the OCPP16, OCPP20, OCPP21
namespaces:
``typescript`
import { OCPP16, OCPP20, OCPP21 } from 'typed-ocpp';
All three namespaces export identical APIs while typings and schemas differ
according to the differences in the respective OCPP versions. All of the
examples below apply to all namespaces.
The validate() function is a [user-defined, validating type guard][v1] whichtrue
returns if the provided value is a spec-compliant OCPP message andfalse otherwise.
`typescript`
import { OCPP16 } from 'typed-ocpp';
const value = [2,"test","BootNotification",{"chargePointModel":"model","chargePointVendor":"vendor"}];
if (OCPP16.validate(value)) {
// valid
}
If validate() returns true, the TS compiler will infer the provided value
to be of one of the following types:
`typescript`
OCPP16.Call // Union of all types of Call messages
OCPP16.CallError // Type for Call Error messages
OCPP16.UncheckedCallResult // Type for "unchecked" Call Result messages
The TS compiler will then be able to use known types to infer others:
`typescript`
const value = [2,"test","BootNotification",{"chargePointModel":"model","chargePointVendor":"vendor"}];
if (OCPP16.validate(value)) {
if (OCPP16.isCall(value)) {
value[2]; // TS gives type "OCPP.Action"
if (value[2] === OCPP16.Action.BootNotification) {
// TS infers the shape of the call payload based on the action
value[3].chargePointModel; // TS gives type "string"
value[3].randomProp; // TS compilation error
}
}
}
If validation fails and validate() returns false, validation errors willvalidate.errors
be stored in the array:
`typescript`
const value = 'foobar';
if (!OCPP16.validate(value)) {
// prints: [ 'Invalid OCPP message: invalid message type or not an array' ]
console.log(OCPP16.validate.errors);
}
[v1]: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
The validateCall(), validateCallError() and validateCallResult()
functions are user-defined, validating type guards specific to each type of
message defined by the OCPP specs: _call_, _call error_ and
_call result_.
These functions behave in the same way as the validate() function but onlytrue
return when provided with values of the corresponding message type..errors
Validation errors can be retrieved via the property, just as withvalidate().
The isCall(), isCallResult() and isCallError() functions are
user-defined, _non-validating_ type guards that facilitate identifying the type
of a valid message:
`typescript`
if (OCPP16.validate(message)) {
if (OCPP16.isCall(message)) {
// TS infers that parsed is of type OCPP16.Call
}
if (OCPP16.isCallResult(message)) {
// TS infers that parsed is of type OCPP16.UncheckedCallResult
}
if (OCPP16.isCallError(message)) {
// TS infers that parsed is of type OCPP16.CallError
}
}
Post-validation, _call result_ messages are inferred by the TS compiler to
be of the UncheckedCallResult type, which is a generic type that does not
constrain the _call result_'s payload to any specific shape as doing so
requires matching against the originating _call_ message.
Complete validation of a _call result_ message against its originating
_call_ message can be done through the checkCallResult() user-defined,
validating type guard.
If checkCallResult() returns true, the provided _call result_ message
is guaranteed to match the provided _call_ message in terms of:
- Matching the expected type, incl. the payload (for example: being of type
OCPP16.BootNotificationCallResult given an originatingOCPP16.BootNotificationCall
essage).
- Sharing the same _call identifier_ with the originating _call_ message.
`typescript
const call = [
2,
"test",
"BootNotification",
{"chargePointModel":"model","chargePointVendor":"vendor"},
] satisfies OCPP16.Call;
const result = [
3,
"test",
{ status: "Accepted", currentTime: "1970-01-01T00:00:00.000Z", interval: 10 },
] satisfies OCPP16.UncheckedCallResult
// Narrows the type of call to OCPP16.BootNotificationCallresult
if (call[2] === OCPP16.Action.BootNotification) {
// Validates against call, narrowing the type ofresult
// to OCPP16.BootNotificationCallResultresult
if (OCPP16.checkCallResult(result, call)) {
// Inferred as "Accepted" | "Pending" | "Rejected"
result[2].status;
} else {
// The message does not match the originating call message`
console.log(OCPP16.checkCallResult.errors);
}
}
Just like validate(), when checkCallResult() returns false it storescheckCallResult.errors
validation errors in the array.
#### Primary types
Within both the OCPP16, OCPP20 and OCPP21 namespaces, typed-ocpp
provides a set of typings and schemas that covers most aspects of OCPP
messages.
`typescript
// Union of all types of Call messages
OCPP16.Call
// Union of all Call Result message types
OCPP16.CallResult
// Type for Call Error messages
OCPP16.CallError
// Type for "unchecked" Call Result messages
OCPP16.UncheckedCallResult
// Generic type of Call Result message that resolves to the specific type of
// Call Result message matching the provided type of Call message "C"
OCPP16.CheckedCallResult
// Message-specific types
OCPP16.AuthorizationCall
OCPP16.AuthorizationCallResult
OCPP16.BootNotificationCall
OCPP16.BootNotificationCallResult
/ ... /
`
#### Types for specific messages
Specific types for _Call_ and _Call Result_ messages making up the
OCPP16.Call and OCPP16.CallResult unions use the Call and CallResult
suffixes:
`typescript`
OCPP16.MeterValuesCall
OCPP16.MeterValuesCallResult
/ ... and so on .../
For each of these Call and CallResult types, the respective Request andResponse types model their specific payloads and map directly to the official
JSON schemas:
`typescript`
OCPP16.MeterValuesRequest
OCPP16.MeterValuesResponse
/ ... and so on .../
#### The CheckedCallResult type
When returning true, the checkCallResult() function leads the TS compilerCheckedCallResult
to infer the generic type , which resolvesC
to the specific type of _call result_ message that corresponds to the type
of _call_ message provided as the type argument.
The generic CheckedCallResult type can also be used on its
own to model a _call result_ message after a known or inferred type of
_call_ message:
`typescript`
const result: OCPP16.CheckedCallResult
OCPP16.MessageType.CALLRESULT,
'
{
configurationKey: [
{ key: 'some_key', value: 'some_value', readonly: true },
],
// the TS compiler will return an error here due to unsupported property
// "foobar" in OCPP16.GetConfigurationCallResult payloads.
foobar: 42,
},
];
#### Utility enums
`typescript`
OCPP16.MessageType // enum of message types (CALL = 2, CALLRESULT = 3, CALLERROR = 4)
OCPP16.Action // enum of actions in Call messages ("Authorize", "BootNotification", ...)
OCPP16.ErrorCode // enum of error code in Call Error messages ("NotImplemented", "NotSupported", ...)
`typescript`
OCPP20.MessageType // enum of message types (CALL = 2, CALLRESULT = 3, CALLERROR = 4)
OCPP20.Action // enum of actions in Call messages ("Authorize", "BootNotification", ...)
OCPP20.ErrorCode // enum of error code in Call Error messages ("NotImplemented", "NotSupported", ...)
`typescript`
OCPP21.MessageType // enum of message types (CALL = 2, CALLRESULT = 3, CALLERROR = 4, CALLRESULTERROR = 5, SEND = 6)
OCPP21.Action // enum of actions in Call messages ("Authorize", "BootNotification", ...)
OCPP21.ErrorCode // enum of error code in Call Error messages ("NotImplemented", "NotSupported", ...)
#### Message types SEND and CALLRESULTERROR in OCPP 2.1
OCPP 2.1 introduced two new types of messages: CALLRESULTERROR and SEND,5
using the values and 6 respectively.
This library allows OCPP 2.1 _Call_ messages to have either the CALL orSEND
the type, regardless of the specific action.
This library also allows OCPP 2.1 _Call Error_ messages to have either the
CALLERROR or the CALLRESULTERROR type.
#### Utility types for OCPP 1.6
The following types may be used to model value descriptors within
MeterValues Call messages:
`typescript`
OCPP16.Context // sampling context ("Transaction.Begin", "Sample.Periodic", ...)
OCPP16.Measurand // value measurand ("Power.Active.Import", "Frequency", ...)
OCPP16.Phase // AC phase ("L1", "L2", "L1-N", ...)
OCPP16.Location // sampling location ("Inlet", "Outlet", ...)
OCPP16.Unit // value unit ("Wh", "kWh", ...)
OCPP16.Format // value format ("Raw" or "SignedData")
OCPP16.SampledValue // individual entry of the "sampledValue" array
OCPP16.MeterValue // individual entry of the "meterValue" array
The following types may be used to model value descriptors within
StatusNotification Call messages:
`typescript`
OCPP16.Status // status ("Available", "Reserved", ...)
#### Utility types for OCPP 2.0
`typescript`
OCPP20.ConnectorStatus // connector status ("Available", "Occupied", ...)
OCPP20.ChargingState // charging status ("Charging", "EVConnected", ...)
#### Utility types for OCPP 2.1
`typescript`
OCPP21.ConnectorStatus // connector status ("Available", "Occupied", ...)
OCPP21.ChargingState // charging status ("Charging", "EVConnected", ...)
> WARNING: experimental!
>
> The ChargingManager class is experimental and unstable. It is only
> available in its OCPP 1.6 variant under the respective namespace, though the
> plan is to eventually provide implementations for OCPP 2.0 and OCPP 2.1.
A _charging schedule_ is an array of _charging periods_, each defined by
a start date, an end date and a set of charging limits:
`typescript`
export type ChargingSchedule = {
start: Date;
end: Date;
data: {
charging: {
min: number;
max: number;
phases: { qty: number; };
};
discharging: {
min: number;
max: number;
phases: { qty: number; };
};
shouldDischarge: boolean;
unit: 'W' | 'A';
},
}[]
The OCPP16.ChargingManager class implements a repository of charging
profiles that can merge all of its entries into charging schedules computed
on-demand. Overlapping charging intervals will be merged together according to
the stack level and purpose of the respective profiles.
`typescript
import { OCPP16, Models } from 'typed-ocpp';
// Instantiate the manager
const manager = new OCPP16.ChargingManager();
// Add a new profile by passing the payload of a SetChargingProfile call.
const setProfileCall = {} as OCPP16.SetChargingProfileCall;
manager.setChargingProfile(setProfileCall[3]);
// Clear profiles by passing the payload of a ClearChargingProfiles call.
const clearProfileCall = {} as OCPP16.ClearChargingProfilesCall;
manager.clearChargingProfile(clearProfileCall[3]);
// Get an absolute schedule for the entire station
const schedule = manager.getStationSchedule(
new Date(), // start date
new Date(Date.now() + 14_400_000), // end date
'W', // charging rate unit ("W" or "A")
new Models.ACChargingStation(230), // model used for unit conversions
);
// Get charging limits for the entire station at the given date
const limits = manager.getStationLimitsAtDate(
new Date(), // reference date
'W', // charging rate unit ("W" or "A")
new Models.ACChargingStation(230), // model used for unit conversions
);
// Get the charging schedule for connector 1
const schedule = manager.getConnectorSchedule(
new Date(), // start date
new Date(Date.now() + 14_400_000), // end date
1, // connector id
'W', // charging rate unit ("W" or "A")
new Models.DCChargingSession(400), // model used for unit conversions
);
// Get charging limits for connector 1 at the given date
const limits = manager.getConnectorLimitsAtDate(
new Date(), // reference date
1, // connector id
'W', // charging rate unit ("W" or "A")
new Models.DCChargingSession(400), // model used for unit conversions
);
// Get the composite charging schedule for connector 1, suitable to be used
// within OCPP16.GetCompositeScheduleCallResult messages
const schedule = manager.getConnectorCompositeSchedule(
new Date(), // start date
new Date(Date.now() + 14_400_000), // end date
1, // connector id
'W', // charging rate unit ("W" or "A")
new Models.DCChargingSession(400), // model used for unit conversions
);
// Uses the getConnectorCompositeSchedule() to get the composite schedule for`
// connector 1 and return it as the payload for an OCPP16.SetChargingProfileCall
// message
const limits = manager.getConnectorCompositeProfile(
new Date(), // start date
new Date(Date.now() + 14_400_000), // end date
1, // connector id
'W', // charging rate unit ("W" or "A")
new Models.DCChargingSession(400), // model used for unit conversions
);
Note that schedules expressed in A (Ampere) indicate _per phase_ currentW
while schedules expressed in (Watt) indicate total power across all phases.
The OCPP16, OCPP20 and OCPP21 namespaces export the official JSON Schema
documents provided by the OCPP Alliance as ready-to-use objects, slightly
tweaked to maximize compat with different versions and configurations of Ajv:
`typescript
import { OCPP16, OCPP20, OCPP21 } from 'typed-ocpp';
OCPP16.schemas.AuthorizeRequest;
OCPP16.schemas.AuthorizeResponse;
/ ... /
OCPP20.schemas.AuthorizeRequest;
OCPP20.schemas.AuthorizeResponse;
/ ... /
OCPP21.schemas.AuthorizeRequest;
OCPP21.schemas.AuthorizeResponse;
/ ... /
``
See [BUILD.md][b1] file.
[b1]: ./BUILD.md
MIT. See [LICENSE][l1] file.
[l1]: ./LICENSE