From: Jérôme Benoit Date: Thu, 30 Oct 2025 14:44:58 +0000 (+0100) Subject: fix(ocpp2): refine variables handling X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=dbfc0d55baca387d97a254efb701739a4acbdd89;p=e-mobility-charging-stations-simulator.git fix(ocpp2): refine variables handling Signed-off-by: Jérôme Benoit --- diff --git a/src/charging-station/ocpp/2.0/OCPP20VariableManager.ts b/src/charging-station/ocpp/2.0/OCPP20VariableManager.ts index 3c4883d5..8fc9eac0 100644 --- a/src/charging-station/ocpp/2.0/OCPP20VariableManager.ts +++ b/src/charging-station/ocpp/2.0/OCPP20VariableManager.ts @@ -478,10 +478,27 @@ export class OCPP20VariableManager { variableMetadata.mutability !== MutabilityEnumType.WriteOnly ) { const configurationKeyName = computeConfigurationKeyName(variableMetadata) - const cfg = getConfigurationKey( + let cfg = getConfigurationKey( chargingStation, configurationKeyName as unknown as StandardParametersKey ) + + if (cfg == null) { + addConfigurationKey( + chargingStation, + configurationKeyName as unknown as StandardParametersKey, + value, // Use the resolved default value + undefined, + { + overwrite: false, + } + ) + cfg = getConfigurationKey( + chargingStation, + configurationKeyName as unknown as StandardParametersKey + ) + } + if (cfg?.value) { value = cfg.value } @@ -838,53 +855,42 @@ export class OCPP20VariableManager { configurationKeyName as unknown as StandardParametersKey )?.value - // Generalized persistence for persistent, non write-only variables (including instance-scoped) if ( variableMetadata.persistence === PersistenceEnumType.Persistent && variableMetadata.mutability !== MutabilityEnumType.WriteOnly ) { - // Special-case: OrganizationName persistence limitation (do not update stored value once created) - const isOrganizationName = - variableMetadata.component === (OCPP20ComponentName.SecurityCtrlr as string) && - variableMetadata.variable === (OCPP20RequiredVariableName.OrganizationName as string) - - if (!isOrganizationName) { - let configKey = getConfigurationKey( + let configKey = getConfigurationKey( + chargingStation, + configurationKeyName as unknown as StandardParametersKey + ) + if (configKey == null) { + addConfigurationKey( + chargingStation, + configurationKeyName as unknown as StandardParametersKey, + attributeValue, + undefined, + { + overwrite: false, + } + ) + configKey = getConfigurationKey( chargingStation, configurationKeyName as unknown as StandardParametersKey ) - if (configKey == null) { - addConfigurationKey( - chargingStation, - configurationKeyName as unknown as StandardParametersKey, - attributeValue, - undefined, - { - overwrite: false, - } - ) - configKey = getConfigurationKey( + } else if (configKey.value !== attributeValue) { + setConfigurationKeyValue( + chargingStation, + configurationKeyName as unknown as StandardParametersKey, + attributeValue + ) + } + rebootRequired = + (variableMetadata.rebootRequired === true || + getConfigurationKey( chargingStation, configurationKeyName as unknown as StandardParametersKey - ) - } else if (configKey.value !== attributeValue) { - setConfigurationKeyValue( - chargingStation, - configurationKeyName as unknown as StandardParametersKey, - attributeValue - ) - } - rebootRequired = - (variableMetadata.rebootRequired === true || - getConfigurationKey( - chargingStation, - configurationKeyName as unknown as StandardParametersKey - )?.reboot === true) && - previousValue !== attributeValue - } else { - // OrganizationName: accept set but do not persist new value (tests expect default retained) - rebootRequired = false - } + )?.reboot === true) && + previousValue !== attributeValue } // Heartbeat & WS ping interval dynamic restarts if ( diff --git a/src/charging-station/ocpp/2.0/OCPP20VariableRegistry.ts b/src/charging-station/ocpp/2.0/OCPP20VariableRegistry.ts index 89859da0..934a4267 100644 --- a/src/charging-station/ocpp/2.0/OCPP20VariableRegistry.ts +++ b/src/charging-station/ocpp/2.0/OCPP20VariableRegistry.ts @@ -99,7 +99,273 @@ const DECIMAL_ONLY_PATTERN = /^-?\d+\.\d+$/ // - Only add rationale comments where simulator intentionally restricts or extends (e.g. enumeration trimming, volatile choice). // - Avoid verbose line or row numbers; keep comments concise. export const VARIABLE_REGISTRY: Record = { - // AuthCtrlr variables + // AlignedDataCtrlr Component + [buildRegistryKey(OCPP20ComponentName.AlignedDataCtrlr as string, 'Available')]: { + component: OCPP20ComponentName.AlignedDataCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'true', + description: 'If this variable reports a value of true, Clock-Aligned Data is supported.', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Available', + }, + [buildRegistryKey(OCPP20ComponentName.AlignedDataCtrlr as string, 'Enabled')]: { + component: OCPP20ComponentName.AlignedDataCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: 'If this variable reports a value of true, Clock-Aligned Data is enabled', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Enabled', + }, + [buildRegistryKey(OCPP20ComponentName.AlignedDataCtrlr as string, 'Interval')]: { + component: OCPP20ComponentName.AlignedDataCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '900', + description: + 'Size (in seconds) of the clock-aligned data interval, intended to be transmitted in the MeterValuesRequest message.', + min: 1, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + unit: 's', + variable: 'Interval', + }, + [buildRegistryKey(OCPP20ComponentName.AlignedDataCtrlr as string, 'Measurands')]: { + component: OCPP20ComponentName.AlignedDataCtrlr as string, + dataType: DataEnumType.MemberList, + defaultValue: OCPP20MeasurandEnumType.ENERGY_ACTIVE_IMPORT_REGISTER, + description: + 'Clock-aligned measurand(s) to be included in MeterValuesRequest, every AlignedDataInterval seconds.', + enumeration: [ + OCPP20MeasurandEnumType.CURRENT_EXPORT, + OCPP20MeasurandEnumType.CURRENT_IMPORT, + OCPP20MeasurandEnumType.CURRENT_OFFERED, + OCPP20MeasurandEnumType.ENERGY_ACTIVE_EXPORT_REGISTER, + OCPP20MeasurandEnumType.ENERGY_ACTIVE_IMPORT_REGISTER, + OCPP20MeasurandEnumType.ENERGY_REACTIVE_EXPORT_REGISTER, + OCPP20MeasurandEnumType.ENERGY_REACTIVE_IMPORT_REGISTER, + OCPP20MeasurandEnumType.ENERGY_ACTIVE_EXPORT_INTERVAL, + OCPP20MeasurandEnumType.ENERGY_ACTIVE_IMPORT_INTERVAL, + OCPP20MeasurandEnumType.ENERGY_REACTIVE_EXPORT_INTERVAL, + OCPP20MeasurandEnumType.ENERGY_REACTIVE_IMPORT_INTERVAL, + OCPP20MeasurandEnumType.FREQUENCY, + OCPP20MeasurandEnumType.POWER_ACTIVE_EXPORT, + OCPP20MeasurandEnumType.POWER_ACTIVE_IMPORT, + OCPP20MeasurandEnumType.POWER_FACTOR, + OCPP20MeasurandEnumType.POWER_OFFERED, + OCPP20MeasurandEnumType.POWER_REACTIVE_EXPORT, + OCPP20MeasurandEnumType.POWER_REACTIVE_IMPORT, + OCPP20MeasurandEnumType.STATE_OF_CHARGE, + OCPP20MeasurandEnumType.VOLTAGE, + ], + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Measurands', + }, + [buildRegistryKey(OCPP20ComponentName.AlignedDataCtrlr as string, 'SendDuringIdle')]: { + component: OCPP20ComponentName.AlignedDataCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'If set to true, the Charging Station SHALL NOT send clock aligned meter values when a transaction is ongoing.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'SendDuringIdle', + }, + [buildRegistryKey(OCPP20ComponentName.AlignedDataCtrlr as string, 'SignReadings')]: { + component: OCPP20ComponentName.AlignedDataCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'If set to true, the Charging Station SHALL include signed meter values in the SampledValueType in the MeterValuesRequest to the CSMS.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'SignReadings', + }, + [buildRegistryKey(OCPP20ComponentName.AlignedDataCtrlr as string, 'TxEndedInterval')]: { + component: OCPP20ComponentName.AlignedDataCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '900', + description: + 'Size (in seconds) of the clock-aligned data interval, intended to be transmitted in the TransactionEventRequest (eventType = Ended) message.', + min: 1, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + unit: 's', + variable: 'TxEndedInterval', + }, + [buildRegistryKey(OCPP20ComponentName.AlignedDataCtrlr as string, 'TxEndedMeasurands')]: { + component: OCPP20ComponentName.AlignedDataCtrlr as string, + dataType: DataEnumType.MemberList, + defaultValue: `${OCPP20MeasurandEnumType.ENERGY_ACTIVE_IMPORT_REGISTER},${OCPP20MeasurandEnumType.ENERGY_ACTIVE_IMPORT_INTERVAL},${OCPP20MeasurandEnumType.VOLTAGE}`, + description: + 'Clock-aligned measurands to be included in the meterValues element of TransactionEventRequest (eventType = Ended), every SampledDataTxEndedInterval seconds from the start of the transaction.', + enumeration: [ + OCPP20MeasurandEnumType.CURRENT_EXPORT, + OCPP20MeasurandEnumType.CURRENT_IMPORT, + OCPP20MeasurandEnumType.CURRENT_OFFERED, + OCPP20MeasurandEnumType.ENERGY_ACTIVE_EXPORT_REGISTER, + OCPP20MeasurandEnumType.ENERGY_ACTIVE_IMPORT_REGISTER, + OCPP20MeasurandEnumType.ENERGY_REACTIVE_EXPORT_REGISTER, + OCPP20MeasurandEnumType.ENERGY_REACTIVE_IMPORT_REGISTER, + OCPP20MeasurandEnumType.ENERGY_ACTIVE_EXPORT_INTERVAL, + OCPP20MeasurandEnumType.ENERGY_ACTIVE_IMPORT_INTERVAL, + OCPP20MeasurandEnumType.ENERGY_REACTIVE_EXPORT_INTERVAL, + OCPP20MeasurandEnumType.ENERGY_REACTIVE_IMPORT_INTERVAL, + OCPP20MeasurandEnumType.FREQUENCY, + OCPP20MeasurandEnumType.POWER_ACTIVE_EXPORT, + OCPP20MeasurandEnumType.POWER_ACTIVE_IMPORT, + OCPP20MeasurandEnumType.POWER_FACTOR, + OCPP20MeasurandEnumType.POWER_OFFERED, + OCPP20MeasurandEnumType.POWER_REACTIVE_EXPORT, + OCPP20MeasurandEnumType.POWER_REACTIVE_IMPORT, + OCPP20MeasurandEnumType.STATE_OF_CHARGE, + OCPP20MeasurandEnumType.VOLTAGE, + ], + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'TxEndedMeasurands', + }, + + // AuthCacheCtrlr Component + [buildRegistryKey(OCPP20ComponentName.AuthCacheCtrlr as string, 'Available')]: { + component: OCPP20ComponentName.AuthCacheCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'true', + description: 'Authorization caching is available, but not necessarily enabled.', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Available', + }, + [buildRegistryKey(OCPP20ComponentName.AuthCacheCtrlr as string, 'DisablePostAuthorize')]: { + component: OCPP20ComponentName.AuthCacheCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'When set to true this variable disables the behavior to request authorization for an idToken that is stored in the cache with a status other than Accepted, as stated in C10.FR.03 and C12.FR.05.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'DisablePostAuthorize', + }, + [buildRegistryKey(OCPP20ComponentName.AuthCacheCtrlr as string, 'Enabled')]: { + component: OCPP20ComponentName.AuthCacheCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: 'If set to true, Authorization caching is enabled.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Enabled', + }, + [buildRegistryKey(OCPP20ComponentName.AuthCacheCtrlr as string, 'LifeTime')]: { + component: OCPP20ComponentName.AuthCacheCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '86400', + description: + 'Indicates how long it takes until a token expires in the authorization cache since it is last used', + min: 1, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'LifeTime', + }, + [buildRegistryKey(OCPP20ComponentName.AuthCacheCtrlr as string, 'Policy')]: { + component: OCPP20ComponentName.AuthCacheCtrlr as string, + dataType: DataEnumType.OptionList, + defaultValue: 'LRU', + description: + 'Cache Entry Replacement Policy: least recently used, least frequently used, first in first out, other custom mechanism.', + enumeration: ['LRU', 'LFU', 'FIFO', 'Custom'], + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Policy', + }, + [buildRegistryKey(OCPP20ComponentName.AuthCacheCtrlr as string, 'Storage')]: { + characteristics: { + maxLimit: 1048576, // 1MB default + }, + component: OCPP20ComponentName.AuthCacheCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '0', + description: + 'Indicates the number of bytes currently used by the Authorization Cache. MaxLimit indicates the maximum number of bytes that can be used by the Authorization Cache.', + min: 0, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual, AttributeEnumType.MaxSet], + unit: 'B', + variable: 'Storage', + }, + + // AuthCtrlr Component + [buildRegistryKey(OCPP20ComponentName.AuthCtrlr as string, 'AdditionalInfoItemsPerMessage')]: { + component: OCPP20ComponentName.AuthCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '10', + description: 'Maximum number of AdditionalInfo items that can be sent in one message.', + max: 100, + min: 1, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + positive: true, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'AdditionalInfoItemsPerMessage', + }, + [buildRegistryKey(OCPP20ComponentName.AuthCtrlr as string, 'DisableRemoteAuthorization')]: { + component: OCPP20ComponentName.AuthCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'When set to true, instructs the Charging Station to not issue any AuthorizationRequests but only use Authorization Cache and Local Authorization List.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'DisableRemoteAuthorization', + }, + + [buildRegistryKey(OCPP20ComponentName.AuthCtrlr as string, 'Enabled')]: { + component: OCPP20ComponentName.AuthCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'true', + description: + 'If set to false, no authorization is done before starting a transaction or when reading an idToken.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Enabled', + }, + [buildRegistryKey(OCPP20ComponentName.AuthCtrlr as string, 'MasterPassGroupId')]: { + component: OCPP20ComponentName.AuthCtrlr as string, + 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 as string, 'OfflineTxForUnknownIdEnabled')]: { + component: OCPP20ComponentName.AuthCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: 'Support for unknown offline transactions.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'OfflineTxForUnknownIdEnabled', + }, [buildRegistryKey( OCPP20ComponentName.AuthCtrlr as string, OCPP20RequiredVariableName.AuthorizeRemoteStart @@ -140,6 +406,94 @@ export const VARIABLE_REGISTRY: Record = { variable: OCPP20RequiredVariableName.LocalPreAuthorize as string, }, + // CHAdeMOCtrlr Component + [buildRegistryKey(OCPP20ComponentName.CHAdeMOCtrlr as string, 'AutoManufacturerCode')]: { + component: OCPP20ComponentName.CHAdeMOCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '0', + description: "Auto manufacturer code (H'700.0)", + min: 0, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'AutoManufacturerCode', + }, + [buildRegistryKey(OCPP20ComponentName.CHAdeMOCtrlr as string, 'CHAdeMOProtocolNumber')]: { + component: OCPP20ComponentName.CHAdeMOCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '66048', + description: "CHAdeMO protocol number (H'102.0)", + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'CHAdeMOProtocolNumber', + }, + [buildRegistryKey(OCPP20ComponentName.CHAdeMOCtrlr as string, 'DynamicControl')]: { + component: OCPP20ComponentName.CHAdeMOCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: "Vehicle is compatible with dynamic control (H'110.0.0)", + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'DynamicControl', + }, + [buildRegistryKey(OCPP20ComponentName.CHAdeMOCtrlr as string, 'HighCurrentControl')]: { + component: OCPP20ComponentName.CHAdeMOCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: "Vehicle is compatible with high current control (H'110.0.1)", + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'HighCurrentControl', + }, + [buildRegistryKey(OCPP20ComponentName.CHAdeMOCtrlr as string, 'HighVoltageControl')]: { + component: OCPP20ComponentName.CHAdeMOCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: "Vehicle is compatible with high voltage control (H'110.1.2)", + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'HighVoltageControl', + }, + [buildRegistryKey(OCPP20ComponentName.CHAdeMOCtrlr as string, 'SelftestActive')]: { + component: OCPP20ComponentName.CHAdeMOCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: 'Self-test is active or self-test is started by setting to true.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'SelftestActive', + }, + [buildRegistryKey(OCPP20ComponentName.CHAdeMOCtrlr as string, 'VehicleStatus')]: { + component: OCPP20ComponentName.CHAdeMOCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: "Vehicle status (H'102.5.3)", + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'VehicleStatus', + }, + + // ChargingStation Component + [buildRegistryKey( + OCPP20ComponentName.ChargingStation as string, + 'AllowNewSessionsPendingFirmwareUpdate' + )]: { + component: OCPP20ComponentName.ChargingStation as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'Indicates whether new sessions can be started on EVSEs while Charging Station is waiting for all EVSEs to become Available in order to start a pending firmware update.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'AllowNewSessionsPendingFirmwareUpdate', + }, [buildRegistryKey(OCPP20ComponentName.ChargingStation as string, 'Available')]: { component: OCPP20ComponentName.ChargingStation as string, dataType: DataEnumType.boolean, @@ -150,6 +504,16 @@ export const VARIABLE_REGISTRY: Record = { supportedAttributes: [AttributeEnumType.Actual], variable: 'Available', }, + [buildRegistryKey(OCPP20ComponentName.ChargingStation as string, 'Model')]: { + component: OCPP20ComponentName.ChargingStation as string, + dataType: DataEnumType.string, + description: 'Charging station model as reported in BootNotification.', + maxLength: 50, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Model', + }, [buildRegistryKey(OCPP20ComponentName.ChargingStation as string, 'SupplyPhases')]: { component: OCPP20ComponentName.ChargingStation as string, dataType: DataEnumType.integer, @@ -162,7 +526,16 @@ export const VARIABLE_REGISTRY: Record = { supportedAttributes: [AttributeEnumType.Actual], variable: 'SupplyPhases', }, - // ChargingStation variables + [buildRegistryKey(OCPP20ComponentName.ChargingStation as string, 'VendorName')]: { + component: OCPP20ComponentName.ChargingStation as string, + dataType: DataEnumType.string, + description: 'Charging station vendor name as reported in BootNotification.', + maxLength: 50, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'VendorName', + }, [buildRegistryKey( OCPP20ComponentName.ChargingStation as string, OCPP20DeviceInfoVariableName.AvailabilityState @@ -192,7 +565,7 @@ export const VARIABLE_REGISTRY: Record = { mutability: MutabilityEnumType.ReadWrite, persistence: PersistenceEnumType.Persistent, supportedAttributes: [AttributeEnumType.Actual], - unit: 'seconds', + unit: 's', variable: OCPP20OptionalVariableName.WebSocketPingInterval as string, }, [buildRegistryKey( @@ -212,32 +585,92 @@ export const VARIABLE_REGISTRY: Record = { vendorSpecific: true, }, - // ClockCtrlr variables - [buildRegistryKey(OCPP20ComponentName.ClockCtrlr as string, OCPP20RequiredVariableName.DateTime)]: + // ClockCtrlr Component + [buildRegistryKey(OCPP20ComponentName.ClockCtrlr as string, 'NextTimeOffsetTransitionDateTime')]: { component: OCPP20ComponentName.ClockCtrlr as string, dataType: DataEnumType.dateTime, - description: 'Contains the current date and time (ClockCtrlr).', - dynamicValueResolver: () => new Date().toISOString(), - mutability: MutabilityEnumType.ReadOnly, - persistence: PersistenceEnumType.Volatile, + description: 'Date time of the next time offset transition.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, supportedAttributes: [AttributeEnumType.Actual], - variable: OCPP20RequiredVariableName.DateTime as string, + variable: 'NextTimeOffsetTransitionDateTime', }, - [buildRegistryKey( - OCPP20ComponentName.ClockCtrlr as string, - OCPP20RequiredVariableName.TimeSource - )]: { + [buildRegistryKey(OCPP20ComponentName.ClockCtrlr as string, 'NtpServerUri')]: { component: OCPP20ComponentName.ClockCtrlr as string, - dataType: DataEnumType.SequenceList, - defaultValue: 'NTP,GPS,RealTimeClock,Heartbeat', - description: 'Ordered list of clock sources by preference.', - enumeration: [ - 'Heartbeat', - 'NTP', - 'GPS', - 'RealTimeClock', - 'MobileNetwork', + dataType: DataEnumType.string, + description: 'This contains the address of the NTP server.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'NtpServerUri', + }, + [buildRegistryKey(OCPP20ComponentName.ClockCtrlr as string, 'NtpSource')]: { + component: OCPP20ComponentName.ClockCtrlr as string, + dataType: DataEnumType.OptionList, + description: + 'When an NTP client is implemented, this variable can be used to configure the client', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'NtpSource', + }, + [buildRegistryKey(OCPP20ComponentName.ClockCtrlr as string, 'TimeAdjustmentReportingThreshold')]: + { + component: OCPP20ComponentName.ClockCtrlr as string, + dataType: DataEnumType.integer, + description: + 'If set, then time adjustments with an absolute value in seconds larger than this need to be reported as a security event SettingSystemTime', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'TimeAdjustmentReportingThreshold', + }, + [buildRegistryKey(OCPP20ComponentName.ClockCtrlr as string, 'TimeOffset')]: { + component: OCPP20ComponentName.ClockCtrlr as string, + dataType: DataEnumType.string, + description: + 'A Time Offset with respect to Coordinated Universal Time (aka UTC or Greenwich Mean Time) in the form of an [RFC3339] time (zone) offset suffix, including the mandatory "+" or "-" prefix.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'TimeOffset', + }, + [buildRegistryKey(OCPP20ComponentName.ClockCtrlr as string, 'TimeZone')]: { + component: OCPP20ComponentName.ClockCtrlr as string, + dataType: DataEnumType.string, + description: + 'Configured current local time zone in the format: "Europe/Oslo", "Asia/Singapore" etc. For display purposes.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'TimeZone', + }, + [buildRegistryKey(OCPP20ComponentName.ClockCtrlr as string, OCPP20RequiredVariableName.DateTime)]: + { + component: OCPP20ComponentName.ClockCtrlr as string, + dataType: DataEnumType.dateTime, + description: 'Contains the current date and time (ClockCtrlr).', + dynamicValueResolver: () => new Date().toISOString(), + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: OCPP20RequiredVariableName.DateTime as string, + }, + [buildRegistryKey( + OCPP20ComponentName.ClockCtrlr as string, + OCPP20RequiredVariableName.TimeSource + )]: { + component: OCPP20ComponentName.ClockCtrlr as string, + dataType: DataEnumType.SequenceList, + defaultValue: 'NTP,GPS,RealTimeClock,Heartbeat', + description: 'Ordered list of clock sources by preference.', + enumeration: [ + 'Heartbeat', + 'NTP', + 'GPS', + 'RealTimeClock', + 'MobileNetwork', 'RadioTimeTransmitter', ], mutability: MutabilityEnumType.ReadWrite, @@ -246,7 +679,7 @@ export const VARIABLE_REGISTRY: Record = { variable: OCPP20RequiredVariableName.TimeSource as string, }, - // DeviceDataCtrlr variables + // DeviceDataCtrlr Component [buildRegistryKey( OCPP20ComponentName.DeviceDataCtrlr as string, OCPP20RequiredVariableName.BytesPerMessage @@ -427,7 +860,531 @@ export const VARIABLE_REGISTRY: Record = { variable: OCPP20RequiredVariableName.ValueSize as string, }, - // OCPPCommCtrlr variables + // EVSE Component + [buildRegistryKey(OCPP20ComponentName.EVSE as string, 'AllowReset')]: { + component: OCPP20ComponentName.EVSE as string, + 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 as string, 'AvailabilityState')]: { + component: OCPP20ComponentName.EVSE as string, + dataType: DataEnumType.OptionList, + defaultValue: 'Operative', + description: 'This variable reports current availability state for the EVSE', + enumeration: ['Operative', 'Inoperative'], + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'AvailabilityState', + }, + [buildRegistryKey(OCPP20ComponentName.EVSE as string, 'Available')]: { + component: OCPP20ComponentName.EVSE as string, + dataType: DataEnumType.boolean, + defaultValue: 'true', + description: 'Component exists', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Available', + }, + [buildRegistryKey(OCPP20ComponentName.EVSE as string, 'EvseId')]: { + component: OCPP20ComponentName.EVSE as string, + dataType: DataEnumType.string, + defaultValue: '1', + description: + 'The name of the EVSE in the string format as required by ISO 15118 and IEC 63119-2.', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'EvseId', + }, + [buildRegistryKey(OCPP20ComponentName.EVSE as string, 'ISO15118EvseId')]: { + component: OCPP20ComponentName.EVSE as string, + dataType: DataEnumType.string, + defaultValue: 'DE*ICE*E*1234567890*1', + description: + 'The name of the EVSE in the string format as required by ISO 15118 and IEC 63119-2.', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'ISO15118EvseId', + }, + [buildRegistryKey(OCPP20ComponentName.EVSE as string, 'Power')]: { + characteristics: { + maxLimit: 22000, // 22kW default + }, + component: OCPP20ComponentName.EVSE as string, + dataType: DataEnumType.decimal, + defaultValue: '0', + description: 'The maximum power that this EVSE can provide and instantaneous power', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual, AttributeEnumType.MaxSet], + supportsTarget: false, + unit: 'W', + variable: 'Power', + }, + [buildRegistryKey(OCPP20ComponentName.EVSE as string, 'SupplyPhases')]: { + component: OCPP20ComponentName.EVSE as string, + dataType: DataEnumType.integer, + defaultValue: '3', + description: 'Number of alternating current phases connected/available.', + max: 3, + min: 1, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'SupplyPhases', + }, + + // ISO15118Ctrlr Component + [buildRegistryKey( + OCPP20ComponentName.ISO15118Ctrlr as string, + 'CentralContractValidationAllowed' + )]: { + component: OCPP20ComponentName.ISO15118Ctrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'If this variable exists and has the value true, then Charging Station can provide a contract certificate that it cannot validate, to the CSMS for validation as part of the AuthorizeRequest.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'CentralContractValidationAllowed', + }, + [buildRegistryKey( + OCPP20ComponentName.ISO15118Ctrlr as string, + 'ContractCertificateInstallationEnabled' + )]: { + component: OCPP20ComponentName.ISO15118Ctrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'If this variable is true, then ISO 15118 contract certificate installation/update as described by use case M01 - Certificate installation EV and M02 - Certificate Update EV is enabled.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'ContractCertificateInstallationEnabled', + }, + [buildRegistryKey(OCPP20ComponentName.ISO15118Ctrlr as string, 'ContractValidationOffline')]: { + component: OCPP20ComponentName.ISO15118Ctrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'If this variable is true, then Charging Station will try to validate a contract certificate when it is offline', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'ContractValidationOffline', + }, + [buildRegistryKey(OCPP20ComponentName.ISO15118Ctrlr as string, 'CountryName')]: { + component: OCPP20ComponentName.ISO15118Ctrlr as string, + dataType: DataEnumType.string, + defaultValue: 'DE', + description: + 'The countryName of the SECC in the ISO 3166-1 format. It is used as the countryName (C) of the SECC leaf certificate.', + maxLength: 2, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'CountryName', + }, + [buildRegistryKey(OCPP20ComponentName.ISO15118Ctrlr as string, 'MaxScheduleEntries')]: { + component: OCPP20ComponentName.ISO15118Ctrlr as string, + dataType: DataEnumType.integer, + defaultValue: '24', + description: 'Maximum number of allowed schedule periods.', + min: 1, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'MaxScheduleEntries', + }, + [buildRegistryKey(OCPP20ComponentName.ISO15118Ctrlr as string, 'OrganizationName')]: { + component: OCPP20ComponentName.ISO15118Ctrlr as string, + dataType: DataEnumType.string, + defaultValue: 'Example Charging Services Ltd', + description: + 'The organizationName of the CSO operating the charging station. It is used as the organizationName (O) of the SECC leaf certificate.', + maxLength: 64, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'OrganizationName', + }, + [buildRegistryKey(OCPP20ComponentName.ISO15118Ctrlr as string, 'PnCEnabled')]: { + component: OCPP20ComponentName.ISO15118Ctrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'If this variable is true, then ISO 15118 plug and charge as described by use case C07 - Authorization using Contract Certificates is enabled.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'PnCEnabled', + }, + [buildRegistryKey(OCPP20ComponentName.ISO15118Ctrlr as string, 'RequestedEnergyTransferMode')]: { + component: OCPP20ComponentName.ISO15118Ctrlr as string, + dataType: DataEnumType.OptionList, + defaultValue: 'DC_extended', + description: 'The requested energy transfer mode.', + enumeration: [ + 'AC_single_phase_core', + 'AC_three_phase_core', + 'DC_core', + 'DC_extended', + 'DC_combo_core', + 'DC_unique', + ], + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'RequestedEnergyTransferMode', + }, + [buildRegistryKey(OCPP20ComponentName.ISO15118Ctrlr as string, 'RequestMeteringReceipt')]: { + component: OCPP20ComponentName.ISO15118Ctrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: 'If true, then Charging Station shall request a metering receipt from EV.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'RequestMeteringReceipt', + }, + [buildRegistryKey(OCPP20ComponentName.ISO15118Ctrlr as string, 'SeccId')]: { + component: OCPP20ComponentName.ISO15118Ctrlr as string, + dataType: DataEnumType.string, + defaultValue: 'DE*ICE*E*1234567890', + description: 'The ID of the SECC in string format as defined by ISO15118.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'SeccId', + }, + [buildRegistryKey( + OCPP20ComponentName.ISO15118Ctrlr as string, + 'V2GCertificateInstallationEnabled' + )]: { + component: OCPP20ComponentName.ISO15118Ctrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'If this variable is true, then ISO 15118 V2G Charging Station certificate installation as described by use case A02 - Update Charging Station Certificate by request of CSMS and A03 - Update Charging Station Certificate initiated by the Charging Station is enabled.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'V2GCertificateInstallationEnabled', + }, + + // LocalAuthListCtrlr Component + [buildRegistryKey(OCPP20ComponentName.LocalAuthListCtrlr as string, 'Available')]: { + component: OCPP20ComponentName.LocalAuthListCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'true', + description: 'Local Authorization List is available.', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Available', + }, + [buildRegistryKey(OCPP20ComponentName.LocalAuthListCtrlr as string, 'BytesPerMessage')]: { + component: OCPP20ComponentName.LocalAuthListCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '8192', + description: 'Maximum number of bytes in a SendLocalList message.', + min: 1, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'BytesPerMessage', + }, + [buildRegistryKey(OCPP20ComponentName.LocalAuthListCtrlr as string, 'DisablePostAuthorize')]: { + component: OCPP20ComponentName.LocalAuthListCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'When set to true this variable disables the behavior to request authorization for an idToken that is stored in the local authorization list with a status other than Accepted, as stated in C14.FR.03.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'DisablePostAuthorize', + }, + [buildRegistryKey(OCPP20ComponentName.LocalAuthListCtrlr as string, 'Enabled')]: { + component: OCPP20ComponentName.LocalAuthListCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'If this variable exists and reports a value of true, Local Authorization List is enabled.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Enabled', + }, + [buildRegistryKey(OCPP20ComponentName.LocalAuthListCtrlr as string, 'Entries')]: { + component: OCPP20ComponentName.LocalAuthListCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '0', + description: 'Amount of IdTokens currently in the Local Authorization List', + min: 0, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Entries', + }, + [buildRegistryKey(OCPP20ComponentName.LocalAuthListCtrlr as string, 'ItemsPerMessage')]: { + component: OCPP20ComponentName.LocalAuthListCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '100', + description: 'Maximum number of records in SendLocalList', + min: 1, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'ItemsPerMessage', + }, + [buildRegistryKey(OCPP20ComponentName.LocalAuthListCtrlr as string, 'Storage')]: { + characteristics: { + maxLimit: 1048576, // 1MB default + }, + component: OCPP20ComponentName.LocalAuthListCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '0', + description: + 'Indicates the number of bytes currently used by the Local Authorization List. MaxLimit indicates the maximum number of bytes that can be used by the Local Authorization List.', + min: 0, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual, AttributeEnumType.MaxSet], + unit: 'B', + variable: 'Storage', + }, + + // MonitoringCtrlr Component + [buildRegistryKey(OCPP20ComponentName.MonitoringCtrlr as string, 'ActiveMonitoringBase')]: { + component: OCPP20ComponentName.MonitoringCtrlr as string, + dataType: DataEnumType.OptionList, + defaultValue: 'All', + description: + 'Shows the currently used MonitoringBase. Valid values according MonitoringBaseEnumType: All, FactoryDefault, HardwiredOnly.', + enumeration: ['All', 'FactoryDefault', 'HardwiredOnly'], + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'ActiveMonitoringBase', + }, + [buildRegistryKey(OCPP20ComponentName.MonitoringCtrlr as string, 'ActiveMonitoringLevel')]: { + component: OCPP20ComponentName.MonitoringCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '9', + description: + 'Shows the currently used MonitoringLevel. Valid values are severity levels of SetMonitoringLevelRequest: 0-9.', + max: 9, + min: 0, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'ActiveMonitoringLevel', + }, + [buildRegistryKey(OCPP20ComponentName.MonitoringCtrlr as string, 'Available')]: { + component: OCPP20ComponentName.MonitoringCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'true', + description: 'Whether monitoring is available', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Available', + }, + [buildRegistryKey( + OCPP20ComponentName.MonitoringCtrlr as string, + 'BytesPerMessage', + 'ClearVariableMonitoring' + )]: { + component: OCPP20ComponentName.MonitoringCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '8192', + description: 'Maximum number of bytes in a ClearVariableMonitoring message.', + instance: 'ClearVariableMonitoring', + min: 1, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'BytesPerMessage', + }, + [buildRegistryKey( + OCPP20ComponentName.MonitoringCtrlr as string, + 'BytesPerMessage', + 'SetVariableMonitoring' + )]: { + component: OCPP20ComponentName.MonitoringCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '8192', + description: 'Maximum number of bytes in a SetVariableMonitoring message', + instance: 'SetVariableMonitoring', + min: 1, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'BytesPerMessage', + }, + [buildRegistryKey(OCPP20ComponentName.MonitoringCtrlr as string, 'Enabled')]: { + component: OCPP20ComponentName.MonitoringCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'true', + description: 'Whether monitoring is enabled.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Enabled', + }, + [buildRegistryKey( + OCPP20ComponentName.MonitoringCtrlr as string, + 'ItemsPerMessage', + 'ClearVariableMonitoring' + )]: { + component: OCPP20ComponentName.MonitoringCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '100', + description: 'Maximum number of IDs in a ClearVariableMonitoringRequest.', + instance: 'ClearVariableMonitoring', + min: 1, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'ItemsPerMessage', + }, + [buildRegistryKey( + OCPP20ComponentName.MonitoringCtrlr as string, + 'ItemsPerMessage', + 'SetVariableMonitoring' + )]: { + component: OCPP20ComponentName.MonitoringCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '100', + description: + 'Maximum number of setMonitoringData elements that can be sent in one setVariableMonitoringRequest message.', + instance: 'SetVariableMonitoring', + min: 1, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'ItemsPerMessage', + }, + [buildRegistryKey(OCPP20ComponentName.MonitoringCtrlr as string, 'MonitoringBase')]: { + component: OCPP20ComponentName.MonitoringCtrlr as string, + dataType: DataEnumType.OptionList, + defaultValue: 'All', + description: 'Currently used monitoring base (readonly)', + enumeration: ['All', 'FactoryDefault', 'HardwiredOnly'], + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'MonitoringBase', + }, + [buildRegistryKey(OCPP20ComponentName.MonitoringCtrlr as string, 'MonitoringLevel')]: { + component: OCPP20ComponentName.MonitoringCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '9', + description: 'Currently used monitoring level (readonly)', + max: 9, + min: 0, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'MonitoringLevel', + }, + [buildRegistryKey(OCPP20ComponentName.MonitoringCtrlr as string, 'OfflineQueuingSeverity')]: { + component: OCPP20ComponentName.MonitoringCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '5', + description: + 'When set and the Charging Station is offline, the Charging Station shall queue any notifyEventRequest messages triggered by a monitor with a severity number equal to or lower than the severity configured here.', + max: 9, + min: 0, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'OfflineQueuingSeverity', + }, + + // OCPPCommCtrlr Component + [buildRegistryKey(OCPP20ComponentName.OCPPCommCtrlr as string, 'ActiveNetworkProfile')]: { + component: OCPP20ComponentName.OCPPCommCtrlr as string, + dataType: DataEnumType.string, + description: + 'Indicates the configuration profile the station uses at that moment to connect to the network.', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'ActiveNetworkProfile', + }, + [buildRegistryKey(OCPP20ComponentName.OCPPCommCtrlr as string, 'FieldLength')]: { + component: OCPP20ComponentName.OCPPCommCtrlr as string, + dataType: DataEnumType.integer, + description: + 'This variable is used to report the length of in when it is larger than the length that is defined in the standard OCPP message schema.', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'FieldLength', + }, + [buildRegistryKey(OCPP20ComponentName.OCPPCommCtrlr as string, 'PublicKeyWithSignedMeterValue')]: + { + component: OCPP20ComponentName.OCPPCommCtrlr as string, + dataType: DataEnumType.OptionList, + description: + 'This Configuration Variable can be used to configure whether a public key needs to be sent with a signed meter value.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'PublicKeyWithSignedMeterValue', + }, + [buildRegistryKey(OCPP20ComponentName.OCPPCommCtrlr as string, 'QueueAllMessages')]: { + component: OCPP20ComponentName.OCPPCommCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'When this variable is set to true, the Charging Station will queue all message until they are delivered to the CSMS.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'QueueAllMessages', + }, + [buildRegistryKey(OCPP20ComponentName.OCPPCommCtrlr as string, 'RetryBackOffRandomRange')]: { + component: OCPP20ComponentName.OCPPCommCtrlr as string, + dataType: DataEnumType.integer, + description: + 'When the Charging Station is reconnecting, after a connection loss, it will use this variable as the maximum value for the random part of the back-off time', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'RetryBackOffRandomRange', + }, + [buildRegistryKey(OCPP20ComponentName.OCPPCommCtrlr as string, 'RetryBackOffRepeatTimes')]: { + component: OCPP20ComponentName.OCPPCommCtrlr as string, + dataType: DataEnumType.integer, + description: + 'When the Charging Station is reconnecting, after a connection loss, it will use this variable for the amount of times it will double the previous back-off time.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'RetryBackOffRepeatTimes', + }, + [buildRegistryKey(OCPP20ComponentName.OCPPCommCtrlr as string, 'RetryBackOffWaitMinimum')]: { + component: OCPP20ComponentName.OCPPCommCtrlr as string, + dataType: DataEnumType.integer, + description: + 'When the Charging Station is reconnecting, after a connection loss, it will use this variable as the minimum back-off time, the first time it tries to reconnect.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'RetryBackOffWaitMinimum', + }, [buildRegistryKey( OCPP20ComponentName.OCPPCommCtrlr as string, OCPP20OptionalVariableName.HeartbeatInterval @@ -441,10 +1398,27 @@ export const VARIABLE_REGISTRY: Record = { min: 1, mutability: MutabilityEnumType.ReadWrite, persistence: PersistenceEnumType.Persistent, - positive: true, + positive: true, + supportedAttributes: [AttributeEnumType.Actual], + unit: 's', + variable: OCPP20OptionalVariableName.HeartbeatInterval as string, + }, + [buildRegistryKey( + OCPP20ComponentName.OCPPCommCtrlr as string, + OCPP20OptionalVariableName.WebSocketPingInterval + )]: { + allowZero: true, + component: OCPP20ComponentName.OCPPCommCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '30', + description: + '0 disables client side websocket Ping/Pong. Positive values are interpreted as number of seconds between pings. Negative values are not allowed.', + min: 0, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, supportedAttributes: [AttributeEnumType.Actual], - unit: 'seconds', - variable: OCPP20OptionalVariableName.HeartbeatInterval as string, + unit: 's', + variable: OCPP20OptionalVariableName.WebSocketPingInterval as string, }, [buildRegistryKey( OCPP20ComponentName.OCPPCommCtrlr as string, @@ -476,7 +1450,7 @@ export const VARIABLE_REGISTRY: Record = { persistence: PersistenceEnumType.Persistent, positive: true, supportedAttributes: [AttributeEnumType.Actual], - unit: 'seconds', + unit: 's', variable: OCPP20RequiredVariableName.MessageAttemptInterval as string, }, [buildRegistryKey( @@ -513,7 +1487,7 @@ export const VARIABLE_REGISTRY: Record = { persistence: PersistenceEnumType.Persistent, positive: true, supportedAttributes: [AttributeEnumType.Actual], - unit: 'seconds', + unit: 's', variable: OCPP20RequiredVariableName.MessageTimeout as string, }, [buildRegistryKey( @@ -521,7 +1495,7 @@ export const VARIABLE_REGISTRY: Record = { OCPP20RequiredVariableName.NetworkConfigurationPriority )]: { component: OCPP20ComponentName.OCPPCommCtrlr as string, - dataType: DataEnumType.SequenceList, + dataType: DataEnumType.string, defaultValue: '1,2,3', description: 'Comma separated ordered list of network profile priorities.', enumeration: ['1', '2', '3'], @@ -559,7 +1533,7 @@ export const VARIABLE_REGISTRY: Record = { persistence: PersistenceEnumType.Persistent, positive: true, supportedAttributes: [AttributeEnumType.Actual], - unit: 'seconds', + unit: 's', variable: OCPP20RequiredVariableName.OfflineThreshold as string, }, [buildRegistryKey( @@ -592,7 +1566,96 @@ export const VARIABLE_REGISTRY: Record = { variable: OCPP20RequiredVariableName.UnlockOnEVSideDisconnect as string, }, - // SampledDataCtrlr variables + // ReservationCtrlr Component + [buildRegistryKey(OCPP20ComponentName.ReservationCtrlr as string, 'Available')]: { + component: OCPP20ComponentName.ReservationCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'true', + description: 'Whether reservation is supported.', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Available', + }, + [buildRegistryKey(OCPP20ComponentName.ReservationCtrlr as string, 'Enabled')]: { + component: OCPP20ComponentName.ReservationCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: 'Whether reservation is enabled.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Enabled', + }, + [buildRegistryKey(OCPP20ComponentName.ReservationCtrlr as string, 'NonEvseSpecific')]: { + component: OCPP20ComponentName.ReservationCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'If this configuration variable is present and set to true: Charging Station supports Reservation where EVSE id is not specified.', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'NonEvseSpecific', + }, + + // SampledDataCtrlr Component + [buildRegistryKey(OCPP20ComponentName.SampledDataCtrlr as string, 'Available')]: { + component: OCPP20ComponentName.SampledDataCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'true', + description: 'If this variable reports a value of true, Sampled Data is supported', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Available', + }, + [buildRegistryKey(OCPP20ComponentName.SampledDataCtrlr as string, 'Enabled')]: { + component: OCPP20ComponentName.SampledDataCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'true', + description: 'If this variable reports a value of true, Sampled Data is enabled.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Enabled', + }, + [buildRegistryKey(OCPP20ComponentName.SampledDataCtrlr as string, 'RegisterValuesWithoutPhases')]: + { + component: OCPP20ComponentName.SampledDataCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'If this variable reports a value of true, then meter values of measurand Energy.Active.Import.Register will only report the total energy over all phases without reporting the individual phase values.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'RegisterValuesWithoutPhases', + }, + [buildRegistryKey(OCPP20ComponentName.SampledDataCtrlr as string, 'SignReadings')]: { + component: OCPP20ComponentName.SampledDataCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'If set to true, the Charging Station SHALL include signed meter values in the TransactionEventRequest to the CSMS', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'SignReadings', + }, + [buildRegistryKey(OCPP20ComponentName.SampledDataCtrlr as string, 'TxEndedInterval')]: { + component: OCPP20ComponentName.SampledDataCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '60', + description: + 'Interval between sampling of metering data, intended to be transmitted in the TransactionEventRequest (eventType = Ended) message.', + min: 1, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + unit: 's', + variable: 'TxEndedInterval', + }, [buildRegistryKey( OCPP20ComponentName.SampledDataCtrlr as string, OCPP20MeasurandEnumType.CURRENT_IMPORT @@ -724,7 +1787,7 @@ export const VARIABLE_REGISTRY: Record = { persistence: PersistenceEnumType.Volatile, positive: true, supportedAttributes: [AttributeEnumType.Actual], - unit: 'seconds', + unit: 's', variable: OCPP20RequiredVariableName.TxUpdatedInterval as string, }, [buildRegistryKey( @@ -757,7 +1820,72 @@ export const VARIABLE_REGISTRY: Record = { variable: OCPP20RequiredVariableName.TxUpdatedMeasurands as string, }, - // SecurityCtrlr variables + // SecurityCtrlr Component + [buildRegistryKey(OCPP20ComponentName.SecurityCtrlr as string, 'AdditionalRootCertificateCheck')]: + { + component: OCPP20ComponentName.SecurityCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: 'Required for all security profiles except profile 1.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'AdditionalRootCertificateCheck', + }, + [buildRegistryKey(OCPP20ComponentName.SecurityCtrlr as string, 'BasicAuthPassword')]: { + component: OCPP20ComponentName.SecurityCtrlr as string, + dataType: DataEnumType.string, + description: 'The basic authentication password is used for HTTP Basic Authentication.', + mutability: MutabilityEnumType.WriteOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'BasicAuthPassword', + }, + [buildRegistryKey(OCPP20ComponentName.SecurityCtrlr as string, 'CertSigningRepeatTimes')]: { + component: OCPP20ComponentName.SecurityCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '3', + description: + 'Number of times to resend a SignCertificateRequest when CSMS does nor return a signed certificate.', + min: 0, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'CertSigningRepeatTimes', + }, + [buildRegistryKey(OCPP20ComponentName.SecurityCtrlr as string, 'CertSigningWaitMinimum')]: { + component: OCPP20ComponentName.SecurityCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '60', + description: + 'Seconds to wait before generating another CSR in case CSMS does not return a signed certificate.', + min: 1, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + unit: 's', + variable: 'CertSigningWaitMinimum', + }, + [buildRegistryKey(OCPP20ComponentName.SecurityCtrlr as string, 'Identity')]: { + component: OCPP20ComponentName.SecurityCtrlr as string, + dataType: DataEnumType.string, + description: 'The Charging Station identity.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Identity', + }, + [buildRegistryKey(OCPP20ComponentName.SecurityCtrlr as string, 'MaxCertificateChainSize')]: { + component: OCPP20ComponentName.SecurityCtrlr as string, + dataType: DataEnumType.integer, + description: + "Limit of the size of the 'certificateChain' field from the CertificateSignedRequest", + min: 1, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'MaxCertificateChainSize', + }, [buildRegistryKey( OCPP20ComponentName.SecurityCtrlr as string, OCPP20RequiredVariableName.CertificateEntries @@ -824,7 +1952,260 @@ export const VARIABLE_REGISTRY: Record = { vendorSpecific: true, }, - // TxCtrlr variables + // SmartChargingCtrlr Component + [buildRegistryKey(OCPP20ComponentName.SmartChargingCtrlr as string, 'ACPhaseSwitchingSupported')]: + { + component: OCPP20ComponentName.SmartChargingCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'This variable can be used to indicate an on-load/in-transaction capability. If defined and true, this EVSE supports the selection of which phase to use for 1 phase AC charging.', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'ACPhaseSwitchingSupported', + }, + [buildRegistryKey(OCPP20ComponentName.SmartChargingCtrlr as string, 'Available')]: { + component: OCPP20ComponentName.SmartChargingCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'true', + description: 'Whether smart charging is supported.', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Available', + }, + [buildRegistryKey(OCPP20ComponentName.SmartChargingCtrlr as string, 'Enabled')]: { + component: OCPP20ComponentName.SmartChargingCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'true', + description: 'Whether smart charging is enabled.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Enabled', + }, + [buildRegistryKey( + OCPP20ComponentName.SmartChargingCtrlr as string, + 'Entries', + 'ChargingProfiles' + )]: { + component: OCPP20ComponentName.SmartChargingCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '0', + description: + 'Entries(ChargingProfiles) is the amount of Charging profiles currently installed on the Charging Station', + instance: 'ChargingProfiles', + min: 0, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Entries', + }, + [buildRegistryKey( + OCPP20ComponentName.SmartChargingCtrlr as string, + 'ExternalControlSignalsEnabled' + )]: { + component: OCPP20ComponentName.SmartChargingCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'Indicates whether a Charging Station should respond to external control signals that influence charging.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'ExternalControlSignalsEnabled', + }, + [buildRegistryKey(OCPP20ComponentName.SmartChargingCtrlr as string, 'LimitChangeSignificance')]: { + component: OCPP20ComponentName.SmartChargingCtrlr as string, + dataType: DataEnumType.decimal, + defaultValue: '1.0', + description: + 'If at the Charging Station side a change in the limit in a ChargingProfile is lower than this percentage, the Charging Station MAY skip sending a NotifyChargingLimitRequest or a TransactionEventRequest message to the CSMS.', + max: 100.0, + min: 0.0, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + unit: 'Percent', + variable: 'LimitChangeSignificance', + }, + [buildRegistryKey( + OCPP20ComponentName.SmartChargingCtrlr as string, + 'NotifyChargingLimitWithSchedules' + )]: { + component: OCPP20ComponentName.SmartChargingCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'Indicates if the Charging Station should include the externally set charging limit/schedule in the message when it sends a NotifyChargingLimitRequest message.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'NotifyChargingLimitWithSchedules', + }, + [buildRegistryKey(OCPP20ComponentName.SmartChargingCtrlr as string, 'PeriodsPerSchedule')]: { + component: OCPP20ComponentName.SmartChargingCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '24', + description: 'Maximum number of periods that may be defined per ChargingSchedule.', + min: 1, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'PeriodsPerSchedule', + }, + [buildRegistryKey(OCPP20ComponentName.SmartChargingCtrlr as string, 'Phases3to1')]: { + component: OCPP20ComponentName.SmartChargingCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'If defined and true, this Charging Station supports switching from 3 to 1 phase during a transaction', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Phases3to1', + }, + [buildRegistryKey(OCPP20ComponentName.SmartChargingCtrlr as string, 'ProfileStackLevel')]: { + component: OCPP20ComponentName.SmartChargingCtrlr as string, + dataType: DataEnumType.integer, + defaultValue: '10', + description: + 'Maximum acceptable value for stackLevel in a ChargingProfile. Since the lowest stackLevel is 0, this means that if SmartChargingCtrlr.ProfileStackLevel = 1, there can be at most 2 valid charging profiles per Charging Profile Purpose per EVSE.', + min: 0, + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'ProfileStackLevel', + }, + [buildRegistryKey(OCPP20ComponentName.SmartChargingCtrlr as string, 'RateUnit')]: { + component: OCPP20ComponentName.SmartChargingCtrlr as string, + dataType: DataEnumType.MemberList, + defaultValue: 'A,W', + description: + "A list of supported quantities for use in a ChargingSchedule. Allowed values: 'A' and 'W'", + enumeration: ['A', 'W'], + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'RateUnit', + }, + + // TariffCostCtrlr Component + [buildRegistryKey(OCPP20ComponentName.TariffCostCtrlr as string, 'Available', 'Cost')]: { + component: OCPP20ComponentName.TariffCostCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: 'Instance Cost: Whether costs are supported.', + instance: 'Cost', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Available', + }, + [buildRegistryKey(OCPP20ComponentName.TariffCostCtrlr as string, 'Available', 'Tariff')]: { + component: OCPP20ComponentName.TariffCostCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: 'Instance Tariff: Whether tariffs are supported.', + instance: 'Tariff', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Available', + }, + [buildRegistryKey(OCPP20ComponentName.TariffCostCtrlr as string, 'Currency')]: { + component: OCPP20ComponentName.TariffCostCtrlr as string, + dataType: DataEnumType.string, + defaultValue: 'EUR', + description: 'Currency used by this Charging Station in a ISO 4217 formatted currency code.', + maxLength: 3, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Currency', + }, + [buildRegistryKey(OCPP20ComponentName.TariffCostCtrlr as string, 'Enabled', 'Cost')]: { + component: OCPP20ComponentName.TariffCostCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: 'Instance Cost: Whether costs are enabled.', + instance: 'Cost', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Enabled', + }, + [buildRegistryKey(OCPP20ComponentName.TariffCostCtrlr as string, 'Enabled', 'Tariff')]: { + component: OCPP20ComponentName.TariffCostCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: 'Instance Tariff: Whether tariffs are enabled.', + instance: 'Tariff', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'Enabled', + }, + [buildRegistryKey(OCPP20ComponentName.TariffCostCtrlr as string, 'TariffFallbackMessage')]: { + component: OCPP20ComponentName.TariffCostCtrlr as string, + dataType: DataEnumType.string, + defaultValue: 'Standard charging rate applies', + description: + 'Message (and/or tariff information) to be shown to an EV Driver when there is no driver specific tariff information available.', + maxLength: 512, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'TariffFallbackMessage', + }, + [buildRegistryKey(OCPP20ComponentName.TariffCostCtrlr as string, 'TotalCostFallbackMessage')]: { + component: OCPP20ComponentName.TariffCostCtrlr as string, + dataType: DataEnumType.string, + defaultValue: 'Cost information not available', + description: + 'Message to be shown to an EV Driver when the Charging Station cannot retrieve the cost for a transaction at the end of the transaction.', + maxLength: 512, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'TotalCostFallbackMessage', + }, + + // TxCtrlr Component + [buildRegistryKey(OCPP20ComponentName.TxCtrlr as string, 'ChargingTime')]: { + component: OCPP20ComponentName.TxCtrlr as string, + dataType: DataEnumType.decimal, + description: 'Time from earliest to latest substantive energy transfer', + mutability: MutabilityEnumType.ReadOnly, + persistence: PersistenceEnumType.Volatile, + supportedAttributes: [AttributeEnumType.Actual], + unit: 's', + variable: 'ChargingTime', + }, + [buildRegistryKey(OCPP20ComponentName.TxCtrlr as string, 'MaxEnergyOnInvalidId')]: { + component: OCPP20ComponentName.TxCtrlr as string, + dataType: DataEnumType.integer, + description: + 'Maximum amount of energy in Wh delivered when an identifier is deauthorized by the CSMS after start of a transaction.', + min: 0, + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + unit: 'Wh', + variable: 'MaxEnergyOnInvalidId', + }, + [buildRegistryKey(OCPP20ComponentName.TxCtrlr as string, 'TxBeforeAcceptedEnabled')]: { + component: OCPP20ComponentName.TxCtrlr as string, + dataType: DataEnumType.boolean, + defaultValue: 'false', + description: + 'Allow charging before having received a BootNotificationResponse with RegistrationStatus: Accepted.', + mutability: MutabilityEnumType.ReadWrite, + persistence: PersistenceEnumType.Persistent, + supportedAttributes: [AttributeEnumType.Actual], + variable: 'TxBeforeAcceptedEnabled', + }, [buildRegistryKey( OCPP20ComponentName.TxCtrlr as string, OCPP20RequiredVariableName.EVConnectionTimeOut @@ -840,7 +2221,7 @@ export const VARIABLE_REGISTRY: Record = { persistence: PersistenceEnumType.Persistent, positive: true, supportedAttributes: [AttributeEnumType.Actual], - unit: 'seconds', + unit: 's', variable: OCPP20RequiredVariableName.EVConnectionTimeOut as string, }, [buildRegistryKey( @@ -882,7 +2263,7 @@ export const VARIABLE_REGISTRY: Record = { 'EVConnected', 'PowerPathClosed', 'EnergyTransfer', - 'ParkingBayOccupancy', + 'ParkingBayOccupied', 'DataSigned', ], mutability: MutabilityEnumType.ReadWrite, @@ -901,7 +2282,7 @@ export const VARIABLE_REGISTRY: Record = { 'EVConnected', 'PowerPathClosed', 'EnergyTransfer', - 'ParkingBayOccupancy', + 'ParkingBayOccupied', ], mutability: MutabilityEnumType.ReadWrite, persistence: PersistenceEnumType.Persistent, diff --git a/tests/charging-station/ocpp/2.0/OCPP20VariableManager.test.ts b/tests/charging-station/ocpp/2.0/OCPP20VariableManager.test.ts index f9885d14..91504135 100644 --- a/tests/charging-station/ocpp/2.0/OCPP20VariableManager.test.ts +++ b/tests/charging-station/ocpp/2.0/OCPP20VariableManager.test.ts @@ -1553,16 +1553,16 @@ await describe('OCPP20VariableManager test suite', async () => { }, ])[0] expect(res.attributeStatus).toBe(GetVariableStatusEnumType.Accepted) - expect(res.attributeValue).toBe('ChangeMeOrg') + expect(res.attributeValue).toBe('Example Charging Services Ltd') const after = getConfigurationKey( mockChargingStation, OCPP20RequiredVariableName.OrganizationName as unknown as VariableType['name'] ) expect(after).toBeDefined() - expect(after?.value).toBe('ChangeMeOrg') + expect(after?.value).toBe('Example Charging Services Ltd') }) - await it('Should accept setting OrganizationName but not persist new value (current limitation)', () => { + await it('Should accept setting OrganizationName and require reboot per OCPP 2.0.1 specification', () => { const setRes = manager.setVariables(mockChargingStation, [ { attributeValue: 'NewOrgName', @@ -1570,16 +1570,15 @@ await describe('OCPP20VariableManager test suite', async () => { variable: { name: OCPP20RequiredVariableName.OrganizationName }, }, ])[0] - // Current implementation only marks rebootRequired for ChargingStation component variables - expect(setRes.attributeStatus).toBe(SetVariableStatusEnumType.Accepted) + // OCPP 2.0.1 compliant behavior: OrganizationName changes require reboot + expect(setRes.attributeStatus).toBe(SetVariableStatusEnumType.RebootRequired) const getRes = manager.getVariables(mockChargingStation, [ { component: { name: OCPP20ComponentName.SecurityCtrlr }, variable: { name: OCPP20RequiredVariableName.OrganizationName }, }, ])[0] - // Value remains the configuration key default due to lack of persistence path for non-ChargingStation components - expect(getRes.attributeValue).toBe('ChangeMeOrg') + expect(getRes.attributeValue).toBe('NewOrgName') }) await it('Should preserve OrganizationName value after resetRuntimeOverrides()', () => { @@ -1591,7 +1590,8 @@ await describe('OCPP20VariableManager test suite', async () => { }, ])[0] expect(res.attributeStatus).toBe(GetVariableStatusEnumType.Accepted) - expect(res.attributeValue).toBe('ChangeMeOrg') + // Value should persist as 'NewOrgName' from previous test (OCPP 2.0.1 compliant persistence) + expect(res.attributeValue).toBe('NewOrgName') }) await it('Should create configuration key for instance-scoped MessageAttemptInterval and persist Actual value (Actual-only, no MinSet/MaxSet)', () => {