- /**
- * 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 }}
- */
- public static getLimitFromChargingProfiles(
- chargingProfiles: ChargingProfile[],
- logPrefix: string
- ): {
- 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();
- const chargingSchedule = chargingProfile.chargingSchedule;
- // Check type (recurring) and if it is already active
- // Adjust the daily recurring schedule to today
- if (
- chargingProfile.chargingProfileKind === ChargingProfileKindType.RECURRING &&
- chargingProfile.recurrencyKind === RecurrencyKindType.DAILY &&
- currentMoment.isAfter(chargingSchedule.startSchedule)
- ) {
- const currentDate = new Date();
- chargingSchedule.startSchedule = new Date(chargingSchedule.startSchedule);
- chargingSchedule.startSchedule.setFullYear(
- currentDate.getFullYear(),
- currentDate.getMonth(),
- currentDate.getDate()
- );
- // Check if the start of the schedule is yesterday
- if (moment(chargingSchedule.startSchedule).isAfter(currentMoment)) {
- chargingSchedule.startSchedule.setDate(currentDate.getDate() - 1);
+interface ChargingProfilesLimit {
+ limit: number;
+ matchingChargingProfile: ChargingProfile;
+}
+
+/**
+ * Charging profiles should already be sorted by connector id and stack level (highest stack level has priority)
+ *
+ * @param chargingProfiles -
+ * @param logPrefix -
+ * @returns ChargingProfilesLimit
+ */
+const getLimitFromChargingProfiles = (
+ chargingStation: ChargingStation,
+ connectorId: number,
+ chargingProfiles: ChargingProfile[],
+ logPrefix: string,
+): 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 (
+ isValidDate(chargingProfile.validFrom) &&
+ isValidDate(chargingProfile.validTo) &&
+ !isWithinInterval(currentDate, {
+ start: chargingProfile.validFrom!,
+ end: chargingProfile.validTo!,
+ })
+ ) {
+ logger.debug(
+ `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${
+ chargingProfile.chargingProfileId
+ } is not valid for the current date ${currentDate.toISOString()}`,
+ );
+ continue;
+ }
+ const chargingSchedule = chargingProfile.chargingSchedule;
+ 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 = connectorStatus?.transactionStart;
+ }
+ if (!(chargingSchedule?.startSchedule instanceof Date)) {
+ logger.warn(
+ `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: startSchedule is not a Date object in charging profile id ${chargingProfile.chargingProfileId}. Trying to convert it to a Date object`,
+ );
+ chargingSchedule.startSchedule = convertToDate(chargingSchedule.startSchedule)!;
+ }
+ if (
+ chargingProfile.chargingProfileKind === ChargingProfileKindType.RECURRING &&
+ isNullOrUndefined(chargingProfile.recurrencyKind)
+ ) {
+ logger.error(
+ `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Recurring charging profile id ${chargingProfile.chargingProfileId} has no recurrencyKind defined`,
+ );
+ continue;
+ }
+ if (chargingProfile.chargingProfileKind === ChargingProfileKindType.RECURRING) {
+ prepareRecurringChargingProfile(chargingProfile, currentDate, logPrefix);
+ } 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 schedule period
+ if (
+ chargingSchedule.chargingSchedulePeriod.length === 1 &&
+ chargingSchedule.chargingSchedulePeriod[0].startPeriod === 0
+ ) {
+ const result: ChargingProfilesLimit = {
+ limit: chargingSchedule.chargingSchedulePeriod[0].limit,
+ matchingChargingProfile: chargingProfile,
+ };
+ logger.debug(debugLogMsg, result);
+ return result;