+ public static composeChargingSchedules = (
+ chargingScheduleHigher: OCPP16ChargingSchedule | undefined,
+ chargingScheduleLower: OCPP16ChargingSchedule | undefined,
+ targetInterval: Interval,
+ ): OCPP16ChargingSchedule | undefined => {
+ if (!chargingScheduleHigher && !chargingScheduleLower) {
+ return undefined;
+ }
+ if (chargingScheduleHigher && !chargingScheduleLower) {
+ return OCPP16ServiceUtils.composeChargingSchedule(chargingScheduleHigher, targetInterval);
+ }
+ if (!chargingScheduleHigher && chargingScheduleLower) {
+ return OCPP16ServiceUtils.composeChargingSchedule(chargingScheduleLower, targetInterval);
+ }
+ const compositeChargingScheduleHigher: OCPP16ChargingSchedule | undefined =
+ OCPP16ServiceUtils.composeChargingSchedule(chargingScheduleHigher!, targetInterval);
+ const compositeChargingScheduleLower: OCPP16ChargingSchedule | undefined =
+ OCPP16ServiceUtils.composeChargingSchedule(chargingScheduleLower!, targetInterval);
+ const compositeChargingScheduleHigherInterval: Interval = {
+ start: compositeChargingScheduleHigher!.startSchedule!,
+ end: addSeconds(
+ compositeChargingScheduleHigher!.startSchedule!,
+ compositeChargingScheduleHigher!.duration!,
+ ),
+ };
+ const compositeChargingScheduleLowerInterval: Interval = {
+ start: compositeChargingScheduleLower!.startSchedule!,
+ end: addSeconds(
+ compositeChargingScheduleLower!.startSchedule!,
+ compositeChargingScheduleLower!.duration!,
+ ),
+ };
+ const higherFirst = isBefore(
+ compositeChargingScheduleHigherInterval.start,
+ compositeChargingScheduleLowerInterval.start,
+ );
+ if (
+ !areIntervalsOverlapping(
+ compositeChargingScheduleHigherInterval,
+ compositeChargingScheduleLowerInterval,
+ )
+ ) {
+ return {
+ ...compositeChargingScheduleLower,
+ ...compositeChargingScheduleHigher!,
+ startSchedule: higherFirst
+ ? (compositeChargingScheduleHigherInterval.start as Date)
+ : (compositeChargingScheduleLowerInterval.start as Date),
+ duration: higherFirst
+ ? differenceInSeconds(
+ compositeChargingScheduleLowerInterval.end,
+ compositeChargingScheduleHigherInterval.start,
+ )
+ : differenceInSeconds(
+ compositeChargingScheduleHigherInterval.end,
+ compositeChargingScheduleLowerInterval.start,
+ ),
+ chargingSchedulePeriod: [
+ ...compositeChargingScheduleHigher!.chargingSchedulePeriod.map((schedulePeriod) => {
+ return {
+ ...schedulePeriod,
+ startPeriod: higherFirst
+ ? 0
+ : schedulePeriod.startPeriod +
+ differenceInSeconds(
+ compositeChargingScheduleHigherInterval.start,
+ compositeChargingScheduleLowerInterval.start,
+ ),
+ };
+ }),
+ ...compositeChargingScheduleLower!.chargingSchedulePeriod.map((schedulePeriod) => {
+ return {
+ ...schedulePeriod,
+ startPeriod: higherFirst
+ ? schedulePeriod.startPeriod +
+ differenceInSeconds(
+ compositeChargingScheduleLowerInterval.start,
+ compositeChargingScheduleHigherInterval.start,
+ )
+ : 0,
+ };
+ }),
+ ].sort((a, b) => a.startPeriod - b.startPeriod),
+ };
+ }
+ return {
+ ...compositeChargingScheduleLower,
+ ...compositeChargingScheduleHigher!,
+ startSchedule: higherFirst
+ ? (compositeChargingScheduleHigherInterval.start as Date)
+ : (compositeChargingScheduleLowerInterval.start as Date),
+ duration: higherFirst
+ ? differenceInSeconds(
+ compositeChargingScheduleLowerInterval.end,
+ compositeChargingScheduleHigherInterval.start,
+ )
+ : differenceInSeconds(
+ compositeChargingScheduleHigherInterval.end,
+ compositeChargingScheduleLowerInterval.start,
+ ),
+ chargingSchedulePeriod: [
+ ...compositeChargingScheduleHigher!.chargingSchedulePeriod.map((schedulePeriod) => {
+ return {
+ ...schedulePeriod,
+ startPeriod: higherFirst
+ ? 0
+ : schedulePeriod.startPeriod +
+ differenceInSeconds(
+ compositeChargingScheduleHigherInterval.start,
+ compositeChargingScheduleLowerInterval.start,
+ ),
+ };
+ }),
+ ...compositeChargingScheduleLower!.chargingSchedulePeriod
+ .filter((schedulePeriod) => {
+ if (
+ higherFirst &&
+ isWithinInterval(
+ addSeconds(
+ compositeChargingScheduleLowerInterval.start,
+ schedulePeriod.startPeriod,
+ ),
+ {
+ start: compositeChargingScheduleLowerInterval.start,
+ end: compositeChargingScheduleHigherInterval.end,
+ },
+ )
+ ) {
+ return false;
+ }
+ if (
+ !higherFirst &&
+ isWithinInterval(
+ addSeconds(
+ compositeChargingScheduleLowerInterval.start,
+ schedulePeriod.startPeriod,
+ ),
+ {
+ start: compositeChargingScheduleHigherInterval.start,
+ end: compositeChargingScheduleLowerInterval.end,
+ },
+ )
+ ) {
+ return false;
+ }
+ return true;
+ })
+ .map((schedulePeriod) => {
+ return {
+ ...schedulePeriod,
+ startPeriod: higherFirst
+ ? schedulePeriod.startPeriod +
+ differenceInSeconds(
+ compositeChargingScheduleLowerInterval.start,
+ compositeChargingScheduleHigherInterval.start,
+ )
+ : 0,
+ };
+ }),
+ ].sort((a, b) => a.startPeriod - b.startPeriod),
+ };
+ };
+