-
- _resetTransactionOnConnector(connectorId: number): void {
- this._initTransactionOnConnector(connectorId);
- if (this.getConnector(connectorId).transactionSetInterval) {
- clearInterval(this.getConnector(connectorId).transactionSetInterval);
- }
- }
-
- async handleResponseStartTransaction(payload: StartTransactionResponse, requestPayload: StartTransactionRequest): Promise<void> {
- const connectorId = requestPayload.connectorId;
- if (this.getConnector(connectorId).transactionStarted) {
- logger.debug(this._logPrefix() + ' Trying to start a transaction on an already used connector ' + connectorId.toString() + ': %j', this.getConnector(connectorId));
- return;
- }
-
- let transactionConnectorId: number;
- for (const connector in this._connectors) {
- if (Utils.convertToInt(connector) > 0 && Utils.convertToInt(connector) === connectorId) {
- transactionConnectorId = Utils.convertToInt(connector);
- break;
- }
- }
- if (!transactionConnectorId) {
- logger.error(this._logPrefix() + ' Trying to start a transaction on a non existing connector Id ' + connectorId.toString());
- return;
- }
- if (payload.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
- this.getConnector(connectorId).transactionStarted = true;
- this.getConnector(connectorId).transactionId = payload.transactionId;
- this.getConnector(connectorId).idTag = requestPayload.idTag;
- this.getConnector(connectorId).lastEnergyActiveImportRegisterValue = 0;
- await this.sendStatusNotification(connectorId, ChargePointStatus.CHARGING);
- logger.info(this._logPrefix() + ' Transaction ' + payload.transactionId.toString() + ' STARTED on ' + this._stationInfo.name + '#' + connectorId.toString() + ' for idTag ' + requestPayload.idTag);
- if (this._stationInfo.powerSharedByConnectors) {
- this._stationInfo.powerDivider++;
- }
- const configuredMeterValueSampleInterval = this._getConfigurationKey('MeterValueSampleInterval');
- this._startMeterValues(connectorId,
- configuredMeterValueSampleInterval ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000 : 60000);
- } else {
- logger.error(this._logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + ' REJECTED with status ' + payload.idTagInfo.status + ', idTag ' + requestPayload.idTag);
- this._resetTransactionOnConnector(connectorId);
- await this.sendStatusNotification(connectorId, ChargePointStatus.AVAILABLE);
- }
- }
-
- async handleResponseStopTransaction(payload: StopTransactionResponse, requestPayload: StopTransactionRequest): Promise<void> {
- let transactionConnectorId: number;
- for (const connector in this._connectors) {
- if (Utils.convertToInt(connector) > 0 && this.getConnector(Utils.convertToInt(connector)).transactionId === requestPayload.transactionId) {
- transactionConnectorId = Utils.convertToInt(connector);
- break;
- }
- }
- if (!transactionConnectorId) {
- logger.error(this._logPrefix() + ' Trying to stop a non existing transaction ' + requestPayload.transactionId.toString());
- return;
- }
- if (payload.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
- await this.sendStatusNotification(transactionConnectorId, ChargePointStatus.AVAILABLE);
- if (this._stationInfo.powerSharedByConnectors) {
- this._stationInfo.powerDivider--;
- }
- logger.info(this._logPrefix() + ' Transaction ' + requestPayload.transactionId.toString() + ' STOPPED on ' + this._stationInfo.name + '#' + transactionConnectorId.toString());
- this._resetTransactionOnConnector(transactionConnectorId);
- } else {
- logger.error(this._logPrefix() + ' Stopping transaction id ' + requestPayload.transactionId.toString() + ' REJECTED with status ' + payload.idTagInfo?.status);
- }
- }
-
- handleResponseStatusNotification(payload: StatusNotificationRequest, requestPayload: StatusNotificationResponse): void {
- logger.debug(this._logPrefix() + ' Status notification response received: %j to StatusNotification request: %j', payload, requestPayload);
- }
-
- handleResponseMeterValues(payload: MeterValuesRequest, requestPayload: MeterValuesResponse): void {
- logger.debug(this._logPrefix() + ' MeterValues response received: %j to MeterValues request: %j', payload, requestPayload);
- }
-
- handleResponseHeartbeat(payload: HeartbeatResponse, requestPayload: HeartbeatRequest): void {
- logger.debug(this._logPrefix() + ' Heartbeat response received: %j to Heartbeat request: %j', payload, requestPayload);
- }
-
- async handleRequest(messageId: string, commandName: string, commandPayload): Promise<void> {
- let response;
- // Call
- if (typeof this['handleRequest' + commandName] === 'function') {
- try {
- // Call the method to build the response
- response = await this['handleRequest' + commandName](commandPayload);
- } catch (error) {
- // Log
- logger.error(this._logPrefix() + ' Handle request error: %j', error);
- // Send back response to inform backend
- await this.sendError(messageId, error, commandName);
- throw error;
- }
- } else {
- // Throw exception
- await this.sendError(messageId, new OCPPError(Constants.OCPP_ERROR_NOT_IMPLEMENTED, `${commandName} is not implemented`, {}), commandName);
- throw new Error(`${commandName} is not implemented ${JSON.stringify(commandPayload, null, ' ')}`);
- }
- // Send response
- await this.sendMessage(messageId, response, Constants.OCPP_JSON_CALL_RESULT_MESSAGE, commandName);
- }
-
- // Simulate charging station restart
- handleRequestReset(commandPayload: ResetRequest): DefaultResponse {
- setImmediate(async () => {
- await this.stop(commandPayload.type + 'Reset' as StopTransactionReason);
- await Utils.sleep(this._stationInfo.resetTime);
- await this.start();
- });
- logger.info(`${this._logPrefix()} ${commandPayload.type} reset command received, simulating it. The station will be back online in ${Utils.milliSecondsToHHMMSS(this._stationInfo.resetTime)}`);
- return Constants.OCPP_RESPONSE_ACCEPTED;
- }
-
- handleRequestClearCache(): DefaultResponse {
- return Constants.OCPP_RESPONSE_ACCEPTED;
- }
-
- async handleRequestUnlockConnector(commandPayload: UnlockConnectorRequest): Promise<UnlockConnectorResponse> {
- const connectorId = commandPayload.connectorId;
- if (connectorId === 0) {
- logger.error(this._logPrefix() + ' Trying to unlock connector ' + connectorId.toString());
- return Constants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED;
- }
- if (this.getConnector(connectorId).transactionStarted) {
- const stopResponse = await this.sendStopTransaction(this.getConnector(connectorId).transactionId, StopTransactionReason.UNLOCK_COMMAND);
- if (stopResponse.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
- return Constants.OCPP_RESPONSE_UNLOCKED;
- }
- return Constants.OCPP_RESPONSE_UNLOCK_FAILED;
- }
- await this.sendStatusNotification(connectorId, ChargePointStatus.AVAILABLE);
- return Constants.OCPP_RESPONSE_UNLOCKED;
- }
-
- _getConfigurationKey(key: string, caseInsensitive = false): ConfigurationKey {
- return this._configuration.configurationKey.find((configElement) => {
- if (caseInsensitive) {
- return configElement.key.toLowerCase() === key.toLowerCase();
- }
- return configElement.key === key;
- });
- }
-
- _addConfigurationKey(key: string, value: string, readonly = false, visible = true, reboot = false): void {
- const keyFound = this._getConfigurationKey(key);
- if (!keyFound) {
- this._configuration.configurationKey.push({
- key,
- readonly,
- value,
- visible,
- reboot,
- });
- }
- }
-
- _setConfigurationKeyValue(key: string, value: string): void {
- const keyFound = this._getConfigurationKey(key);
- if (keyFound) {
- const keyIndex = this._configuration.configurationKey.indexOf(keyFound);
- this._configuration.configurationKey[keyIndex].value = value;
- }
- }
-
- handleRequestGetConfiguration(commandPayload: GetConfigurationRequest): GetConfigurationResponse {
- const configurationKey: ConfigurationKey[] = [];
- const unknownKey: string[] = [];
- if (Utils.isEmptyArray(commandPayload.key)) {
- for (const configuration of this._configuration.configurationKey) {
- if (Utils.isUndefined(configuration.visible)) {
- configuration.visible = true;
- }
- if (!configuration.visible) {
- continue;
- }
- configurationKey.push({
- key: configuration.key,
- readonly: configuration.readonly,
- value: configuration.value,
- });
- }
- } else {
- for (const key of commandPayload.key) {
- const keyFound = this._getConfigurationKey(key);
- if (keyFound) {
- if (Utils.isUndefined(keyFound.visible)) {
- keyFound.visible = true;
- }
- if (!keyFound.visible) {
- continue;
- }
- configurationKey.push({
- key: keyFound.key,
- readonly: keyFound.readonly,
- value: keyFound.value,
- });
- } else {
- unknownKey.push(key);
- }
- }
- }
- return {
- configurationKey,
- unknownKey,
- };
- }
-
- handleRequestChangeConfiguration(commandPayload: ChangeConfigurationRequest): ChangeConfigurationResponse {
- // JSON request fields type sanity check
- if (!Utils.isString(commandPayload.key)) {
- logger.error(`${this._logPrefix()} ChangeConfiguration request key field is not a string:`, commandPayload);
- }
- if (!Utils.isString(commandPayload.value)) {
- logger.error(`${this._logPrefix()} ChangeConfiguration request value field is not a string:`, commandPayload);
- }
- const keyToChange = this._getConfigurationKey(commandPayload.key, true);
- if (!keyToChange) {
- return Constants.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED;
- } else if (keyToChange && keyToChange.readonly) {
- return Constants.OCPP_CONFIGURATION_RESPONSE_REJECTED;
- } else if (keyToChange && !keyToChange.readonly) {
- const keyIndex = this._configuration.configurationKey.indexOf(keyToChange);
- let valueChanged = false;
- if (this._configuration.configurationKey[keyIndex].value !== commandPayload.value) {
- this._configuration.configurationKey[keyIndex].value = commandPayload.value;
- valueChanged = true;
- }
- let triggerHeartbeatRestart = false;
- if (keyToChange.key === 'HeartBeatInterval' && valueChanged) {
- this._setConfigurationKeyValue('HeartbeatInterval', commandPayload.value);
- triggerHeartbeatRestart = true;
- }
- if (keyToChange.key === 'HeartbeatInterval' && valueChanged) {
- this._setConfigurationKeyValue('HeartBeatInterval', commandPayload.value);
- triggerHeartbeatRestart = true;
- }
- if (triggerHeartbeatRestart) {
- this._heartbeatInterval = Utils.convertToInt(commandPayload.value) * 1000;
- this._restartHeartbeat();
- }
- if (keyToChange.key === 'WebSocketPingInterval' && valueChanged) {
- this._restartWebSocketPing();
- }
- if (keyToChange.reboot) {
- return Constants.OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED;
- }
- return Constants.OCPP_CONFIGURATION_RESPONSE_ACCEPTED;
- }
- }
-
- handleRequestSetChargingProfile(commandPayload: SetChargingProfileRequest): SetChargingProfileResponse {
- if (!this.getConnector(commandPayload.connectorId)) {
- logger.error(`${this._logPrefix()} Trying to set a charging profile to a non existing connector Id ${commandPayload.connectorId}`);
- return Constants.OCPP_CHARGING_PROFILE_RESPONSE_REJECTED;
- }
- if (commandPayload.csChargingProfiles.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE && !this.getConnector(commandPayload.connectorId)?.transactionStarted) {
- return Constants.OCPP_CHARGING_PROFILE_RESPONSE_REJECTED;
- }
- this.getConnector(commandPayload.connectorId).chargingProfiles.forEach((chargingProfile: ChargingProfile, index: number) => {
- if (chargingProfile.chargingProfileId === commandPayload.csChargingProfiles.chargingProfileId
- || (chargingProfile.stackLevel === commandPayload.csChargingProfiles.stackLevel && chargingProfile.chargingProfilePurpose === commandPayload.csChargingProfiles.chargingProfilePurpose)) {
- this.getConnector(commandPayload.connectorId).chargingProfiles[index] = chargingProfile;
- return Constants.OCPP_CHARGING_PROFILE_RESPONSE_ACCEPTED;
- }
- });
- this.getConnector(commandPayload.connectorId).chargingProfiles.push(commandPayload.csChargingProfiles);
- return Constants.OCPP_CHARGING_PROFILE_RESPONSE_ACCEPTED;
- }
-
- async handleRequestRemoteStartTransaction(commandPayload: RemoteStartTransactionRequest): Promise<DefaultResponse> {
- 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)) {
- // 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, idTag ' + commandPayload.idTag);
- return Constants.OCPP_RESPONSE_REJECTED;
- }
- // 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;
- }
-
- async handleRequestRemoteStopTransaction(commandPayload: RemoteStopTransactionRequest): Promise<DefaultResponse> {
- const transactionId = commandPayload.transactionId;
- for (const connector in this._connectors) {
- if (Utils.convertToInt(connector) > 0 && this.getConnector(Utils.convertToInt(connector)).transactionId === transactionId) {
- await this.sendStopTransaction(transactionId);
- return Constants.OCPP_RESPONSE_ACCEPTED;
- }
- }
- logger.info(this._logPrefix() + ' Trying to remote stop a non existing transaction ' + transactionId.toString());
- return Constants.OCPP_RESPONSE_REJECTED;
- }