X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fcharging-station%2FChargingStation.ts;h=6870c1f79f2802fec10f002bff3a2fe560090a21;hb=84d4e562327afa2613b07540de63fe39ed838d8c;hp=ce036f7a1dc60b5841e08745548976ce31166098;hpb=4dff73b02dfe0893fdcc84d209c6d7e59ecf6752;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index ce036f7a..6870c1f7 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -3,7 +3,7 @@ import { AvailabilityType, BootNotificationRequest, ChangeAvailabilityRequest, C import { BootNotificationResponse, ChangeAvailabilityResponse, ChangeConfigurationResponse, DefaultResponse, GetConfigurationResponse, HeartbeatResponse, RegistrationStatus, SetChargingProfileResponse, StatusNotificationResponse, UnlockConnectorResponse } from '../types/ocpp/1.6/RequestResponses'; import { ChargingProfile, ChargingProfilePurposeType } from '../types/ocpp/1.6/ChargingProfile'; import ChargingStationConfiguration, { ConfigurationKey } from '../types/ChargingStationConfiguration'; -import ChargingStationTemplate, { PowerOutType } from '../types/ChargingStationTemplate'; +import ChargingStationTemplate, { PowerOutType, VoltageOut } from '../types/ChargingStationTemplate'; import Connectors, { Connector } from '../types/Connectors'; import { MeterValue, MeterValueLocation, MeterValueMeasurand, MeterValuePhase, MeterValueUnit, MeterValuesRequest, MeterValuesResponse, SampledValue } from '../types/ocpp/1.6/MeterValues'; import { PerformanceObserver, performance } from 'perf_hooks'; @@ -304,6 +304,10 @@ export default class ChargingStation { return this.getConnector(id).availability === AvailabilityType.OPERATIVE; } + _isChargingStationAvailable(): boolean { + return this.getConnector(0).availability === AvailabilityType.OPERATIVE; + } + _getTemplateMaxNumberOfConnectors(): number { return Object.keys(this._stationInfo.Connectors).length; } @@ -331,10 +335,10 @@ export default class ChargingStation { let defaultVoltageOut: number; switch (this._getPowerOutType()) { case PowerOutType.AC: - defaultVoltageOut = 230; + defaultVoltageOut = VoltageOut.VOLTAGE_230; break; case PowerOutType.DC: - defaultVoltageOut = 400; + defaultVoltageOut = VoltageOut.VOLTAGE_400; break; default: logger.error(errMsg); @@ -576,7 +580,7 @@ export default class ChargingStation { } }, interval); } else { - logger.error(`${this._logPrefix()} Charging station MeterValueSampleInterval configuration set to ${Utils.milliSecondsToHHMMSS(interval)}, not sending MeterValues`); + logger.error(`${this._logPrefix()} Charging station ${StandardParametersKey.MeterValueSampleInterval} configuration set to ${Utils.milliSecondsToHHMMSS(interval)}, not sending MeterValues`); } } @@ -661,7 +665,7 @@ export default class ChargingStation { this._bootNotificationResponse = await this.sendBootNotification(); if (!this._isRegistered()) { registrationRetryCount++; - await Utils.sleep(this._bootNotificationResponse.interval * 1000); + await Utils.sleep(this._bootNotificationResponse?.interval ? this._bootNotificationResponse.interval * 1000 : Constants.OCPP_DEFAULT_BOOT_NOTIFICATION_INTERVAL); } } while (!this._isRegistered() && (registrationRetryCount <= this._getRegistrationMaxRetries() || this._getRegistrationMaxRetries() === -1)); } @@ -714,8 +718,8 @@ export default class ChargingStation { } async onMessage(messageEvent: MessageEvent): Promise { - let [messageType, messageId, commandName, commandPayload, errorDetails]: IncomingRequest = [0, '', '' as IncomingRequestCommand, '', '']; - let responseCallback: (payload?, requestPayload?) => void; + let [messageType, messageId, commandName, commandPayload, errorDetails]: IncomingRequest = [0, '', '' as IncomingRequestCommand, {}, {}]; + let responseCallback: (payload?: Record | string, requestPayload?: Record) => void; let rejectCallback: (error: OCPPError) => void; let requestPayload: Record; let errMsg: string; @@ -760,7 +764,7 @@ export default class ChargingStation { throw new Error(`Error request for message id ${messageId} is not iterable`); } delete this._requests[messageId]; - rejectCallback(new OCPPError(commandName, commandPayload, errorDetails)); + rejectCallback(new OCPPError(commandName, commandPayload.toString(), errorDetails)); break; // Error default: @@ -837,14 +841,12 @@ export default class ChargingStation { } } - async sendError(messageId: string, err: Error | OCPPError, commandName: RequestCommand | IncomingRequestCommand): Promise { - // Check exception type: only OCPP error are accepted - const error = err instanceof OCPPError ? err : new OCPPError(ErrorType.INTERNAL_ERROR, err.message, err.stack && err.stack); + async sendError(messageId: string, error: OCPPError, commandName: RequestCommand | IncomingRequestCommand): Promise { // Send error return this.sendMessage(messageId, error, MessageType.CALL_ERROR_MESSAGE, commandName); } - async sendMessage(messageId: string, commandParams, messageType: MessageType = MessageType.CALL_RESULT_MESSAGE, commandName: RequestCommand | IncomingRequestCommand): Promise { + async sendMessage(messageId: string, commandParams: any, messageType: MessageType = MessageType.CALL_RESULT_MESSAGE, commandName: RequestCommand | IncomingRequestCommand): Promise { // eslint-disable-next-line @typescript-eslint/no-this-alias const self = this; // Send a message through wsConnection @@ -876,7 +878,7 @@ export default class ChargingStation { } // Yes: Send Message this._wsConnection.send(messageToSend); - } else { + } else if (commandName !== RequestCommand.BOOT_NOTIFICATION) { let dups = false; // Handle dups in buffer for (const message of this._messageQueue) { @@ -903,7 +905,7 @@ export default class ChargingStation { } // Function that will receive the request's response - async function responseCallback(payload, requestPayload): Promise { + async function responseCallback(payload: Record | string, requestPayload: Record): Promise { if (self.getEnableStatistics()) { self._statistics.addMessage(commandName, messageType); } @@ -927,7 +929,7 @@ export default class ChargingStation { }); } - async handleResponse(commandName: RequestCommand, payload, requestPayload): Promise { + async handleResponse(commandName: RequestCommand, payload: Record | string, requestPayload: Record): Promise { const responseCallbackFn = 'handleResponse' + commandName; if (typeof this[responseCallbackFn] === 'function') { await this[responseCallbackFn](payload, requestPayload); @@ -1015,7 +1017,11 @@ export default class ChargingStation { return; } if (payload.idTagInfo?.status === AuthorizationStatus.ACCEPTED) { - await this.sendStatusNotification(transactionConnectorId, ChargePointStatus.AVAILABLE); + if (!this._isChargingStationAvailable() || !this._isConnectorAvailable(transactionConnectorId)) { + await this.sendStatusNotification(transactionConnectorId, ChargePointStatus.UNAVAILABLE); + } else { + await this.sendStatusNotification(transactionConnectorId, ChargePointStatus.AVAILABLE); + } if (this._stationInfo.powerSharedByConnectors) { this._stationInfo.powerDivider--; } @@ -1038,7 +1044,7 @@ export default class ChargingStation { logger.debug(this._logPrefix() + ' Heartbeat response received: %j to Heartbeat request: %j', payload, requestPayload); } - async handleRequest(messageId: string, commandName: IncomingRequestCommand, commandPayload): Promise { + async handleRequest(messageId: string, commandName: IncomingRequestCommand, commandPayload: Record): Promise { let response; // Call if (typeof this['handleRequest' + commandName] === 'function') { @@ -1232,7 +1238,6 @@ export default class ChargingStation { return Constants.OCPP_CHARGING_PROFILE_RESPONSE_ACCEPTED; } - // FIXME: Handle properly the transaction started case handleRequestChangeAvailability(commandPayload: ChangeAvailabilityRequest): ChangeAvailabilityResponse { const connectorId: number = commandPayload.connectorId; if (!this.getConnector(connectorId)) { @@ -1247,13 +1252,12 @@ export default class ChargingStation { response = Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED; } this.getConnector(Utils.convertToInt(connector)).availability = commandPayload.type; - void this.sendStatusNotification(Utils.convertToInt(connector), chargePointStatus); + response === Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED && this.sendStatusNotification(Utils.convertToInt(connector), chargePointStatus); } return response; } else if (connectorId > 0 && (this.getConnector(0).availability === AvailabilityType.OPERATIVE || (this.getConnector(0).availability === AvailabilityType.INOPERATIVE && commandPayload.type === AvailabilityType.INOPERATIVE))) { if (this.getConnector(connectorId)?.transactionStarted) { this.getConnector(connectorId).availability = commandPayload.type; - void this.sendStatusNotification(connectorId, chargePointStatus); return Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED; } this.getConnector(connectorId).availability = commandPayload.type; @@ -1265,23 +1269,27 @@ export default class ChargingStation { async handleRequestRemoteStartTransaction(commandPayload: RemoteStartTransactionRequest): Promise { const transactionConnectorID: number = commandPayload.connectorId ? commandPayload.connectorId : 1; - if (this._getAuthorizeRemoteTxRequests() && this._getLocalAuthListEnabled() && this.hasAuthorizedTags()) { - // Check if authorized - if (this._authorizedTags.find((value) => value === commandPayload.idTag)) { - await this.sendStatusNotification(transactionConnectorID, ChargePointStatus.PREPARING); - // Authorization successful start transaction - await this.sendStartTransaction(transactionConnectorID, commandPayload.idTag); - logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag); - return Constants.OCPP_RESPONSE_ACCEPTED; + if (this._isChargingStationAvailable() && this._isConnectorAvailable(transactionConnectorID)) { + if (this._getAuthorizeRemoteTxRequests() && this._getLocalAuthListEnabled() && this.hasAuthorizedTags()) { + // Check if authorized + if (this._authorizedTags.find((value) => value === commandPayload.idTag)) { + await this.sendStatusNotification(transactionConnectorID, ChargePointStatus.PREPARING); + // Authorization successful start transaction + await this.sendStartTransaction(transactionConnectorID, commandPayload.idTag); + logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag); + return Constants.OCPP_RESPONSE_ACCEPTED; + } + logger.error(this._logPrefix() + ' Remote starting transaction REJECTED on connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag); + return Constants.OCPP_RESPONSE_REJECTED; } - logger.error(this._logPrefix() + ' Remote starting transaction REJECTED, idTag ' + commandPayload.idTag); - return Constants.OCPP_RESPONSE_REJECTED; + await this.sendStatusNotification(transactionConnectorID, ChargePointStatus.PREPARING); + // No local authorization check required => start transaction + await this.sendStartTransaction(transactionConnectorID, commandPayload.idTag); + logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag); + return Constants.OCPP_RESPONSE_ACCEPTED; } - await this.sendStatusNotification(transactionConnectorID, ChargePointStatus.PREPARING); - // No local authorization check required => start transaction - await this.sendStartTransaction(transactionConnectorID, commandPayload.idTag); - logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag); - return Constants.OCPP_RESPONSE_ACCEPTED; + logger.error(this._logPrefix() + ' Remote starting transaction REJECTED on unavailable connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag); + return Constants.OCPP_RESPONSE_REJECTED; } async handleRequestRemoteStopTransaction(commandPayload: RemoteStopTransactionRequest): Promise {