chore: bump volta pnpm version
[e-mobility-charging-stations-simulator.git] / src / charging-station / Helpers.ts
index c2694498ecec09789f5fa02f6bbfd62cabc4d5d4..112fb904159c95210b49fa532445fdfc97d70578 100644 (file)
@@ -1,29 +1,30 @@
-import { createHash, randomBytes } from 'node:crypto'
 import type { EventEmitter } from 'node:events'
-import { basename, dirname, join } from 'node:path'
-import { env } from 'node:process'
-import { fileURLToPath } from 'node:url'
 
 import chalk from 'chalk'
 import {
-  type Interval,
   addDays,
   addSeconds,
   addWeeks,
   differenceInDays,
   differenceInSeconds,
   differenceInWeeks,
+  type Interval,
   isAfter,
   isBefore,
   isDate,
   isPast,
   isWithinInterval,
-  toDate
+  toDate,
 } from 'date-fns'
 import { maxTime } from 'date-fns/constants'
+import { createHash, randomBytes } from 'node:crypto'
+import { basename, dirname, isAbsolute, join, parse, relative, resolve } from 'node:path'
+import { env } from 'node:process'
+import { fileURLToPath } from 'node:url'
+import { isEmpty } from 'rambda'
 
 import type { ChargingStation } from './ChargingStation.js'
-import { getConfigurationKey } from './ConfigurationKeyUtils.js'
+
 import { BaseError } from '../exception/index.js'
 import {
   AmpereUnits,
@@ -32,10 +33,12 @@ import {
   BootReasonEnumType,
   type ChargingProfile,
   ChargingProfileKindType,
+  ChargingProfilePurposeType,
   ChargingRateUnitType,
   type ChargingSchedulePeriod,
   type ChargingStationConfiguration,
   type ChargingStationInfo,
+  type ChargingStationOptions,
   type ChargingStationTemplate,
   type ChargingStationWorkerMessageEvents,
   ConnectorPhaseRotation,
@@ -51,27 +54,37 @@ import {
   ReservationTerminationReason,
   StandardParametersKey,
   type SupportedFeatureProfiles,
-  Voltage
+  Voltage,
 } from '../types/index.js'
 import {
   ACElectricUtils,
+  clone,
   Constants,
-  DCElectricUtils,
-  cloneObject,
   convertToDate,
   convertToInt,
+  DCElectricUtils,
   isArraySorted,
-  isEmptyObject,
-  isEmptyString,
   isNotEmptyArray,
   isNotEmptyString,
-  isValidTime,
+  isValidDate,
   logger,
-  secureRandom
+  secureRandom,
 } from '../utils/index.js'
+import { getConfigurationKey } from './ConfigurationKeyUtils.js'
 
 const moduleName = 'Helpers'
 
+export const buildTemplateName = (templateFile: string): string => {
+  if (isAbsolute(templateFile)) {
+    templateFile = relative(
+      resolve(join(dirname(fileURLToPath(import.meta.url)), 'assets', 'station-templates')),
+      templateFile
+    )
+  }
+  const templateFileParsedPath = parse(templateFile)
+  return join(templateFileParsedPath.dir, templateFileParsedPath.name)
+}
+
 export const getChargingStationId = (
   index: number,
   stationTemplate: ChargingStationTemplate | undefined
@@ -145,25 +158,86 @@ export const getHashId = (index: number, stationTemplate: ChargingStationTemplat
   const chargingStationInfo = {
     chargePointModel: stationTemplate.chargePointModel,
     chargePointVendor: stationTemplate.chargePointVendor,
-    ...(stationTemplate.chargeBoxSerialNumberPrefix !== undefined && {
-      chargeBoxSerialNumber: stationTemplate.chargeBoxSerialNumberPrefix
+    ...(stationTemplate.chargeBoxSerialNumberPrefix != null && {
+      chargeBoxSerialNumber: stationTemplate.chargeBoxSerialNumberPrefix,
     }),
-    ...(stationTemplate.chargePointSerialNumberPrefix !== undefined && {
-      chargePointSerialNumber: stationTemplate.chargePointSerialNumberPrefix
+    ...(stationTemplate.chargePointSerialNumberPrefix != null && {
+      chargePointSerialNumber: stationTemplate.chargePointSerialNumberPrefix,
     }),
-    ...(stationTemplate.meterSerialNumberPrefix !== undefined && {
-      meterSerialNumber: stationTemplate.meterSerialNumberPrefix
+    ...(stationTemplate.meterSerialNumberPrefix != null && {
+      meterSerialNumber: stationTemplate.meterSerialNumberPrefix,
+    }),
+    ...(stationTemplate.meterType != null && {
+      meterType: stationTemplate.meterType,
     }),
-    ...(stationTemplate.meterType !== undefined && {
-      meterType: stationTemplate.meterType
-    })
   }
   return createHash(Constants.DEFAULT_HASH_ALGORITHM)
     .update(`${JSON.stringify(chargingStationInfo)}${getChargingStationId(index, stationTemplate)}`)
     .digest('hex')
 }
 
-export const checkChargingStation = (
+export const validateStationInfo = (chargingStation: ChargingStation): void => {
+  if (chargingStation.stationInfo == null || isEmpty(chargingStation.stationInfo)) {
+    throw new BaseError('Missing charging station information')
+  }
+  if (
+    chargingStation.stationInfo.chargingStationId == null ||
+    isEmpty(chargingStation.stationInfo.chargingStationId.trim())
+  ) {
+    throw new BaseError('Missing chargingStationId in stationInfo properties')
+  }
+  const chargingStationId = chargingStation.stationInfo.chargingStationId
+  if (
+    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+    chargingStation.stationInfo.hashId == null ||
+    isEmpty(chargingStation.stationInfo.hashId.trim())
+  ) {
+    throw new BaseError(`${chargingStationId}: Missing hashId in stationInfo properties`)
+  }
+  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+  if (chargingStation.stationInfo.templateIndex == null) {
+    throw new BaseError(`${chargingStationId}: Missing templateIndex in stationInfo properties`)
+  }
+  if (chargingStation.stationInfo.templateIndex <= 0) {
+    throw new BaseError(
+      `${chargingStationId}: Invalid templateIndex value in stationInfo properties`
+    )
+  }
+  if (
+    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+    chargingStation.stationInfo.templateName == null ||
+    isEmpty(chargingStation.stationInfo.templateName.trim())
+  ) {
+    throw new BaseError(`${chargingStationId}: Missing templateName in stationInfo properties`)
+  }
+  if (chargingStation.stationInfo.maximumPower == null) {
+    throw new BaseError(`${chargingStationId}: Missing maximumPower in stationInfo properties`)
+  }
+  if (chargingStation.stationInfo.maximumPower <= 0) {
+    throw new RangeError(
+      `${chargingStationId}: Invalid maximumPower value in stationInfo properties`
+    )
+  }
+  if (chargingStation.stationInfo.maximumAmperage == null) {
+    throw new BaseError(`${chargingStationId}: Missing maximumAmperage in stationInfo properties`)
+  }
+  if (chargingStation.stationInfo.maximumAmperage <= 0) {
+    throw new RangeError(
+      `${chargingStationId}: Invalid maximumAmperage value in stationInfo properties`
+    )
+  }
+  switch (chargingStation.stationInfo.ocppVersion) {
+    case OCPPVersion.VERSION_20:
+    case OCPPVersion.VERSION_201:
+      if (chargingStation.evses.size === 0) {
+        throw new BaseError(
+          `${chargingStationId}: OCPP 2.0 or superior requires at least one EVSE defined in the charging station template/configuration`
+        )
+      }
+  }
+}
+
+export const checkChargingStationState = (
   chargingStation: ChargingStation,
   logPrefix: string
 ): boolean => {
@@ -180,14 +254,14 @@ export const getPhaseRotationValue = (
 ): string | undefined => {
   // AC/DC
   if (connectorId === 0 && numberOfPhases === 0) {
-    return `${connectorId}.${ConnectorPhaseRotation.RST}`
+    return `${connectorId.toString()}.${ConnectorPhaseRotation.RST}`
   } else if (connectorId > 0 && numberOfPhases === 0) {
-    return `${connectorId}.${ConnectorPhaseRotation.NotApplicable}`
+    return `${connectorId.toString()}.${ConnectorPhaseRotation.NotApplicable}`
     // AC
   } else if (connectorId >= 0 && numberOfPhases === 1) {
-    return `${connectorId}.${ConnectorPhaseRotation.NotApplicable}`
+    return `${connectorId.toString()}.${ConnectorPhaseRotation.NotApplicable}`
   } else if (connectorId >= 0 && numberOfPhases === 3) {
-    return `${connectorId}.${ConnectorPhaseRotation.RST}`
+    return `${connectorId.toString()}.${ConnectorPhaseRotation.RST}`
   }
 }
 
@@ -242,20 +316,12 @@ export const checkTemplate = (
     logger.error(`${logPrefix} ${errorMsg}`)
     throw new BaseError(errorMsg)
   }
-  if (isEmptyObject(stationTemplate)) {
+  if (isEmpty(stationTemplate)) {
     const errorMsg = `Empty charging station information from template file ${templateFile}`
     logger.error(`${logPrefix} ${errorMsg}`)
     throw new BaseError(errorMsg)
   }
-  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-  if (isEmptyObject(stationTemplate.AutomaticTransactionGenerator!)) {
-    stationTemplate.AutomaticTransactionGenerator = Constants.DEFAULT_ATG_CONFIGURATION
-    logger.warn(
-      `${logPrefix} Empty automatic transaction generator configuration from template file ${templateFile}, set to default: %j`,
-      Constants.DEFAULT_ATG_CONFIGURATION
-    )
-  }
-  if (stationTemplate.idTagsFile == null || isEmptyString(stationTemplate.idTagsFile)) {
+  if (stationTemplate.idTagsFile == null || isEmpty(stationTemplate.idTagsFile)) {
     logger.warn(
       `${logPrefix} Missing id tags file in template file ${templateFile}. That can lead to issues with the Automatic Transaction Generator`
     )
@@ -272,7 +338,7 @@ export const checkConfiguration = (
     logger.error(`${logPrefix} ${errorMsg}`)
     throw new BaseError(errorMsg)
   }
-  if (isEmptyObject(stationConfiguration)) {
+  if (isEmpty(stationConfiguration)) {
     const errorMsg = `Empty charging station configuration from file ${configurationFile}`
     logger.error(`${logPrefix} ${errorMsg}`)
     throw new BaseError(errorMsg)
@@ -285,8 +351,8 @@ export const checkConnectorsConfiguration = (
   templateFile: string
 ): {
   configuredMaxConnectors: number
-  templateMaxConnectors: number
   templateMaxAvailableConnectors: number
+  templateMaxConnectors: number
 } => {
   const configuredMaxConnectors = getConfiguredMaxNumberOfConnectors(stationTemplate)
   checkConfiguredMaxConnectors(configuredMaxConnectors, logPrefix, templateFile)
@@ -303,7 +369,11 @@ export const checkConnectorsConfiguration = (
     )
     stationTemplate.randomConnectors = true
   }
-  return { configuredMaxConnectors, templateMaxConnectors, templateMaxAvailableConnectors }
+  return {
+    configuredMaxConnectors,
+    templateMaxAvailableConnectors,
+    templateMaxConnectors,
+  }
 }
 
 export const checkStationInfoConnectorStatus = (
@@ -314,12 +384,43 @@ export const checkStationInfoConnectorStatus = (
 ): void => {
   if (connectorStatus.status != null) {
     logger.warn(
-      `${logPrefix} Charging station information from template ${templateFile} with connector id ${connectorId} status configuration defined, undefine it`
+      `${logPrefix} Charging station information from template ${templateFile} with connector id ${connectorId.toString()} status configuration defined, undefine it`
     )
     delete connectorStatus.status
   }
 }
 
+export const setChargingStationOptions = (
+  stationInfo: ChargingStationInfo,
+  options?: ChargingStationOptions
+): ChargingStationInfo => {
+  if (options?.supervisionUrls != null) {
+    stationInfo.supervisionUrls = options.supervisionUrls
+  }
+  if (options?.persistentConfiguration != null) {
+    stationInfo.stationInfoPersistentConfiguration = options.persistentConfiguration
+    stationInfo.ocppPersistentConfiguration = options.persistentConfiguration
+    stationInfo.automaticTransactionGeneratorPersistentConfiguration =
+      options.persistentConfiguration
+  }
+  if (options?.autoStart != null) {
+    stationInfo.autoStart = options.autoStart
+  }
+  if (options?.autoRegister != null) {
+    stationInfo.autoRegister = options.autoRegister
+  }
+  if (options?.enableStatistics != null) {
+    stationInfo.enableStatistics = options.enableStatistics
+  }
+  if (options?.ocppStrictCompliance != null) {
+    stationInfo.ocppStrictCompliance = options.ocppStrictCompliance
+  }
+  if (options?.stopTransactionsOnStopped != null) {
+    stationInfo.stopTransactionsOnStopped = options.stopTransactionsOnStopped
+  }
+  return stationInfo
+}
+
 export const buildConnectorsMap = (
   connectors: Record<string, ConnectorStatus>,
   logPrefix: string,
@@ -331,7 +432,7 @@ export const buildConnectorsMap = (
       const connectorStatus = connectors[connector]
       const connectorId = convertToInt(connector)
       checkStationInfoConnectorStatus(connectorId, connectorStatus, logPrefix, templateFile)
-      connectorsMap.set(connectorId, cloneObject<ConnectorStatus>(connectorStatus))
+      connectorsMap.set(connectorId, clone<ConnectorStatus>(connectorStatus))
     }
   } else {
     logger.warn(
@@ -348,9 +449,10 @@ export const initializeConnectorsMapStatus = (
   for (const connectorId of connectors.keys()) {
     if (connectorId > 0 && connectors.get(connectorId)?.transactionStarted === true) {
       logger.warn(
-        `${logPrefix} Connector id ${connectorId} at initialization has a transaction started with id ${
-          connectors.get(connectorId)?.transactionId
-        }`
+        // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+        `${logPrefix} Connector id ${connectorId.toString()} at initialization has a transaction started with id ${connectors
+          .get(connectorId)
+          ?.transactionId?.toString()}`
       )
     }
     if (connectorId === 0) {
@@ -367,29 +469,60 @@ export const initializeConnectorsMapStatus = (
   }
 }
 
+export const resetAuthorizeConnectorStatus = (connectorStatus: ConnectorStatus): void => {
+  connectorStatus.idTagLocalAuthorized = false
+  connectorStatus.idTagAuthorized = false
+  delete connectorStatus.localAuthorizeIdTag
+  delete connectorStatus.authorizeIdTag
+}
+
 export const resetConnectorStatus = (connectorStatus: ConnectorStatus | undefined): void => {
   if (connectorStatus == null) {
     return
   }
-  connectorStatus.chargingProfiles =
-    connectorStatus.transactionId != null && isNotEmptyArray(connectorStatus.chargingProfiles)
-      ? connectorStatus.chargingProfiles?.filter(
-        (chargingProfile) => chargingProfile.transactionId !== connectorStatus.transactionId
-      )
-      : []
-  connectorStatus.idTagLocalAuthorized = false
-  connectorStatus.idTagAuthorized = false
+  if (isNotEmptyArray(connectorStatus.chargingProfiles)) {
+    connectorStatus.chargingProfiles = connectorStatus.chargingProfiles.filter(
+      chargingProfile =>
+        (chargingProfile.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE &&
+          chargingProfile.transactionId != null &&
+          connectorStatus.transactionId != null &&
+          chargingProfile.transactionId !== connectorStatus.transactionId) ||
+        chargingProfile.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE
+    )
+  }
+  resetAuthorizeConnectorStatus(connectorStatus)
   connectorStatus.transactionRemoteStarted = false
   connectorStatus.transactionStarted = false
   delete connectorStatus.transactionStart
   delete connectorStatus.transactionId
-  delete connectorStatus.localAuthorizeIdTag
-  delete connectorStatus.authorizeIdTag
   delete connectorStatus.transactionIdTag
   connectorStatus.transactionEnergyActiveImportRegisterValue = 0
   delete connectorStatus.transactionBeginMeterValue
 }
 
+export const prepareConnectorStatus = (connectorStatus: ConnectorStatus): ConnectorStatus => {
+  if (connectorStatus.reservation != null) {
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    connectorStatus.reservation.expiryDate = convertToDate(connectorStatus.reservation.expiryDate)!
+  }
+  if (isNotEmptyArray(connectorStatus.chargingProfiles)) {
+    connectorStatus.chargingProfiles = connectorStatus.chargingProfiles
+      .filter(
+        chargingProfile =>
+          chargingProfile.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE
+      )
+      .map(chargingProfile => {
+        chargingProfile.chargingSchedule.startSchedule = convertToDate(
+          chargingProfile.chargingSchedule.startSchedule
+        )
+        chargingProfile.validFrom = convertToDate(chargingProfile.validFrom)
+        chargingProfile.validTo = convertToDate(chargingProfile.validTo)
+        return chargingProfile
+      })
+  }
+  return connectorStatus
+}
+
 export const createBootNotificationRequest = (
   stationInfo: ChargingStationInfo,
   bootReason: BootReasonEnumType = BootReasonEnumType.PowerUp
@@ -400,44 +533,44 @@ export const createBootNotificationRequest = (
       return {
         chargePointModel: stationInfo.chargePointModel,
         chargePointVendor: stationInfo.chargePointVendor,
-        ...(stationInfo.chargeBoxSerialNumber !== undefined && {
-          chargeBoxSerialNumber: stationInfo.chargeBoxSerialNumber
+        ...(stationInfo.chargeBoxSerialNumber != null && {
+          chargeBoxSerialNumber: stationInfo.chargeBoxSerialNumber,
+        }),
+        ...(stationInfo.chargePointSerialNumber != null && {
+          chargePointSerialNumber: stationInfo.chargePointSerialNumber,
         }),
-        ...(stationInfo.chargePointSerialNumber !== undefined && {
-          chargePointSerialNumber: stationInfo.chargePointSerialNumber
+        ...(stationInfo.firmwareVersion != null && {
+          firmwareVersion: stationInfo.firmwareVersion,
         }),
-        ...(stationInfo.firmwareVersion !== undefined && {
-          firmwareVersion: stationInfo.firmwareVersion
+        ...(stationInfo.iccid != null && { iccid: stationInfo.iccid }),
+        ...(stationInfo.imsi != null && { imsi: stationInfo.imsi }),
+        ...(stationInfo.meterSerialNumber != null && {
+          meterSerialNumber: stationInfo.meterSerialNumber,
         }),
-        ...(stationInfo.iccid !== undefined && { iccid: stationInfo.iccid }),
-        ...(stationInfo.imsi !== undefined && { imsi: stationInfo.imsi }),
-        ...(stationInfo.meterSerialNumber !== undefined && {
-          meterSerialNumber: stationInfo.meterSerialNumber
+        ...(stationInfo.meterType != null && {
+          meterType: stationInfo.meterType,
         }),
-        ...(stationInfo.meterType !== undefined && {
-          meterType: stationInfo.meterType
-        })
       } satisfies OCPP16BootNotificationRequest
     case OCPPVersion.VERSION_20:
     case OCPPVersion.VERSION_201:
       return {
-        reason: bootReason,
         chargingStation: {
           model: stationInfo.chargePointModel,
           vendorName: stationInfo.chargePointVendor,
-          ...(stationInfo.firmwareVersion !== undefined && {
-            firmwareVersion: stationInfo.firmwareVersion
+          ...(stationInfo.firmwareVersion != null && {
+            firmwareVersion: stationInfo.firmwareVersion,
           }),
-          ...(stationInfo.chargeBoxSerialNumber !== undefined && {
-            serialNumber: stationInfo.chargeBoxSerialNumber
+          ...(stationInfo.chargeBoxSerialNumber != null && {
+            serialNumber: stationInfo.chargeBoxSerialNumber,
           }),
-          ...((stationInfo.iccid !== undefined || stationInfo.imsi !== undefined) && {
+          ...((stationInfo.iccid != null || stationInfo.imsi != null) && {
             modem: {
-              ...(stationInfo.iccid !== undefined && { iccid: stationInfo.iccid }),
-              ...(stationInfo.imsi !== undefined && { imsi: stationInfo.imsi })
-            }
-          })
-        }
+              ...(stationInfo.iccid != null && { iccid: stationInfo.iccid }),
+              ...(stationInfo.imsi != null && { imsi: stationInfo.imsi }),
+            },
+          }),
+        },
+        reason: bootReason,
       } satisfies OCPP20BootNotificationRequest
   }
 }
@@ -447,11 +580,11 @@ export const warnTemplateKeysDeprecation = (
   logPrefix: string,
   templateFile: string
 ): void => {
-  const templateKeys: Array<{ deprecatedKey: string, key?: string }> = [
+  const templateKeys: { deprecatedKey: string; key?: string }[] = [
     { deprecatedKey: 'supervisionUrl', key: 'supervisionUrls' },
     { deprecatedKey: 'authorizationFile', key: 'idTagsFile' },
     { deprecatedKey: 'payloadSchemaValidation', key: 'ocppStrictCompliance' },
-    { deprecatedKey: 'mustAuthorizeAtRemoteStart', key: 'remoteAuthorization' }
+    { deprecatedKey: 'mustAuthorizeAtRemoteStart', key: 'remoteAuthorization' },
   ]
   for (const templateKey of templateKeys) {
     warnDeprecatedTemplateKey(
@@ -459,7 +592,7 @@ export const warnTemplateKeysDeprecation = (
       templateKey.deprecatedKey,
       logPrefix,
       templateFile,
-      templateKey.key !== undefined ? `Use '${templateKey.key}' instead` : undefined
+      templateKey.key != null ? `Use '${templateKey.key}' instead` : undefined
     )
     convertDeprecatedTemplateKey(stationTemplate, templateKey.deprecatedKey, templateKey.key)
   }
@@ -468,13 +601,14 @@ export const warnTemplateKeysDeprecation = (
 export const stationTemplateToStationInfo = (
   stationTemplate: ChargingStationTemplate
 ): ChargingStationInfo => {
-  stationTemplate = cloneObject<ChargingStationTemplate>(stationTemplate)
+  stationTemplate = clone<ChargingStationTemplate>(stationTemplate)
   delete stationTemplate.power
   delete stationTemplate.powerUnit
   delete stationTemplate.Connectors
   delete stationTemplate.Evses
   delete stationTemplate.Configuration
   delete stationTemplate.AutomaticTransactionGenerator
+  delete stationTemplate.numberOfConnectors
   delete stationTemplate.chargeBoxSerialNumberPrefix
   delete stationTemplate.chargePointSerialNumberPrefix
   delete stationTemplate.meterSerialNumberPrefix
@@ -485,17 +619,19 @@ export const createSerialNumber = (
   stationTemplate: ChargingStationTemplate,
   stationInfo: ChargingStationInfo,
   params?: {
-    randomSerialNumberUpperCase?: boolean
     randomSerialNumber?: boolean
+    randomSerialNumberUpperCase?: boolean
   }
 ): void => {
-  params = { ...{ randomSerialNumberUpperCase: true, randomSerialNumber: true }, ...params }
-  const serialNumberSuffix =
-    params.randomSerialNumber === true
-      ? getRandomSerialNumberSuffix({
-        upperCase: params.randomSerialNumberUpperCase
-      })
-      : ''
+  params = {
+    ...{ randomSerialNumber: true, randomSerialNumberUpperCase: true },
+    ...params,
+  }
+  const serialNumberSuffix = params.randomSerialNumber
+    ? getRandomSerialNumberSuffix({
+      upperCase: params.randomSerialNumberUpperCase,
+    })
+    : ''
   isNotEmptyString(stationTemplate.chargePointSerialNumberPrefix) &&
     (stationInfo.chargePointSerialNumber = `${stationTemplate.chargePointSerialNumberPrefix}${serialNumberSuffix}`)
   isNotEmptyString(stationTemplate.chargeBoxSerialNumberPrefix) &&
@@ -554,80 +690,134 @@ export const getAmperageLimitationUnitDivider = (stationInfo: ChargingStationInf
   return unitDivider
 }
 
+const getChargingStationChargingProfiles = (
+  chargingStation: ChargingStation
+): ChargingProfile[] => {
+  return (chargingStation.getConnectorStatus(0)?.chargingProfiles ?? [])
+    .filter(
+      chargingProfile =>
+        chargingProfile.chargingProfilePurpose ===
+        ChargingProfilePurposeType.CHARGE_POINT_MAX_PROFILE
+    )
+    .sort((a, b) => b.stackLevel - a.stackLevel)
+}
+
+export const getChargingStationChargingProfilesLimit = (
+  chargingStation: ChargingStation
+): number | undefined => {
+  const chargingProfiles = getChargingStationChargingProfiles(chargingStation)
+  if (isNotEmptyArray(chargingProfiles)) {
+    const chargingProfilesLimit = getChargingProfilesLimit(chargingStation, 0, chargingProfiles)
+    if (chargingProfilesLimit != null) {
+      const limit = buildChargingProfilesLimit(chargingStation, chargingProfilesLimit)
+      const chargingStationMaximumPower =
+        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+        chargingStation.stationInfo!.maximumPower!
+      if (limit > chargingStationMaximumPower) {
+        logger.error(
+          `${chargingStation.logPrefix()} ${moduleName}.getChargingStationChargingProfilesLimit: Charging profile id ${chargingProfilesLimit.chargingProfile.chargingProfileId.toString()} limit ${limit.toString()} is greater than charging station maximum ${chargingStationMaximumPower.toString()}: %j`,
+          chargingProfilesLimit
+        )
+        return chargingStationMaximumPower
+      }
+      return limit
+    }
+  }
+}
+
 /**
- * Gets the connector cloned charging profiles applying a power limitation
- * and sorted by connector id descending then stack level descending
- *
- * @param chargingStation -
- * @param connectorId -
+ * Gets the connector charging profiles relevant for power limitation shallow cloned
+ * and sorted by priorities
+ * @param chargingStation - Charging station
+ * @param connectorId - Connector id
  * @returns connector charging profiles array
  */
 export const getConnectorChargingProfiles = (
   chargingStation: ChargingStation,
   connectorId: number
 ): ChargingProfile[] => {
-  return cloneObject<ChargingProfile[]>(
-    (chargingStation.getConnectorStatus(connectorId)?.chargingProfiles ?? [])
-      .sort((a, b) => b.stackLevel - a.stackLevel)
-      .concat(
-        (chargingStation.getConnectorStatus(0)?.chargingProfiles ?? []).sort(
-          (a, b) => b.stackLevel - a.stackLevel
+  return (chargingStation.getConnectorStatus(connectorId)?.chargingProfiles ?? [])
+    .slice()
+    .sort((a, b) => {
+      if (
+        a.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE &&
+        b.chargingProfilePurpose === ChargingProfilePurposeType.TX_DEFAULT_PROFILE
+      ) {
+        return -1
+      } else if (
+        a.chargingProfilePurpose === ChargingProfilePurposeType.TX_DEFAULT_PROFILE &&
+        b.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE
+      ) {
+        return 1
+      }
+      return b.stackLevel - a.stackLevel
+    })
+    .concat(
+      (chargingStation.getConnectorStatus(0)?.chargingProfiles ?? [])
+        .filter(
+          chargingProfile =>
+            chargingProfile.chargingProfilePurpose === ChargingProfilePurposeType.TX_DEFAULT_PROFILE
         )
-      )
-  )
+        .sort((a, b) => b.stackLevel - a.stackLevel)
+    )
 }
 
-export const getChargingStationConnectorChargingProfilesPowerLimit = (
+export const getConnectorChargingProfilesLimit = (
   chargingStation: ChargingStation,
   connectorId: number
 ): number | undefined => {
-  let limit: number | undefined, chargingProfile: ChargingProfile | undefined
-  // Get charging profiles sorted by connector id then stack level
   const chargingProfiles = getConnectorChargingProfiles(chargingStation, connectorId)
   if (isNotEmptyArray(chargingProfiles)) {
-    const result = getLimitFromChargingProfiles(
+    const chargingProfilesLimit = getChargingProfilesLimit(
       chargingStation,
       connectorId,
-      chargingProfiles,
-      chargingStation.logPrefix()
+      chargingProfiles
     )
-    if (result != null) {
-      limit = result.limit
-      chargingProfile = result.chargingProfile
-      switch (chargingStation.stationInfo?.currentOutType) {
-        case CurrentType.AC:
-          limit =
-            chargingProfile.chargingSchedule.chargingRateUnit === ChargingRateUnitType.WATT
-              ? limit
-              : ACElectricUtils.powerTotal(
-                chargingStation.getNumberOfPhases(),
-                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-                chargingStation.stationInfo.voltageOut!,
-                limit
-              )
-          break
-        case CurrentType.DC:
-          limit =
-            chargingProfile.chargingSchedule.chargingRateUnit === ChargingRateUnitType.WATT
-              ? limit
-              : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-              DCElectricUtils.power(chargingStation.stationInfo.voltageOut!, limit)
-      }
+    if (chargingProfilesLimit != null) {
+      const limit = buildChargingProfilesLimit(chargingStation, chargingProfilesLimit)
       const connectorMaximumPower =
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         chargingStation.stationInfo!.maximumPower! / chargingStation.powerDivider!
       if (limit > connectorMaximumPower) {
         logger.error(
-          `${chargingStation.logPrefix()} ${moduleName}.getChargingStationConnectorChargingProfilesPowerLimit: Charging profile id ${
-            chargingProfile.chargingProfileId
-          } limit ${limit} is greater than connector id ${connectorId} maximum ${connectorMaximumPower}: %j`,
-          result
+          `${chargingStation.logPrefix()} ${moduleName}.getConnectorChargingProfilesLimit: Charging profile id ${chargingProfilesLimit.chargingProfile.chargingProfileId.toString()} limit ${limit.toString()} is greater than connector ${connectorId.toString()} maximum ${connectorMaximumPower.toString()}: %j`,
+          chargingProfilesLimit
         )
-        limit = connectorMaximumPower
+        return connectorMaximumPower
       }
+      return limit
     }
   }
-  return limit
+}
+
+const buildChargingProfilesLimit = (
+  chargingStation: ChargingStation,
+  chargingProfilesLimit: ChargingProfilesLimit
+): number => {
+  // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+  const errorMsg = `Unknown ${chargingStation.stationInfo?.currentOutType} currentOutType in charging station information, cannot build charging profiles limit`
+  const { chargingProfile, limit } = chargingProfilesLimit
+  switch (chargingStation.stationInfo?.currentOutType) {
+    case CurrentType.AC:
+      return chargingProfile.chargingSchedule.chargingRateUnit === ChargingRateUnitType.WATT
+        ? limit
+        : ACElectricUtils.powerTotal(
+          chargingStation.getNumberOfPhases(),
+          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+          chargingStation.stationInfo.voltageOut!,
+          limit
+        )
+    case CurrentType.DC:
+      return chargingProfile.chargingSchedule.chargingRateUnit === ChargingRateUnitType.WATT
+        ? limit
+        : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+        DCElectricUtils.power(chargingStation.stationInfo.voltageOut!, limit)
+    default:
+      logger.error(
+        `${chargingStation.logPrefix()} ${moduleName}.buildChargingProfilesLimit: ${errorMsg}`
+      )
+      throw new BaseError(errorMsg)
+  }
 }
 
 export const getDefaultVoltageOut = (
@@ -662,7 +852,7 @@ export const waitChargingStationEvents = async (
   event: ChargingStationWorkerMessageEvents,
   eventsToWait: number
 ): Promise<number> => {
-  return await new Promise<number>((resolve) => {
+  return await new Promise<number>(resolve => {
     let events = 0
     if (eventsToWait === 0) {
       resolve(events)
@@ -679,12 +869,12 @@ export const waitChargingStationEvents = async (
 
 const getConfiguredMaxNumberOfConnectors = (stationTemplate: ChargingStationTemplate): number => {
   let configuredMaxNumberOfConnectors = 0
-  if (isNotEmptyArray(stationTemplate.numberOfConnectors)) {
-    const numberOfConnectors = stationTemplate.numberOfConnectors as number[]
+  if (isNotEmptyArray<number>(stationTemplate.numberOfConnectors)) {
+    const numberOfConnectors = stationTemplate.numberOfConnectors
     configuredMaxNumberOfConnectors =
       numberOfConnectors[Math.floor(secureRandom() * numberOfConnectors.length)]
-  } else if (stationTemplate.numberOfConnectors != null) {
-    configuredMaxNumberOfConnectors = stationTemplate.numberOfConnectors as number
+  } else if (typeof stationTemplate.numberOfConnectors === 'number') {
+    configuredMaxNumberOfConnectors = stationTemplate.numberOfConnectors
   } else if (stationTemplate.Connectors != null && stationTemplate.Evses == null) {
     configuredMaxNumberOfConnectors =
       // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@@ -711,7 +901,7 @@ const checkConfiguredMaxConnectors = (
 ): void => {
   if (configuredMaxConnectors <= 0) {
     logger.warn(
-      `${logPrefix} Charging station information from template ${templateFile} with ${configuredMaxConnectors} connectors`
+      `${logPrefix} Charging station information from template ${templateFile} with ${configuredMaxConnectors.toString()} connectors`
     )
   }
 }
@@ -752,7 +942,7 @@ const warnDeprecatedTemplateKey = (
   templateFile: string,
   logMsgToAppend = ''
 ): void => {
-  if (template[key as keyof ChargingStationTemplate] !== undefined) {
+  if (template[key as keyof ChargingStationTemplate] != null) {
     const logMsg = `Deprecated template key '${key}' usage in file '${templateFile}'${
       isNotEmptyString(logMsgToAppend) ? `. ${logMsgToAppend}` : ''
     }`
@@ -766,9 +956,9 @@ const convertDeprecatedTemplateKey = (
   deprecatedKey: string,
   key?: string
 ): void => {
-  if (template[deprecatedKey as keyof ChargingStationTemplate] !== undefined) {
-    if (key !== undefined) {
-      (template as unknown as Record<string, unknown>)[key] =
+  if (template[deprecatedKey as keyof ChargingStationTemplate] != null) {
+    if (key != null) {
+      ;(template as unknown as Record<string, unknown>)[key] =
         template[deprecatedKey as keyof ChargingStationTemplate]
     }
     // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
@@ -777,65 +967,71 @@ const convertDeprecatedTemplateKey = (
 }
 
 interface ChargingProfilesLimit {
-  limit: number
   chargingProfile: ChargingProfile
+  limit: number
 }
 
 /**
- * Charging profiles shall already be sorted by connector id descending then stack level descending
- *
+ * Get the charging profiles limit for a connector
+ * Charging profiles shall already be sorted by priorities
  * @param chargingStation -
  * @param connectorId -
  * @param chargingProfiles -
- * @param logPrefix -
  * @returns ChargingProfilesLimit
  */
-const getLimitFromChargingProfiles = (
+const getChargingProfilesLimit = (
   chargingStation: ChargingStation,
   connectorId: number,
-  chargingProfiles: ChargingProfile[],
-  logPrefix: string
+  chargingProfiles: ChargingProfile[]
 ): ChargingProfilesLimit | undefined => {
-  const debugLogMsg = `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Matching charging profile found for power limitation: %j`
+  const debugLogMsg = `${chargingStation.logPrefix()} ${moduleName}.getChargingProfilesLimit: Charging profiles limit found: %j`
   const currentDate = new Date()
   const connectorStatus = chargingStation.getConnectorStatus(connectorId)
+  let previousActiveChargingProfile: ChargingProfile | undefined
   for (const chargingProfile of chargingProfiles) {
     const chargingSchedule = chargingProfile.chargingSchedule
     if (chargingSchedule.startSchedule == null) {
       logger.debug(
-        `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} has no startSchedule defined. Trying to set it to the connector current transaction start date`
+        `${chargingStation.logPrefix()} ${moduleName}.getChargingProfilesLimit: Charging profile id ${chargingProfile.chargingProfileId.toString()} 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 (!isDate(chargingSchedule.startSchedule)) {
       logger.warn(
-        `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} startSchedule property is not a Date instance. Trying to convert it to a Date instance`
+        `${chargingStation.logPrefix()} ${moduleName}.getChargingProfilesLimit: Charging profile id ${chargingProfile.chargingProfileId.toString()} startSchedule property is not a Date instance. Trying to convert it to a Date instance`
       )
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
       chargingSchedule.startSchedule = convertToDate(chargingSchedule.startSchedule)!
     }
     if (chargingSchedule.duration == null) {
       logger.debug(
-        `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} has no duration defined and will be set to the maximum time allowed`
+        `${chargingStation.logPrefix()} ${moduleName}.getChargingProfilesLimit: Charging profile id ${chargingProfile.chargingProfileId.toString()} 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
       chargingSchedule.duration = differenceInSeconds(maxTime, chargingSchedule.startSchedule)
     }
-    if (!prepareChargingProfileKind(connectorStatus, chargingProfile, currentDate, logPrefix)) {
+    if (
+      !prepareChargingProfileKind(
+        connectorStatus,
+        chargingProfile,
+        currentDate,
+        chargingStation.logPrefix()
+      )
+    ) {
       continue
     }
-    if (!canProceedChargingProfile(chargingProfile, currentDate, logPrefix)) {
+    if (!canProceedChargingProfile(chargingProfile, currentDate, chargingStation.logPrefix())) {
       continue
     }
     // Check if the charging profile is active
     if (
       isWithinInterval(currentDate, {
+        end: addSeconds(chargingSchedule.startSchedule, chargingSchedule.duration),
         start: chargingSchedule.startSchedule,
-        end: addSeconds(chargingSchedule.startSchedule, chargingSchedule.duration)
       })
     ) {
-      if (isNotEmptyArray(chargingSchedule.chargingSchedulePeriod)) {
+      if (isNotEmptyArray<ChargingSchedulePeriod>(chargingSchedule.chargingSchedulePeriod)) {
         const chargingSchedulePeriodCompareFn = (
           a: ChargingSchedulePeriod,
           b: ChargingSchedulePeriod
@@ -847,31 +1043,31 @@ const getLimitFromChargingProfiles = (
           )
         ) {
           logger.warn(
-            `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} schedule periods are not sorted by start period`
+            `${chargingStation.logPrefix()} ${moduleName}.getChargingProfilesLimit: Charging profile id ${chargingProfile.chargingProfileId.toString()} schedule periods are not sorted by start period`
           )
           chargingSchedule.chargingSchedulePeriod.sort(chargingSchedulePeriodCompareFn)
         }
         // Check if the first schedule period startPeriod property is equal to 0
         if (chargingSchedule.chargingSchedulePeriod[0].startPeriod !== 0) {
           logger.error(
-            `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} first schedule period start period ${chargingSchedule.chargingSchedulePeriod[0].startPeriod} is not equal to 0`
+            `${chargingStation.logPrefix()} ${moduleName}.getChargingProfilesLimit: Charging profile id ${chargingProfile.chargingProfileId.toString()} first schedule period start period ${chargingSchedule.chargingSchedulePeriod[0].startPeriod.toString()} is not equal to 0`
           )
           continue
         }
         // Handle only one schedule period
         if (chargingSchedule.chargingSchedulePeriod.length === 1) {
-          const result: ChargingProfilesLimit = {
+          const chargingProfilesLimit: ChargingProfilesLimit = {
+            chargingProfile,
             limit: chargingSchedule.chargingSchedulePeriod[0].limit,
-            chargingProfile
           }
-          logger.debug(debugLogMsg, result)
-          return result
+          logger.debug(debugLogMsg, chargingProfilesLimit)
+          return chargingProfilesLimit
         }
         let previousChargingSchedulePeriod: ChargingSchedulePeriod | undefined
         // Search for the right schedule period
         for (const [
           index,
-          chargingSchedulePeriod
+          chargingSchedulePeriod,
         ] of chargingSchedule.chargingSchedulePeriod.entries()) {
           // Find the right schedule period
           if (
@@ -881,16 +1077,13 @@ const getLimitFromChargingProfiles = (
             )
           ) {
             // Found the schedule period: previous is the correct one
-            const result: ChargingProfilesLimit = {
-              // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-              limit: previousChargingSchedulePeriod!.limit,
-              chargingProfile
+            const chargingProfilesLimit: ChargingProfilesLimit = {
+              chargingProfile: previousActiveChargingProfile ?? chargingProfile,
+              limit: previousChargingSchedulePeriod?.limit ?? chargingSchedulePeriod.limit,
             }
-            logger.debug(debugLogMsg, result)
-            return result
+            logger.debug(debugLogMsg, chargingProfilesLimit)
+            return chargingProfilesLimit
           }
-          // Keep a reference to previous one
-          previousChargingSchedulePeriod = chargingSchedulePeriod
           // Handle the last schedule period within the charging profile duration
           if (
             index === chargingSchedule.chargingSchedulePeriod.length - 1 ||
@@ -903,15 +1096,19 @@ const getLimitFromChargingProfiles = (
                 chargingSchedule.startSchedule
               ) > chargingSchedule.duration)
           ) {
-            const result: ChargingProfilesLimit = {
-              limit: previousChargingSchedulePeriod.limit,
-              chargingProfile
+            const chargingProfilesLimit: ChargingProfilesLimit = {
+              chargingProfile,
+              limit: chargingSchedulePeriod.limit,
             }
-            logger.debug(debugLogMsg, result)
-            return result
+            logger.debug(debugLogMsg, chargingProfilesLimit)
+            return chargingProfilesLimit
           }
+          // Keep a reference to previous charging schedule period
+          previousChargingSchedulePeriod = chargingSchedulePeriod
         }
       }
+      // Keep a reference to previous active charging profile
+      previousActiveChargingProfile = chargingProfile
     }
   }
 }
@@ -919,7 +1116,7 @@ const getLimitFromChargingProfiles = (
 export const prepareChargingProfileKind = (
   connectorStatus: ConnectorStatus | undefined,
   chargingProfile: ChargingProfile,
-  currentDate: string | number | Date,
+  currentDate: Date | number | string,
   logPrefix: string
 ): boolean => {
   switch (chargingProfile.chargingProfileKind) {
@@ -932,14 +1129,14 @@ export const prepareChargingProfileKind = (
     case ChargingProfileKindType.RELATIVE:
       if (chargingProfile.chargingSchedule.startSchedule != null) {
         logger.warn(
-          `${logPrefix} ${moduleName}.prepareChargingProfileKind: Relative charging profile id ${chargingProfile.chargingProfileId} has a startSchedule property defined. It will be ignored or used if the connector has a transaction started`
+          `${logPrefix} ${moduleName}.prepareChargingProfileKind: Relative charging profile id ${chargingProfile.chargingProfileId.toString()} has a startSchedule property defined. It will be ignored or used if the connector has a transaction started`
         )
         delete chargingProfile.chargingSchedule.startSchedule
       }
       if (connectorStatus?.transactionStarted === true) {
         chargingProfile.chargingSchedule.startSchedule = connectorStatus.transactionStart
       }
-      // FIXME: Handle relative charging profile duration
+      // FIXME: handle relative charging profile duration
       break
   }
   return true
@@ -947,20 +1144,16 @@ export const prepareChargingProfileKind = (
 
 export const canProceedChargingProfile = (
   chargingProfile: ChargingProfile,
-  currentDate: string | number | Date,
+  currentDate: Date | number | string,
   logPrefix: string
 ): boolean => {
   if (
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    (isValidTime(chargingProfile.validFrom) && isBefore(currentDate, chargingProfile.validFrom!)) ||
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    (isValidTime(chargingProfile.validTo) && isAfter(currentDate, chargingProfile.validTo!))
+    (isValidDate(chargingProfile.validFrom) && isBefore(currentDate, chargingProfile.validFrom)) ||
+    (isValidDate(chargingProfile.validTo) && isAfter(currentDate, chargingProfile.validTo))
   ) {
     logger.debug(
-      `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${
-        chargingProfile.chargingProfileId
-      } is not valid for the current date ${
-        currentDate instanceof Date ? currentDate.toISOString() : currentDate
+      `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId.toString()} is not valid for the current date ${
+        isDate(currentDate) ? currentDate.toISOString() : currentDate.toString()
       }`
     )
     return false
@@ -970,19 +1163,19 @@ export const canProceedChargingProfile = (
     chargingProfile.chargingSchedule.duration == null
   ) {
     logger.error(
-      `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId} has no startSchedule or duration defined`
+      `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId.toString()} has no startSchedule or duration defined`
     )
     return false
   }
-  if (!isValidTime(chargingProfile.chargingSchedule.startSchedule)) {
+  if (!isValidDate(chargingProfile.chargingSchedule.startSchedule)) {
     logger.error(
-      `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId} has an invalid startSchedule date defined`
+      `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId.toString()} has an invalid startSchedule date defined`
     )
     return false
   }
   if (!Number.isSafeInteger(chargingProfile.chargingSchedule.duration)) {
     logger.error(
-      `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId} has non integer duration defined`
+      `${logPrefix} ${moduleName}.canProceedChargingProfile: Charging profile id ${chargingProfile.chargingProfileId.toString()} has non integer duration defined`
     )
     return false
   }
@@ -998,7 +1191,7 @@ const canProceedRecurringChargingProfile = (
     chargingProfile.recurrencyKind == null
   ) {
     logger.error(
-      `${logPrefix} ${moduleName}.canProceedRecurringChargingProfile: Recurring charging profile id ${chargingProfile.chargingProfileId} has no recurrencyKind defined`
+      `${logPrefix} ${moduleName}.canProceedRecurringChargingProfile: Recurring charging profile id ${chargingProfile.chargingProfileId.toString()} has no recurrencyKind defined`
     )
     return false
   }
@@ -1007,7 +1200,7 @@ const canProceedRecurringChargingProfile = (
     chargingProfile.chargingSchedule.startSchedule == null
   ) {
     logger.error(
-      `${logPrefix} ${moduleName}.canProceedRecurringChargingProfile: Recurring charging profile id ${chargingProfile.chargingProfileId} has no startSchedule defined`
+      `${logPrefix} ${moduleName}.canProceedRecurringChargingProfile: Recurring charging profile id ${chargingProfile.chargingProfileId.toString()} has no startSchedule defined`
     )
     return false
   }
@@ -1016,26 +1209,26 @@ const canProceedRecurringChargingProfile = (
 
 /**
  * Adjust recurring charging profile startSchedule to the current recurrency time interval if needed
- *
  * @param chargingProfile -
  * @param currentDate -
  * @param logPrefix -
+ * @returns boolean
  */
 const prepareRecurringChargingProfile = (
   chargingProfile: ChargingProfile,
-  currentDate: string | number | Date,
+  currentDate: Date | number | string,
   logPrefix: string
 ): boolean => {
   const chargingSchedule = chargingProfile.chargingSchedule
   let recurringIntervalTranslated = false
-  let recurringInterval: Interval
+  let recurringInterval: Interval | undefined
   switch (chargingProfile.recurrencyKind) {
     case RecurrencyKindType.DAILY:
       recurringInterval = {
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        start: chargingSchedule.startSchedule!,
+        end: addDays(chargingSchedule.startSchedule!, 1),
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        end: addDays(chargingSchedule.startSchedule!, 1)
+        start: chargingSchedule.startSchedule!,
       }
       checkRecurringChargingProfileDuration(chargingProfile, recurringInterval, logPrefix)
       if (
@@ -1047,8 +1240,8 @@ const prepareRecurringChargingProfile = (
           differenceInDays(currentDate, recurringInterval.start)
         )
         recurringInterval = {
+          end: addDays(chargingSchedule.startSchedule, 1),
           start: chargingSchedule.startSchedule,
-          end: addDays(chargingSchedule.startSchedule, 1)
         }
         recurringIntervalTranslated = true
       }
@@ -1056,9 +1249,9 @@ const prepareRecurringChargingProfile = (
     case RecurrencyKindType.WEEKLY:
       recurringInterval = {
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        start: chargingSchedule.startSchedule!,
+        end: addWeeks(chargingSchedule.startSchedule!, 1),
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        end: addWeeks(chargingSchedule.startSchedule!, 1)
+        start: chargingSchedule.startSchedule!,
       }
       checkRecurringChargingProfileDuration(chargingProfile, recurringInterval, logPrefix)
       if (
@@ -1070,30 +1263,30 @@ const prepareRecurringChargingProfile = (
           differenceInWeeks(currentDate, recurringInterval.start)
         )
         recurringInterval = {
+          end: addWeeks(chargingSchedule.startSchedule, 1),
           start: chargingSchedule.startSchedule,
-          end: addWeeks(chargingSchedule.startSchedule, 1)
         }
         recurringIntervalTranslated = true
       }
       break
     default:
       logger.error(
-        `${logPrefix} ${moduleName}.prepareRecurringChargingProfile: Recurring ${chargingProfile.recurrencyKind} charging profile id ${chargingProfile.chargingProfileId} is not supported`
+        // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+        `${logPrefix} ${moduleName}.prepareRecurringChargingProfile: Recurring ${chargingProfile.recurrencyKind} charging profile id ${chargingProfile.chargingProfileId.toString()} is not supported`
       )
   }
   // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
   if (recurringIntervalTranslated && !isWithinInterval(currentDate, recurringInterval!)) {
     logger.error(
       `${logPrefix} ${moduleName}.prepareRecurringChargingProfile: Recurring ${
+        // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
         chargingProfile.recurrencyKind
-      } charging profile id ${chargingProfile.chargingProfileId} recurrency time interval [${toDate(
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        recurringInterval!.start
+      } charging profile id ${chargingProfile.chargingProfileId.toString()} recurrency time interval [${toDate(
+        recurringInterval?.start as Date
       ).toISOString()}, ${toDate(
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        recurringInterval!.end
+        recurringInterval?.end as Date
       ).toISOString()}] has not been properly translated to current date ${
-        currentDate instanceof Date ? currentDate.toISOString() : currentDate
+        isDate(currentDate) ? currentDate.toISOString() : currentDate.toString()
       } `
     )
   }
@@ -1109,12 +1302,10 @@ const checkRecurringChargingProfileDuration = (
     logger.warn(
       `${logPrefix} ${moduleName}.checkRecurringChargingProfileDuration: Recurring ${
         chargingProfile.chargingProfileKind
-      } charging profile id ${
-        chargingProfile.chargingProfileId
-      } duration is not defined, set it to the recurrency time interval duration ${differenceInSeconds(
+      } charging profile id ${chargingProfile.chargingProfileId.toString()} duration is not defined, set it to the recurrency time interval duration ${differenceInSeconds(
         interval.end,
         interval.start
-      )}`
+      ).toString()}`
     )
     chargingProfile.chargingSchedule.duration = differenceInSeconds(interval.end, interval.start)
   } else if (
@@ -1123,12 +1314,10 @@ const checkRecurringChargingProfileDuration = (
     logger.warn(
       `${logPrefix} ${moduleName}.checkRecurringChargingProfileDuration: Recurring ${
         chargingProfile.chargingProfileKind
-      } charging profile id ${chargingProfile.chargingProfileId} duration ${
-        chargingProfile.chargingSchedule.duration
-      } is greater than the recurrency time interval duration ${differenceInSeconds(
+      } charging profile id ${chargingProfile.chargingProfileId.toString()} duration ${chargingProfile.chargingSchedule.duration.toString()} is greater than the recurrency time interval duration ${differenceInSeconds(
         interval.end,
         interval.start
-      )}`
+      ).toString()}`
     )
     chargingProfile.chargingSchedule.duration = differenceInSeconds(interval.end, interval.start)
   }
@@ -1139,7 +1328,7 @@ const getRandomSerialNumberSuffix = (params?: {
   upperCase?: boolean
 }): string => {
   const randomSerialNumberSuffix = randomBytes(params?.randomBytesLength ?? 16).toString('hex')
-  if (params?.upperCase === true) {
+  if (params?.upperCase) {
     return randomSerialNumberSuffix.toUpperCase()
   }
   return randomSerialNumberSuffix