Factor out connectors initialization code
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16IncomingRequestService.ts
CommitLineData
c8eeb62b
JB
1// Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
2
e7aeea18
JB
3import {
4 ChangeAvailabilityRequest,
5 ChangeConfigurationRequest,
6 ClearChargingProfileRequest,
ef6fa3fb 7 DiagnosticsStatusNotificationRequest,
e7aeea18
JB
8 GetConfigurationRequest,
9 GetDiagnosticsRequest,
10 MessageTrigger,
11 OCPP16AvailabilityType,
ef6fa3fb
JB
12 OCPP16BootNotificationRequest,
13 OCPP16HeartbeatRequest,
e7aeea18 14 OCPP16IncomingRequestCommand,
94a464f9 15 OCPP16RequestCommand,
ef6fa3fb 16 OCPP16StatusNotificationRequest,
e7aeea18
JB
17 OCPP16TriggerMessageRequest,
18 RemoteStartTransactionRequest,
19 RemoteStopTransactionRequest,
20 ResetRequest,
21 SetChargingProfileRequest,
22 UnlockConnectorRequest,
23} from '../../../types/ocpp/1.6/Requests';
24import {
25 ChangeAvailabilityResponse,
26 ChangeConfigurationResponse,
27 ClearChargingProfileResponse,
f22266fd 28 DiagnosticsStatusNotificationResponse,
e7aeea18
JB
29 GetConfigurationResponse,
30 GetDiagnosticsResponse,
f22266fd
JB
31 OCPP16BootNotificationResponse,
32 OCPP16HeartbeatResponse,
33 OCPP16StatusNotificationResponse,
e7aeea18
JB
34 OCPP16TriggerMessageResponse,
35 SetChargingProfileResponse,
36 UnlockConnectorResponse,
37} from '../../../types/ocpp/1.6/Responses';
38import {
39 ChargingProfilePurposeType,
40 OCPP16ChargingProfile,
41} from '../../../types/ocpp/1.6/ChargingProfile';
47e22477 42import { Client, FTPResponse } from 'basic-ftp';
e7aeea18
JB
43import {
44 OCPP16AuthorizationStatus,
ef6fa3fb 45 OCPP16AuthorizeRequest,
2e3d65ae 46 OCPP16AuthorizeResponse,
ef6fa3fb 47 OCPP16StartTransactionRequest,
e7454a1f 48 OCPP16StartTransactionResponse,
e7aeea18 49 OCPP16StopTransactionReason,
ef6fa3fb 50 OCPP16StopTransactionRequest,
68c993d5 51 OCPP16StopTransactionResponse,
e7aeea18 52} from '../../../types/ocpp/1.6/Transaction';
ef6fa3fb
JB
53import {
54 OCPP16MeterValuesRequest,
55 OCPP16MeterValuesResponse,
56} from '../../../types/ocpp/1.6/MeterValues';
68cb8b91
JB
57import {
58 OCPP16StandardParametersKey,
59 OCPP16SupportedFeatureProfiles,
60} from '../../../types/ocpp/1.6/Configuration';
c0560973 61
73b9adec 62import type ChargingStation from '../../ChargingStation';
c0560973 63import Constants from '../../../utils/Constants';
9ccca265 64import { DefaultResponse } from '../../../types/ocpp/Responses';
c0560973 65import { ErrorType } from '../../../types/ocpp/ErrorType';
58144adb 66import { IncomingRequestHandler } from '../../../types/ocpp/Requests';
d1888640 67import { JsonType } from '../../../types/JsonType';
93b4a429 68import { OCPP16ChargePointErrorCode } from '../../../types/ocpp/1.6/ChargePointErrorCode';
c0560973 69import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus';
47e22477 70import { OCPP16DiagnosticsStatus } from '../../../types/ocpp/1.6/DiagnosticsStatus';
68c993d5 71import { OCPP16ServiceUtils } from './OCPP16ServiceUtils';
c0560973 72import { OCPPConfigurationKey } from '../../../types/ocpp/Configuration';
e58068fd 73import OCPPError from '../../../exception/OCPPError';
c0560973 74import OCPPIncomingRequestService from '../OCPPIncomingRequestService';
a3868ec4 75import { URL } from 'url';
c0560973 76import Utils from '../../../utils/Utils';
47e22477 77import fs from 'fs';
9f2e3130 78import logger from '../../../utils/Logger';
47e22477
JB
79import path from 'path';
80import tar from 'tar';
c0560973 81
2a115f87 82const moduleName = 'OCPP16IncomingRequestService';
909dcf2d 83
c0560973 84export default class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
58144adb
JB
85 private incomingRequestHandlers: Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>;
86
9f2e3130 87 public constructor(chargingStation: ChargingStation) {
909dcf2d 88 if (new.target?.name === moduleName) {
06127450 89 throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
9f2e3130 90 }
58144adb
JB
91 super(chargingStation);
92 this.incomingRequestHandlers = new Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>([
93 [OCPP16IncomingRequestCommand.RESET, this.handleRequestReset.bind(this)],
94 [OCPP16IncomingRequestCommand.CLEAR_CACHE, this.handleRequestClearCache.bind(this)],
95 [OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR, this.handleRequestUnlockConnector.bind(this)],
e7aeea18
JB
96 [
97 OCPP16IncomingRequestCommand.GET_CONFIGURATION,
98 this.handleRequestGetConfiguration.bind(this),
99 ],
100 [
101 OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
102 this.handleRequestChangeConfiguration.bind(this),
103 ],
104 [
105 OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
106 this.handleRequestSetChargingProfile.bind(this),
107 ],
108 [
109 OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
110 this.handleRequestClearChargingProfile.bind(this),
111 ],
112 [
113 OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
114 this.handleRequestChangeAvailability.bind(this),
115 ],
116 [
117 OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
118 this.handleRequestRemoteStartTransaction.bind(this),
119 ],
120 [
121 OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
122 this.handleRequestRemoteStopTransaction.bind(this),
123 ],
734d790d 124 [OCPP16IncomingRequestCommand.GET_DIAGNOSTICS, this.handleRequestGetDiagnostics.bind(this)],
e7aeea18 125 [OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, this.handleRequestTriggerMessage.bind(this)],
58144adb
JB
126 ]);
127 }
128
f7f98c68 129 public async incomingRequestHandler(
e7aeea18
JB
130 messageId: string,
131 commandName: OCPP16IncomingRequestCommand,
132 commandPayload: JsonType
133 ): Promise<void> {
d1888640 134 let result: JsonType;
e7aeea18
JB
135 if (
136 this.chargingStation.getOcppStrictCompliance() &&
137 this.chargingStation.isInPendingState() &&
138 (commandName === OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION ||
139 commandName === OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION)
140 ) {
141 throw new OCPPError(
142 ErrorType.SECURITY_ERROR,
143 `${commandName} cannot be issued to handle request payload ${JSON.stringify(
144 commandPayload,
145 null,
146 2
147 )} while the charging station is in pending state on the central server`,
148 commandName
149 );
caad9d6b 150 }
e7aeea18
JB
151 if (
152 this.chargingStation.isRegistered() ||
153 (!this.chargingStation.getOcppStrictCompliance() && this.chargingStation.isInUnknownState())
154 ) {
124f3553
JB
155 if (this.incomingRequestHandlers.has(commandName)) {
156 try {
157 // Call the method to build the result
158 result = await this.incomingRequestHandlers.get(commandName)(commandPayload);
159 } catch (error) {
160 // Log
9f2e3130 161 logger.error(this.chargingStation.logPrefix() + ' Handle request error: %j', error);
124f3553
JB
162 throw error;
163 }
164 } else {
165 // Throw exception
e7aeea18
JB
166 throw new OCPPError(
167 ErrorType.NOT_IMPLEMENTED,
168 `${commandName} is not implemented to handle request payload ${JSON.stringify(
169 commandPayload,
170 null,
171 2
172 )}`,
173 commandName
174 );
c0560973
JB
175 }
176 } else {
e7aeea18
JB
177 throw new OCPPError(
178 ErrorType.SECURITY_ERROR,
179 `${commandName} cannot be issued to handle request payload ${JSON.stringify(
180 commandPayload,
181 null,
182 2
183 )} while the charging station is not registered on the central server.`,
184 commandName
185 );
c0560973 186 }
de3dbcf5
JB
187 // Send the built result
188 await this.chargingStation.ocppRequestService.sendResult(messageId, result, commandName);
c0560973
JB
189 }
190
191 // Simulate charging station restart
192 private handleRequestReset(commandPayload: ResetRequest): DefaultResponse {
71623267
JB
193 // eslint-disable-next-line @typescript-eslint/no-misused-promises
194 setImmediate(async (): Promise<void> => {
94ec7e96 195 await this.chargingStation.reset(
e7aeea18
JB
196 (commandPayload.type + 'Reset') as OCPP16StopTransactionReason
197 );
c0560973 198 });
e7aeea18
JB
199 logger.info(
200 `${this.chargingStation.logPrefix()} ${
201 commandPayload.type
202 } reset command received, simulating it. The station will be back online in ${Utils.formatDurationMilliSeconds(
203 this.chargingStation.stationInfo.resetTime
204 )}`
205 );
c0560973
JB
206 return Constants.OCPP_RESPONSE_ACCEPTED;
207 }
208
209 private handleRequestClearCache(): DefaultResponse {
210 return Constants.OCPP_RESPONSE_ACCEPTED;
211 }
212
e7aeea18
JB
213 private async handleRequestUnlockConnector(
214 commandPayload: UnlockConnectorRequest
215 ): Promise<UnlockConnectorResponse> {
c0560973
JB
216 const connectorId = commandPayload.connectorId;
217 if (connectorId === 0) {
e7aeea18
JB
218 logger.error(
219 this.chargingStation.logPrefix() + ' Trying to unlock connector ' + connectorId.toString()
220 );
c0560973
JB
221 return Constants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED;
222 }
734d790d
JB
223 if (this.chargingStation.getConnectorStatus(connectorId)?.transactionStarted) {
224 const transactionId = this.chargingStation.getConnectorStatus(connectorId).transactionId;
68c993d5
JB
225 if (
226 this.chargingStation.getBeginEndMeterValues() &&
227 this.chargingStation.getOcppStrictCompliance() &&
228 !this.chargingStation.getOutOfOrderEndMeterValues()
229 ) {
230 // FIXME: Implement OCPP version agnostic helpers
231 const transactionEndMeterValue = OCPP16ServiceUtils.buildTransactionEndMeterValue(
232 this.chargingStation,
233 connectorId,
234 this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId)
235 );
f7f98c68 236 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
237 OCPP16MeterValuesRequest,
238 OCPP16MeterValuesResponse
239 >(OCPP16RequestCommand.METER_VALUES, {
240 connectorId,
241 transactionId,
242 meterValue: transactionEndMeterValue,
243 });
68c993d5 244 }
f7f98c68 245 const stopResponse = await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
246 OCPP16StopTransactionRequest,
247 OCPP16StopTransactionResponse
248 >(OCPP16RequestCommand.STOP_TRANSACTION, {
249 transactionId,
250 meterStop: this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId),
251 idTag: this.chargingStation.getTransactionIdTag(transactionId),
252 reason: OCPP16StopTransactionReason.UNLOCK_COMMAND,
253 });
c0560973
JB
254 if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
255 return Constants.OCPP_RESPONSE_UNLOCKED;
256 }
257 return Constants.OCPP_RESPONSE_UNLOCK_FAILED;
258 }
f7f98c68 259 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
260 OCPP16StatusNotificationRequest,
261 OCPP16StatusNotificationResponse
262 >(OCPP16RequestCommand.STATUS_NOTIFICATION, {
263 connectorId,
264 status: OCPP16ChargePointStatus.AVAILABLE,
265 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
266 });
734d790d 267 this.chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
c0560973
JB
268 return Constants.OCPP_RESPONSE_UNLOCKED;
269 }
270
e7aeea18
JB
271 private handleRequestGetConfiguration(
272 commandPayload: GetConfigurationRequest
273 ): GetConfigurationResponse {
c0560973
JB
274 const configurationKey: OCPPConfigurationKey[] = [];
275 const unknownKey: string[] = [];
276 if (Utils.isEmptyArray(commandPayload.key)) {
7f7b65ca
JB
277 for (const configuration of this.chargingStation.ocppConfiguration.configurationKey) {
278 if (Utils.isUndefined(configuration.visible)) {
279 configuration.visible = true;
c0560973 280 }
7f7b65ca 281 if (!configuration.visible) {
c0560973
JB
282 continue;
283 }
284 configurationKey.push({
7f7b65ca
JB
285 key: configuration.key,
286 readonly: configuration.readonly,
287 value: configuration.value,
c0560973
JB
288 });
289 }
290 } else {
291 for (const key of commandPayload.key) {
292 const keyFound = this.chargingStation.getConfigurationKey(key);
293 if (keyFound) {
294 if (Utils.isUndefined(keyFound.visible)) {
295 keyFound.visible = true;
296 }
297 if (!keyFound.visible) {
298 continue;
299 }
300 configurationKey.push({
301 key: keyFound.key,
302 readonly: keyFound.readonly,
303 value: keyFound.value,
304 });
305 } else {
306 unknownKey.push(key);
307 }
308 }
309 }
310 return {
311 configurationKey,
312 unknownKey,
313 };
314 }
315
e7aeea18
JB
316 private handleRequestChangeConfiguration(
317 commandPayload: ChangeConfigurationRequest
318 ): ChangeConfigurationResponse {
c0560973
JB
319 // JSON request fields type sanity check
320 if (!Utils.isString(commandPayload.key)) {
e7aeea18
JB
321 logger.error(
322 `${this.chargingStation.logPrefix()} ${
78085c42 323 OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION
e7aeea18
JB
324 } request key field is not a string:`,
325 commandPayload
326 );
c0560973
JB
327 }
328 if (!Utils.isString(commandPayload.value)) {
e7aeea18
JB
329 logger.error(
330 `${this.chargingStation.logPrefix()} ${
78085c42 331 OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION
e7aeea18
JB
332 } request value field is not a string:`,
333 commandPayload
334 );
c0560973
JB
335 }
336 const keyToChange = this.chargingStation.getConfigurationKey(commandPayload.key, true);
337 if (!keyToChange) {
338 return Constants.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED;
339 } else if (keyToChange && keyToChange.readonly) {
340 return Constants.OCPP_CONFIGURATION_RESPONSE_REJECTED;
341 } else if (keyToChange && !keyToChange.readonly) {
c0560973 342 let valueChanged = false;
a95873d8
JB
343 if (keyToChange.value !== commandPayload.value) {
344 this.chargingStation.setConfigurationKeyValue(
345 commandPayload.key,
346 commandPayload.value,
347 true
348 );
c0560973
JB
349 valueChanged = true;
350 }
351 let triggerHeartbeatRestart = false;
352 if (keyToChange.key === OCPP16StandardParametersKey.HeartBeatInterval && valueChanged) {
e7aeea18
JB
353 this.chargingStation.setConfigurationKeyValue(
354 OCPP16StandardParametersKey.HeartbeatInterval,
355 commandPayload.value
356 );
c0560973
JB
357 triggerHeartbeatRestart = true;
358 }
359 if (keyToChange.key === OCPP16StandardParametersKey.HeartbeatInterval && valueChanged) {
e7aeea18
JB
360 this.chargingStation.setConfigurationKeyValue(
361 OCPP16StandardParametersKey.HeartBeatInterval,
362 commandPayload.value
363 );
c0560973
JB
364 triggerHeartbeatRestart = true;
365 }
366 if (triggerHeartbeatRestart) {
367 this.chargingStation.restartHeartbeat();
368 }
369 if (keyToChange.key === OCPP16StandardParametersKey.WebSocketPingInterval && valueChanged) {
370 this.chargingStation.restartWebSocketPing();
371 }
372 if (keyToChange.reboot) {
373 return Constants.OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED;
374 }
375 return Constants.OCPP_CONFIGURATION_RESPONSE_ACCEPTED;
376 }
377 }
378
e7aeea18
JB
379 private handleRequestSetChargingProfile(
380 commandPayload: SetChargingProfileRequest
381 ): SetChargingProfileResponse {
370ae4ee
JB
382 if (
383 !OCPP16ServiceUtils.checkFeatureProfile(
384 this.chargingStation,
385 OCPP16SupportedFeatureProfiles.SmartCharging,
386 OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE
387 )
388 ) {
68cb8b91
JB
389 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_NOT_SUPPORTED;
390 }
734d790d 391 if (!this.chargingStation.getConnectorStatus(commandPayload.connectorId)) {
e7aeea18
JB
392 logger.error(
393 `${this.chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector Id ${
394 commandPayload.connectorId
395 }`
396 );
c0560973
JB
397 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
398 }
e7aeea18
JB
399 if (
400 commandPayload.csChargingProfiles.chargingProfilePurpose ===
401 ChargingProfilePurposeType.CHARGE_POINT_MAX_PROFILE &&
402 commandPayload.connectorId !== 0
403 ) {
c0560973
JB
404 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
405 }
e7aeea18
JB
406 if (
407 commandPayload.csChargingProfiles.chargingProfilePurpose ===
408 ChargingProfilePurposeType.TX_PROFILE &&
409 (commandPayload.connectorId === 0 ||
410 !this.chargingStation.getConnectorStatus(commandPayload.connectorId)?.transactionStarted)
411 ) {
c0560973
JB
412 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
413 }
e7aeea18
JB
414 this.chargingStation.setChargingProfile(
415 commandPayload.connectorId,
416 commandPayload.csChargingProfiles
417 );
418 logger.debug(
ad8537a7
JB
419 `${this.chargingStation.logPrefix()} Charging profile(s) set on connector id ${
420 commandPayload.connectorId
421 }, dump their stack: %j`,
e7aeea18
JB
422 this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles
423 );
c0560973
JB
424 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED;
425 }
426
e7aeea18
JB
427 private handleRequestClearChargingProfile(
428 commandPayload: ClearChargingProfileRequest
429 ): ClearChargingProfileResponse {
370ae4ee
JB
430 if (
431 !OCPP16ServiceUtils.checkFeatureProfile(
432 this.chargingStation,
433 OCPP16SupportedFeatureProfiles.SmartCharging,
434 OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE
435 )
436 ) {
68cb8b91
JB
437 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
438 }
658e2d16
JB
439 const connectorStatus = this.chargingStation.getConnectorStatus(commandPayload.connectorId);
440 if (!connectorStatus) {
e7aeea18
JB
441 logger.error(
442 `${this.chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector Id ${
443 commandPayload.connectorId
444 }`
445 );
c0560973
JB
446 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
447 }
658e2d16
JB
448 if (commandPayload.connectorId && !Utils.isEmptyArray(connectorStatus.chargingProfiles)) {
449 connectorStatus.chargingProfiles = [];
e7aeea18 450 logger.debug(
ad8537a7
JB
451 `${this.chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${
452 commandPayload.connectorId
453 }, dump their stack: %j`,
658e2d16 454 connectorStatus.chargingProfiles
e7aeea18 455 );
c0560973
JB
456 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED;
457 }
458 if (!commandPayload.connectorId) {
459 let clearedCP = false;
734d790d 460 for (const connectorId of this.chargingStation.connectors.keys()) {
e7aeea18
JB
461 if (
462 !Utils.isEmptyArray(this.chargingStation.getConnectorStatus(connectorId).chargingProfiles)
463 ) {
464 this.chargingStation
465 .getConnectorStatus(connectorId)
466 .chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => {
467 let clearCurrentCP = false;
468 if (chargingProfile.chargingProfileId === commandPayload.id) {
469 clearCurrentCP = true;
470 }
471 if (
472 !commandPayload.chargingProfilePurpose &&
473 chargingProfile.stackLevel === commandPayload.stackLevel
474 ) {
475 clearCurrentCP = true;
476 }
477 if (
478 !chargingProfile.stackLevel &&
479 chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose
480 ) {
481 clearCurrentCP = true;
482 }
483 if (
484 chargingProfile.stackLevel === commandPayload.stackLevel &&
485 chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose
486 ) {
487 clearCurrentCP = true;
488 }
489 if (clearCurrentCP) {
658e2d16 490 connectorStatus.chargingProfiles[index] = {} as OCPP16ChargingProfile;
e7aeea18 491 logger.debug(
ad8537a7
JB
492 `${this.chargingStation.logPrefix()} Matching charging profile(s) cleared on connector id ${
493 commandPayload.connectorId
494 }, dump their stack: %j`,
658e2d16 495 connectorStatus.chargingProfiles
e7aeea18
JB
496 );
497 clearedCP = true;
498 }
499 });
c0560973
JB
500 }
501 }
502 if (clearedCP) {
503 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED;
504 }
505 }
506 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
507 }
508
e7aeea18
JB
509 private async handleRequestChangeAvailability(
510 commandPayload: ChangeAvailabilityRequest
511 ): Promise<ChangeAvailabilityResponse> {
c0560973 512 const connectorId: number = commandPayload.connectorId;
734d790d 513 if (!this.chargingStation.getConnectorStatus(connectorId)) {
e7aeea18
JB
514 logger.error(
515 `${this.chargingStation.logPrefix()} Trying to change the availability of a non existing connector Id ${connectorId.toString()}`
516 );
c0560973
JB
517 return Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED;
518 }
e7aeea18
JB
519 const chargePointStatus: OCPP16ChargePointStatus =
520 commandPayload.type === OCPP16AvailabilityType.OPERATIVE
521 ? OCPP16ChargePointStatus.AVAILABLE
522 : OCPP16ChargePointStatus.UNAVAILABLE;
c0560973
JB
523 if (connectorId === 0) {
524 let response: ChangeAvailabilityResponse = Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED;
734d790d
JB
525 for (const id of this.chargingStation.connectors.keys()) {
526 if (this.chargingStation.getConnectorStatus(id)?.transactionStarted) {
c0560973
JB
527 response = Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
528 }
734d790d 529 this.chargingStation.getConnectorStatus(id).availability = commandPayload.type;
c0560973 530 if (response === Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) {
f7f98c68 531 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
532 OCPP16StatusNotificationRequest,
533 OCPP16StatusNotificationResponse
534 >(OCPP16RequestCommand.STATUS_NOTIFICATION, {
535 connectorId: id,
536 status: chargePointStatus,
537 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
538 });
734d790d 539 this.chargingStation.getConnectorStatus(id).status = chargePointStatus;
c0560973
JB
540 }
541 }
542 return response;
e7aeea18
JB
543 } else if (
544 connectorId > 0 &&
545 (this.chargingStation.getConnectorStatus(0).availability ===
546 OCPP16AvailabilityType.OPERATIVE ||
547 (this.chargingStation.getConnectorStatus(0).availability ===
548 OCPP16AvailabilityType.INOPERATIVE &&
549 commandPayload.type === OCPP16AvailabilityType.INOPERATIVE))
550 ) {
734d790d
JB
551 if (this.chargingStation.getConnectorStatus(connectorId)?.transactionStarted) {
552 this.chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type;
c0560973
JB
553 return Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
554 }
734d790d 555 this.chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type;
f7f98c68 556 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
557 OCPP16StatusNotificationRequest,
558 OCPP16StatusNotificationResponse
559 >(OCPP16RequestCommand.STATUS_NOTIFICATION, {
560 connectorId,
561 status: chargePointStatus,
562 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
563 });
734d790d 564 this.chargingStation.getConnectorStatus(connectorId).status = chargePointStatus;
c0560973
JB
565 return Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED;
566 }
567 return Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED;
568 }
569
e7aeea18
JB
570 private async handleRequestRemoteStartTransaction(
571 commandPayload: RemoteStartTransactionRequest
572 ): Promise<DefaultResponse> {
658e2d16
JB
573 const transactionConnectorId = commandPayload.connectorId;
574 const connectorStatus = this.chargingStation.getConnectorStatus(transactionConnectorId);
a7fc8211 575 if (transactionConnectorId) {
f7f98c68 576 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
577 OCPP16StatusNotificationRequest,
578 OCPP16StatusNotificationResponse
579 >(OCPP16RequestCommand.STATUS_NOTIFICATION, {
580 connectorId: transactionConnectorId,
581 status: OCPP16ChargePointStatus.PREPARING,
582 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
583 });
658e2d16
JB
584 connectorStatus.status = OCPP16ChargePointStatus.PREPARING;
585 if (this.chargingStation.isChargingStationAvailable() && connectorStatus) {
e060fe58 586 // Check if authorized
a7fc8211
JB
587 if (this.chargingStation.getAuthorizeRemoteTxRequests()) {
588 let authorized = false;
e7aeea18
JB
589 if (
590 this.chargingStation.getLocalAuthListEnabled() &&
591 this.chargingStation.hasAuthorizedTags() &&
592 this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)
593 ) {
658e2d16
JB
594 connectorStatus.localAuthorizeIdTag = commandPayload.idTag;
595 connectorStatus.idTagLocalAuthorized = true;
36f6a92e 596 authorized = true;
71068fb9 597 } else if (this.chargingStation.getMayAuthorizeAtRemoteStart()) {
658e2d16 598 connectorStatus.authorizeIdTag = commandPayload.idTag;
2e3d65ae 599 const authorizeResponse: OCPP16AuthorizeResponse =
f7f98c68 600 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
601 OCPP16AuthorizeRequest,
602 OCPP16AuthorizeResponse
603 >(OCPP16RequestCommand.AUTHORIZE, {
604 idTag: commandPayload.idTag,
605 });
a7fc8211
JB
606 if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
607 authorized = true;
a7fc8211 608 }
71068fb9 609 } else {
e7aeea18
JB
610 logger.warn(
611 `${this.chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled`
612 );
a7fc8211
JB
613 }
614 if (authorized) {
615 // Authorization successful, start transaction
e7aeea18
JB
616 if (
617 this.setRemoteStartTransactionChargingProfile(
618 transactionConnectorId,
619 commandPayload.chargingProfile
620 )
621 ) {
658e2d16 622 connectorStatus.transactionRemoteStarted = true;
e7aeea18
JB
623 if (
624 (
f7f98c68 625 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
626 OCPP16StartTransactionRequest,
627 OCPP16StartTransactionResponse
628 >(OCPP16RequestCommand.START_TRANSACTION, {
629 connectorId: transactionConnectorId,
630 idTag: commandPayload.idTag,
631 })
e7aeea18
JB
632 ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED
633 ) {
634 logger.debug(
635 this.chargingStation.logPrefix() +
636 ' Transaction remotely STARTED on ' +
637 this.chargingStation.stationInfo.chargingStationId +
638 '#' +
639 transactionConnectorId.toString() +
640 ' for idTag ' +
641 commandPayload.idTag
642 );
e060fe58
JB
643 return Constants.OCPP_RESPONSE_ACCEPTED;
644 }
e7aeea18
JB
645 return this.notifyRemoteStartTransactionRejected(
646 transactionConnectorId,
647 commandPayload.idTag
648 );
e060fe58 649 }
e7aeea18
JB
650 return this.notifyRemoteStartTransactionRejected(
651 transactionConnectorId,
652 commandPayload.idTag
653 );
a7fc8211 654 }
e7aeea18
JB
655 return this.notifyRemoteStartTransactionRejected(
656 transactionConnectorId,
657 commandPayload.idTag
658 );
36f6a92e 659 }
a7fc8211 660 // No authorization check required, start transaction
e7aeea18
JB
661 if (
662 this.setRemoteStartTransactionChargingProfile(
663 transactionConnectorId,
664 commandPayload.chargingProfile
665 )
666 ) {
658e2d16 667 connectorStatus.transactionRemoteStarted = true;
e7aeea18
JB
668 if (
669 (
f7f98c68 670 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
671 OCPP16StartTransactionRequest,
672 OCPP16StartTransactionResponse
673 >(OCPP16RequestCommand.START_TRANSACTION, {
674 connectorId: transactionConnectorId,
675 idTag: commandPayload.idTag,
676 })
e7aeea18
JB
677 ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED
678 ) {
679 logger.debug(
680 this.chargingStation.logPrefix() +
681 ' Transaction remotely STARTED on ' +
682 this.chargingStation.stationInfo.chargingStationId +
683 '#' +
684 transactionConnectorId.toString() +
685 ' for idTag ' +
686 commandPayload.idTag
687 );
e060fe58
JB
688 return Constants.OCPP_RESPONSE_ACCEPTED;
689 }
e7aeea18
JB
690 return this.notifyRemoteStartTransactionRejected(
691 transactionConnectorId,
692 commandPayload.idTag
693 );
e060fe58 694 }
e7aeea18
JB
695 return this.notifyRemoteStartTransactionRejected(
696 transactionConnectorId,
697 commandPayload.idTag
698 );
c0560973 699 }
e7aeea18
JB
700 return this.notifyRemoteStartTransactionRejected(
701 transactionConnectorId,
702 commandPayload.idTag
703 );
c0560973 704 }
57939a9d 705 return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
a7fc8211
JB
706 }
707
e7aeea18
JB
708 private async notifyRemoteStartTransactionRejected(
709 connectorId: number,
710 idTag: string
711 ): Promise<DefaultResponse> {
712 if (
713 this.chargingStation.getConnectorStatus(connectorId).status !==
714 OCPP16ChargePointStatus.AVAILABLE
715 ) {
f7f98c68 716 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
717 OCPP16StatusNotificationRequest,
718 OCPP16StatusNotificationResponse
719 >(OCPP16RequestCommand.STATUS_NOTIFICATION, {
720 connectorId,
721 status: OCPP16ChargePointStatus.AVAILABLE,
722 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
723 });
e7aeea18
JB
724 this.chargingStation.getConnectorStatus(connectorId).status =
725 OCPP16ChargePointStatus.AVAILABLE;
e060fe58 726 }
e7aeea18
JB
727 logger.warn(
728 this.chargingStation.logPrefix() +
729 ' Remote starting transaction REJECTED on connector Id ' +
730 connectorId.toString() +
731 ', idTag ' +
732 idTag +
733 ', availability ' +
734 this.chargingStation.getConnectorStatus(connectorId).availability +
735 ', status ' +
736 this.chargingStation.getConnectorStatus(connectorId).status
737 );
c0560973
JB
738 return Constants.OCPP_RESPONSE_REJECTED;
739 }
740
e7aeea18
JB
741 private setRemoteStartTransactionChargingProfile(
742 connectorId: number,
743 cp: OCPP16ChargingProfile
744 ): boolean {
a7fc8211
JB
745 if (cp && cp.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE) {
746 this.chargingStation.setChargingProfile(connectorId, cp);
e7aeea18 747 logger.debug(
ad8537a7 748 `${this.chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on connector id ${connectorId}, dump their stack: %j`,
e7aeea18
JB
749 this.chargingStation.getConnectorStatus(connectorId).chargingProfiles
750 );
a7fc8211
JB
751 return true;
752 } else if (cp && cp.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE) {
e7aeea18
JB
753 logger.warn(
754 `${this.chargingStation.logPrefix()} Not allowed to set ${
755 cp.chargingProfilePurpose
756 } charging profile(s) at remote start transaction`
757 );
a7fc8211 758 return false;
e060fe58
JB
759 } else if (!cp) {
760 return true;
a7fc8211
JB
761 }
762 }
763
e7aeea18
JB
764 private async handleRequestRemoteStopTransaction(
765 commandPayload: RemoteStopTransactionRequest
766 ): Promise<DefaultResponse> {
c0560973 767 const transactionId = commandPayload.transactionId;
734d790d 768 for (const connectorId of this.chargingStation.connectors.keys()) {
e7aeea18
JB
769 if (
770 connectorId > 0 &&
771 this.chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId
772 ) {
f7f98c68 773 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
774 OCPP16StatusNotificationRequest,
775 OCPP16StatusNotificationResponse
776 >(OCPP16RequestCommand.STATUS_NOTIFICATION, {
777 connectorId,
778 status: OCPP16ChargePointStatus.FINISHING,
779 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
780 });
e7aeea18
JB
781 this.chargingStation.getConnectorStatus(connectorId).status =
782 OCPP16ChargePointStatus.FINISHING;
68c993d5
JB
783 if (
784 this.chargingStation.getBeginEndMeterValues() &&
785 this.chargingStation.getOcppStrictCompliance() &&
786 !this.chargingStation.getOutOfOrderEndMeterValues()
787 ) {
788 // FIXME: Implement OCPP version agnostic helpers
789 const transactionEndMeterValue = OCPP16ServiceUtils.buildTransactionEndMeterValue(
790 this.chargingStation,
791 connectorId,
792 this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId)
793 );
f7f98c68 794 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
795 OCPP16MeterValuesRequest,
796 OCPP16MeterValuesResponse
797 >(OCPP16RequestCommand.METER_VALUES, {
798 connectorId,
68c993d5 799 transactionId,
ef6fa3fb
JB
800 meterValue: transactionEndMeterValue,
801 });
802 }
f7f98c68 803 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
804 OCPP16StopTransactionRequest,
805 OCPP16StopTransactionResponse
806 >(OCPP16RequestCommand.STOP_TRANSACTION, {
807 transactionId,
808 meterStop:
809 this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId),
810 idTag: this.chargingStation.getTransactionIdTag(transactionId),
811 });
c0560973
JB
812 return Constants.OCPP_RESPONSE_ACCEPTED;
813 }
814 }
e7aeea18
JB
815 logger.info(
816 this.chargingStation.logPrefix() +
817 ' Trying to remote stop a non existing transaction ' +
818 transactionId.toString()
819 );
c0560973
JB
820 return Constants.OCPP_RESPONSE_REJECTED;
821 }
47e22477 822
e7aeea18
JB
823 private async handleRequestGetDiagnostics(
824 commandPayload: GetDiagnosticsRequest
825 ): Promise<GetDiagnosticsResponse> {
68cb8b91 826 if (
370ae4ee
JB
827 !OCPP16ServiceUtils.checkFeatureProfile(
828 this.chargingStation,
829 OCPP16SupportedFeatureProfiles.FirmwareManagement,
830 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
831 )
68cb8b91 832 ) {
68cb8b91
JB
833 return Constants.OCPP_RESPONSE_EMPTY;
834 }
e7aeea18
JB
835 logger.debug(
836 this.chargingStation.logPrefix() +
837 ' ' +
838 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS +
839 ' request received: %j',
840 commandPayload
841 );
a3868ec4 842 const uri = new URL(commandPayload.location);
47e22477
JB
843 if (uri.protocol.startsWith('ftp:')) {
844 let ftpClient: Client;
845 try {
e7aeea18
JB
846 const logFiles = fs
847 .readdirSync(path.resolve(__dirname, '../../../../'))
848 .filter((file) => file.endsWith('.log'))
849 .map((file) => path.join('./', file));
850 const diagnosticsArchive =
851 this.chargingStation.stationInfo.chargingStationId + '_logs.tar.gz';
47e22477
JB
852 tar.create({ gzip: true }, logFiles).pipe(fs.createWriteStream(diagnosticsArchive));
853 ftpClient = new Client();
854 const accessResponse = await ftpClient.access({
855 host: uri.host,
e8191622
JB
856 ...(!Utils.isEmptyString(uri.port) && { port: Utils.convertToInt(uri.port) }),
857 ...(!Utils.isEmptyString(uri.username) && { user: uri.username }),
858 ...(!Utils.isEmptyString(uri.password) && { password: uri.password }),
47e22477
JB
859 });
860 let uploadResponse: FTPResponse;
861 if (accessResponse.code === 220) {
862 // eslint-disable-next-line @typescript-eslint/no-misused-promises
863 ftpClient.trackProgress(async (info) => {
e7aeea18
JB
864 logger.info(
865 `${this.chargingStation.logPrefix()} ${
866 info.bytes / 1024
867 } bytes transferred from diagnostics archive ${info.name}`
868 );
f7f98c68 869 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
870 DiagnosticsStatusNotificationRequest,
871 DiagnosticsStatusNotificationResponse
872 >(OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
873 status: OCPP16DiagnosticsStatus.Uploading,
874 });
47e22477 875 });
e7aeea18
JB
876 uploadResponse = await ftpClient.uploadFrom(
877 path.join(path.resolve(__dirname, '../../../../'), diagnosticsArchive),
878 uri.pathname + diagnosticsArchive
879 );
47e22477 880 if (uploadResponse.code === 226) {
f7f98c68 881 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
882 DiagnosticsStatusNotificationRequest,
883 DiagnosticsStatusNotificationResponse
884 >(OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
885 status: OCPP16DiagnosticsStatus.Uploaded,
886 });
47e22477
JB
887 if (ftpClient) {
888 ftpClient.close();
889 }
890 return { fileName: diagnosticsArchive };
891 }
e7aeea18
JB
892 throw new OCPPError(
893 ErrorType.GENERIC_ERROR,
894 `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
895 uploadResponse?.code && '|' + uploadResponse?.code.toString()
896 }`,
897 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
898 );
47e22477 899 }
e7aeea18
JB
900 throw new OCPPError(
901 ErrorType.GENERIC_ERROR,
902 `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
903 uploadResponse?.code && '|' + uploadResponse?.code.toString()
904 }`,
905 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
906 );
47e22477 907 } catch (error) {
f7f98c68 908 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
909 DiagnosticsStatusNotificationRequest,
910 DiagnosticsStatusNotificationResponse
911 >(OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
912 status: OCPP16DiagnosticsStatus.UploadFailed,
913 });
47e22477
JB
914 if (ftpClient) {
915 ftpClient.close();
916 }
e7aeea18
JB
917 return this.handleIncomingRequestError(
918 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
919 error as Error,
920 { errorResponse: Constants.OCPP_RESPONSE_EMPTY }
921 );
47e22477
JB
922 }
923 } else {
e7aeea18
JB
924 logger.error(
925 `${this.chargingStation.logPrefix()} Unsupported protocol ${
926 uri.protocol
927 } to transfer the diagnostic logs archive`
928 );
f7f98c68 929 await this.chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
930 DiagnosticsStatusNotificationRequest,
931 DiagnosticsStatusNotificationResponse
932 >(OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
933 status: OCPP16DiagnosticsStatus.UploadFailed,
934 });
47e22477
JB
935 return Constants.OCPP_RESPONSE_EMPTY;
936 }
937 }
802cfa13 938
e7aeea18
JB
939 private handleRequestTriggerMessage(
940 commandPayload: OCPP16TriggerMessageRequest
941 ): OCPP16TriggerMessageResponse {
370ae4ee
JB
942 if (
943 !OCPP16ServiceUtils.checkFeatureProfile(
944 this.chargingStation,
945 OCPP16SupportedFeatureProfiles.RemoteTrigger,
946 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE
947 )
948 ) {
68cb8b91
JB
949 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED;
950 }
dc661702
JB
951 // TODO: factor out the check on connector id
952 if (commandPayload?.connectorId < 0) {
953 logger.warn(
954 `${this.chargingStation.logPrefix()} ${
955 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE
956 } incoming request received with invalid connectorId ${commandPayload.connectorId}`
957 );
958 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED;
959 }
802cfa13
JB
960 try {
961 switch (commandPayload.requestedMessage) {
962 case MessageTrigger.BootNotification:
963 setTimeout(() => {
e7aeea18 964 this.chargingStation.ocppRequestService
f7f98c68 965 .requestHandler<OCPP16BootNotificationRequest, OCPP16BootNotificationResponse>(
6a8b180d
JB
966 OCPP16RequestCommand.BOOT_NOTIFICATION,
967 {
968 chargePointModel:
969 this.chargingStation.getBootNotificationRequest().chargePointModel,
970 chargePointVendor:
971 this.chargingStation.getBootNotificationRequest().chargePointVendor,
972 chargeBoxSerialNumber:
973 this.chargingStation.getBootNotificationRequest().chargeBoxSerialNumber,
974 firmwareVersion:
975 this.chargingStation.getBootNotificationRequest().firmwareVersion,
976 chargePointSerialNumber:
977 this.chargingStation.getBootNotificationRequest().chargePointSerialNumber,
978 iccid: this.chargingStation.getBootNotificationRequest().iccid,
979 imsi: this.chargingStation.getBootNotificationRequest().imsi,
980 meterSerialNumber:
981 this.chargingStation.getBootNotificationRequest().meterSerialNumber,
982 meterType: this.chargingStation.getBootNotificationRequest().meterType,
983 },
984 { skipBufferingOnError: true, triggerMessage: true }
e7aeea18 985 )
ae711c83
JB
986 .then((value) => {
987 this.chargingStation.bootNotificationResponse = value;
988 })
e7aeea18
JB
989 .catch(() => {
990 /* This is intentional */
991 });
802cfa13
JB
992 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
993 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
994 case MessageTrigger.Heartbeat:
995 setTimeout(() => {
e7aeea18 996 this.chargingStation.ocppRequestService
f7f98c68 997 .requestHandler<OCPP16HeartbeatRequest, OCPP16HeartbeatResponse>(
ef6fa3fb
JB
998 OCPP16RequestCommand.HEARTBEAT,
999 null,
1000 {
1001 triggerMessage: true,
1002 }
1003 )
e7aeea18
JB
1004 .catch(() => {
1005 /* This is intentional */
1006 });
802cfa13
JB
1007 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
1008 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
dc661702
JB
1009 case MessageTrigger.StatusNotification:
1010 setTimeout(() => {
1011 if (commandPayload?.connectorId) {
1012 this.chargingStation.ocppRequestService
1013 .requestHandler<OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse>(
1014 OCPP16RequestCommand.STATUS_NOTIFICATION,
1015 {
1016 connectorId: commandPayload.connectorId,
1017 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
1018 status: this.chargingStation.getConnectorStatus(commandPayload.connectorId)
1019 .status,
1020 },
1021 {
1022 triggerMessage: true,
1023 }
1024 )
1025 .catch(() => {
1026 /* This is intentional */
1027 });
1028 } else {
1029 for (const connectorId of this.chargingStation.connectors.keys()) {
1030 this.chargingStation.ocppRequestService
1031 .requestHandler<
1032 OCPP16StatusNotificationRequest,
1033 OCPP16StatusNotificationResponse
1034 >(
1035 OCPP16RequestCommand.STATUS_NOTIFICATION,
1036 {
1037 connectorId,
1038 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
1039 status: this.chargingStation.getConnectorStatus(connectorId).status,
1040 },
1041 {
1042 triggerMessage: true,
1043 }
1044 )
1045 .catch(() => {
1046 /* This is intentional */
1047 });
1048 }
1049 }
1050 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
1051 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
802cfa13
JB
1052 default:
1053 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED;
1054 }
1055 } catch (error) {
e7aeea18
JB
1056 return this.handleIncomingRequestError(
1057 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
1058 error as Error,
1059 { errorResponse: Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED }
1060 );
802cfa13
JB
1061 }
1062 }
c0560973 1063}