From: Jérôme Benoit Date: Wed, 29 Sep 2021 21:11:45 +0000 (+0200) Subject: Use a map a register response and incoming request handlers X-Git-Tag: v1.1.18~1 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=58144adb13fbef619e8b75b36bad7c325d7cae50;p=e-mobility-charging-stations-simulator.git Use a map a register response and incoming request handlers Signed-off-by: Jérôme Benoit --- diff --git a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts index 9f00f9fd..150a41b1 100644 --- a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts @@ -1,15 +1,16 @@ // Partial Copyright Jerome Benoit. 2021. All Rights Reserved. -import { ChangeAvailabilityRequest, ChangeConfigurationRequest, ClearChargingProfileRequest, GetConfigurationRequest, GetDiagnosticsRequest, MessageTrigger, OCPP16AvailabilityType, OCPP16IncomingRequestCommand, OCPP16TriggerMessageRequest, RemoteStartTransactionRequest, RemoteStopTransactionRequest, ResetRequest, SetChargingProfileRequest, UnlockConnectorRequest } from '../../../types/ocpp/1.6/Requests'; +import { ChangeAvailabilityRequest, ChangeConfigurationRequest, ClearChargingProfileRequest, GetConfigurationRequest, GetDiagnosticsRequest, MessageTrigger, OCPP16AvailabilityType, OCPP16IncomingRequestCommand, OCPP16RequestCommand, OCPP16TriggerMessageRequest, RemoteStartTransactionRequest, RemoteStopTransactionRequest, ResetRequest, SetChargingProfileRequest, UnlockConnectorRequest } from '../../../types/ocpp/1.6/Requests'; import { ChangeAvailabilityResponse, ChangeConfigurationResponse, ClearChargingProfileResponse, GetConfigurationResponse, GetDiagnosticsResponse, OCPP16TriggerMessageResponse, SetChargingProfileResponse, UnlockConnectorResponse } from '../../../types/ocpp/1.6/Responses'; import { ChargingProfilePurposeType, OCPP16ChargingProfile } from '../../../types/ocpp/1.6/ChargingProfile'; import { Client, FTPResponse } from 'basic-ftp'; -import { IncomingRequestCommand, RequestCommand } from '../../../types/ocpp/Requests'; import { OCPP16AuthorizationStatus, OCPP16StopTransactionReason } from '../../../types/ocpp/1.6/Transaction'; +import ChargingStation from '../../ChargingStation'; import Constants from '../../../utils/Constants'; import { DefaultResponse } from '../../../types/ocpp/Responses'; import { ErrorType } from '../../../types/ocpp/ErrorType'; +import { IncomingRequestHandler } from '../../../types/ocpp/Requests'; import { MessageType } from '../../../types/ocpp/MessageType'; import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus'; import { OCPP16DiagnosticsStatus } from '../../../types/ocpp/1.6/DiagnosticsStatus'; @@ -25,14 +26,31 @@ import path from 'path'; import tar from 'tar'; export default class OCPP16IncomingRequestService extends OCPPIncomingRequestService { + private incomingRequestHandlers: Map; + + constructor(chargingStation: ChargingStation) { + super(chargingStation); + this.incomingRequestHandlers = new Map([ + [OCPP16IncomingRequestCommand.RESET, this.handleRequestReset.bind(this)], + [OCPP16IncomingRequestCommand.CLEAR_CACHE, this.handleRequestClearCache.bind(this)], + [OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR, this.handleRequestUnlockConnector.bind(this)], + [OCPP16IncomingRequestCommand.GET_CONFIGURATION, this.handleRequestGetConfiguration.bind(this)], + [OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION, this.handleRequestChangeConfiguration.bind(this)], + [OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE, this.handleRequestSetChargingProfile.bind(this)], + [OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE, this.handleRequestClearChargingProfile.bind(this)], + [OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY, this.handleRequestChangeAvailability.bind(this)], + [OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION, this.handleRequestRemoteStartTransaction.bind(this)], + [OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION, this.handleRequestRemoteStopTransaction.bind(this)], + [OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, this.handleRequestTriggerMessage.bind(this)] + ]); + } + public async handleRequest(messageId: string, commandName: OCPP16IncomingRequestCommand, commandPayload: Record): Promise { let response: Record; - const methodName = `handleRequest${commandName}`; - // Call - if (typeof this[methodName] === 'function') { + if (this.incomingRequestHandlers.has(commandName)) { try { // Call the method to build the response - response = await this[methodName](commandPayload); + response = await this.incomingRequestHandlers.get(commandName)(commandPayload); } catch (error) { // Log logger.error(this.chargingStation.logPrefix() + ' Handle request error: %j', error); @@ -130,10 +148,10 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer private handleRequestChangeConfiguration(commandPayload: ChangeConfigurationRequest): ChangeConfigurationResponse { // JSON request fields type sanity check if (!Utils.isString(commandPayload.key)) { - logger.error(`${this.chargingStation.logPrefix()} ${RequestCommand.CHANGE_CONFIGURATION} request key field is not a string:`, commandPayload); + logger.error(`${this.chargingStation.logPrefix()} ${OCPP16RequestCommand.CHANGE_CONFIGURATION} request key field is not a string:`, commandPayload); } if (!Utils.isString(commandPayload.value)) { - logger.error(`${this.chargingStation.logPrefix()} ${RequestCommand.CHANGE_CONFIGURATION} request value field is not a string:`, commandPayload); + logger.error(`${this.chargingStation.logPrefix()} ${OCPP16RequestCommand.CHANGE_CONFIGURATION} request value field is not a string:`, commandPayload); } const keyToChange = this.chargingStation.getConfigurationKey(commandPayload.key, true); if (!keyToChange) { @@ -348,7 +366,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } private async handleRequestGetDiagnostics(commandPayload: GetDiagnosticsRequest): Promise { - logger.debug(this.chargingStation.logPrefix() + ' ' + IncomingRequestCommand.GET_DIAGNOSTICS + ' request received: %j', commandPayload); + logger.debug(this.chargingStation.logPrefix() + ' ' + OCPP16IncomingRequestCommand.GET_DIAGNOSTICS + ' request received: %j', commandPayload); const uri = new URL(commandPayload.location); if (uri.protocol.startsWith('ftp:')) { let ftpClient: Client; @@ -378,15 +396,15 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } return { fileName: diagnosticsArchive }; } - throw new OCPPError(ErrorType.GENERIC_ERROR, `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${uploadResponse?.code && '|' + uploadResponse?.code.toString()}`, IncomingRequestCommand.GET_DIAGNOSTICS); + throw new OCPPError(ErrorType.GENERIC_ERROR, `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${uploadResponse?.code && '|' + uploadResponse?.code.toString()}`, OCPP16IncomingRequestCommand.GET_DIAGNOSTICS); } - throw new OCPPError(ErrorType.GENERIC_ERROR, `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${uploadResponse?.code && '|' + uploadResponse?.code.toString()}`, IncomingRequestCommand.GET_DIAGNOSTICS); + throw new OCPPError(ErrorType.GENERIC_ERROR, `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${uploadResponse?.code && '|' + uploadResponse?.code.toString()}`, OCPP16IncomingRequestCommand.GET_DIAGNOSTICS); } catch (error) { await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(OCPP16DiagnosticsStatus.UploadFailed); if (ftpClient) { ftpClient.close(); } - return this.handleIncomingRequestError(IncomingRequestCommand.GET_DIAGNOSTICS, error, Constants.OCPP_RESPONSE_EMPTY); + return this.handleIncomingRequestError(OCPP16IncomingRequestCommand.GET_DIAGNOSTICS, error, Constants.OCPP_RESPONSE_EMPTY); } } else { logger.error(`${this.chargingStation.logPrefix()} Unsupported protocol ${uri.protocol} to transfer the diagnostic logs archive`); @@ -414,7 +432,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED; } } catch (error) { - return this.handleIncomingRequestError(IncomingRequestCommand.TRIGGER_MESSAGE, error, Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED); + return this.handleIncomingRequestError(OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, error, Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED); } } } diff --git a/src/charging-station/ocpp/1.6/OCPP16RequestService.ts b/src/charging-station/ocpp/1.6/OCPP16RequestService.ts index a8fb4890..d08404c9 100644 --- a/src/charging-station/ocpp/1.6/OCPP16RequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16RequestService.ts @@ -18,7 +18,6 @@ import { OCPP16DiagnosticsStatus } from '../../../types/ocpp/1.6/DiagnosticsStat import { OCPP16ServiceUtils } from './OCPP16ServiceUtils'; import OCPPError from '../OCPPError'; import OCPPRequestService from '../OCPPRequestService'; -import { RequestCommand } from '../../../types/ocpp/Requests'; import Utils from '../../../utils/Utils'; import logger from '../../../utils/Logger'; @@ -222,7 +221,7 @@ export default class OCPP16RequestService extends OCPPRequestService { break; default: logger.error(errMsg); - throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES); + throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES); } meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(powerSampledValueTemplate, powerMeasurandValues.allPhases)); const sampledValuesIndex = meterValue.sampledValue.length - 1; @@ -288,7 +287,7 @@ export default class OCPP16RequestService extends OCPPRequestService { break; default: logger.error(errMsg); - throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES); + throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES); } meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(currentSampledValueTemplate, currentMeasurandValues.allPhases)); const sampledValuesIndex = meterValue.sampledValue.length - 1; diff --git a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts index 5d1b04e9..7dac13e3 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts @@ -5,20 +5,36 @@ import { HeartbeatRequest, OCPP16RequestCommand, StatusNotificationRequest } fro import { HeartbeatResponse, OCPP16BootNotificationResponse, OCPP16RegistrationStatus, StatusNotificationResponse } from '../../../types/ocpp/1.6/Responses'; import { MeterValuesRequest, MeterValuesResponse } from '../../../types/ocpp/1.6/MeterValues'; +import ChargingStation from '../../ChargingStation'; import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus'; import { OCPP16ServiceUtils } from './OCPP16ServiceUtils'; import { OCPP16StandardParametersKey } from '../../../types/ocpp/1.6/Configuration'; import OCPPResponseService from '../OCPPResponseService'; +import { ResponseHandler } from '../../../types/ocpp/Responses'; import Utils from '../../../utils/Utils'; import logger from '../../../utils/Logger'; export default class OCPP16ResponseService extends OCPPResponseService { + private responseHandlers: Map; + + constructor(chargingStation: ChargingStation) { + super(chargingStation); + this.responseHandlers = new Map([ + [OCPP16RequestCommand.BOOT_NOTIFICATION, this.handleResponseBootNotification.bind(this)], + [OCPP16RequestCommand.HEARTBEAT, this.handleResponseHeartbeat.bind(this)], + [OCPP16RequestCommand.AUTHORIZE, this.handleResponseAuthorize.bind(this)], + [OCPP16RequestCommand.START_TRANSACTION, this.handleResponseStartTransaction.bind(this)], + [OCPP16RequestCommand.STOP_TRANSACTION, this.handleResponseStopTransaction.bind(this)], + [OCPP16RequestCommand.STATUS_NOTIFICATION, this.handleResponseStatusNotification.bind(this)], + [OCPP16RequestCommand.METER_VALUES, this.handleResponseMeterValues.bind(this)], + ]); + } + public async handleResponse(commandName: OCPP16RequestCommand, payload: Record | string, requestPayload: Record): Promise { - const responseCallbackMethodName = `handleResponse${commandName}`; - if (typeof this[responseCallbackMethodName] === 'function') { - await this[responseCallbackMethodName](payload, requestPayload); + if (this.responseHandlers.has(commandName)) { + await this.responseHandlers.get(commandName)(payload, requestPayload); } else { - logger.error(this.chargingStation.logPrefix() + ' Trying to call an undefined response callback method: ' + responseCallbackMethodName); + logger.error(this.chargingStation.logPrefix() + ' Trying to call an undefined method for command ' + commandName + ' response'); } } @@ -34,6 +50,28 @@ export default class OCPP16ResponseService extends OCPPResponseService { } } + private handleResponseHeartbeat(payload: HeartbeatResponse, requestPayload: HeartbeatRequest): void { + logger.debug(this.chargingStation.logPrefix() + ' Heartbeat response received: %j to Heartbeat request: %j', payload, requestPayload); + } + + private handleResponseAuthorize(payload: OCPP16AuthorizeResponse, requestPayload: AuthorizeRequest): void { + let authorizeConnectorId: number; + for (const connector in this.chargingStation.connectors) { + if (Utils.convertToInt(connector) > 0 && this.chargingStation.getConnector(Utils.convertToInt(connector))?.authorizeIdTag === requestPayload.idTag) { + authorizeConnectorId = Utils.convertToInt(connector); + break; + } + } + if (payload.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) { + this.chargingStation.getConnector(authorizeConnectorId).authorized = true; + logger.debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} authorized on connector ${authorizeConnectorId}`); + } else { + this.chargingStation.getConnector(authorizeConnectorId).authorized = false; + delete this.chargingStation.getConnector(authorizeConnectorId).authorizeIdTag; + logger.debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} refused with status ${payload.idTagInfo.status} on connector ${authorizeConnectorId}`); + } + } + private async handleResponseStartTransaction(payload: OCPP16StartTransactionResponse, requestPayload: StartTransactionRequest): Promise { const connectorId = requestPayload.connectorId; @@ -57,7 +95,7 @@ export default class OCPP16ResponseService extends OCPPResponseService { return; } if (this.chargingStation.getConnector(connectorId)?.status !== OCPP16ChargePointStatus.AVAILABLE - && this.chargingStation.getConnector(connectorId)?.status !== OCPP16ChargePointStatus.PREPARING) { + && this.chargingStation.getConnector(connectorId)?.status !== OCPP16ChargePointStatus.PREPARING) { logger.error(`${this.chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with status ${this.chargingStation.getConnector(connectorId)?.status}`); return; } @@ -133,26 +171,4 @@ export default class OCPP16ResponseService extends OCPPResponseService { private handleResponseMeterValues(payload: MeterValuesRequest, requestPayload: MeterValuesResponse): void { logger.debug(this.chargingStation.logPrefix() + ' MeterValues response received: %j to MeterValues request: %j', payload, requestPayload); } - - private handleResponseHeartbeat(payload: HeartbeatResponse, requestPayload: HeartbeatRequest): void { - logger.debug(this.chargingStation.logPrefix() + ' Heartbeat response received: %j to Heartbeat request: %j', payload, requestPayload); - } - - private handleResponseAuthorize(payload: OCPP16AuthorizeResponse, requestPayload: AuthorizeRequest): void { - let authorizeConnectorId: number; - for (const connector in this.chargingStation.connectors) { - if (Utils.convertToInt(connector) > 0 && this.chargingStation.getConnector(Utils.convertToInt(connector))?.authorizeIdTag === requestPayload.idTag) { - authorizeConnectorId = Utils.convertToInt(connector); - break; - } - } - if (payload.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) { - this.chargingStation.getConnector(authorizeConnectorId).authorized = true; - logger.debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} authorized on connector ${authorizeConnectorId}`); - } else { - this.chargingStation.getConnector(authorizeConnectorId).authorized = false; - delete this.chargingStation.getConnector(authorizeConnectorId).authorizeIdTag; - logger.debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} refused with status ${payload.idTagInfo.status} on connector ${authorizeConnectorId}`); - } - } } diff --git a/src/types/ocpp/Requests.ts b/src/types/ocpp/Requests.ts index b2adad37..f32db002 100644 --- a/src/types/ocpp/Requests.ts +++ b/src/types/ocpp/Requests.ts @@ -4,6 +4,8 @@ import { MessageType } from './MessageType'; import { OCPP16DiagnosticsStatus } from './1.6/DiagnosticsStatus'; import OCPPError from '../../charging-station/ocpp/OCPPError'; +export type IncomingRequestHandler = (commandPayload: Record) => Record | Promise>; + export type BootNotificationRequest = OCPP16BootNotificationRequest; export type AvailabilityType = OCPP16AvailabilityType; diff --git a/src/types/ocpp/Responses.ts b/src/types/ocpp/Responses.ts index 77497074..7a851170 100644 --- a/src/types/ocpp/Responses.ts +++ b/src/types/ocpp/Responses.ts @@ -1,5 +1,7 @@ import { OCPP16AvailabilityStatus, OCPP16BootNotificationResponse, OCPP16ChargingProfileStatus, OCPP16ClearChargingProfileStatus, OCPP16ConfigurationStatus, OCPP16RegistrationStatus, OCPP16TriggerMessageStatus, OCPP16UnlockStatus } from './1.6/Responses'; +export type ResponseHandler = (payload: Record | string, requestPayload?: Record) => void | Promise; + export type BootNotificationResponse = OCPP16BootNotificationResponse; export enum DefaultStatus {