Convert sendStartTransaction 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 sendStopTransaction(
64 transactionId: number,
65 meterStop: number,
66 idTag?: string,
67 reason: OCPP16StopTransactionReason = OCPP16StopTransactionReason.NONE
68 ): Promise<OCPP16StopTransactionResponse> {
69 let connectorId: number;
70 for (const id of this.chargingStation.connectors.keys()) {
71 if (id > 0 && this.chargingStation.getConnectorStatus(id)?.transactionId === transactionId) {
72 connectorId = id;
73 break;
74 }
75 }
76 const transactionEndMeterValue = OCPP16ServiceUtils.buildTransactionEndMeterValue(
77 this.chargingStation,
78 connectorId,
79 meterStop
80 );
81 // FIXME: should be a callback, each OCPP commands implementation must do only one job
82 this.chargingStation.getBeginEndMeterValues() &&
83 this.chargingStation.getOcppStrictCompliance() &&
84 !this.chargingStation.getOutOfOrderEndMeterValues() &&
85 (await this.sendTransactionEndMeterValues(
86 connectorId,
87 transactionId,
88 transactionEndMeterValue
89 ));
90 const payload: StopTransactionRequest = {
91 transactionId,
92 ...(!Utils.isUndefined(idTag) && { idTag }),
93 meterStop,
94 timestamp: new Date().toISOString(),
95 ...(reason && { reason }),
96 ...(this.chargingStation.getTransactionDataMeterValues() && {
97 transactionData: OCPP16ServiceUtils.buildTransactionDataMeterValues(
98 this.chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue,
99 transactionEndMeterValue
100 ),
101 }),
102 };
103 return (await this.sendMessage(
104 Utils.generateUUID(),
105 payload,
106 OCPP16RequestCommand.STOP_TRANSACTION
107 )) as OCPP16StartTransactionResponse;
108 }
109
110 public async sendMeterValues(
111 connectorId: number,
112 transactionId: number,
113 interval: number
114 ): Promise<void> {
115 const meterValue: OCPP16MeterValue = OCPP16ServiceUtils.buildMeterValue(
116 this.chargingStation,
117 connectorId,
118 transactionId,
119 interval
120 );
121 const payload: MeterValuesRequest = {
122 connectorId,
123 transactionId,
124 meterValue: [meterValue],
125 };
126 await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.METER_VALUES);
127 }
128
129 public async sendTransactionBeginMeterValues(
130 connectorId: number,
131 transactionId: number,
132 beginMeterValue: OCPP16MeterValue
133 ): Promise<void> {
134 const payload: MeterValuesRequest = {
135 connectorId,
136 transactionId,
137 meterValue: [beginMeterValue],
138 };
139 await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.METER_VALUES);
140 }
141
142 public async sendTransactionEndMeterValues(
143 connectorId: number,
144 transactionId: number,
145 endMeterValue: OCPP16MeterValue
146 ): Promise<void> {
147 const payload: MeterValuesRequest = {
148 connectorId,
149 transactionId,
150 meterValue: [endMeterValue],
151 };
152 await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.METER_VALUES);
153 }
154
155 public async sendDiagnosticsStatusNotification(
156 diagnosticsStatus: OCPP16DiagnosticsStatus
157 ): Promise<void> {
158 const payload: DiagnosticsStatusNotificationRequest = {
159 status: diagnosticsStatus,
160 };
161 await this.sendMessage(
162 Utils.generateUUID(),
163 payload,
164 OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION
165 );
166 }
167
168 private buildCommandPayload(
169 commandName: OCPP16RequestCommand,
170 commandParams?: JsonType
171 ): JsonType {
172 switch (commandName) {
173 case OCPP16RequestCommand.AUTHORIZE:
174 return {
175 ...(!Utils.isUndefined(commandParams?.idTag)
176 ? { idTag: commandParams.idTag }
177 : { idTag: Constants.DEFAULT_IDTAG }),
178 } as AuthorizeRequest;
179 case OCPP16RequestCommand.BOOT_NOTIFICATION:
180 return {
181 chargePointModel: commandParams?.chargePointModel,
182 chargePointVendor: commandParams?.chargePointVendor,
183 ...(!Utils.isUndefined(commandParams?.chargeBoxSerialNumber) && {
184 chargeBoxSerialNumber: commandParams.chargeBoxSerialNumber,
185 }),
186 ...(!Utils.isUndefined(commandParams?.chargePointSerialNumber) && {
187 chargePointSerialNumber: commandParams.chargePointSerialNumber,
188 }),
189 ...(!Utils.isUndefined(commandParams?.firmwareVersion) && {
190 firmwareVersion: commandParams.firmwareVersion,
191 }),
192 ...(!Utils.isUndefined(commandParams?.iccid) && { iccid: commandParams.iccid }),
193 ...(!Utils.isUndefined(commandParams?.imsi) && { imsi: commandParams.imsi }),
194 ...(!Utils.isUndefined(commandParams?.meterSerialNumber) && {
195 meterSerialNumber: commandParams.meterSerialNumber,
196 }),
197 ...(!Utils.isUndefined(commandParams?.meterType) && {
198 meterType: commandParams.meterType,
199 }),
200 } as OCPP16BootNotificationRequest;
201 case OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION:
202 return {
203 status: commandParams?.diagnosticsStatus,
204 } as DiagnosticsStatusNotificationRequest;
205 case OCPP16RequestCommand.HEARTBEAT:
206 return {} as HeartbeatRequest;
207 case OCPP16RequestCommand.METER_VALUES:
208 return {
209 connectorId: commandParams?.connectorId,
210 transactionId: commandParams?.transactionId,
211 meterValue: Array.isArray(commandParams?.meterValues)
212 ? commandParams?.meterValues
213 : [commandParams?.meterValue],
214 } as MeterValuesRequest;
215 case OCPP16RequestCommand.STATUS_NOTIFICATION:
216 return {
217 connectorId: commandParams?.connectorId,
218 status: commandParams?.status,
219 errorCode: commandParams?.errorCode,
220 } as StatusNotificationRequest;
221 case OCPP16RequestCommand.START_TRANSACTION:
222 return {
223 connectorId: commandParams?.connectorId,
224 ...(!Utils.isUndefined(commandParams?.idTag)
225 ? { idTag: commandParams?.idTag }
226 : { idTag: Constants.DEFAULT_IDTAG }),
227 meterStart: this.chargingStation.getEnergyActiveImportRegisterByConnectorId(
228 commandParams?.connectorId as number
229 ),
230 timestamp: new Date().toISOString(),
231 } as StartTransactionRequest;
232 case OCPP16RequestCommand.STOP_TRANSACTION:
233 return {
234 transactionId: commandParams?.transactionId,
235 ...(!Utils.isUndefined(commandParams?.idTag) && { idTag: commandParams.idTag }),
236 meterStop: commandParams?.meterStop,
237 timestamp: new Date().toISOString(),
238 ...(commandParams?.reason && { reason: commandParams.reason }),
239 ...(this.chargingStation.getTransactionDataMeterValues() && {
240 transactionData: OCPP16ServiceUtils.buildTransactionDataMeterValues(
241 this.chargingStation.getConnectorStatus(commandParams?.connectorId as number)
242 .transactionBeginMeterValue,
243 OCPP16ServiceUtils.buildTransactionEndMeterValue(
244 this.chargingStation,
245 commandParams?.connectorId as number,
246 commandParams?.meterStop as number
247 )
248 ),
249 }),
250 } as StopTransactionRequest;
251 default:
252 throw new OCPPError(
253 ErrorType.NOT_SUPPORTED,
254 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
255 `${moduleName}.buildCommandPayload: Unsupported OCPP command: ${commandName}`,
256 commandName,
257 { commandName }
258 );
259 }
260 }
261 }