18c73918fb9111851dd1fa43174750fe5265a475
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16IncomingRequestService.ts
1 // Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
2
3 import { ChangeAvailabilityRequest, ChangeConfigurationRequest, ClearChargingProfileRequest, GetConfigurationRequest, GetDiagnosticsRequest, MessageTrigger, OCPP16AvailabilityType, OCPP16IncomingRequestCommand, OCPP16TriggerMessageRequest, RemoteStartTransactionRequest, RemoteStopTransactionRequest, ResetRequest, SetChargingProfileRequest, UnlockConnectorRequest } from '../../../types/ocpp/1.6/Requests';
4 import { ChangeAvailabilityResponse, ChangeConfigurationResponse, ClearChargingProfileResponse, GetConfigurationResponse, GetDiagnosticsResponse, OCPP16TriggerMessageResponse, SetChargingProfileResponse, UnlockConnectorResponse } from '../../../types/ocpp/1.6/Responses';
5 import { ChargingProfilePurposeType, OCPP16ChargingProfile } from '../../../types/ocpp/1.6/ChargingProfile';
6 import { Client, FTPResponse } from 'basic-ftp';
7 import { IncomingRequestCommand, RequestCommand } from '../../../types/ocpp/Requests';
8 import { OCPP16AuthorizationStatus, OCPP16StopTransactionReason } from '../../../types/ocpp/1.6/Transaction';
9
10 import Constants from '../../../utils/Constants';
11 import { DefaultResponse } from '../../../types/ocpp/Responses';
12 import { ErrorType } from '../../../types/ocpp/ErrorType';
13 import { MessageType } from '../../../types/ocpp/MessageType';
14 import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus';
15 import { OCPP16DiagnosticsStatus } from '../../../types/ocpp/1.6/DiagnosticsStatus';
16 import { OCPP16StandardParametersKey } from '../../../types/ocpp/1.6/Configuration';
17 import { OCPPConfigurationKey } from '../../../types/ocpp/Configuration';
18 import OCPPError from '../OCPPError';
19 import OCPPIncomingRequestService from '../OCPPIncomingRequestService';
20 import { URL } from 'url';
21 import Utils from '../../../utils/Utils';
22 import fs from 'fs';
23 import logger from '../../../utils/Logger';
24 import path from 'path';
25 import tar from 'tar';
26
27 export default class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
28 public async handleRequest(messageId: string, commandName: OCPP16IncomingRequestCommand, commandPayload: Record<string, unknown>): Promise<void> {
29 let response;
30 const methodName = `handleRequest${commandName}`;
31 // Call
32 if (typeof this[methodName] === 'function') {
33 try {
34 // Call the method to build the response
35 response = await this[methodName](commandPayload);
36 } catch (error) {
37 // Log
38 logger.error(this.chargingStation.logPrefix() + ' Handle request error: %j', error);
39 throw error;
40 }
41 } else {
42 // Throw exception
43 throw new OCPPError(ErrorType.NOT_IMPLEMENTED, `${commandName} is not implemented to handle payload ${JSON.stringify(commandPayload, null, 2)}`, commandName);
44 }
45 // Send the built response
46 await this.chargingStation.ocppRequestService.sendMessage(messageId, response, MessageType.CALL_RESULT_MESSAGE, commandName);
47 }
48
49 // Simulate charging station restart
50 private handleRequestReset(commandPayload: ResetRequest): DefaultResponse {
51 // eslint-disable-next-line @typescript-eslint/no-misused-promises
52 setImmediate(async (): Promise<void> => {
53 await this.chargingStation.stop(commandPayload.type + 'Reset' as OCPP16StopTransactionReason);
54 await Utils.sleep(this.chargingStation.stationInfo.resetTime);
55 this.chargingStation.start();
56 });
57 logger.info(`${this.chargingStation.logPrefix()} ${commandPayload.type} reset command received, simulating it. The station will be back online in ${Utils.formatDurationMilliSeconds(this.chargingStation.stationInfo.resetTime)}`);
58 return Constants.OCPP_RESPONSE_ACCEPTED;
59 }
60
61 private handleRequestClearCache(): DefaultResponse {
62 return Constants.OCPP_RESPONSE_ACCEPTED;
63 }
64
65 private async handleRequestUnlockConnector(commandPayload: UnlockConnectorRequest): Promise<UnlockConnectorResponse> {
66 const connectorId = commandPayload.connectorId;
67 if (connectorId === 0) {
68 logger.error(this.chargingStation.logPrefix() + ' Trying to unlock connector ' + connectorId.toString());
69 return Constants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED;
70 }
71 if (this.chargingStation.getConnector(connectorId)?.transactionStarted) {
72 const transactionId = this.chargingStation.getConnector(connectorId).transactionId;
73 const stopResponse = await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId,
74 this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId),
75 this.chargingStation.getTransactionIdTag(transactionId),
76 OCPP16StopTransactionReason.UNLOCK_COMMAND);
77 if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
78 return Constants.OCPP_RESPONSE_UNLOCKED;
79 }
80 return Constants.OCPP_RESPONSE_UNLOCK_FAILED;
81 }
82 await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.AVAILABLE);
83 this.chargingStation.getConnector(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
84 return Constants.OCPP_RESPONSE_UNLOCKED;
85 }
86
87 private handleRequestGetConfiguration(commandPayload: GetConfigurationRequest): GetConfigurationResponse {
88 const configurationKey: OCPPConfigurationKey[] = [];
89 const unknownKey: string[] = [];
90 if (Utils.isEmptyArray(commandPayload.key)) {
91 for (const configuration of this.chargingStation.configuration.configurationKey) {
92 if (Utils.isUndefined(configuration.visible)) {
93 configuration.visible = true;
94 }
95 if (!configuration.visible) {
96 continue;
97 }
98 configurationKey.push({
99 key: configuration.key,
100 readonly: configuration.readonly,
101 value: configuration.value,
102 });
103 }
104 } else {
105 for (const key of commandPayload.key) {
106 const keyFound = this.chargingStation.getConfigurationKey(key);
107 if (keyFound) {
108 if (Utils.isUndefined(keyFound.visible)) {
109 keyFound.visible = true;
110 }
111 if (!keyFound.visible) {
112 continue;
113 }
114 configurationKey.push({
115 key: keyFound.key,
116 readonly: keyFound.readonly,
117 value: keyFound.value,
118 });
119 } else {
120 unknownKey.push(key);
121 }
122 }
123 }
124 return {
125 configurationKey,
126 unknownKey,
127 };
128 }
129
130 private handleRequestChangeConfiguration(commandPayload: ChangeConfigurationRequest): ChangeConfigurationResponse {
131 // JSON request fields type sanity check
132 if (!Utils.isString(commandPayload.key)) {
133 logger.error(`${this.chargingStation.logPrefix()} ${RequestCommand.CHANGE_CONFIGURATION} request key field is not a string:`, commandPayload);
134 }
135 if (!Utils.isString(commandPayload.value)) {
136 logger.error(`${this.chargingStation.logPrefix()} ${RequestCommand.CHANGE_CONFIGURATION} request value field is not a string:`, commandPayload);
137 }
138 const keyToChange = this.chargingStation.getConfigurationKey(commandPayload.key, true);
139 if (!keyToChange) {
140 return Constants.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED;
141 } else if (keyToChange && keyToChange.readonly) {
142 return Constants.OCPP_CONFIGURATION_RESPONSE_REJECTED;
143 } else if (keyToChange && !keyToChange.readonly) {
144 const keyIndex = this.chargingStation.configuration.configurationKey.indexOf(keyToChange);
145 let valueChanged = false;
146 if (this.chargingStation.configuration.configurationKey[keyIndex].value !== commandPayload.value) {
147 this.chargingStation.configuration.configurationKey[keyIndex].value = commandPayload.value;
148 valueChanged = true;
149 }
150 let triggerHeartbeatRestart = false;
151 if (keyToChange.key === OCPP16StandardParametersKey.HeartBeatInterval && valueChanged) {
152 this.chargingStation.setConfigurationKeyValue(OCPP16StandardParametersKey.HeartbeatInterval, commandPayload.value);
153 triggerHeartbeatRestart = true;
154 }
155 if (keyToChange.key === OCPP16StandardParametersKey.HeartbeatInterval && valueChanged) {
156 this.chargingStation.setConfigurationKeyValue(OCPP16StandardParametersKey.HeartBeatInterval, commandPayload.value);
157 triggerHeartbeatRestart = true;
158 }
159 if (triggerHeartbeatRestart) {
160 this.chargingStation.restartHeartbeat();
161 }
162 if (keyToChange.key === OCPP16StandardParametersKey.WebSocketPingInterval && valueChanged) {
163 this.chargingStation.restartWebSocketPing();
164 }
165 if (keyToChange.reboot) {
166 return Constants.OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED;
167 }
168 return Constants.OCPP_CONFIGURATION_RESPONSE_ACCEPTED;
169 }
170 }
171
172 private handleRequestSetChargingProfile(commandPayload: SetChargingProfileRequest): SetChargingProfileResponse {
173 if (!this.chargingStation.getConnector(commandPayload.connectorId)) {
174 logger.error(`${this.chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector Id ${commandPayload.connectorId}`);
175 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
176 }
177 if (commandPayload.csChargingProfiles.chargingProfilePurpose === ChargingProfilePurposeType.CHARGE_POINT_MAX_PROFILE && commandPayload.connectorId !== 0) {
178 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
179 }
180 if (commandPayload.csChargingProfiles.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE && (commandPayload.connectorId === 0 || !this.chargingStation.getConnector(commandPayload.connectorId)?.transactionStarted)) {
181 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
182 }
183 this.chargingStation.setChargingProfile(commandPayload.connectorId, commandPayload.csChargingProfiles);
184 logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) set, dump their stack: %j`, this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles);
185 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED;
186 }
187
188 private handleRequestClearChargingProfile(commandPayload: ClearChargingProfileRequest): ClearChargingProfileResponse {
189 if (!this.chargingStation.getConnector(commandPayload.connectorId)) {
190 logger.error(`${this.chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector Id ${commandPayload.connectorId}`);
191 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
192 }
193 if (commandPayload.connectorId && !Utils.isEmptyArray(this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles)) {
194 this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles = [];
195 logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`, this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles);
196 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED;
197 }
198 if (!commandPayload.connectorId) {
199 let clearedCP = false;
200 for (const connector in this.chargingStation.connectors) {
201 if (!Utils.isEmptyArray(this.chargingStation.getConnector(Utils.convertToInt(connector)).chargingProfiles)) {
202 this.chargingStation.getConnector(Utils.convertToInt(connector)).chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => {
203 let clearCurrentCP = false;
204 if (chargingProfile.chargingProfileId === commandPayload.id) {
205 clearCurrentCP = true;
206 }
207 if (!commandPayload.chargingProfilePurpose && chargingProfile.stackLevel === commandPayload.stackLevel) {
208 clearCurrentCP = true;
209 }
210 if (!chargingProfile.stackLevel && chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose) {
211 clearCurrentCP = true;
212 }
213 if (chargingProfile.stackLevel === commandPayload.stackLevel && chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose) {
214 clearCurrentCP = true;
215 }
216 if (clearCurrentCP) {
217 this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles[index] = {} as OCPP16ChargingProfile;
218 logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`, this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles);
219 clearedCP = true;
220 }
221 });
222 }
223 }
224 if (clearedCP) {
225 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED;
226 }
227 }
228 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
229 }
230
231 private async handleRequestChangeAvailability(commandPayload: ChangeAvailabilityRequest): Promise<ChangeAvailabilityResponse> {
232 const connectorId: number = commandPayload.connectorId;
233 if (!this.chargingStation.getConnector(connectorId)) {
234 logger.error(`${this.chargingStation.logPrefix()} Trying to change the availability of a non existing connector Id ${connectorId.toString()}`);
235 return Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED;
236 }
237 const chargePointStatus: OCPP16ChargePointStatus = commandPayload.type === OCPP16AvailabilityType.OPERATIVE ? OCPP16ChargePointStatus.AVAILABLE : OCPP16ChargePointStatus.UNAVAILABLE;
238 if (connectorId === 0) {
239 let response: ChangeAvailabilityResponse = Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED;
240 for (const connector in this.chargingStation.connectors) {
241 if (this.chargingStation.getConnector(Utils.convertToInt(connector))?.transactionStarted) {
242 response = Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
243 }
244 this.chargingStation.getConnector(Utils.convertToInt(connector)).availability = commandPayload.type;
245 if (response === Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) {
246 await this.chargingStation.ocppRequestService.sendStatusNotification(Utils.convertToInt(connector), chargePointStatus);
247 this.chargingStation.getConnector(Utils.convertToInt(connector)).status = chargePointStatus;
248 }
249 }
250 return response;
251 } else if (connectorId > 0 && (this.chargingStation.getConnector(0).availability === OCPP16AvailabilityType.OPERATIVE || (this.chargingStation.getConnector(0).availability === OCPP16AvailabilityType.INOPERATIVE && commandPayload.type === OCPP16AvailabilityType.INOPERATIVE))) {
252 if (this.chargingStation.getConnector(connectorId)?.transactionStarted) {
253 this.chargingStation.getConnector(connectorId).availability = commandPayload.type;
254 return Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
255 }
256 this.chargingStation.getConnector(connectorId).availability = commandPayload.type;
257 await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, chargePointStatus);
258 this.chargingStation.getConnector(connectorId).status = chargePointStatus;
259 return Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED;
260 }
261 return Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED;
262 }
263
264 private async handleRequestRemoteStartTransaction(commandPayload: RemoteStartTransactionRequest): Promise<DefaultResponse> {
265 const transactionConnectorId: number = commandPayload.connectorId;
266 if (transactionConnectorId) {
267 await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorId, OCPP16ChargePointStatus.PREPARING);
268 this.chargingStation.getConnector(transactionConnectorId).status = OCPP16ChargePointStatus.PREPARING;
269 if (this.chargingStation.isChargingStationAvailable() && this.chargingStation.isConnectorAvailable(transactionConnectorId)) {
270 // Check if authorized
271 if (this.chargingStation.getAuthorizeRemoteTxRequests()) {
272 let authorized = false;
273 if (this.chargingStation.getLocalAuthListEnabled() && this.chargingStation.hasAuthorizedTags()
274 && this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)) {
275 authorized = true;
276 }
277 if (!authorized || (authorized && this.chargingStation.getMayAuthorizeAtRemoteStart())) {
278 const authorizeResponse = await this.chargingStation.ocppRequestService.sendAuthorize(transactionConnectorId, commandPayload.idTag);
279 if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
280 authorized = true;
281 } else {
282 authorized = false;
283 }
284 }
285 if (authorized) {
286 // Authorization successful, start transaction
287 if (this.setRemoteStartTransactionChargingProfile(transactionConnectorId, commandPayload.chargingProfile)) {
288 if ((await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorId, commandPayload.idTag)).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
289 logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + commandPayload.idTag);
290 return Constants.OCPP_RESPONSE_ACCEPTED;
291 }
292 return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
293 }
294 return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
295 }
296 return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
297 }
298 // No authorization check required, start transaction
299 if (this.setRemoteStartTransactionChargingProfile(transactionConnectorId, commandPayload.chargingProfile)) {
300 if ((await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorId, commandPayload.idTag)).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
301 logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + commandPayload.idTag);
302 return Constants.OCPP_RESPONSE_ACCEPTED;
303 }
304 return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
305 }
306 return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
307 }
308 return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
309 }
310 return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
311 }
312
313 private async notifyRemoteStartTransactionRejected(connectorId: number, idTag: string): Promise<DefaultResponse> {
314 if (this.chargingStation.getConnector(connectorId).status !== OCPP16ChargePointStatus.AVAILABLE) {
315 await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.AVAILABLE);
316 this.chargingStation.getConnector(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
317 }
318 logger.warn(this.chargingStation.logPrefix() + ' Remote starting transaction REJECTED on connector Id ' + connectorId.toString() + ', idTag ' + idTag + ', availability ' + this.chargingStation.getConnector(connectorId).availability + ', status ' + this.chargingStation.getConnector(connectorId).status);
319 return Constants.OCPP_RESPONSE_REJECTED;
320 }
321
322 private setRemoteStartTransactionChargingProfile(connectorId: number, cp: OCPP16ChargingProfile): boolean {
323 if (cp && cp.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE) {
324 this.chargingStation.setChargingProfile(connectorId, cp);
325 logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) set at remote start transaction, dump their stack: %j`, this.chargingStation.getConnector(connectorId).chargingProfiles);
326 return true;
327 } else if (cp && cp.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE) {
328 logger.warn(`${this.chargingStation.logPrefix()} Not allowed to set ${cp.chargingProfilePurpose} charging profile(s) at remote start transaction`);
329 return false;
330 } else if (!cp) {
331 return true;
332 }
333 }
334
335 private async handleRequestRemoteStopTransaction(commandPayload: RemoteStopTransactionRequest): Promise<DefaultResponse> {
336 const transactionId = commandPayload.transactionId;
337 for (const connector in this.chargingStation.connectors) {
338 if (Utils.convertToInt(connector) > 0 && this.chargingStation.getConnector(Utils.convertToInt(connector))?.transactionId === transactionId) {
339 await this.chargingStation.ocppRequestService.sendStatusNotification(Utils.convertToInt(connector), OCPP16ChargePointStatus.FINISHING);
340 this.chargingStation.getConnector(Utils.convertToInt(connector)).status = OCPP16ChargePointStatus.FINISHING;
341 await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId),
342 this.chargingStation.getTransactionIdTag(transactionId));
343 return Constants.OCPP_RESPONSE_ACCEPTED;
344 }
345 }
346 logger.info(this.chargingStation.logPrefix() + ' Trying to remote stop a non existing transaction ' + transactionId.toString());
347 return Constants.OCPP_RESPONSE_REJECTED;
348 }
349
350 private async handleRequestGetDiagnostics(commandPayload: GetDiagnosticsRequest): Promise<GetDiagnosticsResponse> {
351 logger.debug(this.chargingStation.logPrefix() + ' ' + IncomingRequestCommand.GET_DIAGNOSTICS + ' request received: %j', commandPayload);
352 const uri = new URL(commandPayload.location);
353 if (uri.protocol.startsWith('ftp:')) {
354 let ftpClient: Client;
355 try {
356 const logFiles = fs.readdirSync(path.resolve(__dirname, '../../../../')).filter((file) => file.endsWith('.log')).map((file) => path.join('./', file));
357 const diagnosticsArchive = this.chargingStation.stationInfo.chargingStationId + '_logs.tar.gz';
358 tar.create({ gzip: true }, logFiles).pipe(fs.createWriteStream(diagnosticsArchive));
359 ftpClient = new Client();
360 const accessResponse = await ftpClient.access({
361 host: uri.host,
362 ...(uri.port !== '') && { port: Utils.convertToInt(uri.port) },
363 ...(uri.username !== '') && { user: uri.username },
364 ...(uri.password !== '') && { password: uri.password },
365 });
366 let uploadResponse: FTPResponse;
367 if (accessResponse.code === 220) {
368 // eslint-disable-next-line @typescript-eslint/no-misused-promises
369 ftpClient.trackProgress(async (info) => {
370 logger.info(`${this.chargingStation.logPrefix()} ${info.bytes / 1024} bytes transferred from diagnostics archive ${info.name}`);
371 await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(OCPP16DiagnosticsStatus.Uploading);
372 });
373 uploadResponse = await ftpClient.uploadFrom(path.join(path.resolve(__dirname, '../../../../'), diagnosticsArchive), uri.pathname + diagnosticsArchive);
374 if (uploadResponse.code === 226) {
375 await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(OCPP16DiagnosticsStatus.Uploaded);
376 if (ftpClient) {
377 ftpClient.close();
378 }
379 return { fileName: diagnosticsArchive };
380 }
381 throw new OCPPError(ErrorType.GENERIC_ERROR, `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${uploadResponse?.code && '|' + uploadResponse?.code.toString()}`, IncomingRequestCommand.GET_DIAGNOSTICS);
382 }
383 throw new OCPPError(ErrorType.GENERIC_ERROR, `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${uploadResponse?.code && '|' + uploadResponse?.code.toString()}`, IncomingRequestCommand.GET_DIAGNOSTICS);
384 } catch (error) {
385 await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(OCPP16DiagnosticsStatus.UploadFailed);
386 if (ftpClient) {
387 ftpClient.close();
388 }
389 return this.handleIncomingRequestError(IncomingRequestCommand.GET_DIAGNOSTICS, error, Constants.OCPP_RESPONSE_EMPTY);
390 }
391 } else {
392 logger.error(`${this.chargingStation.logPrefix()} Unsupported protocol ${uri.protocol} to transfer the diagnostic logs archive`);
393 await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(OCPP16DiagnosticsStatus.UploadFailed);
394 return Constants.OCPP_RESPONSE_EMPTY;
395 }
396 }
397
398 private handleRequestTriggerMessage(commandPayload: OCPP16TriggerMessageRequest): OCPP16TriggerMessageResponse {
399 try {
400 switch (commandPayload.requestedMessage) {
401 case MessageTrigger.BootNotification:
402 setTimeout(() => {
403 this.chargingStation.ocppRequestService.sendBootNotification(this.chargingStation.getBootNotificationRequest().chargePointModel,
404 this.chargingStation.getBootNotificationRequest().chargePointVendor, this.chargingStation.getBootNotificationRequest().chargeBoxSerialNumber,
405 this.chargingStation.getBootNotificationRequest().firmwareVersion).catch(() => { /* This is intentional */ });
406 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
407 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
408 case MessageTrigger.Heartbeat:
409 setTimeout(() => {
410 this.chargingStation.ocppRequestService.sendHeartbeat().catch(() => { /* This is intentional */ });
411 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
412 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
413 default:
414 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED;
415 }
416 } catch (error) {
417 return this.handleIncomingRequestError(IncomingRequestCommand.TRIGGER_MESSAGE, error, Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED);
418 }
419 }
420 }