Add BootNotification and ClearCache OCPP 2.0.1 commands support
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStationUtils.ts
index e378fdec87bd26832ce1abf4ebe2cddd53b8a1b9..540ec4ffa36bfef0dccbdb45afc2a8ca1e6a0769 100644 (file)
@@ -12,23 +12,17 @@ import {
   CurrentType,
   Voltage,
 } from '../types/ChargingStationTemplate';
-import type { SampledValueTemplate } from '../types/MeasurandPerPhaseSampledValueTemplates';
 import { ChargingProfileKindType, RecurrencyKindType } from '../types/ocpp/1.6/ChargingProfile';
+import type { OCPP16BootNotificationRequest } from '../types/ocpp/1.6/Requests';
+import { BootReasonEnumType, OCPP20BootNotificationRequest } from '../types/ocpp/2.0/Requests';
 import type { ChargingProfile, ChargingSchedulePeriod } from '../types/ocpp/ChargingProfile';
-import { StandardParametersKey } from '../types/ocpp/Configuration';
-import { MeterValueMeasurand, MeterValuePhase } from '../types/ocpp/MeterValues';
-import {
-  type BootNotificationRequest,
-  IncomingRequestCommand,
-  RequestCommand,
-} from '../types/ocpp/Requests';
+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 logger from '../utils/Logger';
 import Utils from '../utils/Utils';
-import type ChargingStation from './ChargingStation';
-import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils';
 
 const moduleName = 'ChargingStationUtils';
 
@@ -64,6 +58,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,
       }),
@@ -140,27 +135,50 @@ export class ChargingStationUtils {
   public static createBootNotificationRequest(
     stationInfo: ChargingStationInfo
   ): 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: BootReasonEnumType.PowerUp,
+          chargingStation: {
+            model: stationInfo.chargePointModel,
+            vendorName: stationInfo.chargePointVendor,
+            ...(!Utils.isUndefined(stationInfo.firmwareVersion) && {
+              firmwareVersion: stationInfo.firmwareVersion,
+            }),
+            ...(!Utils.isUndefined(stationInfo.chargeBoxSerialNumber) && {
+              serialNumber: stationInfo.chargeBoxSerialNumber,
+            }),
+            modem: {
+              ...(!Utils.isUndefined(stationInfo.iccid) && { iccid: stationInfo.iccid }),
+              ...(!Utils.isUndefined(stationInfo.imsi) && { imsi: stationInfo.imsi }),
+            },
+          },
+        } as OCPP20BootNotificationRequest;
+    }
   }
 
   public static workerPoolInUse(): boolean {
@@ -289,47 +307,12 @@ export class ChargingStationUtils {
     return unitDivider;
   }
 
-  public static setChargingProfile(
-    chargingStation: ChargingStation,
-    connectorId: number,
-    cp: ChargingProfile
-  ): void {
-    if (Utils.isNullOrUndefined(chargingStation.getConnectorStatus(connectorId).chargingProfiles)) {
-      logger.error(
-        `${chargingStation.logPrefix()} Trying to set a charging profile on connectorId ${connectorId} with an uninitialized charging profiles array attribute, applying deferred initialization`
-      );
-      chargingStation.getConnectorStatus(connectorId).chargingProfiles = [];
-    }
-    if (Array.isArray(chargingStation.getConnectorStatus(connectorId).chargingProfiles) === false) {
-      logger.error(
-        `${chargingStation.logPrefix()} Trying to set a charging profile on connectorId ${connectorId} with an improper attribute type for the charging profiles array, applying proper type initialization`
-      );
-      chargingStation.getConnectorStatus(connectorId).chargingProfiles = [];
-    }
-    let cpReplaced = false;
-    if (!Utils.isEmptyArray(chargingStation.getConnectorStatus(connectorId).chargingProfiles)) {
-      chargingStation
-        .getConnectorStatus(connectorId)
-        .chargingProfiles?.forEach((chargingProfile: ChargingProfile, index: number) => {
-          if (
-            chargingProfile.chargingProfileId === cp.chargingProfileId ||
-            (chargingProfile.stackLevel === cp.stackLevel &&
-              chargingProfile.chargingProfilePurpose === cp.chargingProfilePurpose)
-          ) {
-            chargingStation.getConnectorStatus(connectorId).chargingProfiles[index] = cp;
-            cpReplaced = true;
-          }
-        });
-    }
-    !cpReplaced && chargingStation.getConnectorStatus(connectorId).chargingProfiles?.push(cp);
-  }
-
   /**
    * 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(
     chargingProfiles: ChargingProfile[],
@@ -442,87 +425,6 @@ export class ChargingStationUtils {
     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) === false) {
-      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
-        ) === false
-      ) {
-        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) === true
-      ) {
-        return sampledValueTemplates[index];
-      } else if (
-        !phase &&
-        !sampledValueTemplates[index].phase &&
-        sampledValueTemplates[index]?.measurand === measurand &&
-        ChargingStationConfigurationUtils.getConfigurationKey(
-          chargingStation,
-          StandardParametersKey.MeterValuesSampledData
-        )?.value.includes(measurand) === true
-      ) {
-        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 = `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}`
-    );
-  }
-
   public static getAuthorizationFile(stationInfo: ChargingStationInfo): string | undefined {
     return (
       stationInfo.authorizationFile &&
@@ -534,46 +436,6 @@ 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;