Factor out power limitation code into static helper
authorJérôme Benoit <jerome.benoit@sap.com>
Sun, 15 Jan 2023 13:42:56 +0000 (14:42 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Sun, 15 Jan 2023 13:42:56 +0000 (14:42 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ChargingStation.ts
src/charging-station/ChargingStationUtils.ts

index ad68f09cb9265eefd84969387c6fe1f64449f32e..e531aa0f04bc5962518998a1affa76ded4b477c5 100644 (file)
@@ -43,7 +43,6 @@ import { SupervisionUrlDistribution } from '../types/ConfigurationData';
 import type { ConnectorStatus } from '../types/ConnectorStatus';
 import { FileType } from '../types/FileType';
 import type { JsonType } from '../types/JsonType';
-import { ChargingProfile, ChargingRateUnitType } from '../types/ocpp/ChargingProfile';
 import {
   ConnectorPhaseRotation,
   StandardParametersKey,
@@ -265,6 +264,11 @@ export default class ChargingStation {
       : defaultVoltageOut;
   }
 
+  public getMaximumPower(stationInfo?: ChargingStationInfo): number {
+    const localStationInfo = stationInfo ?? this.stationInfo;
+    return (localStationInfo['maxPower'] as number) ?? localStationInfo.maximumPower;
+  }
+
   public getConnectorMaximumAvailablePower(connectorId: number): number {
     let connectorAmperageLimitationPowerLimit: number;
     if (
@@ -282,13 +286,14 @@ export default class ChargingStation {
         this.powerDivider;
     }
     const connectorMaximumPower = this.getMaximumPower() / this.powerDivider;
-    const connectorChargingProfilePowerLimit = this.getChargingProfilePowerLimit(connectorId);
+    const connectorChargingProfilesPowerLimit =
+      ChargingStationUtils.getChargingStationConnectorChargingProfilesPowerLimit(this, connectorId);
     return Math.min(
       isNaN(connectorMaximumPower) ? Infinity : connectorMaximumPower,
       isNaN(connectorAmperageLimitationPowerLimit)
         ? Infinity
         : connectorAmperageLimitationPowerLimit,
-      isNaN(connectorChargingProfilePowerLimit) ? Infinity : connectorChargingProfilePowerLimit
+      isNaN(connectorChargingProfilesPowerLimit) ? Infinity : connectorChargingProfilesPowerLimit
     );
   }
 
@@ -1724,11 +1729,6 @@ export default class ChargingStation {
     return powerDivider;
   }
 
-  private getMaximumPower(stationInfo?: ChargingStationInfo): number {
-    const localStationInfo = stationInfo ?? this.stationInfo;
-    return (localStationInfo['maxPower'] as number) ?? localStationInfo.maximumPower;
-  }
-
   private getMaximumAmperage(stationInfo: ChargingStationInfo): number | undefined {
     const maximumPower = this.getMaximumPower(stationInfo);
     switch (this.getCurrentOutType(stationInfo)) {
@@ -1762,57 +1762,6 @@ export default class ChargingStation {
     }
   }
 
-  private getChargingProfilePowerLimit(connectorId: number): number | undefined {
-    let limit: number, matchingChargingProfile: ChargingProfile;
-    let chargingProfiles: ChargingProfile[] = [];
-    // Get charging profiles for connector and sort by stack level
-    chargingProfiles = this.getConnectorStatus(connectorId).chargingProfiles.sort(
-      (a, b) => b.stackLevel - a.stackLevel
-    );
-    // Get profiles on connector 0
-    if (this.getConnectorStatus(0).chargingProfiles) {
-      chargingProfiles.push(
-        ...this.getConnectorStatus(0).chargingProfiles.sort((a, b) => b.stackLevel - a.stackLevel)
-      );
-    }
-    if (!Utils.isEmptyArray(chargingProfiles)) {
-      const result = ChargingStationUtils.getLimitFromChargingProfiles(
-        chargingProfiles,
-        this.logPrefix()
-      );
-      if (!Utils.isNullOrUndefined(result)) {
-        limit = result.limit;
-        matchingChargingProfile = result.matchingChargingProfile;
-        switch (this.getCurrentOutType()) {
-          case CurrentType.AC:
-            limit =
-              matchingChargingProfile.chargingSchedule.chargingRateUnit ===
-              ChargingRateUnitType.WATT
-                ? limit
-                : ACElectricUtils.powerTotal(this.getNumberOfPhases(), this.getVoltageOut(), limit);
-            break;
-          case CurrentType.DC:
-            limit =
-              matchingChargingProfile.chargingSchedule.chargingRateUnit ===
-              ChargingRateUnitType.WATT
-                ? limit
-                : DCElectricUtils.power(this.getVoltageOut(), limit);
-        }
-        const connectorMaximumPower = this.getMaximumPower() / this.powerDivider;
-        if (limit > connectorMaximumPower) {
-          logger.error(
-            `${this.logPrefix()} Charging profile id ${
-              matchingChargingProfile.chargingProfileId
-            } limit ${limit} is greater than connector id ${connectorId} maximum ${connectorMaximumPower}: %j`,
-            result
-          );
-          limit = connectorMaximumPower;
-        }
-      }
-    }
-    return limit;
-  }
-
   private async startMessageSequence(): Promise<void> {
     if (this.stationInfo?.autoRegister === true) {
       await this.ocppRequestService.requestHandler<
index 4cf1b386fde85cd580e7b1a6f159bd7aafe4d125..aa021663dba1ca2daac6bc3e84128ea1aaa39023 100644 (file)
@@ -4,6 +4,7 @@ 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 {
@@ -14,13 +15,18 @@ import {
 } from '../types/ChargingStationTemplate';
 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 { 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 { ACElectricUtils, DCElectricUtils } from '../utils/ElectricUtils';
 import logger from '../utils/Logger';
 import Utils from '../utils/Utils';
 
@@ -133,7 +139,8 @@ export class ChargingStationUtils {
   }
 
   public static createBootNotificationRequest(
-    stationInfo: ChargingStationInfo
+    stationInfo: ChargingStationInfo,
+    bootReason: BootReasonEnumType = BootReasonEnumType.PowerUp
   ): BootNotificationRequest {
     const ocppVersion = stationInfo.ocppVersion ?? OCPPVersion.VERSION_16;
     switch (ocppVersion) {
@@ -162,7 +169,7 @@ export class ChargingStationUtils {
       case OCPPVersion.VERSION_20:
       case OCPPVersion.VERSION_201:
         return {
-          reason: BootReasonEnumType.PowerUp,
+          reason: bootReason,
           chargingStation: {
             model: stationInfo.chargePointModel,
             vendorName: stationInfo.chargePointVendor,
@@ -309,6 +316,99 @@ 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)
    *
@@ -316,7 +416,7 @@ export class ChargingStationUtils {
    * @param logPrefix -
    * @returns
    */
-  public static getLimitFromChargingProfiles(
+  private static getLimitFromChargingProfiles(
     chargingProfiles: ChargingProfile[],
     logPrefix: string
   ): {
@@ -406,38 +506,6 @@ export class ChargingStationUtils {
     return null;
   }
 
-  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)
-      )
-    );
-  }
-
   private static getRandomSerialNumberSuffix(params?: {
     randomBytesLength?: number;
     upperCase?: boolean;