]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
refactor: replace string literals with OCPP enum constants
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 3 Apr 2026 15:09:52 +0000 (17:09 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 3 Apr 2026 15:09:52 +0000 (17:09 +0200)
Add AllowReset and MasterPassGroupId to OCPP20OptionalVariableName
enum. Replace all hardcoded OCPP variable name strings with enum
references in source and test files. Move EVSE Component section
comment to correct position.

src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts
src/charging-station/ocpp/2.0/OCPP20VariableRegistry.ts
src/types/ocpp/2.0/Variables.ts
tests/charging-station/SharedLRUCache.test.ts
tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-MasterPass.test.ts
tests/charging-station/ocpp/2.0/OCPP20Integration.test.ts
tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-enforceMessageLimits.test.ts

index a175e806752719eabd5452d916db9c6dc16fcde6..eeb89f2b677f4869863afd249e178a5aca110b43 100644 (file)
@@ -1971,7 +1971,7 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
       !OCPP20ServiceUtils.readVariableAsBoolean(
         chargingStation,
         OCPP20ComponentName.EVSE,
-        'AllowReset',
+        OCPP20OptionalVariableName.AllowReset,
         true
       )
     ) {
@@ -2371,7 +2371,7 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
       const masterPassGroupId = OCPP20ServiceUtils.readVariableValue(
         chargingStation,
         OCPP20ComponentName.AuthCtrlr,
-        'MasterPassGroupId'
+        OCPP20OptionalVariableName.MasterPassGroupId
       )
       if (
         masterPassGroupId != null &&
index f8819f8c446d5e94df5e949006f6b0c40459c9b7..1de52d7eff520d15d21c4672d1829df0cf32c575 100644 (file)
@@ -365,17 +365,6 @@ export const VARIABLE_REGISTRY: Record<string, VariableMetadata> = {
     variable: 'DisableRemoteAuthorization',
   },
 
-  [buildRegistryKey(OCPP20ComponentName.AuthCtrlr, 'MasterPassGroupId')]: {
-    component: OCPP20ComponentName.AuthCtrlr,
-    dataType: DataEnumType.string,
-    description:
-      'IdTokens that have this id as groupId belong to the Master Pass Group. They can stop any ongoing transaction but cannot start transactions.',
-    maxLength: 36,
-    mutability: MutabilityEnumType.ReadWrite,
-    persistence: PersistenceEnumType.Persistent,
-    supportedAttributes: [AttributeEnumType.Actual],
-    variable: 'MasterPassGroupId',
-  },
   [buildRegistryKey(OCPP20ComponentName.AuthCtrlr, 'OfflineTxForUnknownIdEnabled')]: {
     component: OCPP20ComponentName.AuthCtrlr,
     dataType: DataEnumType.boolean,
@@ -386,6 +375,17 @@ export const VARIABLE_REGISTRY: Record<string, VariableMetadata> = {
     supportedAttributes: [AttributeEnumType.Actual],
     variable: 'OfflineTxForUnknownIdEnabled',
   },
+  [buildRegistryKey(OCPP20ComponentName.AuthCtrlr, OCPP20OptionalVariableName.MasterPassGroupId)]: {
+    component: OCPP20ComponentName.AuthCtrlr,
+    dataType: DataEnumType.string,
+    description:
+      'IdTokens that have this id as groupId belong to the Master Pass Group. They can stop any ongoing transaction but cannot start transactions.',
+    maxLength: 36,
+    mutability: MutabilityEnumType.ReadWrite,
+    persistence: PersistenceEnumType.Persistent,
+    supportedAttributes: [AttributeEnumType.Actual],
+    variable: OCPP20OptionalVariableName.MasterPassGroupId,
+  },
   [buildRegistryKey(
     OCPP20ComponentName.AuthCtrlr,
     OCPP20RequiredVariableName.AuthorizeRemoteStart
@@ -944,16 +944,6 @@ export const VARIABLE_REGISTRY: Record<string, VariableMetadata> = {
   },
 
   // EVSE Component
-  [buildRegistryKey(OCPP20ComponentName.EVSE, 'AllowReset')]: {
-    component: OCPP20ComponentName.EVSE,
-    dataType: DataEnumType.boolean,
-    defaultValue: 'true',
-    description: 'Can be used to announce that an EVSE can be reset individually',
-    mutability: MutabilityEnumType.ReadOnly,
-    persistence: PersistenceEnumType.Persistent,
-    supportedAttributes: [AttributeEnumType.Actual],
-    variable: 'AllowReset',
-  },
   [buildRegistryKey(OCPP20ComponentName.EVSE, 'Available')]: {
     component: OCPP20ComponentName.EVSE,
     dataType: DataEnumType.boolean,
@@ -1031,6 +1021,16 @@ export const VARIABLE_REGISTRY: Record<string, VariableMetadata> = {
     supportedAttributes: [AttributeEnumType.Actual],
     variable: OCPP20DeviceInfoVariableName.AvailabilityState,
   },
+  [buildRegistryKey(OCPP20ComponentName.EVSE, OCPP20OptionalVariableName.AllowReset)]: {
+    component: OCPP20ComponentName.EVSE,
+    dataType: DataEnumType.boolean,
+    defaultValue: 'true',
+    description: 'Can be used to announce that an EVSE can be reset individually',
+    mutability: MutabilityEnumType.ReadOnly,
+    persistence: PersistenceEnumType.Persistent,
+    supportedAttributes: [AttributeEnumType.Actual],
+    variable: OCPP20OptionalVariableName.AllowReset,
+  },
 
   // FirmwareCtrlr Component
   [buildRegistryKey(
index 9c59e0f663a918f02f4be40e56db12b9d4629863..d2a01c8943aeea057708a53a694bf67b7ba6e4a5 100644 (file)
@@ -33,10 +33,12 @@ export enum OCPP20DeviceInfoVariableName {
 }
 
 export enum OCPP20OptionalVariableName {
+  AllowReset = 'AllowReset',
   CertSigningRepeatTimes = 'CertSigningRepeatTimes',
   CertSigningWaitMinimum = 'CertSigningWaitMinimum',
   ConfigurationValueSize = 'ConfigurationValueSize',
   HeartbeatInterval = 'HeartbeatInterval',
+  MasterPassGroupId = 'MasterPassGroupId',
   MaxCertificateChainSize = 'MaxCertificateChainSize',
   MaxEnergyOnInvalidId = 'MaxEnergyOnInvalidId',
   NonEvseSpecific = 'NonEvseSpecific',
index e803d810f5033e8f52f35ff3f5d62349dfbb6d32..e81c36eee5ee8c5f65525b6e54655ae88fd7224f 100644 (file)
@@ -19,6 +19,7 @@ import type {
 
 import { Bootstrap } from '../../src/charging-station/Bootstrap.js'
 import { SharedLRUCache } from '../../src/charging-station/SharedLRUCache.js'
+import { OCPP16StandardParametersKey } from '../../src/types/index.js'
 import { standardCleanup } from '../helpers/TestLifecycleHelpers.js'
 
 interface BootstrapStatic {
@@ -34,7 +35,9 @@ function createCacheableConfiguration (hash: string): ChargingStationConfigurati
   return {
     automaticTransactionGenerator: { enable: false, maxDuration: 120, minDuration: 60 },
     configurationHash: hash,
-    configurationKey: [{ key: 'HeartbeatInterval', readonly: false, value: '60' }],
+    configurationKey: [
+      { key: OCPP16StandardParametersKey.HeartbeatInterval, readonly: false, value: '60' },
+    ],
     stationInfo: { chargingStationId: 'test-station' },
   } as unknown as ChargingStationConfiguration
 }
index 170873d5c4aefccd5fbc48ad17df52533758ed3d..bd30481beabfbcfa216f098cdef291900fc6c6f6 100644 (file)
@@ -18,6 +18,7 @@ import { OCPPAuthServiceFactory } from '../../../../src/charging-station/ocpp/au
 import {
   GetVariableStatusEnumType,
   OCPP20IdTokenEnumType,
+  OCPP20OptionalVariableName,
   OCPPVersion,
   RequestStartStopStatusEnumType,
 } from '../../../../src/types/index.js'
@@ -81,7 +82,7 @@ await describe('C12.FR.09 - MasterPassGroupId Check', async () => {
         const results = originalGetVariables(station, requests)
         for (let i = 0; i < (requests as { variable?: { name?: string } }[]).length; i++) {
           const req = (requests as { variable?: { name?: string } }[])[i]
-          if (req.variable?.name === 'MasterPassGroupId') {
+          if (req.variable?.name === OCPP20OptionalVariableName.MasterPassGroupId) {
             results[i] = {
               ...results[i],
               attributeStatus: GetVariableStatusEnumType.Accepted,
@@ -142,7 +143,7 @@ await describe('C12.FR.09 - MasterPassGroupId Check', async () => {
         const results = originalGetVariables(station, requests)
         for (let i = 0; i < (requests as { variable?: { name?: string } }[]).length; i++) {
           const req = (requests as { variable?: { name?: string } }[])[i]
-          if (req.variable?.name === 'MasterPassGroupId') {
+          if (req.variable?.name === OCPP20OptionalVariableName.MasterPassGroupId) {
             results[i] = {
               ...results[i],
               attributeStatus: GetVariableStatusEnumType.Accepted,
@@ -185,7 +186,7 @@ await describe('C12.FR.09 - MasterPassGroupId Check', async () => {
         const results = originalGetVariables(station, requests)
         for (let i = 0; i < (requests as { variable?: { name?: string } }[]).length; i++) {
           const req = (requests as { variable?: { name?: string } }[])[i]
-          if (req.variable?.name === 'MasterPassGroupId') {
+          if (req.variable?.name === OCPP20OptionalVariableName.MasterPassGroupId) {
             results[i] = {
               ...results[i],
               attributeStatus: GetVariableStatusEnumType.Accepted,
index 5c71ab6cbedf1100d12710cb05fcc114ad8bf7e0..69d3b4e80bbb7c14b2e95d4ae768f61ae8ef15bf 100644 (file)
@@ -21,6 +21,7 @@ import {
   AttributeEnumType,
   GetVariableStatusEnumType,
   OCPP20ComponentName,
+  OCPP20OptionalVariableName,
   OCPPVersion,
   SetVariableStatusEnumType,
 } from '../../../../src/types/index.js'
@@ -72,7 +73,7 @@ await describe('OCPP 2.0 Integration — SetVariables → GetVariables consisten
         {
           attributeValue: '60',
           component: { name: OCPP20ComponentName.OCPPCommCtrlr },
-          variable: { name: 'HeartbeatInterval' },
+          variable: { name: OCPP20OptionalVariableName.HeartbeatInterval },
         },
       ],
     }
@@ -81,7 +82,7 @@ await describe('OCPP 2.0 Integration — SetVariables → GetVariables consisten
         {
           attributeType: AttributeEnumType.Actual,
           component: { name: OCPP20ComponentName.OCPPCommCtrlr },
-          variable: { name: 'HeartbeatInterval' },
+          variable: { name: OCPP20OptionalVariableName.HeartbeatInterval },
         },
       ],
     }
@@ -133,12 +134,12 @@ await describe('OCPP 2.0 Integration — SetVariables → GetVariables consisten
         {
           attributeValue: '30',
           component: { name: OCPP20ComponentName.OCPPCommCtrlr },
-          variable: { name: 'HeartbeatInterval' },
+          variable: { name: OCPP20OptionalVariableName.HeartbeatInterval },
         },
         {
           attributeValue: '20',
           component: { name: OCPP20ComponentName.OCPPCommCtrlr },
-          variable: { name: 'WebSocketPingInterval' },
+          variable: { name: OCPP20OptionalVariableName.WebSocketPingInterval },
         },
       ],
     }
@@ -150,11 +151,11 @@ await describe('OCPP 2.0 Integration — SetVariables → GetVariables consisten
       getVariableData: [
         {
           component: { name: OCPP20ComponentName.OCPPCommCtrlr },
-          variable: { name: 'HeartbeatInterval' },
+          variable: { name: OCPP20OptionalVariableName.HeartbeatInterval },
         },
         {
           component: { name: OCPP20ComponentName.OCPPCommCtrlr },
-          variable: { name: 'WebSocketPingInterval' },
+          variable: { name: OCPP20OptionalVariableName.WebSocketPingInterval },
         },
       ],
     }
index de5a44848c7c2b3187377777b7488899f8b86d8c..3d4cd91100fc6e00927bbff31e1ba8dbc60a3da1 100644 (file)
@@ -10,7 +10,7 @@ import {
   OCPP20ServiceUtils,
   type RejectionReason,
 } from '../../../../src/charging-station/ocpp/2.0/OCPP20ServiceUtils.js'
-import { ReasonCodeEnumType } from '../../../../src/types/index.js'
+import { OCPP20OptionalVariableName, ReasonCodeEnumType } from '../../../../src/types/index.js'
 import { standardCleanup } from '../../../helpers/TestLifecycleHelpers.js'
 
 interface MockLogger {
@@ -77,7 +77,7 @@ await describe('OCPP20ServiceUtils.enforceMessageLimits', async () => {
     await it('should return rejected:false and empty results when both limits are 0', () => {
       const station = makeMockStation()
       const logger = makeMockLogger()
-      const items = [makeItem('HeartbeatInterval', '30')]
+      const items = [makeItem(OCPP20OptionalVariableName.HeartbeatInterval, '30')]
 
       const result = OCPP20ServiceUtils.enforceMessageLimits(
         station,
@@ -227,7 +227,7 @@ await describe('OCPP20ServiceUtils.enforceMessageLimits', async () => {
     await it('should return rejected:false when data size is under the bytes limit', () => {
       const station = makeMockStation()
       const logger = makeMockLogger()
-      const items = [makeItem('HeartbeatInterval', '30')]
+      const items = [makeItem(OCPP20OptionalVariableName.HeartbeatInterval, '30')]
 
       const result = OCPP20ServiceUtils.enforceMessageLimits(
         station,
@@ -339,7 +339,7 @@ await describe('OCPP20ServiceUtils.enforceMessageLimits', async () => {
     await it('should pass original item to buildRejected callback', () => {
       const station = makeMockStation()
       const logger = makeMockLogger()
-      const item = makeItem('HeartbeatInterval', 'abc')
+      const item = makeItem(OCPP20OptionalVariableName.HeartbeatInterval, 'abc')
       const capturedItems: TestItem[] = []
 
       OCPP20ServiceUtils.enforceMessageLimits(
@@ -363,7 +363,7 @@ await describe('OCPP20ServiceUtils.enforceMessageLimits', async () => {
     await it('should pass reason with info and reasonCode to buildRejected callback', () => {
       const station = makeMockStation()
       const logger = makeMockLogger()
-      const item = makeItem('WebSocketPingInterval', 'xyz')
+      const item = makeItem(OCPP20OptionalVariableName.WebSocketPingInterval, 'xyz')
       const capturedReasons: RejectionReason[] = []
 
       OCPP20ServiceUtils.enforceMessageLimits(