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