@citrineos/util
Version:
The OCPP util module which supplies helpful utilities like cache and queue connectors, etc.
131 lines • 7.83 kB
JavaScript
;
// 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