isDate,
isPast,
isWithinInterval,
+ maxTime,
toDate,
} from 'date-fns';
};
export const resetConnectorStatus = (connectorStatus: ConnectorStatus): void => {
+ connectorStatus.chargingProfiles =
+ connectorStatus.transactionId && isNotEmptyArray(connectorStatus.chargingProfiles)
+ ? connectorStatus.chargingProfiles?.filter(
+ (chargingProfile) => chargingProfile.transactionId !== connectorStatus.transactionId,
+ )
+ : [];
connectorStatus.idTagLocalAuthorized = false;
connectorStatus.idTagAuthorized = false;
connectorStatus.transactionRemoteStarted = false;
/**
* Gets the connector cloned charging profiles applying a power limitation
- * and sorted by connector id ascending then stack level descending
+ * and sorted by connector id descending then stack level descending
*
* @param chargingStation -
* @param connectorId -
connectorId: number,
) => {
return cloneObject<ChargingProfile[]>(
- (chargingStation.getConnectorStatus(0)?.chargingProfiles ?? [])
+ (chargingStation.getConnectorStatus(connectorId)?.chargingProfiles ?? [])
.sort((a, b) => b.stackLevel - a.stackLevel)
.concat(
- (chargingStation.getConnectorStatus(connectorId)?.chargingProfiles ?? []).sort(
+ (chargingStation.getConnectorStatus(0)?.chargingProfiles ?? []).sort(
(a, b) => b.stackLevel - a.stackLevel,
),
),
}
/**
- * Charging profiles should already be sorted by connector id ascending then stack level descending
+ * Charging profiles shall already be sorted by connector id descending 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 (!isDate(chargingSchedule?.startSchedule)) {
+ if (
+ !isNullOrUndefined(chargingSchedule?.startSchedule) &&
+ !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`,
+ `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} startSchedule property is not a Date instance. Trying to convert it to a Date instance`,
);
chargingSchedule.startSchedule = convertToDate(chargingSchedule?.startSchedule)!;
}
+ 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 (!prepareChargingProfileKind(connectorStatus, chargingProfile, currentDate, logPrefix)) {
continue;
}
}
// Check if the charging profile is active
if (
- isValidTime(chargingSchedule?.startSchedule) &&
isWithinInterval(currentDate, {
start: chargingSchedule.startSchedule!,
end: addSeconds(chargingSchedule.startSchedule!, chargingSchedule.duration!),
);
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`,
);
delete chargingProfile.chargingSchedule.startSchedule;
}
- connectorStatus?.transactionStarted &&
- (chargingProfile.chargingSchedule.startSchedule = connectorStatus?.transactionStart);
+ if (connectorStatus?.transactionStarted) {
+ chargingProfile.chargingSchedule.startSchedule = connectorStatus?.transactionStart;
+ }
+ // FIXME: Handle relative charging profile duration
break;
}
return true;
);
return false;
}
- const chargingSchedule = chargingProfile.chargingSchedule;
- if (isNullOrUndefined(chargingSchedule?.startSchedule)) {
+ if (
+ isNullOrUndefined(chargingProfile.chargingSchedule.startSchedule) ||
+ isNullOrUndefined(chargingProfile.chargingSchedule.duration)
+ ) {
logger.error(
- `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId} has no startSchedule defined`,
+ `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId} has no startSchedule or duration defined`,
);
return false;
}
- if (isNullOrUndefined(chargingSchedule?.duration)) {
+ if (
+ !isNullOrUndefined(chargingProfile.chargingSchedule.startSchedule) &&
+ !isValidTime(chargingProfile.chargingSchedule.startSchedule)
+ ) {
+ logger.error(
+ `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId} has an invalid startSchedule date defined`,
+ );
+ return false;
+ }
+ if (
+ !isNullOrUndefined(chargingProfile.chargingSchedule.duration) &&
+ !Number.isSafeInteger(chargingProfile.chargingSchedule.duration)
+ ) {
logger.error(
- `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId} has no duration defined, not yet supported`,
+ `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId} has non integer duration defined`,
);
return false;
}
);
return false;
}
+ if (
+ chargingProfile.chargingProfileKind === ChargingProfileKindType.RECURRING &&
+ isNullOrUndefined(chargingProfile.chargingSchedule.startSchedule)
+ ) {
+ logger.error(
+ `${logPrefix} ${moduleName}.canProceedRecurringChargingProfile: Recurring charging profile id ${chargingProfile.chargingProfileId} has no startSchedule defined`,
+ );
+ return false;
+ }
return true;
};