isDate,
isPast,
isWithinInterval,
+ maxTime,
toDate,
} from 'date-fns';
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,
}
/**
- * Charging profiles shall already be sorted by connector id and stack level (highest stack level has priority)
+ * Charging profiles shall already be sorted by connector id ascending then stack level descending
*
* @param chargingStation -
* @param connectorId -
const debugLogMsg = `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Matching charging profile found for power limitation: %j`;
const currentDate = new Date();
const connectorStatus = chargingStation.getConnectorStatus(connectorId)!;
- if (!isArraySorted(chargingProfiles, (a, b) => b.stackLevel - a.stackLevel)) {
- logger.warn(
- `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profiles are not sorted by stack level. Trying to sort them`,
- );
- chargingProfiles.sort((a, b) => b.stackLevel - a.stackLevel);
- }
for (const chargingProfile of chargingProfiles) {
const chargingSchedule = chargingProfile.chargingSchedule;
- if (connectorStatus?.transactionStarted && isNullOrUndefined(chargingSchedule?.startSchedule)) {
+ if (isNullOrUndefined(chargingSchedule?.startSchedule) && connectorStatus?.transactionStarted) {
logger.debug(
`${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 (
+ !isNullOrUndefined(chargingSchedule?.startSchedule) &&
+ isNullOrUndefined(chargingSchedule?.duration)
+ ) {
+ logger.debug(
+ `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} has no duration defined and will be set to the maximum time allowed`,
+ );
+ // OCPP specifies that if duration is not defined, it should be infinite
+ chargingSchedule.duration = differenceInSeconds(maxTime, chargingSchedule.startSchedule!);
+ }
if (!isDate(chargingSchedule?.startSchedule)) {
logger.warn(
`${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} startSchedule property is not a Date object. Trying to convert it to a Date object`,
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`,
);
chargingSchedule.chargingSchedulePeriod.sort(chargingSchedulePeriodCompareFn);
}
- // Check if the first schedule period start period is equal to 0
+ // Check if the first schedule period startPeriod property 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`,
// Found the schedule period: previous is the correct one
const result: ChargingProfilesLimit = {
limit: previousChargingSchedulePeriod!.limit,
- chargingProfile: chargingProfile,
+ chargingProfile,
};
logger.debug(debugLogMsg, result);
return result;
) {
const result: ChargingProfilesLimit = {
limit: previousChargingSchedulePeriod.limit,
- chargingProfile: chargingProfile,
+ chargingProfile,
};
logger.debug(debugLogMsg, result);
return result;
case ChargingProfileKindType.RELATIVE:
if (!isNullOrUndefined(chargingProfile.chargingSchedule.startSchedule)) {
logger.warn(
- `${logPrefix} ${moduleName}.prepareChargingProfileKind: Charging profile id ${chargingProfile.chargingProfileId} has a startSchedule property defined. It will be ignored or used if the connector has a transaction started`,
+ `${logPrefix} ${moduleName}.prepareChargingProfileKind: Relative charging profile id ${chargingProfile.chargingProfileId} has a startSchedule property defined. It will be ignored or used if the connector has a transaction started`,
);
delete chargingProfile.chargingSchedule.startSchedule;
}
);
return false;
}
- if (isNullOrUndefined(chargingSchedule?.duration)) {
- logger.error(
- `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId} has no duration defined, not yet supported`,
- );
- return false;
- }
return true;
};
break;
default:
logger.error(
- `${logPrefix} ${moduleName}.prepareRecurringChargingProfile: Recurring charging profile id ${chargingProfile.chargingProfileId} recurrency kind ${chargingProfile.recurrencyKind} is not supported`,
+ `${logPrefix} ${moduleName}.prepareRecurringChargingProfile: Recurring ${chargingProfile.recurrencyKind} charging profile id ${chargingProfile.chargingProfileId} is not supported`,
);
}
if (recurringIntervalTranslated && !isWithinInterval(currentDate, recurringInterval!)) {