X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2Focpp%2F1.6%2FOCPP16IncomingRequestService.ts;h=66a6ee5960a95b7050a1888122e9bcef4cfe7a24;hb=6fc0c6f3db444377c0fdea238183a14823278046;hp=6912f765742efd86b9970066e92240aa45cc5b9c;hpb=bbb55ee4d90133cdba3669ef407175b4062a9300;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts index 6912f765..66a6ee59 100644 --- a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts @@ -8,6 +8,7 @@ import type { JSONSchemaType } from 'ajv'; import { Client, type FTPResponse } from 'basic-ftp'; import { addSeconds, + differenceInSeconds, isAfter, isBefore, isDate, @@ -27,6 +28,7 @@ import { canProceedChargingProfile, checkChargingStation, getConfigurationKey, + getConnectorChargingProfiles, prepareChargingProfileKind, removeExpiredReservations, setConfigurationKeyValue, @@ -104,7 +106,6 @@ import { } from '../../../types'; import { Constants, - cloneObject, convertToDate, convertToInt, formatDurationMilliSeconds, @@ -703,11 +704,11 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { start: currentDate, end: addSeconds(currentDate, duration), }; - const storedChargingProfiles: OCPP16ChargingProfile[] = cloneObject( - (connectorStatus?.chargingProfiles ?? []).concat( - chargingStation.getConnectorStatus(0)?.chargingProfiles ?? [], - ), - ).sort((a, b) => b.stackLevel - a.stackLevel); + // Get charging profiles sorted by connector id then stack level + const storedChargingProfiles: OCPP16ChargingProfile[] = getConnectorChargingProfiles( + chargingStation, + connectorId, + ); const chargingProfiles: OCPP16ChargingProfile[] = []; for (const storedChargingProfile of storedChargingProfiles) { if ( @@ -754,31 +755,107 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { // Add active charging profiles into chargingProfiles array if ( isValidTime(storedChargingProfile.chargingSchedule?.startSchedule) && - isWithinInterval(storedChargingProfile.chargingSchedule.startSchedule!, interval) && - (isEmptyArray(chargingProfiles) || - (isNotEmptyArray(chargingProfiles) && - (isBefore( + isWithinInterval(storedChargingProfile.chargingSchedule.startSchedule!, interval) + ) { + if (isEmptyArray(chargingProfiles)) { + if ( + isAfter( + addSeconds( + storedChargingProfile.chargingSchedule.startSchedule!, + storedChargingProfile.chargingSchedule.duration!, + ), + interval.end, + ) + ) { + storedChargingProfile.chargingSchedule.chargingSchedulePeriod = + storedChargingProfile.chargingSchedule.chargingSchedulePeriod.filter( + (schedulePeriod) => + isWithinInterval( + addSeconds( + storedChargingProfile.chargingSchedule.startSchedule!, + schedulePeriod.startPeriod, + )!, + interval, + ), + ); + storedChargingProfile.chargingSchedule.duration = differenceInSeconds( + interval.end, storedChargingProfile.chargingSchedule.startSchedule!, - min( - chargingProfiles.map( - (chargingProfile) => chargingProfile.chargingSchedule.startSchedule ?? maxTime, - ), + ); + } + chargingProfiles.push(storedChargingProfile); + } else if (isNotEmptyArray(chargingProfiles)) { + const chargingProfilesInterval: Interval = { + start: min( + chargingProfiles.map( + (chargingProfile) => chargingProfile.chargingSchedule.startSchedule ?? maxTime, ), - ) || - isAfter( + ), + end: max( + chargingProfiles.map( + (chargingProfile) => + addSeconds( + chargingProfile.chargingSchedule.startSchedule!, + chargingProfile.chargingSchedule.duration!, + ) ?? minTime, + ), + ), + }; + let addChargingProfile = false; + if ( + isBefore(interval.start, chargingProfilesInterval.start) && + isBefore( + storedChargingProfile.chargingSchedule.startSchedule!, + chargingProfilesInterval.start, + ) + ) { + // Remove charging schedule periods that are after the start of the active profiles interval + storedChargingProfile.chargingSchedule.chargingSchedulePeriod = + storedChargingProfile.chargingSchedule.chargingSchedulePeriod.filter( + (schedulePeriod) => + isWithinInterval( + addSeconds( + storedChargingProfile.chargingSchedule.startSchedule!, + schedulePeriod.startPeriod, + ), + { + start: interval.start, + end: chargingProfilesInterval.start, + }, + ), + ); + addChargingProfile = true; + } + if ( + isBefore(chargingProfilesInterval.end, interval.end) && + isAfter( + addSeconds( storedChargingProfile.chargingSchedule.startSchedule!, - max( - chargingProfiles.map( - (chargingProfile) => - addSeconds( - chargingProfile.chargingSchedule.startSchedule!, - chargingProfile.chargingSchedule.duration!, - ) ?? minTime, + storedChargingProfile.chargingSchedule.duration!, + ), + chargingProfilesInterval.end, + ) + ) { + // Remove charging schedule periods that are before the end of the active profiles interval + // FIXME: can lead to a gap in the charging schedule: chargingProfilesInterval.end -> first matching schedulePeriod.startPeriod + storedChargingProfile.chargingSchedule.chargingSchedulePeriod = + storedChargingProfile.chargingSchedule.chargingSchedulePeriod.filter( + (schedulePeriod) => + isWithinInterval( + addSeconds( + storedChargingProfile.chargingSchedule.startSchedule!, + schedulePeriod.startPeriod, + ), + { + start: chargingProfilesInterval.end, + end: interval.end, + }, ), - ), - )))) - ) { - chargingProfiles.push(storedChargingProfile); + ); + addChargingProfile = true; + } + addChargingProfile && chargingProfiles.push(storedChargingProfile); + } } } const compositeScheduleStart: Date = min( @@ -787,11 +864,12 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { ), ); const compositeScheduleDuration: number = Math.max( - ...chargingProfiles.map( - (chargingProfile) => chargingProfile.chargingSchedule.duration ?? -Infinity, + ...chargingProfiles.map((chargingProfile) => + isNaN(chargingProfile.chargingSchedule.duration!) + ? -Infinity + : chargingProfile.chargingSchedule.duration!, ), ); - // FIXME: remove overlapping charging schedule periods const compositeSchedulePeriods: OCPP16ChargingSchedulePeriod[] = chargingProfiles .map((chargingProfile) => chargingProfile.chargingSchedule.chargingSchedulePeriod) .reduce( @@ -815,8 +893,10 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { : OCPP16ChargingRateUnitType.AMPERE, chargingSchedulePeriod: compositeSchedulePeriods, minChargeRate: Math.min( - ...chargingProfiles.map( - (chargingProfile) => chargingProfile.chargingSchedule.minChargeRate ?? Infinity, + ...chargingProfiles.map((chargingProfile) => + isNaN(chargingProfile.chargingSchedule.minChargeRate!) + ? Infinity + : chargingProfile.chargingSchedule.minChargeRate!, ), ), };