X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FChargingStationUtils.ts;h=6c2732460c8cbd84c388ce58958f2d8f7f231657;hb=66b537dc52309a7025813c238dcc29d44bcf4e0d;hp=0eeb205189456c4d0ea44ec96d3cfdf434722075;hpb=142a66c9948adf165706107e1fcadf9f87bae559;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ChargingStationUtils.ts b/src/charging-station/ChargingStationUtils.ts index 0eeb2051..6c273246 100644 --- a/src/charging-station/ChargingStationUtils.ts +++ b/src/charging-station/ChargingStationUtils.ts @@ -13,6 +13,7 @@ import { differenceInWeeks, isAfter, isBefore, + isDate, isWithinInterval, toDate, } from 'date-fns'; @@ -56,7 +57,7 @@ import { isNotEmptyString, isNullOrUndefined, isUndefined, - isValidDate, + isValidTime, logger, secureRandom, } from '../utils'; @@ -399,7 +400,7 @@ export const stationTemplateToStationInfo = ( delete stationTemplate.chargeBoxSerialNumberPrefix; delete stationTemplate.chargePointSerialNumberPrefix; delete stationTemplate.meterSerialNumberPrefix; - return stationTemplate as unknown as ChargingStationInfo; + return stationTemplate as ChargingStationInfo; }; export const createSerialNumber = ( @@ -672,8 +673,10 @@ interface ChargingProfilesLimit { } /** - * 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 @@ -688,58 +691,38 @@ const getLimitFromChargingProfiles = ( const currentDate = new Date(); const connectorStatus = chargingStation.getConnectorStatus(connectorId); for (const chargingProfile of chargingProfiles) { - if ( - (isValidDate(chargingProfile.validFrom) && - isBefore(currentDate, chargingProfile.validFrom!)) || - (isValidDate(chargingProfile.validTo) && isAfter(currentDate, 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) { + if (connectorStatus?.transactionStarted && isNullOrUndefined(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)) { + if (!isDate(chargingSchedule?.startSchedule)) { 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)!; } - 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; + switch (chargingProfile.chargingProfileKind) { + case ChargingProfileKindType.RECURRING: + if (!canProceedRecurringChargingProfile(chargingProfile, logPrefix)) { + continue; + } + prepareRecurringChargingProfile(chargingProfile, currentDate, logPrefix); + break; + case ChargingProfileKindType.RELATIVE: + connectorStatus?.transactionStarted && + (chargingSchedule.startSchedule = connectorStatus?.transactionStart); + break; } - if (isNullOrUndefined(chargingSchedule?.duration)) { - logger.error( - `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} has no duration defined, not yet supported`, - ); + if (!canProceedChargingProfile(chargingProfile, currentDate, logPrefix)) { continue; } // Check if the charging profile is active if ( - isValidDate(chargingSchedule?.startSchedule) && + isValidTime(chargingSchedule?.startSchedule) && isWithinInterval(currentDate, { start: chargingSchedule.startSchedule!, end: addSeconds(chargingSchedule.startSchedule!, chargingSchedule.duration!), @@ -777,26 +760,29 @@ const getLimitFromChargingProfiles = ( logger.debug(debugLogMsg, result); return result; } - let lastButOneSchedule: ChargingSchedulePeriod | undefined; + let previousChargingSchedulePeriod: ChargingSchedulePeriod | undefined; // Search for the right schedule period - for (const [index, schedulePeriod] of chargingSchedule.chargingSchedulePeriod.entries()) { + 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; + // Keep a reference to previous one + previousChargingSchedulePeriod = chargingSchedulePeriod; // Handle the last schedule period within the charging profile duration if ( index === chargingSchedule.chargingSchedulePeriod.length - 1 || @@ -811,7 +797,7 @@ const getLimitFromChargingProfiles = ( )) ) { const result: ChargingProfilesLimit = { - limit: lastButOneSchedule.limit, + limit: previousChargingSchedulePeriod.limit, matchingChargingProfile: chargingProfile, }; logger.debug(debugLogMsg, result); @@ -823,8 +809,56 @@ const getLimitFromChargingProfiles = ( } }; +const canProceedChargingProfile = ( + chargingProfile: ChargingProfile, + currentDate: Date, + logPrefix: string, +): boolean => { + if ( + (isValidTime(chargingProfile.validFrom) && isBefore(currentDate, chargingProfile.validFrom!)) || + (isValidTime(chargingProfile.validTo) && isAfter(currentDate, chargingProfile.validTo!)) + ) { + logger.debug( + `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${ + chargingProfile.chargingProfileId + } is not valid for the current date ${currentDate.toISOString()}`, + ); + return false; + } + const chargingSchedule = chargingProfile.chargingSchedule; + if (isNullOrUndefined(chargingSchedule?.startSchedule)) { + logger.error( + `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId} has (still) no startSchedule defined`, + ); + 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; +}; + +const canProceedRecurringChargingProfile = ( + chargingProfile: ChargingProfile, + logPrefix: string, +): boolean => { + if ( + chargingProfile.chargingProfileKind === ChargingProfileKindType.RECURRING && + isNullOrUndefined(chargingProfile.recurrencyKind) + ) { + logger.error( + `${logPrefix} ${moduleName}.canProceedRecurringChargingProfile: Recurring charging profile id ${chargingProfile.chargingProfileId} has no recurrencyKind defined`, + ); + return false; + } + return true; +}; + /** - * 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 - @@ -834,8 +868,9 @@ const prepareRecurringChargingProfile = ( chargingProfile: ChargingProfile, currentDate: Date, logPrefix: string, -) => { +): boolean => { const chargingSchedule = chargingProfile.chargingSchedule; + let recurringIntervalTranslated = false; let recurringInterval: Interval; switch (chargingProfile.recurrencyKind) { case RecurrencyKindType.DAILY: @@ -856,6 +891,7 @@ const prepareRecurringChargingProfile = ( start: chargingSchedule.startSchedule, end: addDays(chargingSchedule.startSchedule, 1), }; + recurringIntervalTranslated = true; } break; case RecurrencyKindType.WEEKLY: @@ -876,10 +912,15 @@ const prepareRecurringChargingProfile = ( 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}.prepareRecurringChargingProfile: Recurring ${ chargingProfile.recurrencyKind @@ -887,16 +928,17 @@ const prepareRecurringChargingProfile = ( recurringInterval!.start, ).toISOString()}, ${toDate( recurringInterval!.end, - ).toISOString()}] is not properly translated to current date ${currentDate.toISOString()} `, + ).toISOString()}] has not been properly translated to current date ${currentDate.toISOString()} `, ); } + return recurringIntervalTranslated; }; const checkRecurringChargingProfileDuration = ( chargingProfile: ChargingProfile, interval: Interval, logPrefix: string, -) => { +): void => { if (isNullOrUndefined(chargingProfile.chargingSchedule.duration)) { logger.warn( `${logPrefix} ${moduleName}.checkRecurringChargingProfileDuration: Recurring ${