+ public static clearChargingProfiles = (
+ chargingStation: ChargingStation,
+ commandPayload: OCPP16ClearChargingProfileRequest,
+ chargingProfiles: OCPP16ChargingProfile[] | undefined
+ ): boolean => {
+ const { id, chargingProfilePurpose, stackLevel } = commandPayload
+ let clearedCP = false
+ if (isNotEmptyArray(chargingProfiles)) {
+ chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => {
+ let clearCurrentCP = false
+ if (chargingProfile.chargingProfileId === id) {
+ clearCurrentCP = true
+ }
+ if (chargingProfilePurpose == null && chargingProfile.stackLevel === stackLevel) {
+ clearCurrentCP = true
+ }
+ if (
+ stackLevel == null &&
+ chargingProfile.chargingProfilePurpose === chargingProfilePurpose
+ ) {
+ clearCurrentCP = true
+ }
+ if (
+ chargingProfile.stackLevel === stackLevel &&
+ chargingProfile.chargingProfilePurpose === chargingProfilePurpose
+ ) {
+ clearCurrentCP = true
+ }
+ if (clearCurrentCP) {
+ chargingProfiles.splice(index, 1)
+ logger.debug(
+ `${chargingStation.logPrefix()} Matching charging profile(s) cleared: %j`,
+ chargingProfile
+ )
+ clearedCP = true
+ }
+ })
+ }
+ return clearedCP
+ }
+
+ public static composeChargingSchedules = (
+ chargingScheduleHigher: OCPP16ChargingSchedule | undefined,
+ chargingScheduleLower: OCPP16ChargingSchedule | undefined,
+ compositeInterval: Interval
+ ): OCPP16ChargingSchedule | undefined => {
+ if (chargingScheduleHigher == null && chargingScheduleLower == null) {
+ return undefined
+ }
+ if (chargingScheduleHigher != null && chargingScheduleLower == null) {
+ return OCPP16ServiceUtils.composeChargingSchedule(chargingScheduleHigher, compositeInterval)
+ }
+ if (chargingScheduleHigher == null && chargingScheduleLower != null) {
+ return OCPP16ServiceUtils.composeChargingSchedule(chargingScheduleLower, compositeInterval)
+ }
+ const compositeChargingScheduleHigher: OCPP16ChargingSchedule | undefined =
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ OCPP16ServiceUtils.composeChargingSchedule(chargingScheduleHigher!, compositeInterval)
+ const compositeChargingScheduleLower: OCPP16ChargingSchedule | undefined =
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ OCPP16ServiceUtils.composeChargingSchedule(chargingScheduleLower!, compositeInterval)
+ const compositeChargingScheduleHigherInterval: Interval = {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ start: compositeChargingScheduleHigher!.startSchedule!,
+ end: addSeconds(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ compositeChargingScheduleHigher!.startSchedule!,
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ compositeChargingScheduleHigher!.duration!
+ )
+ }
+ const compositeChargingScheduleLowerInterval: Interval = {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ start: compositeChargingScheduleLower!.startSchedule!,
+ end: addSeconds(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ compositeChargingScheduleLower!.startSchedule!,
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ compositeChargingScheduleLower!.duration!
+ )
+ }
+ const higherFirst = isBefore(
+ compositeChargingScheduleHigherInterval.start,
+ compositeChargingScheduleLowerInterval.start
+ )
+ if (
+ !areIntervalsOverlapping(
+ compositeChargingScheduleHigherInterval,
+ compositeChargingScheduleLowerInterval
+ )
+ ) {
+ return {
+ ...compositeChargingScheduleLower,
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ ...compositeChargingScheduleHigher!,
+ startSchedule: higherFirst
+ ? (compositeChargingScheduleHigherInterval.start as Date)
+ : (compositeChargingScheduleLowerInterval.start as Date),
+ duration: higherFirst
+ ? differenceInSeconds(
+ compositeChargingScheduleLowerInterval.end,
+ compositeChargingScheduleHigherInterval.start
+ )
+ : differenceInSeconds(
+ compositeChargingScheduleHigherInterval.end,
+ compositeChargingScheduleLowerInterval.start
+ ),
+ chargingSchedulePeriod: [
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ ...compositeChargingScheduleHigher!.chargingSchedulePeriod.map(schedulePeriod => {
+ return {
+ ...schedulePeriod,
+ startPeriod: higherFirst
+ ? 0
+ : schedulePeriod.startPeriod +
+ differenceInSeconds(
+ compositeChargingScheduleHigherInterval.start,
+ compositeChargingScheduleLowerInterval.start
+ )
+ }
+ }),
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ ...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,
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ ...compositeChargingScheduleHigher!,
+ startSchedule: higherFirst
+ ? (compositeChargingScheduleHigherInterval.start as Date)
+ : (compositeChargingScheduleLowerInterval.start as Date),
+ duration: higherFirst
+ ? differenceInSeconds(
+ compositeChargingScheduleLowerInterval.end,
+ compositeChargingScheduleHigherInterval.start
+ )
+ : differenceInSeconds(
+ compositeChargingScheduleHigherInterval.end,
+ compositeChargingScheduleLowerInterval.start
+ ),
+ chargingSchedulePeriod: [
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ ...compositeChargingScheduleHigher!.chargingSchedulePeriod.map(schedulePeriod => {
+ return {
+ ...schedulePeriod,
+ startPeriod: higherFirst
+ ? 0
+ : schedulePeriod.startPeriod +
+ differenceInSeconds(
+ compositeChargingScheduleHigherInterval.start,
+ compositeChargingScheduleLowerInterval.start
+ )
+ }
+ }),
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ ...compositeChargingScheduleLower!.chargingSchedulePeriod
+ .filter((schedulePeriod, index) => {
+ if (
+ higherFirst &&
+ isWithinInterval(
+ addSeconds(
+ compositeChargingScheduleLowerInterval.start,
+ schedulePeriod.startPeriod
+ ),
+ {
+ start: compositeChargingScheduleLowerInterval.start,
+ end: compositeChargingScheduleHigherInterval.end
+ }
+ )
+ ) {
+ return false
+ }
+ if (
+ higherFirst &&
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ index < compositeChargingScheduleLower!.chargingSchedulePeriod.length - 1 &&
+ !isWithinInterval(
+ addSeconds(
+ compositeChargingScheduleLowerInterval.start,
+ schedulePeriod.startPeriod
+ ),
+ {
+ start: compositeChargingScheduleLowerInterval.start,
+ end: compositeChargingScheduleHigherInterval.end
+ }
+ ) &&
+ isWithinInterval(
+ addSeconds(
+ compositeChargingScheduleLowerInterval.start,
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ compositeChargingScheduleLower!.chargingSchedulePeriod[index + 1].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, index) => {
+ if (index === 0 && schedulePeriod.startPeriod !== 0) {
+ schedulePeriod.startPeriod = 0
+ }
+ return {
+ ...schedulePeriod,
+ startPeriod: higherFirst
+ ? schedulePeriod.startPeriod +
+ differenceInSeconds(
+ compositeChargingScheduleLowerInterval.start,
+ compositeChargingScheduleHigherInterval.start
+ )
+ : 0
+ }
+ })
+ ].sort((a, b) => a.startPeriod - b.startPeriod)
+ }
+ }
+
+ public static isConfigurationKeyVisible (key: ConfigurationKey): boolean {
+ if (key.visible == null) {
+ return true
+ }
+ return key.visible
+ }
+
+ public static hasReservation = (