X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FChargingStationUtils.ts;h=24556120b4b9db9862dfae478ce3fcb468e2a309;hb=c72f6634184bc83a6476152446ac9f0d7d02acf5;hp=2ac8a81bd4feb8f3df01972d8b473a435d04caa0;hpb=d5bd1c008c3b2fbe6426ae12e1e12afe97807c57;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ChargingStationUtils.ts b/src/charging-station/ChargingStationUtils.ts index 2ac8a81b..24556120 100644 --- a/src/charging-station/ChargingStationUtils.ts +++ b/src/charging-station/ChargingStationUtils.ts @@ -1,29 +1,36 @@ -import { ChargingProfile, ChargingSchedulePeriod } from '../types/ocpp/ChargingProfile'; -import { ChargingProfileKindType, RecurrencyKindType } from '../types/ocpp/1.6/ChargingProfile'; -import ChargingStationTemplate, { +import crypto from 'crypto'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +import moment from 'moment'; + +import BaseError from '../exception/BaseError'; +import type { ChargingStationInfo } from '../types/ChargingStationInfo'; +import { AmpereUnits, + type ChargingStationTemplate, CurrentType, Voltage, } from '../types/ChargingStationTemplate'; +import type { SampledValueTemplate } from '../types/MeasurandPerPhaseSampledValueTemplates'; +import { ChargingProfileKindType, RecurrencyKindType } from '../types/ocpp/1.6/ChargingProfile'; +import type { ChargingProfile, ChargingSchedulePeriod } from '../types/ocpp/ChargingProfile'; +import { StandardParametersKey } from '../types/ocpp/Configuration'; import { MeterValueMeasurand, MeterValuePhase } from '../types/ocpp/MeterValues'; - -import BaseError from '../exception/BaseError'; -import { BootNotificationRequest } from '../types/ocpp/Requests'; -import ChargingStation from './ChargingStation'; -import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils'; -import ChargingStationInfo from '../types/ChargingStationInfo'; +import { + type BootNotificationRequest, + IncomingRequestCommand, + RequestCommand, +} from '../types/ocpp/Requests'; +import { WorkerProcessType } from '../types/Worker'; import Configuration from '../utils/Configuration'; import Constants from '../utils/Constants'; -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 { fileURLToPath } from 'url'; import logger from '../utils/Logger'; -import moment from 'moment'; -import path from 'path'; +import Utils from '../utils/Utils'; +import type ChargingStation from './ChargingStation'; +import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils'; + +const moduleName = 'ChargingStationUtils'; export class ChargingStationUtils { private constructor() { @@ -102,16 +109,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] @@ -169,32 +173,6 @@ export class ChargingStationUtils { return Configuration.getWorker().processType === 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)'; - } - public static warnDeprecatedTemplateKey( template: ChargingStationTemplate, key: string, @@ -233,7 +211,7 @@ export class ChargingStationUtils { delete stationTemplate.chargeBoxSerialNumberPrefix; delete stationTemplate.chargePointSerialNumberPrefix; delete stationTemplate.meterSerialNumberPrefix; - return stationTemplate; + return stationTemplate as unknown as ChargingStationInfo; } public static createStationInfoHash(stationInfo: ChargingStationInfo): void { @@ -325,6 +303,7 @@ export class ChargingStationUtils { 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(); @@ -368,10 +347,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 @@ -385,10 +361,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 @@ -404,10 +377,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; } } @@ -421,7 +391,7 @@ export class ChargingStationUtils { templateFile: string, logPrefix: string ): Voltage { - const errMsg = `${logPrefix} Unknown ${currentType} currentOutType in template file ${templateFile}, cannot define default voltage out`; + const errMsg = `Unknown ${currentType} currentOutType in template file ${templateFile}, cannot define default voltage out`; let defaultVoltageOut: number; switch (currentType) { case CurrentType.AC: @@ -431,8 +401,8 @@ export class ChargingStationUtils { defaultVoltageOut = Voltage.VOLTAGE_400; break; default: - logger.error(errMsg); - throw new Error(errMsg); + logger.error(`${logPrefix} ${errMsg}`); + throw new BaseError(errMsg); } return defaultVoltageOut; } @@ -444,7 +414,7 @@ export class ChargingStationUtils { phase?: MeterValuePhase ): SampledValueTemplate | undefined { const onPhaseStr = phase ? `on phase ${phase} ` : ''; - if (!Constants.SUPPORTED_MEASURANDS.includes(measurand)) { + if (Constants.SUPPORTED_MEASURANDS.includes(measurand) === false) { logger.warn( `${chargingStation.logPrefix()} Trying to get unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}` ); @@ -472,10 +442,10 @@ export class ChargingStationUtils { index++ ) { if ( - !Constants.SUPPORTED_MEASURANDS.includes( + Constants.SUPPORTED_MEASURANDS.includes( sampledValueTemplates[index]?.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER - ) + ) === false ) { logger.warn( `${chargingStation.logPrefix()} Unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}` @@ -487,7 +457,7 @@ export class ChargingStationUtils { ChargingStationConfigurationUtils.getConfigurationKey( chargingStation, StandardParametersKey.MeterValuesSampledData - )?.value.includes(measurand) + )?.value.includes(measurand) === true ) { return sampledValueTemplates[index]; } else if ( @@ -497,7 +467,7 @@ export class ChargingStationUtils { ChargingStationConfigurationUtils.getConfigurationKey( chargingStation, StandardParametersKey.MeterValuesSampledData - )?.value.includes(measurand) + )?.value.includes(measurand) === true ) { return sampledValueTemplates[index]; } else if ( @@ -509,9 +479,9 @@ export class ChargingStationUtils { } } 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); + const errorMsg = `Missing MeterValues for default measurand '${measurand}' in template on connectorId ${connectorId}`; + logger.error(`${chargingStation.logPrefix()} ${errorMsg}`); + throw new BaseError(errorMsg); } logger.debug( `${chargingStation.logPrefix()} No MeterValues for measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}` @@ -529,6 +499,46 @@ export class ChargingStationUtils { ); } + public static isRequestCommandSupported( + command: RequestCommand, + chargingStation: ChargingStation + ): boolean { + const isRequestCommand = Object.values(RequestCommand).includes(command); + if ( + isRequestCommand === true && + !chargingStation.stationInfo?.commandsSupport?.outgoingCommands + ) { + return true; + } else if ( + isRequestCommand === true && + chargingStation.stationInfo?.commandsSupport?.outgoingCommands + ) { + return chargingStation.stationInfo?.commandsSupport?.outgoingCommands[command] ?? false; + } + logger.error(`${chargingStation.logPrefix()} Unknown outgoing OCPP command '${command}'`); + return false; + } + + public static isIncomingRequestCommandSupported( + command: IncomingRequestCommand, + chargingStation: ChargingStation + ): boolean { + const isIncomingRequestCommand = Object.values(IncomingRequestCommand).includes(command); + if ( + isIncomingRequestCommand === true && + !chargingStation.stationInfo?.commandsSupport?.incomingCommands + ) { + return true; + } else if ( + isIncomingRequestCommand === true && + chargingStation.stationInfo?.commandsSupport?.incomingCommands + ) { + return chargingStation.stationInfo?.commandsSupport?.incomingCommands[command] ?? false; + } + logger.error(`${chargingStation.logPrefix()} Unknown incoming OCPP command '${command}'`); + return false; + } + private static getRandomSerialNumberSuffix(params?: { randomBytesLength?: number; upperCase?: boolean;