fix: ensure charging profiles used for power limitation are properly sorted
authorJérôme Benoit <jerome.benoit@sap.com>
Wed, 2 Aug 2023 16:55:46 +0000 (18:55 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Wed, 2 Aug 2023 16:55:46 +0000 (18:55 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/Helpers.ts
src/charging-station/index.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts

index 2f775ccfccf002e4dfe12835cb86e8d83cd7f19a..9de547776ed470188274cc066bf7b51a3e09fea7 100644 (file)
@@ -514,17 +514,36 @@ export const getAmperageLimitationUnitDivider = (stationInfo: ChargingStationInf
   return unitDivider;
 };
 
+/**
+ * Gets the connector cloned charging profiles applying a power limitation
+ * and sorted by connector id ascending then stack level descending
+ *
+ * @param chargingStation -
+ * @param connectorId -
+ * @returns connector charging profiles array
+ */
+export const getConnectorChargingProfiles = (
+  chargingStation: ChargingStation,
+  connectorId: number,
+) => {
+  return cloneObject<ChargingProfile[]>(
+    (chargingStation.getConnectorStatus(0)?.chargingProfiles ?? [])
+      .sort((a, b) => b.stackLevel - a.stackLevel)
+      .concat(
+        (chargingStation.getConnectorStatus(connectorId)?.chargingProfiles ?? []).sort(
+          (a, b) => b.stackLevel - a.stackLevel,
+        ),
+      ),
+  );
+};
+
 export const getChargingStationConnectorChargingProfilesPowerLimit = (
   chargingStation: ChargingStation,
   connectorId: number,
 ): number | undefined => {
   let limit: number | undefined, chargingProfile: ChargingProfile | undefined;
-  // Get charging profiles for connector id and sort by stack level
-  const chargingProfiles = cloneObject<ChargingProfile[]>(
-    (chargingStation.getConnectorStatus(connectorId)?.chargingProfiles ?? []).concat(
-      chargingStation.getConnectorStatus(0)?.chargingProfiles ?? [],
-    ),
-  ).sort((a, b) => b.stackLevel - a.stackLevel);
+  // Get charging profiles sorted by connector id then stack level
+  const chargingProfiles = getConnectorChargingProfiles(chargingStation, connectorId);
   if (isNotEmptyArray(chargingProfiles)) {
     const result = getLimitFromChargingProfiles(
       chargingStation,
@@ -715,7 +734,7 @@ interface ChargingProfilesLimit {
 }
 
 /**
- * Charging profiles shall already be sorted by connector id and stack level (highest stack level has priority)
+ * Charging profiles should already be sorted by connector id ascending then stack level descending
  *
  * @param chargingStation -
  * @param connectorId -
@@ -773,10 +792,10 @@ const getLimitFromChargingProfiles = (
           b: ChargingSchedulePeriod,
         ) => a.startPeriod - b.startPeriod;
         if (
-          isArraySorted<ChargingSchedulePeriod>(
+          !isArraySorted<ChargingSchedulePeriod>(
             chargingSchedule.chargingSchedulePeriod,
             chargingSchedulePeriodCompareFn,
-          ) === false
+          )
         ) {
           logger.warn(
             `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} schedule periods are not sorted by start period`,
@@ -815,7 +834,7 @@ const getLimitFromChargingProfiles = (
             // Found the schedule period: previous is the correct one
             const result: ChargingProfilesLimit = {
               limit: previousChargingSchedulePeriod!.limit,
-              chargingProfile: chargingProfile,
+              chargingProfile,
             };
             logger.debug(debugLogMsg, result);
             return result;
@@ -836,7 +855,7 @@ const getLimitFromChargingProfiles = (
           ) {
             const result: ChargingProfilesLimit = {
               limit: previousChargingSchedulePeriod.limit,
-              chargingProfile: chargingProfile,
+              chargingProfile,
             };
             logger.debug(debugLogMsg, result);
             return result;
index 3eccd2581deb7fbc23c1fce1ce9a54856b7a7193..ed055a8d830b94cf878210c64e2e30c57a670e35 100644 (file)
@@ -8,6 +8,7 @@ export {
 export {
   canProceedChargingProfile,
   checkChargingStation,
+  getConnectorChargingProfiles,
   getIdTagsFile,
   hasFeatureProfile,
   hasReservationExpired,
index 1941b665f00a5f7da58756c8186850abbb24b5ec..66a6ee5960a95b7050a1888122e9bcef4cfe7a24 100644 (file)
@@ -28,6 +28,7 @@ import {
   canProceedChargingProfile,
   checkChargingStation,
   getConfigurationKey,
+  getConnectorChargingProfiles,
   prepareChargingProfileKind,
   removeExpiredReservations,
   setConfigurationKeyValue,
@@ -105,7 +106,6 @@ import {
 } from '../../../types';
 import {
   Constants,
-  cloneObject,
   convertToDate,
   convertToInt,
   formatDurationMilliSeconds,
@@ -704,11 +704,11 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       start: currentDate,
       end: addSeconds(currentDate, duration),
     };
-    const storedChargingProfiles: OCPP16ChargingProfile[] = cloneObject<OCPP16ChargingProfile[]>(
-      (connectorStatus?.chargingProfiles ?? []).concat(
-        chargingStation.getConnectorStatus(0)?.chargingProfiles ?? [],
-      ),
-    ).sort((a, b) => b.stackLevel - a.stackLevel);
+    // Get charging profiles sorted by connector id then stack level
+    const storedChargingProfiles: OCPP16ChargingProfile[] = getConnectorChargingProfiles(
+      chargingStation,
+      connectorId,
+    );
     const chargingProfiles: OCPP16ChargingProfile[] = [];
     for (const storedChargingProfile of storedChargingProfiles) {
       if (