Commit | Line | Data |
---|---|---|
edd13439 | 1 | // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved. |
c8eeb62b | 2 | |
6c1761d4 | 3 | import type { JSONSchemaType } from 'ajv'; |
b52c969d | 4 | |
4c3c0d59 JB |
5 | import { OCPP16Constants } from './OCPP16Constants'; |
6 | import { OCPP16ServiceUtils } from './OCPP16ServiceUtils'; | |
2896e06d | 7 | import type { ChargingStation } from '../../../charging-station'; |
268a74bb | 8 | import { OCPPError } from '../../../exception'; |
b52c969d | 9 | import { |
268a74bb JB |
10 | ErrorType, |
11 | type JsonObject, | |
12 | type JsonType, | |
13 | type OCPP16AuthorizeRequest, | |
27782dbc JB |
14 | type OCPP16BootNotificationRequest, |
15 | type OCPP16DataTransferRequest, | |
c9a4f9ea | 16 | type OCPP16DiagnosticsStatusNotificationRequest, |
e9a4164c | 17 | type OCPP16FirmwareStatusNotificationRequest, |
27782dbc | 18 | type OCPP16HeartbeatRequest, |
268a74bb | 19 | type OCPP16MeterValuesRequest, |
b52c969d | 20 | OCPP16RequestCommand, |
268a74bb | 21 | type OCPP16StartTransactionRequest, |
27782dbc | 22 | type OCPP16StatusNotificationRequest, |
268a74bb JB |
23 | type OCPP16StopTransactionRequest, |
24 | OCPPVersion, | |
25 | type RequestParams, | |
26 | } from '../../../types'; | |
d193a949 JB |
27 | import type { |
28 | OCPP16CancelReservationRequest, | |
29 | OCPP16ReserveNowRequest, | |
30 | } from '../../../types/ocpp/1.6/Requests'; | |
60a74391 | 31 | import { Constants, Utils } from '../../../utils'; |
4c3c0d59 JB |
32 | import { OCPPRequestService } from '../OCPPRequestService'; |
33 | import type { OCPPResponseService } from '../OCPPResponseService'; | |
c0560973 | 34 | |
909dcf2d JB |
35 | const moduleName = 'OCPP16RequestService'; |
36 | ||
268a74bb | 37 | export class OCPP16RequestService extends OCPPRequestService { |
b3fc3ff5 | 38 | protected jsonSchemas: Map<OCPP16RequestCommand, JSONSchemaType<JsonObject>>; |
b52c969d | 39 | |
08f130a0 | 40 | public constructor(ocppResponseService: OCPPResponseService) { |
b768993d JB |
41 | // if (new.target?.name === moduleName) { |
42 | // throw new TypeError(`Cannot construct ${new.target?.name} instances directly`); | |
43 | // } | |
d270cc87 | 44 | super(OCPPVersion.VERSION_16, ocppResponseService); |
b52c969d JB |
45 | this.jsonSchemas = new Map<OCPP16RequestCommand, JSONSchemaType<JsonObject>>([ |
46 | [ | |
47 | OCPP16RequestCommand.AUTHORIZE, | |
130783a7 | 48 | OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16AuthorizeRequest>( |
51022aa0 | 49 | 'assets/json-schemas/ocpp/1.6/Authorize.json', |
1b271a54 JB |
50 | moduleName, |
51 | 'constructor' | |
e9a4164c | 52 | ), |
b52c969d JB |
53 | ], |
54 | [ | |
55 | OCPP16RequestCommand.BOOT_NOTIFICATION, | |
130783a7 | 56 | OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16BootNotificationRequest>( |
51022aa0 | 57 | 'assets/json-schemas/ocpp/1.6/BootNotification.json', |
1b271a54 JB |
58 | moduleName, |
59 | 'constructor' | |
e9a4164c | 60 | ), |
b52c969d JB |
61 | ], |
62 | [ | |
63 | OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, | |
130783a7 | 64 | OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DiagnosticsStatusNotificationRequest>( |
51022aa0 | 65 | 'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotification.json', |
1b271a54 JB |
66 | moduleName, |
67 | 'constructor' | |
e9a4164c | 68 | ), |
b52c969d JB |
69 | ], |
70 | [ | |
71 | OCPP16RequestCommand.HEARTBEAT, | |
130783a7 | 72 | OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16HeartbeatRequest>( |
51022aa0 | 73 | 'assets/json-schemas/ocpp/1.6/Heartbeat.json', |
1b271a54 JB |
74 | moduleName, |
75 | 'constructor' | |
e9a4164c | 76 | ), |
b52c969d JB |
77 | ], |
78 | [ | |
79 | OCPP16RequestCommand.METER_VALUES, | |
130783a7 | 80 | OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16MeterValuesRequest>( |
51022aa0 | 81 | 'assets/json-schemas/ocpp/1.6/MeterValues.json', |
1b271a54 JB |
82 | moduleName, |
83 | 'constructor' | |
e9a4164c | 84 | ), |
b52c969d JB |
85 | ], |
86 | [ | |
87 | OCPP16RequestCommand.STATUS_NOTIFICATION, | |
130783a7 | 88 | OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StatusNotificationRequest>( |
51022aa0 | 89 | 'assets/json-schemas/ocpp/1.6/StatusNotification.json', |
1b271a54 JB |
90 | moduleName, |
91 | 'constructor' | |
e9a4164c | 92 | ), |
b52c969d JB |
93 | ], |
94 | [ | |
95 | OCPP16RequestCommand.START_TRANSACTION, | |
130783a7 | 96 | OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StartTransactionRequest>( |
51022aa0 | 97 | 'assets/json-schemas/ocpp/1.6/StartTransaction.json', |
1b271a54 JB |
98 | moduleName, |
99 | 'constructor' | |
e9a4164c | 100 | ), |
b52c969d JB |
101 | ], |
102 | [ | |
103 | OCPP16RequestCommand.STOP_TRANSACTION, | |
130783a7 | 104 | OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StopTransactionRequest>( |
51022aa0 | 105 | 'assets/json-schemas/ocpp/1.6/StopTransaction.json', |
1b271a54 JB |
106 | moduleName, |
107 | 'constructor' | |
e9a4164c | 108 | ), |
b52c969d | 109 | ], |
91a7d3ea JB |
110 | [ |
111 | OCPP16RequestCommand.DATA_TRANSFER, | |
130783a7 | 112 | OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferRequest>( |
51022aa0 | 113 | 'assets/json-schemas/ocpp/1.6/DataTransfer.json', |
1b271a54 JB |
114 | moduleName, |
115 | 'constructor' | |
e9a4164c | 116 | ), |
91a7d3ea | 117 | ], |
c9a4f9ea JB |
118 | [ |
119 | OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, | |
130783a7 | 120 | OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16FirmwareStatusNotificationRequest>( |
51022aa0 | 121 | 'assets/json-schemas/ocpp/1.6/FirmwareStatusNotification.json', |
1b271a54 JB |
122 | moduleName, |
123 | 'constructor' | |
e9a4164c | 124 | ), |
c9a4f9ea | 125 | ], |
d193a949 JB |
126 | [ |
127 | OCPP16RequestCommand.RESERVE_NOW, | |
128 | OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ReserveNowRequest>( | |
129 | 'assets/json-schemas/ocpp/1.6/ReserveNow.json', | |
130 | moduleName, | |
131 | 'constructor' | |
132 | ), | |
133 | ], | |
134 | [ | |
135 | OCPP16RequestCommand.CANCEL_RESERVATION, | |
136 | OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16CancelReservationRequest>( | |
137 | 'assets/json-schemas/ocpp/1.6/CancelReservation.json', | |
138 | moduleName, | |
139 | 'constructor' | |
140 | ), | |
141 | ], | |
b52c969d | 142 | ]); |
31f59c6d JB |
143 | this.buildRequestPayload = this.buildRequestPayload.bind(this) as <Request extends JsonType>( |
144 | chargingStation: ChargingStation, | |
145 | commandName: OCPP16RequestCommand, | |
146 | commandParams?: JsonType | |
147 | ) => Request; | |
9f2e3130 JB |
148 | } |
149 | ||
6c1761d4 | 150 | public async requestHandler<RequestType extends JsonType, ResponseType extends JsonType>( |
08f130a0 | 151 | chargingStation: ChargingStation, |
94a464f9 | 152 | commandName: OCPP16RequestCommand, |
5cc4b63b | 153 | commandParams?: JsonType, |
be9b0d50 | 154 | params?: RequestParams |
6c1761d4 | 155 | ): Promise<ResponseType> { |
62340a29 | 156 | // FIXME?: add sanity checks on charging station availability, connector availability, connector status, etc. |
ed6cfcff | 157 | if (OCPP16ServiceUtils.isRequestCommandSupported(chargingStation, commandName) === true) { |
f22266fd | 158 | return (await this.sendMessage( |
08f130a0 | 159 | chargingStation, |
94a464f9 | 160 | Utils.generateUUID(), |
18bf8274 | 161 | this.buildRequestPayload<RequestType>(chargingStation, commandName, commandParams), |
94a464f9 JB |
162 | commandName, |
163 | params | |
617cad0c | 164 | )) as ResponseType; |
94a464f9 | 165 | } |
e909d2a7 | 166 | // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError(). |
94a464f9 JB |
167 | throw new OCPPError( |
168 | ErrorType.NOT_SUPPORTED, | |
6c8f5d90 | 169 | `Unsupported OCPP command '${commandName}'`, |
94a464f9 | 170 | commandName, |
7369e417 | 171 | commandParams |
94a464f9 | 172 | ); |
c0560973 JB |
173 | } |
174 | ||
5cc4b63b | 175 | private buildRequestPayload<Request extends JsonType>( |
08f130a0 | 176 | chargingStation: ChargingStation, |
78085c42 | 177 | commandName: OCPP16RequestCommand, |
5cc4b63b | 178 | commandParams?: JsonType |
f22266fd | 179 | ): Request { |
68c993d5 | 180 | let connectorId: number; |
cf058664 | 181 | let energyActiveImportRegister: number; |
5cc4b63b | 182 | commandParams = commandParams as JsonObject; |
78085c42 | 183 | switch (commandName) { |
78085c42 | 184 | case OCPP16RequestCommand.BOOT_NOTIFICATION: |
78085c42 | 185 | case OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION: |
22e0d48e | 186 | case OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION: |
78085c42 | 187 | case OCPP16RequestCommand.METER_VALUES: |
78085c42 | 188 | case OCPP16RequestCommand.STATUS_NOTIFICATION: |
36c462a4 JB |
189 | case OCPP16RequestCommand.DATA_TRANSFER: |
190 | return commandParams as unknown as Request; | |
191 | case OCPP16RequestCommand.AUTHORIZE: | |
78085c42 | 192 | return { |
36c462a4 JB |
193 | idTag: Constants.DEFAULT_IDTAG, |
194 | ...commandParams, | |
f22266fd | 195 | } as unknown as Request; |
36c462a4 | 196 | case OCPP16RequestCommand.HEARTBEAT: |
d8b1fab1 | 197 | return OCPP16Constants.OCPP_REQUEST_EMPTY as unknown as Request; |
78085c42 JB |
198 | case OCPP16RequestCommand.START_TRANSACTION: |
199 | return { | |
36c462a4 JB |
200 | idTag: Constants.DEFAULT_IDTAG, |
201 | meterStart: chargingStation.getEnergyActiveImportRegisterByConnectorId( | |
18bf8274 JB |
202 | commandParams?.connectorId as number, |
203 | true | |
36c462a4 JB |
204 | ), |
205 | timestamp: new Date(), | |
206 | ...commandParams, | |
f22266fd | 207 | } as unknown as Request; |
78085c42 | 208 | case OCPP16RequestCommand.STOP_TRANSACTION: |
f1e731bd | 209 | chargingStation.getTransactionDataMeterValues() && |
f1e731bd JB |
210 | (connectorId = chargingStation.getConnectorIdByTransactionId( |
211 | commandParams?.transactionId as number | |
212 | )); | |
36c462a4 JB |
213 | energyActiveImportRegister = chargingStation.getEnergyActiveImportRegisterByTransactionId( |
214 | commandParams?.transactionId as number, | |
215 | true | |
216 | ); | |
78085c42 | 217 | return { |
36c462a4 JB |
218 | idTag: chargingStation.getTransactionIdTag(commandParams?.transactionId as number), |
219 | meterStop: energyActiveImportRegister, | |
220 | timestamp: new Date(), | |
221 | ...(chargingStation.getTransactionDataMeterValues() && { | |
222 | transactionData: OCPP16ServiceUtils.buildTransactionDataMeterValues( | |
223 | chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue, | |
224 | OCPP16ServiceUtils.buildTransactionEndMeterValue( | |
225 | chargingStation, | |
226 | connectorId, | |
227 | energyActiveImportRegister | |
228 | ) | |
229 | ), | |
78085c42 | 230 | }), |
36c462a4 | 231 | ...commandParams, |
f22266fd | 232 | } as unknown as Request; |
78085c42 | 233 | default: |
e909d2a7 | 234 | // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError(). |
78085c42 JB |
235 | throw new OCPPError( |
236 | ErrorType.NOT_SUPPORTED, | |
237 | // eslint-disable-next-line @typescript-eslint/restrict-template-expressions | |
6c8f5d90 | 238 | `Unsupported OCPP command '${commandName}'`, |
78085c42 | 239 | commandName, |
7369e417 | 240 | commandParams |
78085c42 JB |
241 | ); |
242 | } | |
243 | } | |
c0560973 | 244 | } |