+ delete template[deprecatedKey as keyof ChargingStationTemplate];
+ }
+};
+
+/**
+ * Charging profiles should already be sorted by connector id and stack level (highest stack level has priority)
+ *
+ * @param chargingProfiles -
+ * @param logPrefix -
+ * @returns
+ */
+const getLimitFromChargingProfiles = (
+ chargingProfiles: ChargingProfile[],
+ logPrefix: string,
+):
+ | {
+ limit: number;
+ matchingChargingProfile: ChargingProfile;
+ }
+ | undefined => {
+ const debugLogMsg = `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Matching charging profile found for power limitation: %j`;
+ const currentDate = new Date();
+ for (const chargingProfile of chargingProfiles) {
+ // Set helpers
+ const chargingSchedule = chargingProfile.chargingSchedule;
+ if (!chargingSchedule?.startSchedule) {
+ logger.warn(
+ `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: startSchedule is not defined in charging profile id ${chargingProfile.chargingProfileId}`,
+ );
+ }
+ if (!(chargingSchedule?.startSchedule instanceof Date)) {
+ logger.warn(
+ `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: startSchedule is not a Date object in charging profile id ${chargingProfile.chargingProfileId}. Trying to convert it to a Date object`,
+ );
+ chargingSchedule.startSchedule = convertToDate(chargingSchedule.startSchedule)!;
+ }
+ // Adjust recurring start schedule
+ if (chargingProfile.chargingProfileKind === ChargingProfileKindType.RECURRING) {
+ switch (chargingProfile.recurrencyKind) {
+ case RecurrencyKindType.DAILY:
+ if (isYesterday(chargingSchedule.startSchedule)) {
+ addDays(chargingSchedule.startSchedule, 1);
+ }
+ break;
+ case RecurrencyKindType.WEEKLY:
+ if (isBefore(chargingSchedule.startSchedule, startOfWeek(currentDate))) {
+ addWeeks(chargingSchedule.startSchedule, 1);
+ }
+ break;
+ }
+ }
+ // Check if the charging profile is active
+ if (
+ isAfter(addSeconds(chargingSchedule.startSchedule, chargingSchedule.duration!), currentDate)
+ ) {
+ let lastButOneSchedule: ChargingSchedulePeriod | undefined;
+ // Search the right schedule period
+ for (const schedulePeriod of chargingSchedule.chargingSchedulePeriod) {
+ // Handling of only one period
+ if (
+ chargingSchedule.chargingSchedulePeriod.length === 1 &&
+ schedulePeriod.startPeriod === 0
+ ) {
+ const result = {
+ limit: schedulePeriod.limit,
+ matchingChargingProfile: chargingProfile,
+ };
+ logger.debug(debugLogMsg, result);
+ return result;
+ }
+ // Find the right schedule period
+ if (
+ isAfter(
+ addSeconds(chargingSchedule.startSchedule, schedulePeriod.startPeriod),
+ currentDate,
+ )
+ ) {
+ // Found the schedule: last but one is the correct one
+ const result = {
+ limit: lastButOneSchedule!.limit,
+ matchingChargingProfile: chargingProfile,
+ };
+ logger.debug(debugLogMsg, result);
+ return result;
+ }
+ // Keep it
+ lastButOneSchedule = schedulePeriod;
+ // Handle the last schedule period
+ if (
+ schedulePeriod.startPeriod ===
+ chargingSchedule.chargingSchedulePeriod[
+ chargingSchedule.chargingSchedulePeriod.length - 1
+ ].startPeriod
+ ) {
+ const result = {
+ limit: lastButOneSchedule.limit,
+ matchingChargingProfile: chargingProfile,
+ };
+ logger.debug(debugLogMsg, result);
+ return result;
+ }
+ }
+ }
+ }
+};
+
+const getRandomSerialNumberSuffix = (params?: {
+ randomBytesLength?: number;
+ upperCase?: boolean;
+}): string => {
+ const randomSerialNumberSuffix = randomBytes(params?.randomBytesLength ?? 16).toString('hex');
+ if (params?.upperCase) {
+ return randomSerialNumberSuffix.toUpperCase();