The feature is still buggy ...
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
"ws://server:8010/OCPP16/5c866e81a2d9593de43efdb4"
],
"statisticsDisplayInterval": 60,
"ws://server:8010/OCPP16/5c866e81a2d9593de43efdb4"
],
"statisticsDisplayInterval": 60,
- "autoReconnectTimeout": 10,
+ "connectionTimeout": 10,
"autoReconnectMaxRetries": 10,
"distributeStationsToTenantsEqually": true,
"useWorkerPool": false,
"autoReconnectMaxRetries": 10,
"distributeStationsToTenantsEqually": true,
"useWorkerPool": false,
"supervisionURLs": [
"ws://localhost:8010/OCPP16/5be7fb271014d90008992f06"
],
"supervisionURLs": [
"ws://localhost:8010/OCPP16/5be7fb271014d90008992f06"
],
- "autoReconnectTimeout": 10,
+ "connectionTimeout": 10,
"autoReconnectMaxRetries": 10,
"statisticsDisplayInterval": 60,
"distributeStationsToTenantsEqually": true,
"autoReconnectMaxRetries": 10,
"statisticsDisplayInterval": 60,
"distributeStationsToTenantsEqually": true,
private _wsConnection: WebSocket;
private _hasStopped: boolean;
private _hasSocketRestarted: boolean;
private _wsConnection: WebSocket;
private _hasStopped: boolean;
private _hasSocketRestarted: boolean;
+ private _connectionTimeout: number;
private _autoReconnectRetryCount: number;
private _autoReconnectMaxRetries: number;
private _autoReconnectRetryCount: number;
private _autoReconnectMaxRetries: number;
- private _autoReconnectTimeout: number;
private _requests: Requests;
private _messageQueue: string[];
private _automaticTransactionGeneration: AutomaticTransactionGenerator;
private _requests: Requests;
private _messageQueue: string[];
private _automaticTransactionGeneration: AutomaticTransactionGenerator;
this._hasStopped = false;
this._hasSocketRestarted = false;
this._hasStopped = false;
this._hasSocketRestarted = false;
+ this._connectionTimeout = Configuration.getConnectionTimeout() * 1000; // Ms, zero for disabling
this._autoReconnectRetryCount = 0;
this._autoReconnectMaxRetries = Configuration.getAutoReconnectMaxRetries(); // -1 for unlimited
this._autoReconnectRetryCount = 0;
this._autoReconnectMaxRetries = Configuration.getAutoReconnectMaxRetries(); // -1 for unlimited
- this._autoReconnectTimeout = Configuration.getAutoReconnectTimeout() * 1000; // Ms, zero for disabling
this._requests = {} as Requests;
this._messageQueue = [] as string[];
this._requests = {} as Requests;
this._messageQueue = [] as string[];
return !Utils.isUndefined(this._stationInfo.voltageOut) ? Utils.convertToInt(this._stationInfo.voltageOut) : defaultVoltageOut;
}
return !Utils.isUndefined(this._stationInfo.voltageOut) ? Utils.convertToInt(this._stationInfo.voltageOut) : defaultVoltageOut;
}
- _getTransactionidTag(transactionId: number): string {
+ _getTransactionIdTag(transactionId: number): string {
for (const connector in this._connectors) {
if (this.getConnector(Utils.convertToInt(connector)).transactionId === transactionId) {
return this.getConnector(Utils.convertToInt(connector)).idTag;
for (const connector in this._connectors) {
if (this.getConnector(Utils.convertToInt(connector)).transactionId === transactionId) {
return this.getConnector(Utils.convertToInt(connector)).idTag;
return supervisionUrls as string;
}
return supervisionUrls as string;
}
+ _getReconnectExponentialDelay(): boolean {
+ return !Utils.isUndefined(this._stationInfo.reconnectExponentialDelay) ? this._stationInfo.reconnectExponentialDelay : false;
+ }
+
_getAuthorizeRemoteTxRequests(): boolean {
const authorizeRemoteTxRequests = this._getConfigurationKey('AuthorizeRemoteTxRequests');
return authorizeRemoteTxRequests ? Utils.convertToBoolean(authorizeRemoteTxRequests.value) : false;
_getAuthorizeRemoteTxRequests(): boolean {
const authorizeRemoteTxRequests = this._getConfigurationKey('AuthorizeRemoteTxRequests');
return authorizeRemoteTxRequests ? Utils.convertToBoolean(authorizeRemoteTxRequests.value) : false;
- _openWSConnection(): void {
- this._wsConnection = new WebSocket(this._wsConnectionUrl, 'ocpp' + Constants.OCPP_VERSION_16);
+ _openWSConnection(options?: WebSocket.ClientOptions): void {
+ if (Utils.isUndefined(options)) {
+ options = {} as WebSocket.ClientOptions;
+ }
+ if (Utils.isUndefined(options.handshakeTimeout)) {
+ options.handshakeTimeout = this._connectionTimeout;
+ }
+ this._wsConnection = new WebSocket(this._wsConnectionUrl, 'ocpp' + Constants.OCPP_VERSION_16, options);
logger.info(this._logPrefix() + ' Will communicate through URL ' + this._supervisionUrl);
}
logger.info(this._logPrefix() + ' Will communicate through URL ' + this._supervisionUrl);
}
this._hasStopped = true;
}
this._hasStopped = true;
}
- _reconnect(error): void {
+ async _reconnect(error): Promise<void> {
logger.error(this._logPrefix() + ' Socket: abnormally closed: %j', error);
// Stop heartbeat
this._stopHeartbeat();
logger.error(this._logPrefix() + ' Socket: abnormally closed: %j', error);
// Stop heartbeat
this._stopHeartbeat();
!this._automaticTransactionGeneration.timeToStop) {
this._automaticTransactionGeneration.stop().catch(() => { });
}
!this._automaticTransactionGeneration.timeToStop) {
this._automaticTransactionGeneration.stop().catch(() => { });
}
- if (this._autoReconnectTimeout !== 0 &&
- (this._autoReconnectRetryCount < this._autoReconnectMaxRetries || this._autoReconnectMaxRetries === -1)) {
- logger.error(`${this._logPrefix()} Socket: connection retry with timeout ${this._autoReconnectTimeout}ms`);
+ if (this._autoReconnectRetryCount < this._autoReconnectMaxRetries || this._autoReconnectMaxRetries === -1) {
this._autoReconnectRetryCount++;
this._autoReconnectRetryCount++;
- setTimeout(() => {
- logger.error(this._logPrefix() + ' Socket: reconnecting try #' + this._autoReconnectRetryCount.toString());
- this._openWSConnection();
- }, this._autoReconnectTimeout);
- } else if (this._autoReconnectTimeout !== 0 || this._autoReconnectMaxRetries !== -1) {
- logger.error(`${this._logPrefix()} Socket: max retries reached (${this._autoReconnectRetryCount}) or retry disabled (${this._autoReconnectTimeout})`);
+ const reconnectDelay = (this._getReconnectExponentialDelay() ? Utils.exponentialDelay(this._autoReconnectRetryCount) : this._connectionTimeout);
+ logger.error(`${this._logPrefix()} Socket: connection retry in ${Utils.roundTo(reconnectDelay, 2)}ms, timeout ${reconnectDelay - 100}ms`);
+ await Utils.sleep(reconnectDelay);
+ logger.error(this._logPrefix() + ' Socket: reconnecting try #' + this._autoReconnectRetryCount.toString());
+ this._openWSConnection({ handshakeTimeout : reconnectDelay - 100 });
+ } else if (this._autoReconnectMaxRetries !== -1) {
+ logger.error(`${this._logPrefix()} Socket: max retries reached (${this._autoReconnectRetryCount}) or retry disabled (${this._autoReconnectMaxRetries})`);
- this._hasSocketRestarted = false;
this._autoReconnectRetryCount = 0;
this._autoReconnectRetryCount = 0;
+ this._hasSocketRestarted = false;
- onError(errorEvent): void {
+ async onError(errorEvent): Promise<void> {
switch (errorEvent.code) {
case 'ECONNREFUSED':
this._hasSocketRestarted = true;
switch (errorEvent.code) {
case 'ECONNREFUSED':
this._hasSocketRestarted = true;
- this._reconnect(errorEvent);
+ await this._reconnect(errorEvent);
break;
default:
logger.error(this._logPrefix() + ' Socket error: %j', errorEvent);
break;
default:
logger.error(this._logPrefix() + ' Socket error: %j', errorEvent);
- onClose(closeEvent): void {
+ async onClose(closeEvent): Promise<void> {
switch (closeEvent) {
case 1000: // Normal close
case 1005:
switch (closeEvent) {
case 1000: // Normal close
case 1005:
break;
default: // Abnormal close
this._hasSocketRestarted = true;
break;
default: // Abnormal close
this._hasSocketRestarted = true;
- this._reconnect(closeEvent);
+ await this._reconnect(closeEvent);
}
async sendStopTransaction(transactionId: number, reason: StopTransactionReason = StopTransactionReason.NONE): Promise<StopTransactionResponse> {
}
async sendStopTransaction(transactionId: number, reason: StopTransactionReason = StopTransactionReason.NONE): Promise<StopTransactionResponse> {
- const idTag = this._getTransactionidTag(transactionId);
+ const idTag = this._getTransactionIdTag(transactionId);
try {
const payload = {
transactionId,
try {
const payload = {
transactionId,
useConnectorId0?: boolean;
randomConnectors?: boolean;
resetTime?: number;
useConnectorId0?: boolean;
randomConnectors?: boolean;
resetTime?: number;
+ reconnectExponentialDelay?: boolean;
enableStatistics?: boolean;
voltageOut?: number;
Configuration?: ChargingStationConfiguration;
enableStatistics?: boolean;
voltageOut?: number;
Configuration?: ChargingStationConfiguration;
supervisionURLs?: string[];
stationTemplateURLs: StationTemplateURL[];
statisticsDisplayInterval?: number;
supervisionURLs?: string[];
stationTemplateURLs: StationTemplateURL[];
statisticsDisplayInterval?: number;
- autoReconnectTimeout?: number;
+ connectionTimeout?: number;
autoReconnectMaxRetries?: number;
distributeStationsToTenantsEqually?: boolean;
useWorkerPool?: boolean;
autoReconnectMaxRetries?: number;
distributeStationsToTenantsEqually?: boolean;
useWorkerPool?: boolean;
return Utils.objectHasOwnProperty(Configuration.getConfig(), 'statisticsDisplayInterval') ? Configuration.getConfig().statisticsDisplayInterval : 60;
}
return Utils.objectHasOwnProperty(Configuration.getConfig(), 'statisticsDisplayInterval') ? Configuration.getConfig().statisticsDisplayInterval : 60;
}
- static getAutoReconnectTimeout(): number {
+ static getConnectionTimeout(): number {
+ Configuration.deprecateConfigurationKey('autoReconnectTimeout', 'Use \'connectionTimeout\' instead');
- return Utils.objectHasOwnProperty(Configuration.getConfig(), 'autoReconnectTimeout') ? Configuration.getConfig().autoReconnectTimeout : 10;
+ return Utils.objectHasOwnProperty(Configuration.getConfig(), 'connectionTimeout') ? Configuration.getConfig().connectionTimeout : 10;
}
static getAutoReconnectMaxRetries(): number {
}
static getAutoReconnectMaxRetries(): number {
}
static insertAt = (str: string, subStr: string, pos: number): string => `${str.slice(0, pos)}${subStr}${str.slice(pos)}`;
}
static insertAt = (str: string, subStr: string, pos: number): string => `${str.slice(0, pos)}${subStr}${str.slice(pos)}`;
+
+ /**
+ * @param {number} [retryNumber=0]
+ * @return {number} - delay in milliseconds
+ */
+ static exponentialDelay(retryNumber = 0): number {
+ const delay = Math.pow(2, retryNumber) * 100;
+ const randomSum = delay * 0.2 * Math.random(); // 0-20% of the delay
+ return delay + randomSum;
+ }