]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
fix: align ConnectionTimeOut semantics with OCPP spec
authorJérôme Benoit <jerome.benoit@sap.com>
Sat, 28 Mar 2026 14:36:18 +0000 (15:36 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Sat, 28 Mar 2026 14:36:18 +0000 (15:36 +0100)
ConnectionTimeOut/EVConnectionTimeOut is the EV cable insertion timeout
per OCPP 1.6 §9.1.6 and OCPP 2.0.1 TxCtrlr spec, not a WebSocket
timeout. Split DEFAULT_CONNECTION_TIMEOUT into three purpose-specific
constants:
- DEFAULT_EV_CONNECTION_TIMEOUT (180s): OCPP cable insertion timeout
- DEFAULT_WS_HANDSHAKE_TIMEOUT (30s): WebSocket handshake timeout
- DEFAULT_WS_RECONNECT_DELAY (30s): WebSocket reconnection delay
- DEFAULT_MESSAGE_TIMEOUT (30s): OCPP 2.0 MessageTimeout default

Dissociate WebSocket handshake/reconnect from OCPP ConnectionTimeOut
configuration. Initialize ConnectionTimeOut with 180s per spec.

src/charging-station/ChargingStation.ts
src/charging-station/ocpp/2.0/OCPP20VariableRegistry.ts
src/utils/Constants.ts
tests/charging-station/ocpp/2.0/OCPP20VariableManager.test.ts

index d2049f4038df0b8c420f1c346a2fbdbf3ffae707..47e644fb0fe3deaf72ccac4a1a2eaebe985ed50d 100644 (file)
@@ -448,10 +448,10 @@ export class ChargingStation extends EventEmitter {
     if (getConfigurationKey(this, StandardParametersKey.ConnectionTimeOut) != null) {
       return convertToInt(
         getConfigurationKey(this, StandardParametersKey.ConnectionTimeOut)?.value ??
-          Constants.DEFAULT_CONNECTION_TIMEOUT
+          Constants.DEFAULT_EV_CONNECTION_TIMEOUT
       )
     }
-    return Constants.DEFAULT_CONNECTION_TIMEOUT
+    return Constants.DEFAULT_EV_CONNECTION_TIMEOUT
   }
 
   /**
@@ -904,7 +904,7 @@ export class ChargingStation extends EventEmitter {
     params?: { closeOpened?: boolean; terminateOpened?: boolean }
   ): void {
     options = {
-      handshakeTimeout: secondsToMilliseconds(this.getConnectionTimeout()),
+      handshakeTimeout: secondsToMilliseconds(Constants.DEFAULT_WS_HANDSHAKE_TIMEOUT),
       ...this.stationInfo?.wsOptions,
       ...options,
     }
@@ -2154,7 +2154,7 @@ export class ChargingStation extends EventEmitter {
       addConfigurationKey(
         this,
         StandardParametersKey.ConnectionTimeOut,
-        Constants.DEFAULT_CONNECTION_TIMEOUT.toString()
+        Constants.DEFAULT_EV_CONNECTION_TIMEOUT.toString()
       )
     }
     this.saveOcppConfiguration()
@@ -2407,7 +2407,7 @@ export class ChargingStation extends EventEmitter {
       const reconnectDelay =
         this.stationInfo?.reconnectExponentialDelay === true
           ? exponentialDelay(this.wsConnectionRetryCount)
-          : secondsToMilliseconds(this.getConnectionTimeout())
+          : secondsToMilliseconds(Constants.DEFAULT_WS_RECONNECT_DELAY)
       const reconnectDelayWithdraw = 1000
       const reconnectTimeout =
         reconnectDelay - reconnectDelayWithdraw > 0 ? reconnectDelay - reconnectDelayWithdraw : 0
index 88b7f0c1063f58be901b6be458cf17fac4da6b23..617e235fc3c550f44e02e3cdf770810448e9617a 100644 (file)
@@ -1529,7 +1529,7 @@ export const VARIABLE_REGISTRY: Record<string, VariableMetadata> = {
   )]: {
     component: OCPP20ComponentName.OCPPCommCtrlr,
     dataType: DataEnumType.integer,
-    defaultValue: Constants.DEFAULT_CONNECTION_TIMEOUT.toString(),
+    defaultValue: Constants.DEFAULT_MESSAGE_TIMEOUT.toString(),
     description: 'Timeout (in seconds) waiting for responses to general OCPP messages.',
     instance: 'Default',
     max: 3600,
index 750942321cde1a0016eed52c415df3e9dfd0a930..18f745faf9b154863481da1f6e6bf3e21dbc8dca 100644 (file)
@@ -27,26 +27,25 @@ export class Constants {
   static readonly DEFAULT_BOOT_NOTIFICATION_INTERVAL = 60000 // Ms
 
   static readonly DEFAULT_CIRCULAR_BUFFER_CAPACITY = 386
-  static readonly DEFAULT_CONNECTION_TIMEOUT = 30 // Seconds
   static readonly DEFAULT_EV_CONNECTION_TIMEOUT = 180 // Seconds
-
   static readonly DEFAULT_FLUCTUATION_PERCENT = 5
   static readonly DEFAULT_HASH_ALGORITHM = 'sha384'
 
   static readonly DEFAULT_HEARTBEAT_INTERVAL = 60000 // Ms
-
   static readonly DEFAULT_IDTAG = '00000000'
 
   static readonly DEFAULT_LOG_STATISTICS_INTERVAL = 60 // Seconds
 
   static readonly DEFAULT_MESSAGE_BUFFER_FLUSH_INTERVAL = 60000 // Ms
 
+  static readonly DEFAULT_MESSAGE_TIMEOUT = 30 // Seconds
+
   static readonly DEFAULT_METER_VALUES_INTERVAL = 60000 // Ms
 
   static readonly DEFAULT_PERFORMANCE_DIRECTORY = 'performance'
+
   static readonly DEFAULT_PERFORMANCE_RECORDS_DB_NAME = 'e-mobility-charging-stations-simulator'
   static readonly DEFAULT_PERFORMANCE_RECORDS_FILENAME = 'performanceRecords.json'
-
   static readonly DEFAULT_STATION_INFO: Readonly<Partial<ChargingStationInfo>> = Object.freeze({
     automaticTransactionGeneratorPersistentConfiguration: true,
     autoReconnectMaxRetries: -1,
@@ -86,10 +85,13 @@ export class Constants {
   static readonly DEFAULT_TX_UPDATED_INTERVAL = 30 // Seconds
 
   static readonly DEFAULT_UI_SERVER_HOST = 'localhost'
-  static readonly DEFAULT_UI_SERVER_PORT = 8080
 
+  static readonly DEFAULT_UI_SERVER_PORT = 8080
   static readonly DEFAULT_WEBSOCKET_PING_INTERVAL = 30 // Seconds
 
+  static readonly DEFAULT_WS_HANDSHAKE_TIMEOUT = 30 // Seconds
+  static readonly DEFAULT_WS_RECONNECT_DELAY = 30 // Seconds
+
   static readonly EMPTY_FROZEN_OBJECT = Object.freeze({})
 
   static readonly EMPTY_FUNCTION: () => void = Object.freeze(() => {
index c2accbee28c3fb69fed87824d70084a771742b78..6e5fd3b40658b2d44c2a76184b37d374d6b63e09 100644 (file)
@@ -377,7 +377,7 @@ await describe('B05 - OCPP20VariableManager', async () => {
       // Third variable: MessageTimeout
       assert.strictEqual(result[2].attributeStatus, GetVariableStatusEnumType.Accepted)
       assert.strictEqual(result[2].attributeType, AttributeEnumType.Actual)
-      assert.strictEqual(result[2].attributeValue, Constants.DEFAULT_CONNECTION_TIMEOUT.toString())
+      assert.strictEqual(result[2].attributeValue, Constants.DEFAULT_MESSAGE_TIMEOUT.toString())
       assert.strictEqual(result[2].component.name, OCPP20ComponentName.OCPPCommCtrlr)
       assert.strictEqual(result[2].component.instance, 'Default')
       assert.strictEqual(result[2].variable.name, OCPP20RequiredVariableName.MessageTimeout)
@@ -1009,7 +1009,7 @@ await describe('B05 - OCPP20VariableManager', async () => {
     await it('should validate MessageTimeout positive integer >0 and reject invalid', () => {
       const okRes = manager.setVariables(station, [
         {
-          attributeValue: (Constants.DEFAULT_CONNECTION_TIMEOUT + 5).toString(),
+          attributeValue: (Constants.DEFAULT_MESSAGE_TIMEOUT + 5).toString(),
           component: { instance: 'Default', name: OCPP20ComponentName.OCPPCommCtrlr },
           variable: { name: OCPP20RequiredVariableName.MessageTimeout },
         },