UNPKG

@citrineos/util

Version:

The OCPP util module which supplies helpful utilities like cache and queue connectors, etc.

131 lines 7.83 kB
"use strict"; // Copyright Contributors to the CitrineOS Project // // SPDX-License-Identifier: Apache 2.0 var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateLanguageTag = validateLanguageTag; exports.validateChargingProfileType = validateChargingProfileType; const base_1 = require("@citrineos/base"); const parser_1 = require("./parser"); /** * Validate a language tag is an RFC-5646 tag, see: {@link https://tools.ietf.org/html/rfc5646}, * example: US English is: "en-US" * * @param languageTag * @returns {boolean} true if the languageTag is an RFC-5646 tag */ function validateLanguageTag(languageTag) { return /^((?:(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?:([A-Za-z]{2,3}(-(?:[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-(?:[A-Za-z]{4}))?(-(?:[A-Za-z]{2}|[0-9]{3}))?(-(?:[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-(?:[0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*(-(?:x(-[A-Za-z0-9]{1,8})+))?)|(?:x(-[A-Za-z0-9]{1,8})+))$/.test(languageTag); } /** * Validate constraints of ChargingProfileType defined in OCPP 2.0.1 * * @param chargingProfileType ChargingProfileType from the request * @param stationId station id * @param deviceModelRepository deviceModelRepository * @param chargingProfileRepository chargingProfileRepository * @param transactionEventRepository transactionEventRepository * @param logger logger * @param evseId evse id */ function validateChargingProfileType(chargingProfileType, stationId, deviceModelRepository, chargingProfileRepository, transactionEventRepository, logger, evseId) { return __awaiter(this, void 0, void 0, function* () { if (chargingProfileType.stackLevel < 0) { throw new Error('Lowest Stack level is 0'); } if (chargingProfileType.chargingProfilePurpose === base_1.OCPP2_0_1.ChargingProfilePurposeEnumType.ChargingStationMaxProfile && evseId !== 0) { throw new Error('When chargingProfilePurpose is ChargingStationMaxProfile, evseId SHALL be 0'); } if (chargingProfileType.chargingProfilePurpose !== base_1.OCPP2_0_1.ChargingProfilePurposeEnumType.TxProfile && chargingProfileType.transactionId) { throw new Error('transactionId SHALL only be included when ChargingProfilePurpose is set to TxProfile.'); } let receivedChargingNeeds; if (chargingProfileType.transactionId && evseId) { const transaction = yield transactionEventRepository.readTransactionByStationIdAndTransactionId(stationId, chargingProfileType.transactionId); if (!transaction) { throw new Error(`Transaction ${chargingProfileType.transactionId} not found on station ${stationId}.`); } const evse = yield deviceModelRepository.findEvseByIdAndConnectorId(evseId, null); if (!evse) { throw new Error(`Evse ${evseId} not found.`); } logger.info(`Found evse: ${JSON.stringify(evse)}`); receivedChargingNeeds = yield chargingProfileRepository.findChargingNeedsByEvseDBIdAndTransactionDBId(evse.databaseId, transaction.id); logger.info(`Found ChargingNeeds: ${JSON.stringify(receivedChargingNeeds)}`); } const periodsPerSchedules = yield deviceModelRepository.readAllByQuerystring({ stationId: stationId, component_name: 'SmartChargingCtrlr', variable_name: 'PeriodsPerSchedule', type: base_1.OCPP2_0_1.AttributeEnumType.Actual, }); logger.info(`Found PeriodsPerSchedule: ${JSON.stringify(periodsPerSchedules)}`); let periodsPerSchedule; if (periodsPerSchedules.length > 0 && periodsPerSchedules[0].value) { periodsPerSchedule = Number(periodsPerSchedules[0].value); } for (const chargingSchedule of chargingProfileType.chargingSchedule) { if (chargingSchedule.minChargingRate && (0, parser_1.getNumberOfFractionDigit)(chargingSchedule.minChargingRate) > 1) { throw new Error(`chargingSchedule ${chargingSchedule.id}: minChargingRate accepts at most one digit fraction (e.g. 8.1).`); } if (periodsPerSchedule && chargingSchedule.chargingSchedulePeriod.length > periodsPerSchedule) { throw new Error(`ChargingSchedule ${chargingSchedule.id}: The number of chargingSchedulePeriod SHALL not exceed ${periodsPerSchedule}.`); } for (const chargingSchedulePeriod of chargingSchedule.chargingSchedulePeriod) { if ((0, parser_1.getNumberOfFractionDigit)(chargingSchedulePeriod.limit) > 1) { throw new Error(`ChargingSchedule ${chargingSchedule.id}: chargingSchedulePeriod limit accepts at most one digit fraction (e.g. 8.1).`); } if (receivedChargingNeeds) { if (receivedChargingNeeds.acChargingParameters) { // EV AC charging if (!chargingSchedulePeriod.numberPhases) { chargingSchedulePeriod.numberPhases = 3; } } else if (receivedChargingNeeds.dcChargingParameters) { // EV DC charging chargingSchedulePeriod.numberPhases = undefined; } } } if (chargingSchedule.salesTariff) { if (receivedChargingNeeds && receivedChargingNeeds.maxScheduleTuples && chargingSchedule.salesTariff.salesTariffEntry.length > receivedChargingNeeds.maxScheduleTuples) { throw new Error(`ChargingSchedule ${chargingSchedule.id}: The number of SalesTariffEntry elements (${chargingSchedule.salesTariff.salesTariffEntry.length}) SHALL not exceed maxScheduleTuples (${receivedChargingNeeds.maxScheduleTuples}).`); } for (const salesTariffEntry of chargingSchedule.salesTariff.salesTariffEntry) { if (salesTariffEntry.consumptionCost) { for (const consumptionCost of salesTariffEntry.consumptionCost) { if (consumptionCost.cost) { for (const cost of consumptionCost.cost) { if (cost.amountMultiplier && (cost.amountMultiplier > 3 || cost.amountMultiplier < -3)) { throw new Error(`ChargingSchedule ${chargingSchedule.id}: amountMultiplier SHALL be in [-3, 3].`); } } } } } } } } }); } //# sourceMappingURL=validator.js.map