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