]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
refactor(ocpp): consolidate variable access in auth adapter
authorJérôme Benoit <jerome.benoit@sap.com>
Thu, 2 Apr 2026 11:58:12 +0000 (13:58 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Thu, 2 Apr 2026 11:58:12 +0000 (13:58 +0200)
Remove getVariableValue/getDefaultVariableValue wrappers from
OCPP20AuthAdapter in favor of OCPP20ServiceUtils.readVariableAs*
helpers. Fixes LocalAuthListCtrlr.Enabled default discrepancy
between adapter (true) and registry (false). Add readVariableAsString
helper for consistent string variable access.

src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts
src/charging-station/ocpp/2.0/OCPP20ServiceUtils.ts
src/charging-station/ocpp/auth/adapters/OCPP20AuthAdapter.ts
tests/charging-station/ocpp/auth/adapters/OCPP20AuthAdapter.test.ts

index 6951bc61bc4a212295ba3f176a73a4dd41de8982..d5c30e8b77ad1b6a9c427bb1d49c312c094ec214 100644 (file)
@@ -2242,12 +2242,11 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
       }
     }
 
-    const priorityValue =
-      OCPP20ServiceUtils.readVariableValue(
-        chargingStation,
-        OCPP20ComponentName.OCPPCommCtrlr,
-        OCPP20RequiredVariableName.NetworkConfigurationPriority
-      ) ?? ''
+    const priorityValue = OCPP20ServiceUtils.readVariableAsString(
+      chargingStation,
+      OCPP20ComponentName.OCPPCommCtrlr,
+      OCPP20RequiredVariableName.NetworkConfigurationPriority
+    )
     if (priorityValue.length > 0) {
       const priorities = priorityValue.split(',').map(Number)
       if (!priorities.includes(commandPayload.configurationSlot)) {
index 6a91391012ca640b3866be7307a6b943ffa270e7..9922cb630bc7e312d40596826db2dab7001a7b38 100644 (file)
@@ -506,6 +506,18 @@ export class OCPP20ServiceUtils {
     return defaultValue
   }
 
+  public static readVariableAsString (
+    chargingStation: ChargingStation,
+    componentName: string,
+    variableName: string,
+    defaultValue = ''
+  ): string {
+    return (
+      OCPP20ServiceUtils.readVariableValue(chargingStation, componentName, variableName) ??
+      defaultValue
+    )
+  }
+
   public static readVariableValue (
     chargingStation: ChargingStation,
     componentName: string,
index 0938fcb907b57accc55bf3bc8c985d7e6aa316c5..937d3fcd0674c00d2b2fb9a891c65d31a7102e9b 100644 (file)
@@ -23,7 +23,7 @@ import {
   OCPP20RequiredVariableName,
   OCPPVersion,
 } from '../../../../types/index.js'
-import { convertToBoolean, logger, truncateId } from '../../../../utils/index.js'
+import { logger, truncateId } from '../../../../utils/index.js'
 import {
   AuthContext,
   AuthenticationMethod,
@@ -366,20 +366,13 @@ export class OCPP20AuthAdapter implements OCPPAuthAdapter<OCPP20IdTokenType> {
    */
   isRemoteAvailable (): boolean {
     try {
-      // Check if station supports remote authorization via variables
-      // OCPP 2.0 uses variables instead of configuration keys
-
-      // Check if station is online and can communicate
       const isOnline = this.chargingStation.inAcceptedState()
-
-      // Check AuthorizeRemoteStart variable
-      const remoteStartValue = this.getVariableValue(
+      const remoteStartEnabled = OCPP20ServiceUtils.readVariableAsBoolean(
+        this.chargingStation,
         OCPP20ComponentName.AuthCtrlr,
-        OCPP20RequiredVariableName.AuthorizeRemoteStart
+        OCPP20RequiredVariableName.AuthorizeRemoteStart,
+        true
       )
-      const remoteStartEnabled =
-        remoteStartValue != null ? convertToBoolean(remoteStartValue) : true
-
       return isOnline && remoteStartEnabled
     } catch (error) {
       logger.warn(
@@ -459,61 +452,18 @@ export class OCPP20AuthAdapter implements OCPPAuthAdapter<OCPP20IdTokenType> {
     }
   }
 
-  /**
-   * Get default variable value based on OCPP 2.0.1 specification
-   * @param component - OCPP component name (e.g., OCPP20ComponentName.AuthCtrlr)
-   * @param variable - OCPP variable name (e.g., OCPP20RequiredVariableName.AuthorizeRemoteStart)
-   * @param useFallback - Whether to return fallback values when variable is not configured
-   * @returns Default value according to OCPP 2.0.1 spec, or undefined if no default exists
-   */
-  private getDefaultVariableValue (
-    component: string,
-    variable: string,
-    useFallback: boolean
-  ): string | undefined {
-    if (!useFallback) {
-      return undefined
-    }
-
-    // Default values from OCPP 2.0.1 specification and variable registry
-    if (component === (OCPP20ComponentName.AuthCtrlr as string)) {
-      switch (variable) {
-        case OCPP20RequiredVariableName.AuthorizeRemoteStart as string:
-          return 'true'
-        case OCPP20RequiredVariableName.Enabled as string:
-          return 'true'
-        case OCPP20RequiredVariableName.LocalAuthorizationOffline as string:
-          return 'true'
-        case OCPP20RequiredVariableName.LocalPreAuthorization as string:
-          return 'false'
-        default:
-          return undefined
-      }
-    }
-
-    if (component === (OCPP20ComponentName.LocalAuthListCtrlr as string)) {
-      switch (variable) {
-        case OCPP20RequiredVariableName.Enabled as string:
-          return 'true'
-        default:
-          return undefined
-      }
-    }
-
-    return undefined
-  }
-
   /**
    * Check if offline authorization is allowed
    * @returns True if offline authorization is enabled
    */
   private getOfflineAuthorizationConfig (): boolean {
     try {
-      const value = this.getVariableValue(
+      return OCPP20ServiceUtils.readVariableAsBoolean(
+        this.chargingStation,
         OCPP20ComponentName.AuthCtrlr,
-        OCPP20RequiredVariableName.LocalAuthorizationOffline
+        OCPP20RequiredVariableName.LocalAuthorizationOffline,
+        true
       )
-      return value != null ? convertToBoolean(value) : true
     } catch (error) {
       logger.warn(
         `${this.chargingStation.logPrefix()} ${moduleName}.getOfflineAuthorizationConfig: Error getting offline authorization config`,
@@ -522,35 +472,4 @@ export class OCPP20AuthAdapter implements OCPPAuthAdapter<OCPP20IdTokenType> {
       return false
     }
   }
-
-  /**
-   * Get variable value from OCPP 2.0 variable system
-   * @param component - OCPP component name (e.g., OCPP20ComponentName.AuthCtrlr)
-   * @param variable - OCPP variable name (e.g., OCPP20RequiredVariableName.AuthorizeRemoteStart)
-   * @param useDefaultFallback - If true, use OCPP 2.0.1 spec default values when variable is not found
-   * @returns Promise resolving to variable value as string, or undefined if not available
-   */
-  private getVariableValue (
-    component: string,
-    variable: string,
-    useDefaultFallback = true
-  ): string | undefined {
-    try {
-      const value = OCPP20ServiceUtils.readVariableValue(this.chargingStation, component, variable)
-      if (value != null) {
-        return value
-      }
-
-      logger.debug(
-        `${this.chargingStation.logPrefix()} ${moduleName}.getVariableValue: Variable ${component}.${variable} not available`
-      )
-      return this.getDefaultVariableValue(component, variable, useDefaultFallback)
-    } catch (error) {
-      logger.warn(
-        `${this.chargingStation.logPrefix()} ${moduleName}.getVariableValue: Error getting variable ${component}.${variable}`,
-        error
-      )
-      return this.getDefaultVariableValue(component, variable, useDefaultFallback)
-    }
-  }
 }
index 6d4de7d312d3b20f8aebdafa3f6101946554ff36..985b031509d12a323832ec07a2f40bf13cf29916 100644 (file)
@@ -7,6 +7,7 @@ import { afterEach, beforeEach, describe, it, mock } from 'node:test'
 
 import type { ChargingStation } from '../../../../../src/charging-station/index.js'
 
+import { OCPP20ServiceUtils } from '../../../../../src/charging-station/ocpp/2.0/OCPP20ServiceUtils.js'
 import { OCPP20AuthAdapter } from '../../../../../src/charging-station/ocpp/auth/adapters/OCPP20AuthAdapter.js'
 import {
   type AuthConfiguration,
@@ -239,11 +240,7 @@ await describe('OCPP20AuthAdapter', async () => {
 
   await describe('isRemoteAvailable', async () => {
     await it('should return true when station is online and remote start enabled', t => {
-      t.mock.method(
-        adapter as unknown as { getVariableValue: () => string | undefined },
-        'getVariableValue',
-        () => 'true'
-      )
+      t.mock.method(OCPP20ServiceUtils, 'readVariableAsBoolean', () => true)
 
       const isAvailable = adapter.isRemoteAvailable()
       assert.strictEqual(isAvailable, true)
@@ -251,11 +248,7 @@ await describe('OCPP20AuthAdapter', async () => {
 
     await it('should return false when station is offline', t => {
       mockStation.inAcceptedState = () => false
-      t.mock.method(
-        adapter as unknown as { getVariableValue: () => string | undefined },
-        'getVariableValue',
-        () => 'true'
-      )
+      t.mock.method(OCPP20ServiceUtils, 'readVariableAsBoolean', () => true)
 
       const isAvailable = adapter.isRemoteAvailable()
       assert.strictEqual(isAvailable, false)
@@ -388,25 +381,21 @@ await describe('OCPP20AuthAdapter', async () => {
     })
 
     await describe('C15 - Offline detection', async () => {
-      await it('should detect station is offline when not in accepted state', () => {
-        // Given: Station is offline (not in accepted state)
+      await it('should detect station is offline when not in accepted state', t => {
         offlineMockChargingStation.inAcceptedState = () => false
+        t.mock.method(OCPP20ServiceUtils, 'readVariableAsBoolean', () => true)
 
-        // When: Check if remote authorization is available
         const isAvailable = offlineAdapter.isRemoteAvailable()
 
-        // Then: Remote should not be available
         assert.strictEqual(isAvailable, false)
       })
 
-      await it('should detect station is online when in accepted state', () => {
-        // Given: Station is online (in accepted state)
+      await it('should detect station is online when in accepted state', t => {
         offlineMockChargingStation.inAcceptedState = () => true
+        t.mock.method(OCPP20ServiceUtils, 'readVariableAsBoolean', () => true)
 
-        // When: Check if remote authorization is available
         const isAvailable = offlineAdapter.isRemoteAvailable()
 
-        // Then: Remote should be available (assuming AuthorizeRemoteStart is enabled by default)
         assert.strictEqual(isAvailable, true)
       })
 
@@ -417,14 +406,12 @@ await describe('OCPP20AuthAdapter', async () => {
     })
 
     await describe('C15 - Remote availability check', async () => {
-      await it('should return false when offline even with valid configuration', () => {
-        // Given: Station is offline
+      await it('should return false when offline even with valid configuration', t => {
         offlineMockChargingStation.inAcceptedState = () => false
+        t.mock.method(OCPP20ServiceUtils, 'readVariableAsBoolean', () => true)
 
-        // When: Check remote availability
         const isAvailable = offlineAdapter.isRemoteAvailable()
 
-        // Then: Should not be available
         assert.strictEqual(isAvailable, false)
       })