refactor: add sanity checks to charging profiles handling
authorJérôme Benoit <jerome.benoit@sap.com>
Tue, 25 Jul 2023 10:57:29 +0000 (12:57 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Tue, 25 Jul 2023 10:57:29 +0000 (12:57 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ChargingStationUtils.ts
src/utils/Utils.ts

index 8d595b22acae2be8e7d0a4fe0f19edd243f884ad..939c7b8e433da90eb7f8b561a021306acb0cabb6 100644 (file)
@@ -60,6 +60,7 @@ import {
   logger,
   secureRandom,
 } from '../utils';
+import { isValidDate } from '../utils/Utils';
 
 const moduleName = 'ChargingStationUtils';
 
@@ -686,6 +687,7 @@ const getLimitFromChargingProfiles = (
 ): ChargingProfilesLimit | undefined => {
   const debugLogMsg = `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Matching charging profile found for power limitation: %j`;
   const currentDate = new Date();
+  const connectorStatus = chargingStation.getConnectorStatus(connectorId);
   for (const chargingProfile of chargingProfiles) {
     if (
       chargingProfile.validFrom &&
@@ -703,13 +705,12 @@ const getLimitFromChargingProfiles = (
       continue;
     }
     const chargingSchedule = chargingProfile.chargingSchedule;
-    if (!chargingSchedule?.startSchedule) {
+    if (connectorStatus?.transactionStarted && !chargingSchedule?.startSchedule) {
       logger.debug(
         `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: startSchedule is not defined in charging profile id ${chargingProfile.chargingProfileId}. Trying to set it to the connector transaction start date`,
       );
       // OCPP specifies that if startSchedule is not defined, it should be relative to start of the connector transaction
-      chargingSchedule.startSchedule =
-        chargingStation.getConnectorStatus(connectorId)?.transactionStart;
+      chargingSchedule.startSchedule = connectorStatus?.transactionStart;
     }
     if (!(chargingSchedule?.startSchedule instanceof Date)) {
       logger.warn(
@@ -770,16 +771,19 @@ const getLimitFromChargingProfiles = (
           }
           break;
       }
-    } else if (chargingProfile.chargingProfileKind === ChargingProfileKindType.RELATIVE) {
-      chargingSchedule.startSchedule =
-        chargingStation.getConnectorStatus(connectorId)?.transactionStart;
+    } else if (
+      chargingProfile.chargingProfileKind === ChargingProfileKindType.RELATIVE &&
+      connectorStatus?.transactionStarted
+    ) {
+      chargingSchedule.startSchedule = connectorStatus?.transactionStart;
     }
     // Check if the charging profile is active
     if (
+      isValidDate(chargingSchedule.startSchedule) &&
       isAfter(addSeconds(chargingSchedule.startSchedule!, chargingSchedule.duration!), currentDate)
     ) {
       if (isNotEmptyArray(chargingSchedule.chargingSchedulePeriod)) {
-        // Handling of only one period
+        // Handling of only one schedule period
         if (
           chargingSchedule.chargingSchedulePeriod.length === 1 &&
           chargingSchedule.chargingSchedulePeriod[0].startPeriod === 0
@@ -801,7 +805,7 @@ const getLimitFromChargingProfiles = (
               currentDate,
             )
           ) {
-            // Found the schedule: last but one is the correct one
+            // Found the schedule period: last but one is the correct one
             const result: ChargingProfilesLimit = {
               limit: lastButOneSchedule!.limit,
               matchingChargingProfile: chargingProfile,
index dc7ad9fe0ecf94aa16c46610cf2d1438582c2500..ff41faf8a674540a8b512ac8664cb61e98bfc6ec 100644 (file)
@@ -3,6 +3,7 @@ import { inspect } from 'node:util';
 
 import {
   formatDuration,
+  isDate,
   millisecondsToHours,
   millisecondsToMinutes,
   millisecondsToSeconds,
@@ -51,6 +52,16 @@ export const formatDurationSeconds = (duration: number): string => {
   return formatDurationMilliSeconds(secondsToMilliseconds(duration));
 };
 
+// More efficient date validation function than the one provided by date-fns
+export const isValidDate = (date: unknown): boolean => {
+  if (typeof date === 'number') {
+    return !isNaN(date);
+  } else if (isDate(date)) {
+    return !isNaN((date as Date).getTime());
+  }
+  return false;
+};
+
 export const convertToDate = (
   value: Date | string | number | null | undefined,
 ): Date | null | undefined => {