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