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