+ !OCPP16ServiceUtils.checkFeatureProfile(
+ chargingStation,
+ OCPP16SupportedFeatureProfiles.SmartCharging,
+ OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE
+ )
+ ) {
+ return OCPP16Constants.OCPP_RESPONSE_REJECTED
+ }
+ const { connectorId, duration, chargingRateUnit } = commandPayload
+ if (!chargingStation.hasConnector(connectorId)) {
+ logger.error(
+ `${chargingStation.logPrefix()} Trying to get composite schedule to a non existing connector id ${connectorId}`
+ )
+ return OCPP16Constants.OCPP_RESPONSE_REJECTED
+ }
+ if (connectorId === 0) {
+ logger.error(
+ `${chargingStation.logPrefix()} Get composite schedule on connector id ${connectorId} is not yet supported`
+ )
+ return OCPP16Constants.OCPP_RESPONSE_REJECTED
+ }
+ if (chargingRateUnit != null) {
+ logger.warn(
+ `${chargingStation.logPrefix()} Get composite schedule with a specified rate unit is not yet supported, no conversion will be done`
+ )
+ }
+ const connectorStatus = chargingStation.getConnectorStatus(connectorId)
+ if (
+ isEmptyArray(connectorStatus?.chargingProfiles) &&
+ isEmptyArray(chargingStation.getConnectorStatus(0)?.chargingProfiles)
+ ) {
+ return OCPP16Constants.OCPP_RESPONSE_REJECTED
+ }
+ const currentDate = new Date()
+ const compositeScheduleInterval: Interval = {
+ start: currentDate,
+ end: addSeconds(currentDate, duration)
+ }
+ // Get charging profiles sorted by connector id then stack level
+ const chargingProfiles: OCPP16ChargingProfile[] = getConnectorChargingProfiles(
+ chargingStation,
+ connectorId
+ )
+ let previousCompositeSchedule: OCPP16ChargingSchedule | undefined
+ let compositeSchedule: OCPP16ChargingSchedule | undefined
+ for (const chargingProfile of chargingProfiles) {
+ if (chargingProfile.chargingSchedule.startSchedule == null) {
+ logger.debug(
+ `${chargingStation.logPrefix()} ${moduleName}.handleRequestGetCompositeSchedule: 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
+ chargingProfile.chargingSchedule.startSchedule = connectorStatus?.transactionStart
+ }
+ if (!isDate(chargingProfile.chargingSchedule.startSchedule)) {
+ logger.warn(
+ `${chargingStation.logPrefix()} ${moduleName}.handleRequestGetCompositeSchedule: Charging profile id ${
+ chargingProfile.chargingProfileId
+ } startSchedule property is not a Date instance. Trying to convert it to a Date instance`
+ )
+ chargingProfile.chargingSchedule.startSchedule = convertToDate(
+ chargingProfile.chargingSchedule.startSchedule
+ )
+ }
+ if (chargingProfile.chargingSchedule.duration == null) {
+ logger.debug(
+ `${chargingStation.logPrefix()} ${moduleName}.handleRequestGetCompositeSchedule: Charging profile id ${
+ chargingProfile.chargingProfileId
+ } has no duration defined and will be set to the maximum time allowed`
+ )
+ // OCPP specifies that if duration is not defined, it should be infinite
+ chargingProfile.chargingSchedule.duration = differenceInSeconds(
+ maxTime,
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ chargingProfile.chargingSchedule.startSchedule!
+ )
+ }
+ if (
+ !prepareChargingProfileKind(
+ connectorStatus,
+ chargingProfile,
+ compositeScheduleInterval.start,
+ chargingStation.logPrefix()
+ )
+ ) {
+ continue
+ }
+ if (
+ !canProceedChargingProfile(
+ chargingProfile,
+ compositeScheduleInterval.start,
+ chargingStation.logPrefix()
+ )
+ ) {
+ continue
+ }
+ compositeSchedule = OCPP16ServiceUtils.composeChargingSchedules(
+ previousCompositeSchedule,
+ chargingProfile.chargingSchedule,
+ compositeScheduleInterval
+ )
+ previousCompositeSchedule = compositeSchedule
+ }
+ if (compositeSchedule != null) {
+ return {
+ status: GenericStatus.Accepted,
+ scheduleStart: compositeSchedule.startSchedule,
+ connectorId,
+ chargingSchedule: compositeSchedule
+ }
+ }
+ return OCPP16Constants.OCPP_RESPONSE_REJECTED
+ }
+
+ private handleRequestClearChargingProfile (
+ chargingStation: ChargingStation,
+ commandPayload: OCPP16ClearChargingProfileRequest
+ ): OCPP16ClearChargingProfileResponse {
+ if (
+ !OCPP16ServiceUtils.checkFeatureProfile(