-import { AuthorizationStatus, StartTransactionResponse, StopTransactionReason, StopTransactionResponse } from '../types/Transaction';
+import { AuthorizationStatus, StartTransactionResponse, StopTransactionReason, StopTransactionResponse } from '../types/ocpp/1.6/Transaction';
import ChargingStationConfiguration, { ConfigurationKey } from '../types/ChargingStationConfiguration';
import ChargingStationTemplate, { PowerOutType } from '../types/ChargingStationTemplate';
-import { ConfigurationResponse, DefaultRequestResponse, UnlockResponse } from '../types/RequestResponses';
+import { ConfigurationResponse, DefaultRequestResponse, UnlockResponse } from '../types/ocpp/1.6/RequestResponses';
import Connectors, { Connector } from '../types/Connectors';
-import MeterValue, { MeterValueLocation, MeterValueMeasurand, MeterValuePhase, MeterValueUnit } from '../types/MeterValue';
+import MeterValue, { MeterValueLocation, MeterValueMeasurand, MeterValuePhase, MeterValueUnit } from '../types/ocpp/1.6/MeterValue';
import { PerformanceObserver, performance } from 'perf_hooks';
import AutomaticTransactionGenerator from './AutomaticTransactionGenerator';
-import { ChargePointErrorCode } from '../types/ChargePointErrorCode';
-import { ChargePointStatus } from '../types/ChargePointStatus';
+import { ChargePointErrorCode } from '../types/ocpp/1.6/ChargePointErrorCode';
+import { ChargePointStatus } from '../types/ocpp/1.6/ChargePointStatus';
import ChargingStationInfo from '../types/ChargingStationInfo';
import Configuration from '../utils/Configuration';
-import Constants from '../utils/Constants.js';
+import Constants from '../utils/Constants';
import ElectricUtils from '../utils/ElectricUtils';
import MeasurandValues from '../types/MeasurandValues';
-import OCPPError from './OcppError.js';
+import OCPPError from './OcppError';
+import Requests from '../types/ocpp/1.6/Requests';
import Statistics from '../utils/Statistics';
import Utils from '../utils/Utils';
import WebSocket from 'ws';
private _autoReconnectRetryCount: number;
private _autoReconnectMaxRetries: number;
private _autoReconnectTimeout: number;
- private _requests: { [id: string]: [(payload?, requestPayload?) => void, (error?: OCPPError) => void, object] };
- private _messageQueue: any[];
+ private _requests: Requests;
+ private _messageQueue: string[];
private _automaticTransactionGeneration: AutomaticTransactionGenerator;
private _authorizedTags: string[];
private _heartbeatInterval: number;
constructor(index: number, stationTemplateFile: string) {
this._index = index;
this._stationTemplateFile = stationTemplateFile;
- this._connectors = {};
+ this._connectors = {} as Connectors;
this._initialize();
this._hasStopped = false;
this._autoReconnectMaxRetries = Configuration.getAutoReconnectMaxRetries(); // -1 for unlimited
this._autoReconnectTimeout = Configuration.getAutoReconnectTimeout() * 1000; // Ms, zero for disabling
- this._requests = {};
- this._messageQueue = [];
+ this._requests = {} as Requests;
+ this._messageQueue = [] as string[];
this._authorizedTags = this._loadAndGetAuthorizedTags();
}
stationTemplateFromFile = JSON.parse(fs.readFileSync(fileDescriptor, 'utf8')) as ChargingStationTemplate;
fs.closeSync(fileDescriptor);
} catch (error) {
- logger.error('Template file ' + this._stationTemplateFile + ' loading error: ' + error);
+ logger.error('Template file ' + this._stationTemplateFile + ' loading error: %j', error);
throw error;
}
const stationInfo: ChargingStationInfo = stationTemplateFromFile || {} as ChargingStationInfo;
authorizedTags = JSON.parse(fs.readFileSync(fileDescriptor, 'utf8')) as string[];
fs.closeSync(fileDescriptor);
} catch (error) {
- logger.error(this._logPrefix() + ' Authorization file ' + authorizationFile + ' loading error: ' + error);
+ logger.error(this._logPrefix() + ' Authorization file ' + authorizationFile + ' loading error: %j', error);
throw error;
}
} else {
if (!Utils.isEmptyArray(this._stationInfo.numberOfConnectors)) {
const numberOfConnectors = this._stationInfo.numberOfConnectors as number[];
// Distribute evenly the number of connectors
- maxConnectors = numberOfConnectors[(this._index - 1) % numberOfConnectors.length] ;
+ maxConnectors = numberOfConnectors[(this._index - 1) % numberOfConnectors.length];
} else if (!Utils.isUndefined(this._stationInfo.numberOfConnectors)) {
maxConnectors = this._stationInfo.numberOfConnectors as number;
} else {
}
_getSupervisionURL(): string {
- const supervisionUrls = Utils.cloneObject(this._stationInfo.supervisionURL ? this._stationInfo.supervisionURL : Configuration.getSupervisionURLs()) as string|string[];
+ const supervisionUrls = Utils.cloneObject(this._stationInfo.supervisionURL ? this._stationInfo.supervisionURL : Configuration.getSupervisionURLs()) as string | string[];
let indexUrl = 0;
if (!Utils.isEmptyArray(supervisionUrls)) {
- if (Configuration.getDistributeStationToTenantEqually()) {
+ if (Configuration.getDistributeStationsToTenantsEqually()) {
indexUrl = this._index % supervisionUrls.length;
} else {
// Get a random url
indexUrl = Math.floor(Math.random() * supervisionUrls.length);
}
- return supervisionUrls[indexUrl] ;
+ return supervisionUrls[indexUrl];
}
return supervisionUrls as string;
}
// Initialize _authorizedTags
this._authorizedTags = this._loadAndGetAuthorizedTags();
} catch (error) {
- logger.error(this._logPrefix() + ' Authorization file monitoring error: ' + error);
+ logger.error(this._logPrefix() + ' Authorization file monitoring error: %j', error);
}
});
}
this._automaticTransactionGeneration.stop().catch(() => { });
}
} catch (error) {
- logger.error(this._logPrefix() + ' Charging station template file monitoring error: ' + error);
+ logger.error(this._logPrefix() + ' Charging station template file monitoring error: %j', error);
}
});
}
}
_reconnect(error): void {
- logger.error(this._logPrefix() + ' Socket: abnormally closed', error);
+ logger.error(this._logPrefix() + ' Socket: abnormally closed: %j', error);
// Stop the ATG if needed
if (this._stationInfo.AutomaticTransactionGenerator.enable &&
this._stationInfo.AutomaticTransactionGenerator.stopOnConnectionFailure &&
this._automaticTransactionGeneration &&
!this._automaticTransactionGeneration.timeToStop) {
- this._automaticTransactionGeneration.stop().catch(() => {});
+ this._automaticTransactionGeneration.stop().catch(() => { });
}
// Stop heartbeat
this._stopHeartbeat();
if (this._hasSocketRestarted) {
this._startMessageSequence();
if (!Utils.isEmptyArray(this._messageQueue)) {
- this._messageQueue.forEach((message) => {
+ this._messageQueue.forEach((message, index) => {
if (this._wsConnection && this._wsConnection.readyState === WebSocket.OPEN) {
+ this._messageQueue.splice(index, 1);
this._wsConnection.send(message);
}
});
this._hasSocketRestarted = false;
}
- onError(error): void {
- switch (error) {
+ onError(errorEvent): void {
+ switch (errorEvent) {
case 'ECONNREFUSED':
this._hasSocketRestarted = true;
- this._reconnect(error);
+ this._reconnect(errorEvent);
break;
default:
- logger.error(this._logPrefix() + ' Socket error: ' + error);
+ logger.error(this._logPrefix() + ' Socket error: %j', errorEvent);
break;
}
}
- onClose(error): void {
- switch (error) {
+ onClose(closeEvent): void {
+ switch (closeEvent) {
case 1000: // Normal close
case 1005:
- logger.info(this._logPrefix() + ' Socket normally closed ' + error);
+ logger.info(this._logPrefix() + ' Socket normally closed: %j', closeEvent);
this._autoReconnectRetryCount = 0;
break;
default: // Abnormal close
this._hasSocketRestarted = true;
- this._reconnect(error);
+ this._reconnect(closeEvent);
break;
}
}
logger.debug(this._logPrefix() + ' Has received a WS ping (rfc6455) from the server');
}
- async onMessage(message): Promise<void> {
+ async onMessage(messageEvent): Promise<void> {
let [messageType, messageId, commandName, commandPayload, errorDetails] = [0, '', Constants.ENTITY_CHARGING_STATION, '', ''];
try {
// Parse the message
- [messageType, messageId, commandName, commandPayload, errorDetails] = JSON.parse(message);
+ [messageType, messageId, commandName, commandPayload, errorDetails] = JSON.parse(messageEvent);
// Check the Type of message
switch (messageType) {
}
} catch (error) {
// Log
- logger.error('%s Incoming message %j processing error %s on request content type %s', this._logPrefix(), message, error, this._requests[messageId]);
+ logger.error('%s Incoming message %j processing error %s on request content type %s', this._logPrefix(), messageEvent, error, this._requests[messageId]);
// Send error
await this.sendError(messageId, error, commandName);
}
};
await this.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'Heartbeat');
} catch (error) {
- logger.error(this._logPrefix() + ' Send Heartbeat error: ' + error);
+ logger.error(this._logPrefix() + ' Send Heartbeat error: %j', error);
throw error;
}
}
try {
await this.sendMessage(Utils.generateUUID(), this._bootNotificationMessage, Constants.OCPP_JSON_CALL_MESSAGE, 'BootNotification');
} catch (error) {
- logger.error(this._logPrefix() + ' Send BootNotification error: ' + error);
+ logger.error(this._logPrefix() + ' Send BootNotification error: %j', error);
throw error;
}
}
};
await this.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'StatusNotification');
} catch (error) {
- logger.error(this._logPrefix() + ' Send StatusNotification error: ' + error);
+ logger.error(this._logPrefix() + ' Send StatusNotification error: %j', error);
throw error;
}
}
};
return await this.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'StartTransaction') as StartTransactionResponse;
} catch (error) {
- logger.error(this._logPrefix() + ' Send StartTransaction error: ' + error);
+ logger.error(this._logPrefix() + ' Send StartTransaction error: %j', error);
throw error;
}
}
};
return await this.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'StopTransaction') as StartTransactionResponse;
} catch (error) {
- logger.error(this._logPrefix() + ' Send StopTransaction error: ' + error);
+ logger.error(this._logPrefix() + ' Send StopTransaction error: %j', error);
throw error;
}
}
...!Utils.isUndefined(meterValuesTemplate[index].context) && { context: meterValuesTemplate[index].context },
...!Utils.isUndefined(meterValuesTemplate[index].measurand) && { measurand: meterValuesTemplate[index].measurand },
...!Utils.isUndefined(meterValuesTemplate[index].location) && { location: meterValuesTemplate[index].location },
- ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: powerMeasurandValues[`L${phase}`] },
+ ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: powerMeasurandValues[`L${phase}`] as string },
phase: phaseValue as MeterValuePhase,
});
}
...!Utils.isUndefined(meterValuesTemplate[index].context) && { context: meterValuesTemplate[index].context },
...!Utils.isUndefined(meterValuesTemplate[index].measurand) && { measurand: meterValuesTemplate[index].measurand },
...!Utils.isUndefined(meterValuesTemplate[index].location) && { location: meterValuesTemplate[index].location },
- ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: currentMeasurandValues[phaseValue] },
+ ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: currentMeasurandValues[phaseValue] as string },
phase: phaseValue as MeterValuePhase,
});
}
...!Utils.isUndefined(meterValuesTemplate[index].context) && { context: meterValuesTemplate[index].context },
...!Utils.isUndefined(meterValuesTemplate[index].measurand) && { measurand: meterValuesTemplate[index].measurand },
...!Utils.isUndefined(meterValuesTemplate[index].location) && { location: meterValuesTemplate[index].location },
- ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: connector.lastEnergyActiveImportRegisterValue.toString() },
+ ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } :
+ { value: connector.lastEnergyActiveImportRegisterValue.toString() },
});
const sampledValuesIndex = sampledValues.sampledValue.length - 1;
const maxConsumption = Math.round(self._stationInfo.maxPower * 3600 / (self._stationInfo.powerDivider * interval));
};
await self.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'MeterValues');
} catch (error) {
- logger.error(self._logPrefix() + ' Send MeterValues error: ' + error);
+ logger.error(self._logPrefix() + ' Send MeterValues error: %j', error);
throw error;
}
}
if (self.getEnableStatistics()) {
self._statistics.addMessage(commandName, messageType);
}
- logger.debug(`${self._logPrefix()} Error %j occurred when calling command %s with parameters %j`, error, commandName, commandParams);
+ logger.debug(`${self._logPrefix()} Error: %j occurred when calling command %s with parameters: %j`, error, commandName, commandParams);
// Build Exception
// eslint-disable-next-line no-empty-function
self._requests[messageId] = [() => { }, () => { }, {}]; // Properly format the request
}
handleResponseStartTransaction(payload: StartTransactionResponse, requestPayload): void {
- if (this.getConnector(requestPayload.connectorId).transactionStarted) {
- logger.debug(this._logPrefix() + ' Try to start a transaction on an already used connector ' + requestPayload.connectorId + ': %s', this.getConnector(requestPayload.connectorId));
+ const connectorId = Utils.convertToInt(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) === Utils.convertToInt(requestPayload.connectorId)) {
+ if (Utils.convertToInt(connector) === connectorId) {
transactionConnectorId = Utils.convertToInt(connector);
break;
}
}
if (!transactionConnectorId) {
- logger.error(this._logPrefix() + ' Try to start a transaction on a non existing connector Id ' + requestPayload.connectorId);
+ 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(requestPayload.connectorId).transactionStarted = true;
- this.getConnector(requestPayload.connectorId).transactionId = payload.transactionId;
- this.getConnector(requestPayload.connectorId).idTag = requestPayload.idTag;
- this.getConnector(requestPayload.connectorId).lastEnergyActiveImportRegisterValue = 0;
- this.sendStatusNotification(requestPayload.connectorId, ChargePointStatus.CHARGING);
- logger.info(this._logPrefix() + ' Transaction ' + payload.transactionId + ' STARTED on ' + this._stationInfo.name + '#' + requestPayload.connectorId + ' for idTag ' + requestPayload.idTag);
+ this.getConnector(connectorId).transactionStarted = true;
+ this.getConnector(connectorId).transactionId = payload.transactionId;
+ this.getConnector(connectorId).idTag = requestPayload.idTag;
+ this.getConnector(connectorId).lastEnergyActiveImportRegisterValue = 0;
+ this.sendStatusNotification(connectorId, ChargePointStatus.CHARGING).catch(() => { });
+ 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(requestPayload.connectorId,
+ this._startMeterValues(connectorId,
configuredMeterValueSampleInterval ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000 : 60000);
} else {
- logger.error(this._logPrefix() + ' Starting transaction id ' + payload.transactionId + ' REJECTED with status ' + payload.idTagInfo?.status + ', idTag ' + requestPayload.idTag);
- this._resetTransactionOnConnector(requestPayload.connectorId);
- this.sendStatusNotification(requestPayload.connectorId, ChargePointStatus.AVAILABLE);
+ logger.error(this._logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + ' REJECTED with status ' + payload.idTagInfo?.status + ', idTag ' + requestPayload.idTag);
+ this._resetTransactionOnConnector(connectorId);
+ this.sendStatusNotification(connectorId, ChargePointStatus.AVAILABLE).catch(() => { });
}
}
handleResponseStopTransaction(payload: StopTransactionResponse, requestPayload): void {
let transactionConnectorId: number;
for (const connector in this._connectors) {
- if (this.getConnector(Utils.convertToInt(connector)).transactionId === requestPayload.transactionId) {
+ if (this.getConnector(Utils.convertToInt(connector)).transactionId === Utils.convertToInt(requestPayload.transactionId)) {
transactionConnectorId = Utils.convertToInt(connector);
break;
}
}
if (!transactionConnectorId) {
- logger.error(this._logPrefix() + ' Try to stop a non existing transaction ' + requestPayload.transactionId);
+ logger.error(this._logPrefix() + ' Trying to stop a non existing transaction ' + requestPayload.transactionId);
return;
}
if (payload.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
- this.sendStatusNotification(transactionConnectorId, ChargePointStatus.AVAILABLE);
+ this.sendStatusNotification(transactionConnectorId, ChargePointStatus.AVAILABLE).catch(() => { });
if (this._stationInfo.powerSharedByConnectors) {
this._stationInfo.powerDivider--;
}
response = await this['handleRequest' + commandName](commandPayload);
} catch (error) {
// Log
- logger.error(this._logPrefix() + ' Handle request error: ' + error);
+ logger.error(this._logPrefix() + ' Handle request error: %j', error);
// Send back response to inform backend
await this.sendError(messageId, error, commandName);
throw error;
async handleRequestUnlockConnector(commandPayload): Promise<UnlockResponse> {
const connectorId = Utils.convertToInt(commandPayload.connectorId);
if (connectorId === 0) {
- logger.error(this._logPrefix() + ' Try to unlock connector ' + connectorId.toString());
+ logger.error(this._logPrefix() + ' Trying to unlock connector ' + connectorId.toString());
return Constants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED;
}
if (this.getConnector(connectorId).transactionStarted) {
return Constants.OCPP_RESPONSE_ACCEPTED;
}
}
- logger.info(this._logPrefix() + ' Try to stop remotely a non existing transaction ' + commandPayload.transactionId);
+ logger.info(this._logPrefix() + ' Trying to remote stop a non existing transaction ' + transactionId.toString());
return Constants.OCPP_RESPONSE_REJECTED;
}
}