https://github.com/jacoscaz/typed-ocpp
A library for type-aware parsing, serialization and validation of OCPP 1.6, OCPP 2.0.1 and OCPP 2.1 messages, built against the official JSON Schema documents published by the Open Charge Alliance.
https://github.com/jacoscaz/typed-ocpp
ocpp ocpp16 ocpp16j ocpp201 ocpp21
Last synced: 4 months ago
JSON representation
A library for type-aware parsing, serialization and validation of OCPP 1.6, OCPP 2.0.1 and OCPP 2.1 messages, built against the official JSON Schema documents published by the Open Charge Alliance.
- Host: GitHub
- URL: https://github.com/jacoscaz/typed-ocpp
- Owner: jacoscaz
- License: mit
- Created: 2023-08-08T11:28:35.000Z (almost 2 years ago)
- Default Branch: master
- Last Pushed: 2025-02-04T10:24:34.000Z (4 months ago)
- Last Synced: 2025-02-07T17:52:42.959Z (4 months ago)
- Topics: ocpp, ocpp16, ocpp16j, ocpp201, ocpp21
- Language: TypeScript
- Homepage:
- Size: 742 KB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# `typed-ocpp`
A 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## Table of Contents
- [`typed-ocpp`](#typed-ocpp)
- [Table of Contents](#table-of-contents)
- [Usage](#usage)
- [`OCPP16`, `OCPP20`, `OCPP21` namespaces](#ocpp16-ocpp20-ocpp21-namespaces)
- [`validate()`](#validate)
- [`validateCall()`, `validateCallError()` and `validateCallResult()`](#validatecall-validatecallerror-and-validatecallresult)
- [`isCall()`, `isCallResult()` and `isCallError()`](#iscall-iscallresult-and-iscallerror)
- [`checkCallResult()`](#checkcallresult)
- [Types](#types)
- [Primary types](#primary-types)
- [Types for specific messages](#types-for-specific-messages)
- [The `CheckedCallResult` type](#the-checkedcallresultc-extends-call-type)
- [Utility enums](#utility-enums)
- [Message types `SEND` and `CALLRESULTERROR` in OCPP 2.1](#message-types-send-and-callresulterror-in-ocpp-21)
- [Utility types for OCPP 1.6](#utility-types-for-ocpp-16)
- [Utility types for OCPP 2.0](#utility-types-for-ocpp-20)
- [Utility types for OCPP 2.1](#utility-types-for-ocpp-21)
- [`ChargingScheduleManager` class](#chargingschedulemanager-class)
- [JSON Schema(s)](#json-schemas)
- [Building and testing](#building-and-testing)
- [License](#license)## Usage
### `OCPP16`, `OCPP20`, `OCPP21` namespaces
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.### `validate()`
The `validate()` function is a [user-defined, validating type guard][v1] which
returns `true`if the provided value is a spec-compliant OCPP message and
`false` 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 will
be stored in the `validate.errors` 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
### `validateCall()`, `validateCallError()` and `validateCallResult()`
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 only
return `true` when provided with values of the corresponding message type.
Validation errors can be retrieved via the `.errors` property, just as with
`validate()`.### `isCall()`, `isCallResult()` and `isCallError()`
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
}
}
```### `checkCallResult()`
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 originating
`OCPP16.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.BootNotificationCall`
if (call[2] === OCPP16.Action.BootNotification) {
// Validates `result` against `call`, narrowing the type of
// `result` to `OCPP16.BootNotificationCallResult`
if (OCPP16.checkCallResult(result, call)) {
// Inferred as "Accepted" | "Pending" | "Rejected"
result[2].status;
} else {
// The `result` message does not match the originating `call` message
console.log(OCPP16.checkCallResult.errors);
}
}
```Just like `validate()`, when `checkCallResult()` returns `false` it stores
validation errors in the `checkCallResult.errors` array.### Types
#### 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 ...*/
```#### The `CheckedCallResult` type
When returning `true`, the `checkCallResult()` function leads the TS compiler
to infer the generic type `CheckedCallResult`, which resolves
to the specific type of **_call result_** message that corresponds to the type
of **_call_** message provided as the `C` 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`,
using the values `5` and `6` respectively.This library allows OCPP 2.1 **_Call_** messages to have either the `CALL` or
the `SEND` 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", ...)
```### `ChargingScheduleManager` class
> **WARNING: experimental!**
>
> The `ChargingScheduleManager` 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.ChargingScheduleManager` 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';// Create the store passing the physical characteristics of the EVSE.
const store = new OCPP16.ChargingScheduleManager();// Add a new profile by passing the payload of a SetChargingProfile call.
const setProfileCall = {} as OCPP16.SetChargingProfileCall;
store.setChargingProfile(setProfileCall[3]);// Clear profiles by passing the payload of a ClearChargingProfiles call.
const clearProfileCall = {} as OCPP16.ClearChargingProfiles;
store.clearChargingProfile(clearProfileCall[3]);// Get an absolute schedule for the entire station.
const schedule = store.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 = store.getStationLimitsAtDate(
new Date(), // reference date
'W', // charging rate unit ("W" or "A")
new Models.ACChargingStation(230), // model used for unit conversions
);// Get an absolute schedule for the next 4 hours for connector (OCPP 1.6)
// or evse (OCPP 2.0, 2.1) with id 1.
const schedule = store.getEvseSchedule(
1, // connector id
new Date(), // start date
new Date(Date.now() + 14_400_000), // end date
'W', // charging rate unit ("W" or "A")
new Models.DCChargingSession(400), // model used for unit conversions
);// Get charging limits for connector (OCPP 1.6) or evse (OCPP 2.0, 2.1) with
// id 1 at the given date.
const limits = store.getEvseLimitsAtDate(
1, // connector id
new Date(), // reference date
'W', // charging rate unit ("W" or "A")
new Models.DCChargingSession(400), // model used for unit conversions
);
```### JSON Schema(s)
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;
/* ... */
```## Building and testing
See [BUILD.md][b1] file.
[b1]: ./BUILD.md
## License
MIT. See [LICENSE][l1] file.
[l1]: ./LICENSE