isAfter,
isBefore,
isDate,
+ isPast,
isWithinInterval,
toDate,
} from 'date-fns';
type OCPP20BootNotificationRequest,
OCPPVersion,
RecurrencyKindType,
+ type Reservation,
+ ReservationTerminationReason,
StandardParametersKey,
SupportedFeatureProfiles,
Voltage,
)}${idSuffix}`;
};
-export const countReservableConnectors = (connectors: Map<number, ConnectorStatus>) => {
- let reservableConnectors = 0;
+export const hasReservationExpired = (reservation: Reservation): boolean => {
+ return isPast(reservation.expiryDate);
+};
+
+export const removeExpiredReservations = async (
+ chargingStation: ChargingStation,
+): Promise<void> => {
+ if (chargingStation.hasEvses) {
+ for (const evseStatus of chargingStation.evses.values()) {
+ for (const connectorStatus of evseStatus.connectors.values()) {
+ if (connectorStatus.reservation && hasReservationExpired(connectorStatus.reservation)) {
+ await chargingStation.removeReservation(
+ connectorStatus.reservation,
+ ReservationTerminationReason.EXPIRED,
+ );
+ }
+ }
+ }
+ } else {
+ for (const connectorStatus of chargingStation.connectors.values()) {
+ if (connectorStatus.reservation && hasReservationExpired(connectorStatus.reservation)) {
+ await chargingStation.removeReservation(
+ connectorStatus.reservation,
+ ReservationTerminationReason.EXPIRED,
+ );
+ }
+ }
+ }
+};
+
+export const getNumberOfReservableConnectors = (
+ connectors: Map<number, ConnectorStatus>,
+): number => {
+ let numberOfReservableConnectors = 0;
for (const [connectorId, connectorStatus] of connectors) {
if (connectorId === 0) {
continue;
}
if (connectorStatus.status === ConnectorStatusEnum.Available) {
- ++reservableConnectors;
+ ++numberOfReservableConnectors;
}
}
- return reservableConnectors;
+ return numberOfReservableConnectors;
};
export const getHashId = (index: number, stationTemplate: ChargingStationTemplate): string => {
templateMaxConnectors: number;
templateMaxAvailableConnectors: number;
} => {
- const configuredMaxConnectors = getConfiguredNumberOfConnectors(stationTemplate);
+ const configuredMaxConnectors = getConfiguredMaxNumberOfConnectors(stationTemplate);
checkConfiguredMaxConnectors(configuredMaxConnectors, logPrefix, templateFile);
const templateMaxConnectors = getMaxNumberOfConnectors(stationTemplate.Connectors!);
checkTemplateMaxConnectors(templateMaxConnectors, logPrefix, templateFile);
): number | undefined => {
let limit: number | undefined, matchingChargingProfile: ChargingProfile | undefined;
// Get charging profiles for connector id and sort by stack level
- const chargingProfiles =
- cloneObject<ChargingProfile[]>(
- chargingStation.getConnectorStatus(connectorId)!.chargingProfiles!,
- )?.sort((a, b) => b.stackLevel - a.stackLevel) ?? [];
- // Get charging profiles on connector 0 and sort by stack level
- if (isNotEmptyArray(chargingStation.getConnectorStatus(0)?.chargingProfiles)) {
- chargingProfiles.push(
- ...cloneObject<ChargingProfile[]>(
- chargingStation.getConnectorStatus(0)!.chargingProfiles!,
- ).sort((a, b) => b.stackLevel - a.stackLevel),
- );
- }
+ const chargingProfiles = cloneObject<ChargingProfile[]>(
+ (chargingStation.getConnectorStatus(connectorId)?.chargingProfiles ?? []).concat(
+ chargingStation.getConnectorStatus(0)?.chargingProfiles ?? [],
+ ),
+ ).sort((a, b) => b.stackLevel - a.stackLevel);
if (isNotEmptyArray(chargingProfiles)) {
const result = getLimitFromChargingProfiles(
chargingStation,
});
};
-const getConfiguredNumberOfConnectors = (stationTemplate: ChargingStationTemplate): number => {
- let configuredMaxConnectors = 0;
+const getConfiguredMaxNumberOfConnectors = (stationTemplate: ChargingStationTemplate): number => {
+ let configuredMaxNumberOfConnectors = 0;
if (isNotEmptyArray(stationTemplate.numberOfConnectors) === true) {
const numberOfConnectors = stationTemplate.numberOfConnectors as number[];
- configuredMaxConnectors =
+ configuredMaxNumberOfConnectors =
numberOfConnectors[Math.floor(secureRandom() * numberOfConnectors.length)];
} else if (isUndefined(stationTemplate.numberOfConnectors) === false) {
- configuredMaxConnectors = stationTemplate.numberOfConnectors as number;
+ configuredMaxNumberOfConnectors = stationTemplate.numberOfConnectors as number;
} else if (stationTemplate.Connectors && !stationTemplate.Evses) {
- configuredMaxConnectors = stationTemplate.Connectors[0]
+ configuredMaxNumberOfConnectors = stationTemplate.Connectors[0]
? getMaxNumberOfConnectors(stationTemplate.Connectors) - 1
: getMaxNumberOfConnectors(stationTemplate.Connectors);
} else if (stationTemplate.Evses && !stationTemplate.Connectors) {
if (evse === '0') {
continue;
}
- configuredMaxConnectors += getMaxNumberOfConnectors(stationTemplate.Evses[evse].Connectors);
+ configuredMaxNumberOfConnectors += getMaxNumberOfConnectors(
+ stationTemplate.Evses[evse].Connectors,
+ );
}
}
- return configuredMaxConnectors;
+ return configuredMaxNumberOfConnectors;
};
const checkConfiguredMaxConnectors = (
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)) {
}
};
-const canProceedChargingProfile = (
+export const canProceedChargingProfile = (
chargingProfile: ChargingProfile,
currentDate: Date,
logPrefix: string,
const chargingSchedule = chargingProfile.chargingSchedule;
if (isNullOrUndefined(chargingSchedule?.startSchedule)) {
logger.error(
- `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId} has (still) no startSchedule defined`,
+ `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId} has no startSchedule defined`,
);
return false;
}
return true;
};
-const canProceedRecurringChargingProfile = (
+export const canProceedRecurringChargingProfile = (
chargingProfile: ChargingProfile,
logPrefix: string,
): boolean => {
* @param currentDate -
* @param logPrefix -
*/
-const prepareRecurringChargingProfile = (
+export const prepareRecurringChargingProfile = (
chargingProfile: ChargingProfile,
currentDate: Date,
logPrefix: string,