X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FChargingStationUtils.ts;h=c10a3a15b229579523ad92fbf5efb679a8cf5961;hb=44eb6026079c8dc2c77b10a96a42d0c0b2da7c8f;hp=b57e98e6741222f309d04d8ac84ed3ccbf4bec37;hpb=fa7bccf4a465d2156c43a3b5f33f0b521da52dc3;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ChargingStationUtils.ts b/src/charging-station/ChargingStationUtils.ts index b57e98e6..c10a3a15 100644 --- a/src/charging-station/ChargingStationUtils.ts +++ b/src/charging-station/ChargingStationUtils.ts @@ -1,32 +1,42 @@ -import { ChargingProfile, ChargingSchedulePeriod } from '../types/ocpp/ChargingProfile'; -import { ChargingProfileKindType, RecurrencyKindType } from '../types/ocpp/1.6/ChargingProfile'; -import ChargingStationTemplate, { +import crypto from 'node:crypto'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +import moment from 'moment'; + +import type ChargingStation from './ChargingStation'; +import BaseError from '../exception/BaseError'; +import type { ChargingStationInfo } from '../types/ChargingStationInfo'; +import { AmpereUnits, + type ChargingStationTemplate, CurrentType, Voltage, } from '../types/ChargingStationTemplate'; -import { MeterValueMeasurand, MeterValuePhase } from '../types/ocpp/MeterValues'; - -import { BootNotificationRequest } from '../types/ocpp/Requests'; -import ChargingStation from './ChargingStation'; -import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils'; -import ChargingStationInfo from '../types/ChargingStationInfo'; +import { ChargingProfileKindType, RecurrencyKindType } from '../types/ocpp/1.6/ChargingProfile'; +import type { OCPP16BootNotificationRequest } from '../types/ocpp/1.6/Requests'; +import { BootReasonEnumType, type OCPP20BootNotificationRequest } from '../types/ocpp/2.0/Requests'; +import { + type ChargingProfile, + ChargingRateUnitType, + type ChargingSchedulePeriod, +} from '../types/ocpp/ChargingProfile'; +import { OCPPVersion } from '../types/ocpp/OCPPVersion'; +import type { BootNotificationRequest } from '../types/ocpp/Requests'; +import { WorkerProcessType } from '../types/Worker'; import Configuration from '../utils/Configuration'; import Constants from '../utils/Constants'; -import { FileType } from '../types/FileType'; -import FileUtils from '../utils/FileUtils'; -import { SampledValueTemplate } from '../types/MeasurandPerPhaseSampledValueTemplates'; -import { StandardParametersKey } from '../types/ocpp/Configuration'; -import Utils from '../utils/Utils'; -import { WebSocketCloseEventStatusString } from '../types/WebSocket'; -import { WorkerProcessType } from '../types/Worker'; -import crypto from 'crypto'; -import fs from 'fs'; +import { ACElectricUtils, DCElectricUtils } from '../utils/ElectricUtils'; import logger from '../utils/Logger'; -import moment from 'moment'; -import path from 'path'; +import Utils from '../utils/Utils'; + +const moduleName = 'ChargingStationUtils'; export class ChargingStationUtils { + private constructor() { + // This is intentional + } + public static getChargingStationId( index: number, stationTemplate: ChargingStationTemplate @@ -34,18 +44,16 @@ export class ChargingStationUtils { // In case of multiple instances: add instance index to charging station id const instanceIndex = process.env.CF_INSTANCE_INDEX ?? 0; const idSuffix = stationTemplate.nameSuffix ?? ''; - const idStr = '000000000' + index.toString(); + const idStr = `000000000${index.toString()}`; return stationTemplate?.fixedName ? stationTemplate.baseName - : stationTemplate.baseName + - '-' + - instanceIndex.toString() + - idStr.substring(idStr.length - 4) + - idSuffix; + : `${stationTemplate.baseName}-${instanceIndex.toString()}${idStr.substring( + idStr.length - 4 + )}${idSuffix}`; } public static getHashId(index: number, stationTemplate: ChargingStationTemplate): string { - const hashBootNotificationRequest = { + const chargingStationInfo = { chargePointModel: stationTemplate.chargePointModel, chargePointVendor: stationTemplate.chargePointVendor, ...(!Utils.isUndefined(stationTemplate.chargeBoxSerialNumberPrefix) && { @@ -54,6 +62,7 @@ export class ChargingStationUtils { ...(!Utils.isUndefined(stationTemplate.chargePointSerialNumberPrefix) && { chargePointSerialNumber: stationTemplate.chargePointSerialNumberPrefix, }), + // FIXME?: Should a firmware version change always reference a new configuration file? ...(!Utils.isUndefined(stationTemplate.firmwareVersion) && { firmwareVersion: stationTemplate.firmwareVersion, }), @@ -69,7 +78,7 @@ export class ChargingStationUtils { return crypto .createHash(Constants.DEFAULT_HASH_ALGORITHM) .update( - JSON.stringify(hashBootNotificationRequest) + + JSON.stringify(chargingStationInfo) + ChargingStationUtils.getChargingStationId(index, stationTemplate) ) .digest('hex'); @@ -99,16 +108,13 @@ export class ChargingStationUtils { } } - public static getConfiguredNumberOfConnectors( - index: number, - stationTemplate: ChargingStationTemplate - ): number { + public static getConfiguredNumberOfConnectors(stationTemplate: ChargingStationTemplate): number { let configuredMaxConnectors: number; - if (!Utils.isEmptyArray(stationTemplate.numberOfConnectors)) { + if (Utils.isEmptyArray(stationTemplate.numberOfConnectors) === false) { const numberOfConnectors = stationTemplate.numberOfConnectors as number[]; - // Distribute evenly the number of connectors - configuredMaxConnectors = numberOfConnectors[(index - 1) % numberOfConnectors.length]; - } else if (!Utils.isUndefined(stationTemplate.numberOfConnectors)) { + configuredMaxConnectors = + numberOfConnectors[Math.floor(Utils.secureRandom() * numberOfConnectors.length)]; + } else if (Utils.isUndefined(stationTemplate.numberOfConnectors) === false) { configuredMaxConnectors = stationTemplate.numberOfConnectors as number; } else { configuredMaxConnectors = stationTemplate?.Connectors[0] @@ -131,65 +137,65 @@ export class ChargingStationUtils { } public static createBootNotificationRequest( - stationInfo: ChargingStationInfo + stationInfo: ChargingStationInfo, + bootReason: BootReasonEnumType = BootReasonEnumType.PowerUp ): BootNotificationRequest { - return { - chargePointModel: stationInfo.chargePointModel, - chargePointVendor: stationInfo.chargePointVendor, - ...(!Utils.isUndefined(stationInfo.chargeBoxSerialNumber) && { - chargeBoxSerialNumber: stationInfo.chargeBoxSerialNumber, - }), - ...(!Utils.isUndefined(stationInfo.chargePointSerialNumber) && { - chargePointSerialNumber: stationInfo.chargePointSerialNumber, - }), - ...(!Utils.isUndefined(stationInfo.firmwareVersion) && { - firmwareVersion: stationInfo.firmwareVersion, - }), - ...(!Utils.isUndefined(stationInfo.iccid) && { iccid: stationInfo.iccid }), - ...(!Utils.isUndefined(stationInfo.imsi) && { imsi: stationInfo.imsi }), - ...(!Utils.isUndefined(stationInfo.meterSerialNumber) && { - meterSerialNumber: stationInfo.meterSerialNumber, - }), - ...(!Utils.isUndefined(stationInfo.meterType) && { - meterType: stationInfo.meterType, - }), - }; + const ocppVersion = stationInfo.ocppVersion ?? OCPPVersion.VERSION_16; + switch (ocppVersion) { + case OCPPVersion.VERSION_16: + return { + chargePointModel: stationInfo.chargePointModel, + chargePointVendor: stationInfo.chargePointVendor, + ...(!Utils.isUndefined(stationInfo.chargeBoxSerialNumber) && { + chargeBoxSerialNumber: stationInfo.chargeBoxSerialNumber, + }), + ...(!Utils.isUndefined(stationInfo.chargePointSerialNumber) && { + chargePointSerialNumber: stationInfo.chargePointSerialNumber, + }), + ...(!Utils.isUndefined(stationInfo.firmwareVersion) && { + firmwareVersion: stationInfo.firmwareVersion, + }), + ...(!Utils.isUndefined(stationInfo.iccid) && { iccid: stationInfo.iccid }), + ...(!Utils.isUndefined(stationInfo.imsi) && { imsi: stationInfo.imsi }), + ...(!Utils.isUndefined(stationInfo.meterSerialNumber) && { + meterSerialNumber: stationInfo.meterSerialNumber, + }), + ...(!Utils.isUndefined(stationInfo.meterType) && { + meterType: stationInfo.meterType, + }), + } as OCPP16BootNotificationRequest; + case OCPPVersion.VERSION_20: + case OCPPVersion.VERSION_201: + return { + reason: bootReason, + chargingStation: { + model: stationInfo.chargePointModel, + vendorName: stationInfo.chargePointVendor, + ...(!Utils.isUndefined(stationInfo.firmwareVersion) && { + firmwareVersion: stationInfo.firmwareVersion, + }), + ...(!Utils.isUndefined(stationInfo.chargeBoxSerialNumber) && { + serialNumber: stationInfo.chargeBoxSerialNumber, + }), + ...((!Utils.isUndefined(stationInfo.iccid) || !Utils.isUndefined(stationInfo.imsi)) && { + modem: { + ...(!Utils.isUndefined(stationInfo.iccid) && { iccid: stationInfo.iccid }), + ...(!Utils.isUndefined(stationInfo.imsi) && { imsi: stationInfo.imsi }), + }, + }), + }, + } as OCPP20BootNotificationRequest; + } } public static workerPoolInUse(): boolean { return [WorkerProcessType.DYNAMIC_POOL, WorkerProcessType.STATIC_POOL].includes( - Configuration.getWorkerProcess() + Configuration.getWorker().processType ); } public static workerDynamicPoolInUse(): boolean { - return Configuration.getWorkerProcess() === WorkerProcessType.DYNAMIC_POOL; - } - - /** - * Convert websocket error code to human readable string message - * - * @param code websocket error code - * @returns human readable string message - */ - public static getWebSocketCloseEventStatusString(code: number): string { - if (code >= 0 && code <= 999) { - return '(Unused)'; - } else if (code >= 1016) { - if (code <= 1999) { - return '(For WebSocket standard)'; - } else if (code <= 2999) { - return '(For WebSocket extensions)'; - } else if (code <= 3999) { - return '(For libraries and frameworks)'; - } else if (code <= 4999) { - return '(For applications)'; - } - } - if (!Utils.isUndefined(WebSocketCloseEventStatusString[code])) { - return WebSocketCloseEventStatusString[code] as string; - } - return '(Unknown)'; + return Configuration.getWorker().processType === WorkerProcessType.DYNAMIC_POOL; } public static warnDeprecatedTemplateKey( @@ -202,7 +208,7 @@ export class ChargingStationUtils { if (!Utils.isUndefined(template[key])) { logger.warn( `${logPrefix} Deprecated template key '${key}' usage in file '${templateFile}'${ - logMsgToAppend && '. ' + logMsgToAppend + logMsgToAppend && `. ${logMsgToAppend}` }` ); } @@ -229,24 +235,16 @@ export class ChargingStationUtils { delete stationTemplate.AutomaticTransactionGenerator; delete stationTemplate.chargeBoxSerialNumberPrefix; delete stationTemplate.chargePointSerialNumberPrefix; - return stationTemplate; + delete stationTemplate.meterSerialNumberPrefix; + return stationTemplate as unknown as ChargingStationInfo; } public static createStationInfoHash(stationInfo: ChargingStationInfo): void { - const previousInfoHash = stationInfo?.infoHash ?? ''; delete stationInfo.infoHash; - const currentInfoHash = crypto + stationInfo.infoHash = crypto .createHash(Constants.DEFAULT_HASH_ALGORITHM) .update(JSON.stringify(stationInfo)) .digest('hex'); - if ( - Utils.isEmptyString(previousInfoHash) || - (!Utils.isEmptyString(previousInfoHash) && currentInfoHash !== previousInfoHash) - ) { - stationInfo.infoHash = currentInfoHash; - } else { - stationInfo.infoHash = previousInfoHash; - } } public static createSerialNumber( @@ -268,24 +266,36 @@ export class ChargingStationUtils { upperCase: params.randomSerialNumberUpperCase, }) : ''; - stationTemplate?.chargePointSerialNumberPrefix && - stationInfo && - Utils.isNullOrUndefined(stationInfo?.chargePointSerialNumber) - ? (stationInfo.chargePointSerialNumber = - stationTemplate.chargePointSerialNumberPrefix + serialNumberSuffix) - : stationInfo && delete stationInfo.chargePointSerialNumber; - stationTemplate?.chargeBoxSerialNumberPrefix && - stationInfo && - Utils.isNullOrUndefined(stationInfo?.chargeBoxSerialNumber) - ? (stationInfo.chargeBoxSerialNumber = - stationTemplate.chargeBoxSerialNumberPrefix + serialNumberSuffix) - : stationInfo && delete stationInfo.chargeBoxSerialNumber; - stationTemplate?.meterSerialNumberPrefix && - stationInfo && - Utils.isNullOrUndefined(stationInfo?.meterSerialNumber) - ? (stationInfo.meterSerialNumber = - stationTemplate.meterSerialNumberPrefix + serialNumberSuffix) - : stationInfo && delete stationInfo.meterSerialNumber; + stationInfo.chargePointSerialNumber = + stationTemplate?.chargePointSerialNumberPrefix && + stationTemplate.chargePointSerialNumberPrefix + serialNumberSuffix; + stationInfo.chargeBoxSerialNumber = + stationTemplate?.chargeBoxSerialNumberPrefix && + stationTemplate.chargeBoxSerialNumberPrefix + serialNumberSuffix; + stationInfo.meterSerialNumber = + stationTemplate?.meterSerialNumberPrefix && + stationTemplate.meterSerialNumberPrefix + serialNumberSuffix; + } + + public static propagateSerialNumber( + stationTemplate: ChargingStationTemplate, + stationInfoSrc: ChargingStationInfo, + stationInfoDst: ChargingStationInfo + ) { + if (!stationInfoSrc || !stationTemplate) { + throw new BaseError( + 'Missing charging station template or existing configuration to propagate serial number' + ); + } + stationTemplate?.chargePointSerialNumberPrefix && stationInfoSrc?.chargePointSerialNumber + ? (stationInfoDst.chargePointSerialNumber = stationInfoSrc.chargePointSerialNumber) + : stationInfoDst?.chargePointSerialNumber && delete stationInfoDst.chargePointSerialNumber; + stationTemplate?.chargeBoxSerialNumberPrefix && stationInfoSrc?.chargeBoxSerialNumber + ? (stationInfoDst.chargeBoxSerialNumber = stationInfoSrc.chargeBoxSerialNumber) + : stationInfoDst?.chargeBoxSerialNumber && delete stationInfoDst.chargeBoxSerialNumber; + stationTemplate?.meterSerialNumberPrefix && stationInfoSrc?.meterSerialNumber + ? (stationInfoDst.meterSerialNumber = stationInfoSrc.meterSerialNumber) + : stationInfoDst?.meterSerialNumber && delete stationInfoDst.meterSerialNumber; } public static getAmperageLimitationUnitDivider(stationInfo: ChargingStationInfo): number { @@ -304,20 +314,114 @@ export class ChargingStationUtils { return unitDivider; } + public static getChargingStationConnectorChargingProfilesPowerLimit( + chargingStation: ChargingStation, + connectorId: number + ): number | undefined { + let limit: number, matchingChargingProfile: ChargingProfile; + let chargingProfiles: ChargingProfile[] = []; + // Get charging profiles for connector and sort by stack level + chargingProfiles = chargingStation + .getConnectorStatus(connectorId) + .chargingProfiles.sort((a, b) => b.stackLevel - a.stackLevel); + // Get profiles on connector 0 + if (chargingStation.getConnectorStatus(0).chargingProfiles) { + chargingProfiles.push( + ...chargingStation + .getConnectorStatus(0) + .chargingProfiles.sort((a, b) => b.stackLevel - a.stackLevel) + ); + } + if (!Utils.isEmptyArray(chargingProfiles)) { + const result = ChargingStationUtils.getLimitFromChargingProfiles( + chargingProfiles, + chargingStation.logPrefix() + ); + if (!Utils.isNullOrUndefined(result)) { + limit = result.limit; + matchingChargingProfile = result.matchingChargingProfile; + switch (chargingStation.getCurrentOutType()) { + case CurrentType.AC: + limit = + matchingChargingProfile.chargingSchedule.chargingRateUnit === + ChargingRateUnitType.WATT + ? limit + : ACElectricUtils.powerTotal( + chargingStation.getNumberOfPhases(), + chargingStation.getVoltageOut(), + limit + ); + break; + case CurrentType.DC: + limit = + matchingChargingProfile.chargingSchedule.chargingRateUnit === + ChargingRateUnitType.WATT + ? limit + : DCElectricUtils.power(chargingStation.getVoltageOut(), limit); + } + const connectorMaximumPower = + chargingStation.getMaximumPower() / chargingStation.powerDivider; + if (limit > connectorMaximumPower) { + logger.error( + `${chargingStation.logPrefix()} Charging profile id ${ + matchingChargingProfile.chargingProfileId + } limit ${limit} is greater than connector id ${connectorId} maximum ${connectorMaximumPower}: %j`, + result + ); + limit = connectorMaximumPower; + } + } + } + return limit; + } + + public static getDefaultVoltageOut( + currentType: CurrentType, + templateFile: string, + logPrefix: string + ): Voltage { + const errMsg = `Unknown ${currentType} currentOutType in template file ${templateFile}, cannot define default voltage out`; + let defaultVoltageOut: number; + switch (currentType) { + case CurrentType.AC: + defaultVoltageOut = Voltage.VOLTAGE_230; + break; + case CurrentType.DC: + defaultVoltageOut = Voltage.VOLTAGE_400; + break; + default: + logger.error(`${logPrefix} ${errMsg}`); + throw new BaseError(errMsg); + } + return defaultVoltageOut; + } + + public static getAuthorizationFile(stationInfo: ChargingStationInfo): string | undefined { + return ( + stationInfo.authorizationFile && + path.join( + path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../'), + 'assets', + path.basename(stationInfo.authorizationFile) + ) + ); + } + /** * Charging profiles should already be sorted by connectorId and stack level (highest stack level has priority) * - * @param {ChargingProfile[]} chargingProfiles - * @param {string} logPrefix - * @returns {{ limit, matchingChargingProfile }} + * @param chargingProfiles - + * @param logPrefix - + * @returns */ - public static getLimitFromChargingProfiles( + private static getLimitFromChargingProfiles( chargingProfiles: ChargingProfile[], logPrefix: string ): { limit: number; matchingChargingProfile: ChargingProfile; } | null { + const debugLogMsg = `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Matching charging profile found for power limitation: %j`; for (const chargingProfile of chargingProfiles) { // Set helpers const currentMoment = moment(); @@ -361,10 +465,7 @@ export class ChargingStationUtils { limit: schedulePeriod.limit, matchingChargingProfile: chargingProfile, }; - logger.debug( - `${logPrefix} Matching charging profile found for power limitation: %j`, - result - ); + logger.debug(debugLogMsg, result); return result; } // Find the right schedule period @@ -378,10 +479,7 @@ export class ChargingStationUtils { limit: lastButOneSchedule.limit, matchingChargingProfile: chargingProfile, }; - logger.debug( - `${logPrefix} Matching charging profile found for power limitation: %j`, - result - ); + logger.debug(debugLogMsg, result); return result; } // Keep it @@ -397,10 +495,7 @@ export class ChargingStationUtils { limit: lastButOneSchedule.limit, matchingChargingProfile: chargingProfile, }; - logger.debug( - `${logPrefix} Matching charging profile found for power limitation: %j`, - result - ); + logger.debug(debugLogMsg, result); return result; } } @@ -409,144 +504,6 @@ export class ChargingStationUtils { return null; } - public static getDefaultVoltageOut( - currentType: CurrentType, - templateFile: string, - logPrefix: string - ): Voltage { - const errMsg = `${logPrefix} Unknown ${currentType} currentOutType in template file ${templateFile}, cannot define default voltage out`; - let defaultVoltageOut: number; - switch (currentType) { - case CurrentType.AC: - defaultVoltageOut = Voltage.VOLTAGE_230; - break; - case CurrentType.DC: - defaultVoltageOut = Voltage.VOLTAGE_400; - break; - default: - logger.error(errMsg); - throw new Error(errMsg); - } - return defaultVoltageOut; - } - - public static getSampledValueTemplate( - chargingStation: ChargingStation, - connectorId: number, - measurand: MeterValueMeasurand = MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER, - phase?: MeterValuePhase - ): SampledValueTemplate | undefined { - const onPhaseStr = phase ? `on phase ${phase} ` : ''; - if (!Constants.SUPPORTED_MEASURANDS.includes(measurand)) { - logger.warn( - `${chargingStation.logPrefix()} Trying to get unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}` - ); - return; - } - if ( - measurand !== MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER && - !ChargingStationConfigurationUtils.getConfigurationKey( - chargingStation, - StandardParametersKey.MeterValuesSampledData - )?.value.includes(measurand) - ) { - logger.debug( - `${chargingStation.logPrefix()} Trying to get MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId} not found in '${ - StandardParametersKey.MeterValuesSampledData - }' OCPP parameter` - ); - return; - } - const sampledValueTemplates: SampledValueTemplate[] = - chargingStation.getConnectorStatus(connectorId).MeterValues; - for ( - let index = 0; - !Utils.isEmptyArray(sampledValueTemplates) && index < sampledValueTemplates.length; - index++ - ) { - if ( - !Constants.SUPPORTED_MEASURANDS.includes( - sampledValueTemplates[index]?.measurand ?? - MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER - ) - ) { - logger.warn( - `${chargingStation.logPrefix()} Unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}` - ); - } else if ( - phase && - sampledValueTemplates[index]?.phase === phase && - sampledValueTemplates[index]?.measurand === measurand && - ChargingStationConfigurationUtils.getConfigurationKey( - chargingStation, - StandardParametersKey.MeterValuesSampledData - )?.value.includes(measurand) - ) { - return sampledValueTemplates[index]; - } else if ( - !phase && - !sampledValueTemplates[index].phase && - sampledValueTemplates[index]?.measurand === measurand && - ChargingStationConfigurationUtils.getConfigurationKey( - chargingStation, - StandardParametersKey.MeterValuesSampledData - )?.value.includes(measurand) - ) { - return sampledValueTemplates[index]; - } else if ( - measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER && - (!sampledValueTemplates[index].measurand || - sampledValueTemplates[index].measurand === measurand) - ) { - return sampledValueTemplates[index]; - } - } - if (measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER) { - const errorMsg = `${chargingStation.logPrefix()} Missing MeterValues for default measurand '${measurand}' in template on connectorId ${connectorId}`; - logger.error(errorMsg); - throw new Error(errorMsg); - } - logger.debug( - `${chargingStation.logPrefix()} No MeterValues for measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}` - ); - } - - public static getAuthorizedTags( - stationInfo: ChargingStationInfo, - templateFile: string, - logPrefix: string - ): string[] { - let authorizedTags: string[] = []; - const authorizationFile = ChargingStationUtils.getAuthorizationFile(stationInfo); - if (authorizationFile) { - try { - // Load authorization file - authorizedTags = JSON.parse(fs.readFileSync(authorizationFile, 'utf8')) as string[]; - } catch (error) { - FileUtils.handleFileException( - logPrefix, - FileType.Authorization, - authorizationFile, - error as NodeJS.ErrnoException - ); - } - } else { - logger.info(logPrefix + ' No authorization file given in template file ' + templateFile); - } - return authorizedTags; - } - - public static getAuthorizationFile(stationInfo: ChargingStationInfo): string | undefined { - return ( - stationInfo.authorizationFile && - path.join( - path.resolve(__dirname, '../'), - 'assets', - path.basename(stationInfo.authorizationFile) - ) - ); - } - private static getRandomSerialNumberSuffix(params?: { randomBytesLength?: number; upperCase?: boolean;