Initial code cleanups for the future OCPP requests code optimization
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16RequestService.ts
CommitLineData
c8eeb62b
JB
1// Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
2
e7aeea18
JB
3import {
4 AuthorizeRequest,
5 OCPP16AuthorizeResponse,
6 OCPP16StartTransactionResponse,
7 OCPP16StopTransactionReason,
8 OCPP16StopTransactionResponse,
9 StartTransactionRequest,
10 StopTransactionRequest,
11} from '../../../types/ocpp/1.6/Transaction';
e7aeea18
JB
12import {
13 DiagnosticsStatusNotificationRequest,
14 HeartbeatRequest,
15 OCPP16BootNotificationRequest,
16 OCPP16RequestCommand,
17 StatusNotificationRequest,
18} from '../../../types/ocpp/1.6/Requests';
78085c42 19import { MeterValuesRequest, OCPP16MeterValue } from '../../../types/ocpp/1.6/MeterValues';
c0560973 20
73b9adec 21import type ChargingStation from '../../ChargingStation';
c0560973 22import Constants from '../../../utils/Constants';
14763b46 23import { ErrorType } from '../../../types/ocpp/ErrorType';
78085c42 24import { JsonType } from '../../../types/JsonType';
efa43e52 25import { OCPP16BootNotificationResponse } from '../../../types/ocpp/1.6/Responses';
c0560973
JB
26import { OCPP16ChargePointErrorCode } from '../../../types/ocpp/1.6/ChargePointErrorCode';
27import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus';
47e22477 28import { OCPP16DiagnosticsStatus } from '../../../types/ocpp/1.6/DiagnosticsStatus';
6ed92bc1 29import { OCPP16ServiceUtils } from './OCPP16ServiceUtils';
e58068fd 30import OCPPError from '../../../exception/OCPPError';
c0560973 31import OCPPRequestService from '../OCPPRequestService';
73b9adec 32import type OCPPResponseService from '../OCPPResponseService';
caad9d6b 33import { SendParams } from '../../../types/ocpp/Requests';
c0560973 34import Utils from '../../../utils/Utils';
c0560973 35
909dcf2d
JB
36const moduleName = 'OCPP16RequestService';
37
c0560973 38export default class OCPP16RequestService extends OCPPRequestService {
9f2e3130 39 public constructor(chargingStation: ChargingStation, ocppResponseService: OCPPResponseService) {
909dcf2d 40 if (new.target?.name === moduleName) {
06127450 41 throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
9f2e3130
JB
42 }
43 super(chargingStation, ocppResponseService);
44 }
45
caad9d6b 46 public async sendHeartbeat(params?: SendParams): Promise<void> {
5e0c67e8
JB
47 const payload: HeartbeatRequest = {};
48 await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.HEARTBEAT, params);
c0560973
JB
49 }
50
e7aeea18
JB
51 public async sendBootNotification(
52 chargePointModel: string,
53 chargePointVendor: string,
54 chargeBoxSerialNumber?: string,
55 firmwareVersion?: string,
56 chargePointSerialNumber?: string,
57 iccid?: string,
58 imsi?: string,
59 meterSerialNumber?: string,
60 meterType?: string,
61 params?: SendParams
62 ): Promise<OCPP16BootNotificationResponse> {
5e0c67e8
JB
63 const payload: OCPP16BootNotificationRequest = {
64 chargePointModel,
65 chargePointVendor,
e7aeea18
JB
66 ...(!Utils.isUndefined(chargeBoxSerialNumber) && { chargeBoxSerialNumber }),
67 ...(!Utils.isUndefined(chargePointSerialNumber) && { chargePointSerialNumber }),
68 ...(!Utils.isUndefined(firmwareVersion) && { firmwareVersion }),
69 ...(!Utils.isUndefined(iccid) && { iccid }),
70 ...(!Utils.isUndefined(imsi) && { imsi }),
71 ...(!Utils.isUndefined(meterSerialNumber) && { meterSerialNumber }),
72 ...(!Utils.isUndefined(meterType) && { meterType }),
5e0c67e8 73 };
e7aeea18
JB
74 return (await this.sendMessage(
75 Utils.generateUUID(),
76 payload,
77 OCPP16RequestCommand.BOOT_NOTIFICATION,
78 { ...params, skipBufferingOnError: true }
79 )) as OCPP16BootNotificationResponse;
c0560973
JB
80 }
81
e7aeea18
JB
82 public async sendStatusNotification(
83 connectorId: number,
84 status: OCPP16ChargePointStatus,
85 errorCode: OCPP16ChargePointErrorCode = OCPP16ChargePointErrorCode.NO_ERROR
86 ): Promise<void> {
5e0c67e8
JB
87 const payload: StatusNotificationRequest = {
88 connectorId,
89 errorCode,
90 status,
91 };
92 await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.STATUS_NOTIFICATION);
c0560973
JB
93 }
94
e7aeea18
JB
95 public async sendAuthorize(
96 connectorId: number,
97 idTag?: string
98 ): Promise<OCPP16AuthorizeResponse> {
5e0c67e8 99 const payload: AuthorizeRequest = {
e7aeea18 100 ...(!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.DEFAULT_IDTAG }),
5e0c67e8
JB
101 };
102 this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag = idTag;
e7aeea18
JB
103 return (await this.sendMessage(
104 Utils.generateUUID(),
105 payload,
106 OCPP16RequestCommand.AUTHORIZE
107 )) as OCPP16AuthorizeResponse;
c0560973
JB
108 }
109
e7aeea18
JB
110 public async sendStartTransaction(
111 connectorId: number,
112 idTag?: string
113 ): Promise<OCPP16StartTransactionResponse> {
5e0c67e8
JB
114 const payload: StartTransactionRequest = {
115 connectorId,
e7aeea18 116 ...(!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.DEFAULT_IDTAG }),
5e0c67e8
JB
117 meterStart: this.chargingStation.getEnergyActiveImportRegisterByConnectorId(connectorId),
118 timestamp: new Date().toISOString(),
119 };
e7aeea18
JB
120 return (await this.sendMessage(
121 Utils.generateUUID(),
122 payload,
123 OCPP16RequestCommand.START_TRANSACTION
124 )) as OCPP16StartTransactionResponse;
c0560973
JB
125 }
126
e7aeea18
JB
127 public async sendStopTransaction(
128 transactionId: number,
129 meterStop: number,
130 idTag?: string,
131 reason: OCPP16StopTransactionReason = OCPP16StopTransactionReason.NONE
132 ): Promise<OCPP16StopTransactionResponse> {
5e0c67e8
JB
133 let connectorId: number;
134 for (const id of this.chargingStation.connectors.keys()) {
135 if (id > 0 && this.chargingStation.getConnectorStatus(id)?.transactionId === transactionId) {
136 connectorId = id;
137 break;
326f6e38 138 }
c0560973 139 }
e7aeea18
JB
140 const transactionEndMeterValue = OCPP16ServiceUtils.buildTransactionEndMeterValue(
141 this.chargingStation,
142 connectorId,
143 meterStop
144 );
5e0c67e8 145 // FIXME: should be a callback, each OCPP commands implementation must do only one job
e7aeea18
JB
146 this.chargingStation.getBeginEndMeterValues() &&
147 this.chargingStation.getOcppStrictCompliance() &&
148 !this.chargingStation.getOutOfOrderEndMeterValues() &&
149 (await this.sendTransactionEndMeterValues(
150 connectorId,
151 transactionId,
152 transactionEndMeterValue
153 ));
5e0c67e8
JB
154 const payload: StopTransactionRequest = {
155 transactionId,
e7aeea18 156 ...(!Utils.isUndefined(idTag) && { idTag }),
5e0c67e8
JB
157 meterStop,
158 timestamp: new Date().toISOString(),
e7aeea18
JB
159 ...(reason && { reason }),
160 ...(this.chargingStation.getTransactionDataMeterValues() && {
161 transactionData: OCPP16ServiceUtils.buildTransactionDataMeterValues(
162 this.chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue,
163 transactionEndMeterValue
164 ),
165 }),
5e0c67e8 166 };
e7aeea18
JB
167 return (await this.sendMessage(
168 Utils.generateUUID(),
169 payload,
170 OCPP16RequestCommand.STOP_TRANSACTION
171 )) as OCPP16StartTransactionResponse;
c0560973
JB
172 }
173
e7aeea18
JB
174 public async sendMeterValues(
175 connectorId: number,
176 transactionId: number,
78085c42 177 interval: number
e7aeea18 178 ): Promise<void> {
78085c42
JB
179 const meterValue = OCPP16ServiceUtils.buildMeterValue(
180 this.chargingStation,
e7aeea18 181 connectorId,
78085c42
JB
182 transactionId,
183 interval
e7aeea18 184 );
5e0c67e8
JB
185 const payload: MeterValuesRequest = {
186 connectorId,
187 transactionId,
188 meterValue: [meterValue],
189 };
190 await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.METER_VALUES);
c0560973
JB
191 }
192
e7aeea18
JB
193 public async sendTransactionBeginMeterValues(
194 connectorId: number,
195 transactionId: number,
196 beginMeterValue: OCPP16MeterValue
197 ): Promise<void> {
5e0c67e8
JB
198 const payload: MeterValuesRequest = {
199 connectorId,
200 transactionId,
201 meterValue: [beginMeterValue],
202 };
203 await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.METER_VALUES);
326f6e38
JB
204 }
205
e7aeea18
JB
206 public async sendTransactionEndMeterValues(
207 connectorId: number,
208 transactionId: number,
209 endMeterValue: OCPP16MeterValue
210 ): Promise<void> {
5e0c67e8
JB
211 const payload: MeterValuesRequest = {
212 connectorId,
213 transactionId,
214 meterValue: [endMeterValue],
215 };
216 await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.METER_VALUES);
326f6e38 217 }
6ed92bc1 218
e7aeea18
JB
219 public async sendDiagnosticsStatusNotification(
220 diagnosticsStatus: OCPP16DiagnosticsStatus
221 ): Promise<void> {
5e0c67e8 222 const payload: DiagnosticsStatusNotificationRequest = {
e7aeea18 223 status: diagnosticsStatus,
5e0c67e8 224 };
e7aeea18
JB
225 await this.sendMessage(
226 Utils.generateUUID(),
227 payload,
228 OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION
229 );
6ed92bc1 230 }
78085c42
JB
231
232 private buildCommandPayload(
233 commandName: OCPP16RequestCommand,
234 commandParams: JsonType
235 ): JsonType {
236 switch (commandName) {
237 case OCPP16RequestCommand.AUTHORIZE:
238 return {
239 ...(!Utils.isUndefined(commandParams?.idTag)
240 ? { idTag: commandParams.idTag }
241 : { idTag: Constants.DEFAULT_IDTAG }),
242 } as AuthorizeRequest;
243 case OCPP16RequestCommand.BOOT_NOTIFICATION:
244 return {
245 chargePointModel: commandParams?.chargePointModel,
246 chargePointVendor: commandParams?.chargePointVendor,
247 ...(!Utils.isUndefined(commandParams?.chargeBoxSerialNumber) && {
248 chargeBoxSerialNumber: commandParams.chargeBoxSerialNumber,
249 }),
250 ...(!Utils.isUndefined(commandParams?.chargePointSerialNumber) && {
251 chargePointSerialNumber: commandParams.chargePointSerialNumber,
252 }),
253 ...(!Utils.isUndefined(commandParams?.firmwareVersion) && {
254 firmwareVersion: commandParams.firmwareVersion,
255 }),
256 ...(!Utils.isUndefined(commandParams?.iccid) && { iccid: commandParams.iccid }),
257 ...(!Utils.isUndefined(commandParams?.imsi) && { imsi: commandParams.imsi }),
258 ...(!Utils.isUndefined(commandParams?.meterSerialNumber) && {
259 meterSerialNumber: commandParams.meterSerialNumber,
260 }),
261 ...(!Utils.isUndefined(commandParams?.meterType) && {
262 meterType: commandParams.meterType,
263 }),
264 } as OCPP16BootNotificationRequest;
265 case OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION:
266 return {
267 status: commandParams?.diagnosticsStatus,
268 } as DiagnosticsStatusNotificationRequest;
269 case OCPP16RequestCommand.HEARTBEAT:
270 return {} as HeartbeatRequest;
271 case OCPP16RequestCommand.METER_VALUES:
272 return {
273 connectorId: commandParams?.connectorId,
274 transactionId: commandParams?.transactionId,
275 meterValue: Array.isArray(commandParams?.meterValues)
276 ? commandParams?.meterValues
277 : [commandParams?.meterValue],
278 } as MeterValuesRequest;
279 case OCPP16RequestCommand.STATUS_NOTIFICATION:
280 return {
281 connectorId: commandParams?.connectorId,
282 errorCode: commandParams?.errorCode,
283 status: commandParams?.status,
284 } as StatusNotificationRequest;
285 case OCPP16RequestCommand.START_TRANSACTION:
286 return {
287 connectorId: commandParams?.connectorId,
288 ...(!Utils.isUndefined(commandParams?.idTag)
289 ? { idTag: commandParams?.idTag }
290 : { idTag: Constants.DEFAULT_IDTAG }),
291 meterStart: this.chargingStation.getEnergyActiveImportRegisterByConnectorId(
292 commandParams?.connectorId as number
293 ),
294 timestamp: new Date().toISOString(),
295 } as StartTransactionRequest;
296 case OCPP16RequestCommand.STOP_TRANSACTION:
297 return {
298 transactionId: commandParams?.transactionId,
299 ...(!Utils.isUndefined(commandParams?.idTag) && { idTag: commandParams.idTag }),
300 meterStop: commandParams?.meterStop,
301 timestamp: new Date().toISOString(),
302 ...(commandParams?.reason && { reason: commandParams.reason }),
303 ...(this.chargingStation.getTransactionDataMeterValues() && {
304 transactionData: OCPP16ServiceUtils.buildTransactionDataMeterValues(
305 this.chargingStation.getConnectorStatus(commandParams?.connectorId as number)
306 .transactionBeginMeterValue,
307 OCPP16ServiceUtils.buildTransactionEndMeterValue(
308 this.chargingStation,
309 commandParams?.connectorId as number,
310 commandParams?.meterStop as number
311 )
312 ),
313 }),
314 } as StopTransactionRequest;
315 default:
316 throw new OCPPError(
317 ErrorType.NOT_SUPPORTED,
318 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
319 `Unsupported OCPP command: ${commandName}`,
320 commandName,
321 { commandName }
322 );
323 }
324 }
c0560973 325}