cloneObject,
convertToDate,
convertToInt,
+ isArraySorted,
isEmptyObject,
isEmptyString,
isNotEmptyArray,
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`,
+ `${chargingStation.logPrefix()} ${moduleName}.getChargingStationConnectorChargingProfilesPowerLimit: Charging profile id ${matchingChargingProfile?.chargingProfileId} limit ${limit} is greater than connector id ${connectorId} maximum ${connectorMaximumPower}: %j`,
result,
);
limit = connectorMaximumPower;
}
/**
- * Charging profiles should already be sorted by connector id and stack level (highest stack level has priority)
+ * Charging profiles shall already be sorted by connector id and stack level (highest stack level has priority)
*
+ * @param chargingStation -
+ * @param connectorId -
* @param chargingProfiles -
* @param logPrefix -
* @returns ChargingProfilesLimit
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!,
- })
+ (isValidDate(chargingProfile.validFrom) &&
+ isBefore(currentDate, chargingProfile.validFrom!)) ||
+ (isValidDate(chargingProfile.validTo) && isAfter(currentDate, chargingProfile.validTo!))
) {
logger.debug(
`${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${
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`,
+ `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} has no startSchedule defined. Trying to set it to the connector current 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`,
+ `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} startSchedule property is not a Date object. Trying to convert it to a Date object`,
);
- chargingSchedule.startSchedule = convertToDate(chargingSchedule.startSchedule)!;
+ chargingSchedule.startSchedule = convertToDate(chargingSchedule?.startSchedule)!;
}
if (
chargingProfile.chargingProfileKind === ChargingProfileKindType.RECURRING &&
) {
chargingSchedule.startSchedule = connectorStatus?.transactionStart;
}
+ if (isNullOrUndefined(chargingSchedule?.startSchedule)) {
+ logger.error(
+ `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} has (still) no startSchedule defined`,
+ );
+ continue;
+ }
+ if (isNullOrUndefined(chargingSchedule?.duration)) {
+ logger.error(
+ `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} has no duration defined, not yet supported`,
+ );
+ continue;
+ }
// Check if the charging profile is active
if (
- isValidDate(chargingSchedule.startSchedule) &&
- isAfter(addSeconds(chargingSchedule.startSchedule!, chargingSchedule.duration!), currentDate)
+ isValidDate(chargingSchedule?.startSchedule) &&
+ isWithinInterval(currentDate, {
+ start: chargingSchedule.startSchedule!,
+ end: addSeconds(chargingSchedule.startSchedule!, chargingSchedule.duration!),
+ })
) {
- chargingSchedule.chargingSchedulePeriod.sort((a, b) => a.startPeriod - b.startPeriod);
if (isNotEmptyArray(chargingSchedule.chargingSchedulePeriod)) {
- // Handling of only one schedule period
+ const chargingSchedulePeriodCompareFn = (
+ a: ChargingSchedulePeriod,
+ b: ChargingSchedulePeriod,
+ ) => a.startPeriod - b.startPeriod;
if (
- chargingSchedule.chargingSchedulePeriod.length === 1 &&
- chargingSchedule.chargingSchedulePeriod[0].startPeriod === 0
+ isArraySorted<ChargingSchedulePeriod>(
+ chargingSchedule.chargingSchedulePeriod,
+ chargingSchedulePeriodCompareFn,
+ ) === false
) {
+ logger.warn(
+ `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} schedule periods are not sorted by start period`,
+ );
+ chargingSchedule.chargingSchedulePeriod.sort(chargingSchedulePeriodCompareFn);
+ }
+ // Check if the first schedule period start period is equal to 0
+ if (chargingSchedule.chargingSchedulePeriod[0].startPeriod !== 0) {
+ logger.error(
+ `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} first schedule period start period ${chargingSchedule.chargingSchedulePeriod[0].startPeriod} is not equal to 0`,
+ );
+ continue;
+ }
+ // Handle only one schedule period
+ if (chargingSchedule.chargingSchedulePeriod.length === 1) {
const result: ChargingProfilesLimit = {
limit: chargingSchedule.chargingSchedulePeriod[0].limit,
matchingChargingProfile: chargingProfile,
logger.debug(debugLogMsg, result);
return result;
}
- let lastButOneSchedule: ChargingSchedulePeriod | undefined;
+ let previousChargingSchedulePeriod: ChargingSchedulePeriod | undefined;
// Search for the right schedule period
- for (const schedulePeriod of chargingSchedule.chargingSchedulePeriod) {
+ for (const [
+ index,
+ chargingSchedulePeriod,
+ ] of chargingSchedule.chargingSchedulePeriod.entries()) {
// Find the right schedule period
if (
isAfter(
- addSeconds(chargingSchedule.startSchedule!, schedulePeriod.startPeriod),
+ addSeconds(chargingSchedule.startSchedule!, chargingSchedulePeriod.startPeriod),
currentDate,
)
) {
- // Found the schedule period: last but one is the correct one
+ // Found the schedule period: previous is the correct one
const result: ChargingProfilesLimit = {
- limit: lastButOneSchedule!.limit,
+ limit: previousChargingSchedulePeriod!.limit,
matchingChargingProfile: chargingProfile,
};
logger.debug(debugLogMsg, result);
return result;
}
- // Keep it
- lastButOneSchedule = schedulePeriod;
- // Handle the last schedule period
+ // Keep a reference to previous one
+ previousChargingSchedulePeriod = chargingSchedulePeriod;
+ // Handle the last schedule period within the charging profile duration
if (
- schedulePeriod.startPeriod ===
- chargingSchedule.chargingSchedulePeriod[
- chargingSchedule.chargingSchedulePeriod.length - 1
- ].startPeriod
+ index === chargingSchedule.chargingSchedulePeriod.length - 1 ||
+ (index < chargingSchedule.chargingSchedulePeriod.length - 1 &&
+ chargingSchedule.duration! >
+ differenceInSeconds(
+ addSeconds(
+ chargingSchedule.startSchedule!,
+ chargingSchedule.chargingSchedulePeriod[index + 1].startPeriod,
+ ),
+ chargingSchedule.startSchedule!,
+ ))
) {
const result: ChargingProfilesLimit = {
- limit: lastButOneSchedule.limit,
+ limit: previousChargingSchedulePeriod.limit,
matchingChargingProfile: chargingProfile,
};
logger.debug(debugLogMsg, result);
};
/**
- * Adjust recurring charging profile startSchedule to the current recurrency time interval if needed
+ * Adjust recurring charging profile startSchedule to the current recurrency time interval if needed
*
* @param chargingProfile -
* @param currentDate -
chargingProfile: ChargingProfile,
currentDate: Date,
logPrefix: string,
-) => {
+): boolean => {
const chargingSchedule = chargingProfile.chargingSchedule;
+ let recurringIntervalTranslated = false;
let recurringInterval: Interval;
switch (chargingProfile.recurrencyKind) {
case RecurrencyKindType.DAILY:
checkRecurringChargingProfileDuration(chargingProfile, recurringInterval, logPrefix);
if (
!isWithinInterval(currentDate, recurringInterval) &&
- isBefore(chargingSchedule.startSchedule!, currentDate)
+ isBefore(recurringInterval.end, currentDate)
) {
chargingSchedule.startSchedule = addDays(
- chargingSchedule.startSchedule!,
- differenceInDays(chargingSchedule.startSchedule!, recurringInterval.end),
+ recurringInterval.start,
+ differenceInDays(currentDate, recurringInterval.start),
);
recurringInterval = {
start: chargingSchedule.startSchedule,
end: addDays(chargingSchedule.startSchedule, 1),
};
+ recurringIntervalTranslated = true;
}
break;
case RecurrencyKindType.WEEKLY:
checkRecurringChargingProfileDuration(chargingProfile, recurringInterval, logPrefix);
if (
!isWithinInterval(currentDate, recurringInterval) &&
- isBefore(chargingSchedule.startSchedule!, currentDate)
+ isBefore(recurringInterval.end, currentDate)
) {
chargingSchedule.startSchedule = addWeeks(
- chargingSchedule.startSchedule!,
- differenceInWeeks(chargingSchedule.startSchedule!, recurringInterval.end),
+ recurringInterval.start,
+ differenceInWeeks(currentDate, recurringInterval.start),
);
recurringInterval = {
start: chargingSchedule.startSchedule,
end: addWeeks(chargingSchedule.startSchedule, 1),
};
+ recurringIntervalTranslated = true;
}
break;
+ default:
+ logger.error(
+ `${logPrefix} ${moduleName}.prepareRecurringChargingProfile: Recurring charging profile id ${chargingProfile.chargingProfileId} recurrency kind ${chargingProfile.recurrencyKind} is not supported`,
+ );
}
- if (!isWithinInterval(currentDate, recurringInterval!)) {
+ if (recurringIntervalTranslated && !isWithinInterval(currentDate, recurringInterval!)) {
logger.error(
- `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Recurring ${
+ `${logPrefix} ${moduleName}.prepareRecurringChargingProfile: Recurring ${
chargingProfile.recurrencyKind
- } charging profile id ${
- chargingProfile.chargingProfileId
- } startSchedule ${chargingSchedule.startSchedule!.toISOString()} is not properly translated to current recurrency time interval [${toDate(
+ } charging profile id ${chargingProfile.chargingProfileId} recurrency time interval [${toDate(
recurringInterval!.start,
- ).toISOString()}, ${toDate(recurringInterval!.end).toISOString()}]`,
+ ).toISOString()}, ${toDate(
+ recurringInterval!.end,
+ ).toISOString()}] has not been properly translated to current date ${currentDate.toISOString()} `,
);
}
+ return recurringIntervalTranslated;
};
const checkRecurringChargingProfileDuration = (
chargingProfile: ChargingProfile,
interval: Interval,
logPrefix: string,
-) => {
- if (
+): void => {
+ if (isNullOrUndefined(chargingProfile.chargingSchedule.duration)) {
+ logger.warn(
+ `${logPrefix} ${moduleName}.checkRecurringChargingProfileDuration: Recurring ${
+ chargingProfile.chargingProfileKind
+ } charging profile id ${
+ chargingProfile.chargingProfileId
+ } duration is not defined, set it to the recurrency time interval duration ${differenceInSeconds(
+ interval.end,
+ interval.start,
+ )}`,
+ );
+ chargingProfile.chargingSchedule.duration = differenceInSeconds(interval.end, interval.start);
+ } else if (
chargingProfile.chargingSchedule.duration! > differenceInSeconds(interval.end, interval.start)
) {
logger.warn(
- `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Recurring ${
+ `${logPrefix} ${moduleName}.checkRecurringChargingProfileDuration: Recurring ${
chargingProfile.chargingProfileKind
} charging profile id ${chargingProfile.chargingProfileId} duration ${
chargingProfile.chargingSchedule.duration
interval.start,
)}`,
);
+ chargingProfile.chargingSchedule.duration = differenceInSeconds(interval.end, interval.start);
}
};