@open-charging-cloud/chargy-core 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -10
- package/dist/Alfen.d.ts.map +1 -1
- package/dist/OCMF.d.ts +15 -2
- package/dist/OCMF.d.ts.map +1 -1
- package/dist/OCMF_BET_TariffTextExtension.d.ts +33 -0
- package/dist/OCMF_BET_TariffTextExtension.d.ts.map +1 -0
- package/dist/PTBContainer.d.ts +49 -0
- package/dist/PTBContainer.d.ts.map +1 -0
- package/dist/browser/index.js +410 -22
- package/dist/browser/index.js.map +1 -1
- package/dist/chargy.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/interfaces/chargyInterfaces.d.ts +17 -14
- package/dist/interfaces/chargyInterfaces.d.ts.map +1 -1
- package/dist/node/index.js +410 -22
- package/dist/node/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/verificationResults.d.ts +0 -2
- package/dist/verificationResults.d.ts.map +0 -1
package/dist/browser/index.js
CHANGED
|
@@ -11057,8 +11057,7 @@ var Alfen = class {
|
|
|
11057
11057
|
"connectors": [{
|
|
11058
11058
|
"type": asString(connector?.["type"]) ?? "",
|
|
11059
11059
|
"cable": {
|
|
11060
|
-
"length": asNumber(connector?.["cableLength"]) ?? 0
|
|
11061
|
-
"looses": asNumber(connector?.["cableLooses"]) ?? 0
|
|
11060
|
+
"length": asNumber(connector?.["cableLength"]) ?? 0
|
|
11062
11061
|
}
|
|
11063
11062
|
}],
|
|
11064
11063
|
"energyMeters": [
|
|
@@ -14653,6 +14652,132 @@ function numberToBytesBE(value, length) {
|
|
|
14653
14652
|
}
|
|
14654
14653
|
return bytes;
|
|
14655
14654
|
}
|
|
14655
|
+
var OCMFBonnTariffParseError = class extends Error {
|
|
14656
|
+
tariffText;
|
|
14657
|
+
constructor(tariffText, message) {
|
|
14658
|
+
super(message);
|
|
14659
|
+
this.name = "OCMFBonnTariffParseError";
|
|
14660
|
+
this.tariffText = tariffText;
|
|
14661
|
+
}
|
|
14662
|
+
};
|
|
14663
|
+
function parseCents(value, tariffText, fieldName) {
|
|
14664
|
+
if (!/^(?:0|[1-9][0-9]*)(?:\.[0-9]+)?$/.test(value))
|
|
14665
|
+
throw new OCMFBonnTariffParseError(tariffText, `${fieldName} must be a non-negative decimal number`);
|
|
14666
|
+
const parsedValue = Number(value);
|
|
14667
|
+
if (!Number.isFinite(parsedValue))
|
|
14668
|
+
throw new OCMFBonnTariffParseError(tariffText, `${fieldName} is outside the supported numeric range`);
|
|
14669
|
+
return parsedValue;
|
|
14670
|
+
}
|
|
14671
|
+
function parseOCMFBonnTariffText(tariffText) {
|
|
14672
|
+
const fields = tariffText.split(";");
|
|
14673
|
+
const code = fields[0];
|
|
14674
|
+
if (fields[1] !== "EUR")
|
|
14675
|
+
throw new OCMFBonnTariffParseError(tariffText, "currency must be EUR");
|
|
14676
|
+
switch (code) {
|
|
14677
|
+
case "001":
|
|
14678
|
+
if (fields.length !== 6)
|
|
14679
|
+
throw new OCMFBonnTariffParseError(tariffText, "profile 001 must contain six fields");
|
|
14680
|
+
return {
|
|
14681
|
+
raw: tariffText,
|
|
14682
|
+
code,
|
|
14683
|
+
currency: "EUR",
|
|
14684
|
+
startFeeCents: parseCents(fields[2] ?? "", tariffText, "W"),
|
|
14685
|
+
energyFeeCentsPerKWh: parseCents(fields[3] ?? "", tariffText, "X"),
|
|
14686
|
+
blockingFeeCentsPerMinute: parseCents(fields[4] ?? "", tariffText, "Y"),
|
|
14687
|
+
blockingFeeStartMinute: parseCents(fields[5] ?? "", tariffText, "Z")
|
|
14688
|
+
};
|
|
14689
|
+
case "002":
|
|
14690
|
+
if (fields.length !== 5)
|
|
14691
|
+
throw new OCMFBonnTariffParseError(tariffText, "profile 002 must contain five fields");
|
|
14692
|
+
return {
|
|
14693
|
+
raw: tariffText,
|
|
14694
|
+
code,
|
|
14695
|
+
currency: "EUR",
|
|
14696
|
+
startFeeCents: parseCents(fields[2] ?? "", tariffText, "W"),
|
|
14697
|
+
energyFeeCentsPerKWh: parseCents(fields[3] ?? "", tariffText, "X"),
|
|
14698
|
+
blockingFeeCentsPerMinute: parseCents(fields[4] ?? "", tariffText, "Y"),
|
|
14699
|
+
blockingFeeStartsAfterCharging: true
|
|
14700
|
+
};
|
|
14701
|
+
case "003":
|
|
14702
|
+
if (fields.length !== 4)
|
|
14703
|
+
throw new OCMFBonnTariffParseError(tariffText, "profile 003 must contain four fields");
|
|
14704
|
+
return {
|
|
14705
|
+
raw: tariffText,
|
|
14706
|
+
code,
|
|
14707
|
+
currency: "EUR",
|
|
14708
|
+
startFeeCents: parseCents(fields[2] ?? "", tariffText, "W"),
|
|
14709
|
+
timeFeeCentsPerMinute: parseCents(fields[3] ?? "", tariffText, "X")
|
|
14710
|
+
};
|
|
14711
|
+
default:
|
|
14712
|
+
throw new OCMFBonnTariffParseError(tariffText, "unknown Bonn tariff profile");
|
|
14713
|
+
}
|
|
14714
|
+
}
|
|
14715
|
+
function tryParseOCMFBonnTariffText(tariffText) {
|
|
14716
|
+
try {
|
|
14717
|
+
return parseOCMFBonnTariffText(tariffText);
|
|
14718
|
+
} catch (error) {
|
|
14719
|
+
if (error instanceof OCMFBonnTariffParseError)
|
|
14720
|
+
return void 0;
|
|
14721
|
+
throw error;
|
|
14722
|
+
}
|
|
14723
|
+
}
|
|
14724
|
+
function priceComponent(type, price, stepSize) {
|
|
14725
|
+
return {
|
|
14726
|
+
type,
|
|
14727
|
+
price,
|
|
14728
|
+
step_size: stepSize
|
|
14729
|
+
};
|
|
14730
|
+
}
|
|
14731
|
+
function eurosFromCents(cents) {
|
|
14732
|
+
return new Decimal(cents).dividedBy(100);
|
|
14733
|
+
}
|
|
14734
|
+
function eurosPerHourFromCentsPerMinute(cents) {
|
|
14735
|
+
return eurosFromCents(cents).times(60);
|
|
14736
|
+
}
|
|
14737
|
+
function ocmfBonnTariffToChargingTariff(tariff) {
|
|
14738
|
+
const baseComponents = new Array(
|
|
14739
|
+
priceComponent("FLAT", eurosFromCents(tariff.startFeeCents), 1)
|
|
14740
|
+
);
|
|
14741
|
+
const elements = new Array();
|
|
14742
|
+
switch (tariff.code) {
|
|
14743
|
+
case "001":
|
|
14744
|
+
baseComponents.push(priceComponent("ENERGY", eurosFromCents(tariff.energyFeeCentsPerKWh), 1));
|
|
14745
|
+
elements.push(
|
|
14746
|
+
{ price_components: baseComponents },
|
|
14747
|
+
{
|
|
14748
|
+
price_components: [
|
|
14749
|
+
priceComponent("PARKING_TIME", eurosPerHourFromCentsPerMinute(tariff.blockingFeeCentsPerMinute), 60)
|
|
14750
|
+
],
|
|
14751
|
+
restrictions: {
|
|
14752
|
+
min_duration: tariff.blockingFeeStartMinute * 60
|
|
14753
|
+
}
|
|
14754
|
+
}
|
|
14755
|
+
);
|
|
14756
|
+
break;
|
|
14757
|
+
case "002":
|
|
14758
|
+
baseComponents.push(priceComponent("ENERGY", eurosFromCents(tariff.energyFeeCentsPerKWh), 1));
|
|
14759
|
+
elements.push(
|
|
14760
|
+
{ price_components: baseComponents },
|
|
14761
|
+
{
|
|
14762
|
+
price_components: [
|
|
14763
|
+
priceComponent("PARKING_TIME", eurosPerHourFromCentsPerMinute(tariff.blockingFeeCentsPerMinute), 60)
|
|
14764
|
+
]
|
|
14765
|
+
}
|
|
14766
|
+
);
|
|
14767
|
+
break;
|
|
14768
|
+
case "003":
|
|
14769
|
+
baseComponents.push(priceComponent("TIME", eurosPerHourFromCentsPerMinute(tariff.timeFeeCentsPerMinute), 60));
|
|
14770
|
+
elements.push({ price_components: baseComponents });
|
|
14771
|
+
break;
|
|
14772
|
+
}
|
|
14773
|
+
return {
|
|
14774
|
+
"@id": tariff.raw,
|
|
14775
|
+
currency: tariff.currency,
|
|
14776
|
+
elements
|
|
14777
|
+
};
|
|
14778
|
+
}
|
|
14779
|
+
|
|
14780
|
+
// src/OCMF.ts
|
|
14656
14781
|
var OCMFv1_x = class extends ACrypt {
|
|
14657
14782
|
curve = new this.chargy.elliptic.ec("p256");
|
|
14658
14783
|
constructor(chargy) {
|
|
@@ -14742,6 +14867,8 @@ var OCMFv1_x = class extends ACrypt {
|
|
|
14742
14867
|
return "Reading Current Type";
|
|
14743
14868
|
case "CL":
|
|
14744
14869
|
return "Cumulated Loss";
|
|
14870
|
+
case "EI":
|
|
14871
|
+
return "Error Index";
|
|
14745
14872
|
case "EF":
|
|
14746
14873
|
return "Error Flags";
|
|
14747
14874
|
case "ST":
|
|
@@ -14949,10 +15076,39 @@ var OCMF = class {
|
|
|
14949
15076
|
const identificationType = firstOCMDJSONDocument.payload.IT;
|
|
14950
15077
|
const identificationData = firstOCMDJSONDocument.payload.ID;
|
|
14951
15078
|
const tariffText = firstOCMDJSONDocument.payload.TT;
|
|
14952
|
-
const
|
|
15079
|
+
const tariffTextInterpretation = typeof tariffText === "string" ? tryParseOCMFBonnTariffText(tariffText) : void 0;
|
|
15080
|
+
const chargingTariff = typeof tariffText === "string" && tariffText.length > 0 ? tariffTextInterpretation !== void 0 ? ocmfBonnTariffToChargingTariff(tariffTextInterpretation) : { "@id": tariffText } : void 0;
|
|
15081
|
+
const controllerFirmwareVersion = firstOCMDJSONDocument.payload.CF;
|
|
14953
15082
|
const lossCompensation = firstOCMDJSONDocument.payload.LC;
|
|
15083
|
+
const signedCable = lossCompensation !== void 0 && typeof lossCompensation.LR === "number" && Number.isFinite(lossCompensation.LR) && typeof lossCompensation.LU === "string" && lossCompensation.LU.length > 0 ? {
|
|
15084
|
+
...typeof lossCompensation.LN === "string" ? { lossCompensation: lossCompensation.LN } : {},
|
|
15085
|
+
...typeof lossCompensation.LI === "number" ? { lossCompensationId: lossCompensation.LI.toString() } : {},
|
|
15086
|
+
resistance: lossCompensation.LR,
|
|
15087
|
+
resistanceUnit: lossCompensation.LU
|
|
15088
|
+
} : void 0;
|
|
14954
15089
|
const chargePointIdType = firstOCMDJSONDocument.payload.CT;
|
|
14955
15090
|
const chargePointId = firstOCMDJSONDocument.payload.CI;
|
|
15091
|
+
let signedChargingStationId;
|
|
15092
|
+
let signedEVSEId;
|
|
15093
|
+
let signedConnectorId;
|
|
15094
|
+
if (typeof chargePointId === "string" && chargePointId.trim().length > 0) {
|
|
15095
|
+
const normalizedChargePointId = chargePointId.trim();
|
|
15096
|
+
switch (chargePointIdType?.toUpperCase()) {
|
|
15097
|
+
case void 0:
|
|
15098
|
+
break;
|
|
15099
|
+
case "EVSEID":
|
|
15100
|
+
signedEVSEId = normalizedChargePointId;
|
|
15101
|
+
break;
|
|
15102
|
+
case "CBIDC": {
|
|
15103
|
+
const cbidcMatch = /^(\S+)\s+(\S+)$/.exec(normalizedChargePointId);
|
|
15104
|
+
if (cbidcMatch?.[1] !== void 0 && cbidcMatch[2] !== void 0) {
|
|
15105
|
+
signedChargingStationId = cbidcMatch[1];
|
|
15106
|
+
signedConnectorId = cbidcMatch[2];
|
|
15107
|
+
}
|
|
15108
|
+
break;
|
|
15109
|
+
}
|
|
15110
|
+
}
|
|
15111
|
+
}
|
|
14956
15112
|
if (isOptionalString(formatVersion) && isOptionalString(gatewayInformation) && isOptionalString(gatewaySerial) && isOptionalString(gatewayVersion) && isMandatoryString(paging) && isOptionalString(meterVendor) && isOptionalString(meterModel) && // OCMF 1.0 table 3 lists MS as 1..1, but the later "Relation of Serial Numbers,
|
|
14957
15113
|
// Charge Point and Public Key" section makes the serial-number fields conditionally
|
|
14958
15114
|
// mandatory. KEBA KCP30 records identify the signing gateway via GS and omit MS.
|
|
@@ -14965,7 +15121,7 @@ var OCMF = class {
|
|
|
14965
15121
|
// IT is 1..1 in the user-assignment table for transaction records. Some OCMF 1.0
|
|
14966
15122
|
// implementations omit it when no user is assigned (IS=false, ID empty). We tolerate
|
|
14967
15123
|
// this vendor compatibility case instead of rejecting otherwise valid signatures.
|
|
14968
|
-
isOptionalString(identificationType) && isOptionalString(identificationData) && isOptionalString(tariffText) && isOptionalString(
|
|
15124
|
+
isOptionalString(identificationType) && isOptionalString(identificationData) && isOptionalString(tariffText) && isOptionalString(controllerFirmwareVersion) && isOptionalJSONObject(lossCompensation) && isOptionalString(chargePointIdType) && isOptionalString(chargePointId)) {
|
|
14969
15125
|
const paginationPrefix = paging.length > 0 ? paging.charAt(0).toLowerCase() : null;
|
|
14970
15126
|
const transactionType = paginationPrefix === "t" ? "transaction" /* transaction */ : paginationPrefix === "f" ? "fiscal" /* fiscal */ : "undefined" /* undefined */;
|
|
14971
15127
|
const pagination = paging.length > 1 ? parseNumber(paging.substring(1)) : null;
|
|
@@ -14997,11 +15153,22 @@ var OCMF = class {
|
|
|
14997
15153
|
"@id": identificationData ?? "?",
|
|
14998
15154
|
"type": identificationType ?? "?"
|
|
14999
15155
|
},
|
|
15156
|
+
"chargingTariffs": chargingTariff !== void 0 ? [chargingTariff] : void 0,
|
|
15000
15157
|
"ocmf": {
|
|
15001
15158
|
"formatVersion": formatVersion,
|
|
15002
15159
|
"gatewayInformation": gatewayInformation,
|
|
15003
15160
|
"gatewaySerial": gatewaySerial,
|
|
15004
|
-
"gatewayVersion": gatewayVersion
|
|
15161
|
+
"gatewayVersion": gatewayVersion,
|
|
15162
|
+
"meterVendor": meterVendor,
|
|
15163
|
+
"meterModel": meterModel,
|
|
15164
|
+
"meterSerial": meterSerial,
|
|
15165
|
+
"meterFirmware": meterFirmware,
|
|
15166
|
+
"tariffText": tariffText,
|
|
15167
|
+
"tariffTextInterpretation": tariffTextInterpretation,
|
|
15168
|
+
"controllerFirmwareVersion": controllerFirmwareVersion,
|
|
15169
|
+
"lossCompensation": lossCompensation,
|
|
15170
|
+
"chargePointIdentificationType": chargePointIdType,
|
|
15171
|
+
"chargePointIdentification": chargePointId
|
|
15005
15172
|
},
|
|
15006
15173
|
// "chargingStationOperators": [{
|
|
15007
15174
|
// "chargingPools": [{
|
|
@@ -15068,6 +15235,11 @@ var OCMF = class {
|
|
|
15068
15235
|
"@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/OCMFv1.0+json",
|
|
15069
15236
|
"begin": "?",
|
|
15070
15237
|
"end": "?",
|
|
15238
|
+
"chargingStationId": signedChargingStationId,
|
|
15239
|
+
"EVSEId": signedEVSEId,
|
|
15240
|
+
"ConnectorId": signedConnectorId,
|
|
15241
|
+
"tariffId": chargingTariff?.["@id"],
|
|
15242
|
+
"chargingTariffs": chargingTariff !== void 0 ? [chargingTariff] : void 0,
|
|
15071
15243
|
"authorizationStart": {
|
|
15072
15244
|
"@id": identificationData ?? "?",
|
|
15073
15245
|
"type": identificationType ?? "?",
|
|
@@ -15080,19 +15252,50 @@ var OCMF = class {
|
|
|
15080
15252
|
}],
|
|
15081
15253
|
"certainty": 1
|
|
15082
15254
|
};
|
|
15083
|
-
|
|
15255
|
+
const resolvedChargingStationId = signedChargingStationId ?? containerChargingStation?.["@id"];
|
|
15256
|
+
if (resolvedChargingStationId !== void 0) {
|
|
15257
|
+
const matchingContainerStation = containerChargingStation?.["@id"] === resolvedChargingStationId ? containerChargingStation : void 0;
|
|
15258
|
+
const resolvedChargingStation = {
|
|
15259
|
+
...matchingContainerStation ?? { "@id": resolvedChargingStationId },
|
|
15260
|
+
...controllerFirmwareVersion !== void 0 ? {
|
|
15261
|
+
firmware: {
|
|
15262
|
+
...matchingContainerStation?.firmware,
|
|
15263
|
+
version: controllerFirmwareVersion
|
|
15264
|
+
}
|
|
15265
|
+
} : {}
|
|
15266
|
+
};
|
|
15267
|
+
CTR.chargingStations = [
|
|
15268
|
+
resolvedChargingStation,
|
|
15269
|
+
...ContainerInfos?.chargingStations?.filter((station) => station["@id"] !== resolvedChargingStationId) ?? []
|
|
15270
|
+
];
|
|
15271
|
+
if (CTR.chargingSessions?.[0] !== void 0) {
|
|
15272
|
+
CTR.chargingSessions[0].chargingStationId ??= resolvedChargingStationId;
|
|
15273
|
+
CTR.chargingSessions[0].chargingStation = resolvedChargingStation;
|
|
15274
|
+
}
|
|
15275
|
+
} else if (ContainerInfos?.chargingStations !== void 0)
|
|
15084
15276
|
CTR.chargingStations = ContainerInfos.chargingStations;
|
|
15085
|
-
if (containerChargingStation !== void 0 && CTR.chargingSessions?.[0] !== void 0) {
|
|
15086
|
-
CTR.chargingSessions[0].chargingStationId = containerChargingStation["@id"];
|
|
15087
|
-
CTR.chargingSessions[0].chargingStation = containerChargingStation;
|
|
15088
|
-
}
|
|
15089
15277
|
if (containerEVSE !== void 0 && CTR.chargingSessions?.[0] !== void 0) {
|
|
15090
|
-
CTR.chargingSessions[0]
|
|
15091
|
-
|
|
15092
|
-
|
|
15093
|
-
|
|
15094
|
-
|
|
15095
|
-
|
|
15278
|
+
const chargingSession = CTR.chargingSessions[0];
|
|
15279
|
+
chargingSession.EVSEId ??= containerEVSE["@id"];
|
|
15280
|
+
if (chargingSession.EVSEId === containerEVSE["@id"])
|
|
15281
|
+
chargingSession.EVSE = containerEVSE;
|
|
15282
|
+
}
|
|
15283
|
+
const resolvedConnectorId = signedConnectorId ?? containerConnector?.["@id"];
|
|
15284
|
+
if ((resolvedConnectorId !== void 0 || signedCable !== void 0) && CTR.chargingSessions?.[0] !== void 0) {
|
|
15285
|
+
const matchingContainerConnector = containerConnector?.["@id"] === resolvedConnectorId ? containerConnector : void 0;
|
|
15286
|
+
const resolvedConnector = {
|
|
15287
|
+
...matchingContainerConnector,
|
|
15288
|
+
...resolvedConnectorId !== void 0 ? { "@id": resolvedConnectorId } : {},
|
|
15289
|
+
...signedCable !== void 0 ? {
|
|
15290
|
+
cable: {
|
|
15291
|
+
...matchingContainerConnector?.cable,
|
|
15292
|
+
...signedCable
|
|
15293
|
+
}
|
|
15294
|
+
} : {}
|
|
15295
|
+
};
|
|
15296
|
+
const chargingSession = CTR.chargingSessions[0];
|
|
15297
|
+
chargingSession.ConnectorId ??= resolvedConnectorId;
|
|
15298
|
+
chargingSession.Connector = resolvedConnector;
|
|
15096
15299
|
}
|
|
15097
15300
|
const measurementsByKey = /* @__PURE__ */ new Map();
|
|
15098
15301
|
for (const ocmfJSONDocument of OCMFJSONDocuments) {
|
|
@@ -15106,12 +15309,13 @@ var OCMF = class {
|
|
|
15106
15309
|
const readingUnit = effectiveReading.RU;
|
|
15107
15310
|
const readingCurrentType = effectiveReading.RT;
|
|
15108
15311
|
const cumulatedLoss = effectiveReading.CL;
|
|
15312
|
+
const errorIndex = effectiveReading.EI;
|
|
15109
15313
|
const errorFlags = effectiveReading.EF;
|
|
15110
15314
|
const status = effectiveReading.ST;
|
|
15111
15315
|
inheritedReading = effectiveReading;
|
|
15112
15316
|
if (isMandatoryString(time) && isOptionalString(transaction) && isMandatoryDecimal(readingValue) && // Note: Some vendors use a JSON string here!
|
|
15113
15317
|
isOptionalString(readingIdentification) && isMandatoryString(readingUnit) && isOptionalString(readingCurrentType) && // chargyLib.isOptionalDecimal (cumulatedLoss) &&
|
|
15114
|
-
isOptionalString(errorFlags) && isMandatoryString(status)) {
|
|
15318
|
+
isOptionalNumber(errorIndex) && isOptionalString(errorFlags) && isMandatoryString(status)) {
|
|
15115
15319
|
const timeSplit = time.split(" ");
|
|
15116
15320
|
if (timeSplit.length != 2) return {
|
|
15117
15321
|
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
@@ -15210,6 +15414,7 @@ var OCMF = class {
|
|
|
15210
15414
|
// "T" ToDo: Serialize this to a string!
|
|
15211
15415
|
"pagination": pagination,
|
|
15212
15416
|
// "9289"
|
|
15417
|
+
"errorIndex": errorIndex,
|
|
15213
15418
|
"errorFlags": errorFlags,
|
|
15214
15419
|
// ""
|
|
15215
15420
|
"cumulatedLoss": cumulatedLoss != null && cumulatedLoss !== 0 ? new Decimal(cumulatedLoss) : void 0,
|
|
@@ -15226,10 +15431,8 @@ var OCMF = class {
|
|
|
15226
15431
|
}
|
|
15227
15432
|
}
|
|
15228
15433
|
}
|
|
15229
|
-
if (ContainerInfos?.chargingStations !== void 0)
|
|
15230
|
-
CTR.chargingStations = ContainerInfos.chargingStations;
|
|
15231
15434
|
if (ContainerInfos?.warnings !== void 0)
|
|
15232
|
-
CTR.warnings =
|
|
15435
|
+
CTR.warnings = (CTR.warnings ?? []).concat(ContainerInfos.warnings);
|
|
15233
15436
|
CTR.status = OCMFJSONDocuments.every((ocmfJSONDocument) => ocmfJSONDocument.validationStatus === "ValidSignature" /* ValidSignature */) ? "ValidSignature" /* ValidSignature */ : "InvalidSignature" /* InvalidSignature */;
|
|
15234
15437
|
if (CTR.chargingSessions != null && CTR.chargingSessions.length > 0 && CTR.chargingSessions[0]) {
|
|
15235
15438
|
CTR.begin = CTR.chargingSessions[0].begin;
|
|
@@ -15724,6 +15927,11 @@ var OCMF = class {
|
|
|
15724
15927
|
}
|
|
15725
15928
|
if (ocmfJSONDocumentGroup[0]) {
|
|
15726
15929
|
switch (ocmfJSONDocumentGroup[0].payload.FV) {
|
|
15930
|
+
// FV has cardinality 0..1 in OCMF. All supported 1.x
|
|
15931
|
+
// versions use the same parser, so an omitted version
|
|
15932
|
+
// is parsed as generic OCMF without changing the
|
|
15933
|
+
// signed payload or inventing a concrete version.
|
|
15934
|
+
case void 0:
|
|
15727
15935
|
case "0.1":
|
|
15728
15936
|
// OCMF 0.1 SAFE reference data uses a few legacy field names/forms (VI/VV,
|
|
15729
15937
|
// string based IS values), but the compact signed document structure is close
|
|
@@ -16745,6 +16953,184 @@ function readDERInteger(bytes, getOffset, setOffset) {
|
|
|
16745
16953
|
return hex;
|
|
16746
16954
|
}
|
|
16747
16955
|
|
|
16956
|
+
// src/PTBContainer.ts
|
|
16957
|
+
var base64RegExp = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
16958
|
+
var formatVersionRegExp = /^1(?:\.[0-9]+)?$/;
|
|
16959
|
+
var PTB = class {
|
|
16960
|
+
chargy;
|
|
16961
|
+
constructor(chargy) {
|
|
16962
|
+
this.chargy = chargy;
|
|
16963
|
+
}
|
|
16964
|
+
async TryToParsePTBContainer(container) {
|
|
16965
|
+
const validation = this.validateContainer(container);
|
|
16966
|
+
if (!validation.valid)
|
|
16967
|
+
return this.validationError(validation.issues);
|
|
16968
|
+
const ptbContainer = validation.container;
|
|
16969
|
+
const containerInfos = {
|
|
16970
|
+
chargingStations: [{
|
|
16971
|
+
"@id": ptbContainer.chargeboxIdentifier,
|
|
16972
|
+
address: this.normalizeAddress(ptbContainer.address),
|
|
16973
|
+
geoLocation: {
|
|
16974
|
+
lat: ptbContainer.geoLocation.lat,
|
|
16975
|
+
lng: ptbContainer.geoLocation.lng
|
|
16976
|
+
},
|
|
16977
|
+
EVSEs: [{
|
|
16978
|
+
"@id": ptbContainer.chargeboxIdentifier
|
|
16979
|
+
}]
|
|
16980
|
+
}]
|
|
16981
|
+
};
|
|
16982
|
+
return new OCMF(this.chargy).TryToParseOCMFDocuments(
|
|
16983
|
+
[ptbContainer.ocmfBegin, ptbContainer.ocmfEnd],
|
|
16984
|
+
ptbContainer.publicKey,
|
|
16985
|
+
"base64",
|
|
16986
|
+
containerInfos
|
|
16987
|
+
);
|
|
16988
|
+
}
|
|
16989
|
+
validateContainer(container) {
|
|
16990
|
+
const issues = [];
|
|
16991
|
+
if (!isMandatoryJSONObject(container))
|
|
16992
|
+
return {
|
|
16993
|
+
valid: false,
|
|
16994
|
+
issues: [{
|
|
16995
|
+
path: "$",
|
|
16996
|
+
message: "must be an object"
|
|
16997
|
+
}]
|
|
16998
|
+
};
|
|
16999
|
+
this.requireConstantString(container, "format", "ptb", issues);
|
|
17000
|
+
this.requireString(container, "publicKey", issues);
|
|
17001
|
+
this.requireString(container, "chargeboxIdentifier", issues);
|
|
17002
|
+
this.requireString(container, "ocmfBegin", issues);
|
|
17003
|
+
this.requireString(container, "ocmfEnd", issues);
|
|
17004
|
+
const formatVersion = container["formatVersion"];
|
|
17005
|
+
if (formatVersion !== void 0 && (typeof formatVersion !== "string" || !formatVersionRegExp.test(formatVersion))) {
|
|
17006
|
+
issues.push({
|
|
17007
|
+
path: "$.formatVersion",
|
|
17008
|
+
message: "must match ^1(?:\\.[0-9]+)?$"
|
|
17009
|
+
});
|
|
17010
|
+
}
|
|
17011
|
+
const publicKey = container["publicKey"];
|
|
17012
|
+
if (typeof publicKey === "string" && publicKey.length > 0 && !base64RegExp.test(publicKey))
|
|
17013
|
+
issues.push({
|
|
17014
|
+
path: "$.publicKey",
|
|
17015
|
+
message: "must be a base64 encoded string"
|
|
17016
|
+
});
|
|
17017
|
+
for (const propertyName of ["ocmfBegin", "ocmfEnd"]) {
|
|
17018
|
+
const ocmfDocument = container[propertyName];
|
|
17019
|
+
if (typeof ocmfDocument === "string" && (ocmfDocument.length < 10 || !ocmfDocument.startsWith("OCMF|"))) {
|
|
17020
|
+
issues.push({
|
|
17021
|
+
path: "$." + propertyName,
|
|
17022
|
+
message: "must be an unmodified OCMF record beginning with OCMF|"
|
|
17023
|
+
});
|
|
17024
|
+
}
|
|
17025
|
+
}
|
|
17026
|
+
const address = container["address"];
|
|
17027
|
+
if (!isMandatoryJSONObject(address))
|
|
17028
|
+
issues.push({
|
|
17029
|
+
path: "$.address",
|
|
17030
|
+
message: "must be an object"
|
|
17031
|
+
});
|
|
17032
|
+
else
|
|
17033
|
+
this.validateAddress(address, issues);
|
|
17034
|
+
const geoLocation = container["geoLocation"];
|
|
17035
|
+
if (!isMandatoryJSONObject(geoLocation))
|
|
17036
|
+
issues.push({
|
|
17037
|
+
path: "$.geoLocation",
|
|
17038
|
+
message: "must be an object"
|
|
17039
|
+
});
|
|
17040
|
+
else
|
|
17041
|
+
this.validateGeoLocation(geoLocation, issues);
|
|
17042
|
+
if (issues.length > 0)
|
|
17043
|
+
return {
|
|
17044
|
+
valid: false,
|
|
17045
|
+
issues
|
|
17046
|
+
};
|
|
17047
|
+
return {
|
|
17048
|
+
valid: true,
|
|
17049
|
+
container
|
|
17050
|
+
};
|
|
17051
|
+
}
|
|
17052
|
+
validateAddress(address, issues) {
|
|
17053
|
+
this.requireString(address, "street", issues, "$.address");
|
|
17054
|
+
for (const propertyName of ["houseNumber", "zipCode", "postalCode", "town", "city", "country"]) {
|
|
17055
|
+
const propertyValue = address[propertyName];
|
|
17056
|
+
if (propertyValue !== void 0 && typeof propertyValue !== "string")
|
|
17057
|
+
issues.push({
|
|
17058
|
+
path: "$.address." + propertyName,
|
|
17059
|
+
message: "must be a string"
|
|
17060
|
+
});
|
|
17061
|
+
else if ((propertyName === "town" || propertyName === "city") && propertyValue === "")
|
|
17062
|
+
issues.push({
|
|
17063
|
+
path: "$.address." + propertyName,
|
|
17064
|
+
message: "must be a non-empty string"
|
|
17065
|
+
});
|
|
17066
|
+
}
|
|
17067
|
+
const town = address["town"];
|
|
17068
|
+
const city = address["city"];
|
|
17069
|
+
if ((typeof town !== "string" || town.length === 0) && (typeof city !== "string" || city.length === 0)) {
|
|
17070
|
+
issues.push({
|
|
17071
|
+
path: "$.address",
|
|
17072
|
+
message: "must contain a non-empty town or city"
|
|
17073
|
+
});
|
|
17074
|
+
}
|
|
17075
|
+
}
|
|
17076
|
+
validateGeoLocation(geoLocation, issues) {
|
|
17077
|
+
const latitude = geoLocation["lat"];
|
|
17078
|
+
const longitude = geoLocation["lng"];
|
|
17079
|
+
if (typeof latitude !== "number" || !Number.isFinite(latitude) || latitude < -90 || latitude > 90)
|
|
17080
|
+
issues.push({
|
|
17081
|
+
path: "$.geoLocation.lat",
|
|
17082
|
+
message: "must be a number between -90 and 90"
|
|
17083
|
+
});
|
|
17084
|
+
if (typeof longitude !== "number" || !Number.isFinite(longitude) || longitude < -180 || longitude > 180)
|
|
17085
|
+
issues.push({
|
|
17086
|
+
path: "$.geoLocation.lng",
|
|
17087
|
+
message: "must be a number between -180 and 180"
|
|
17088
|
+
});
|
|
17089
|
+
for (const propertyName of Object.keys(geoLocation))
|
|
17090
|
+
if (propertyName !== "lat" && propertyName !== "lng")
|
|
17091
|
+
issues.push({
|
|
17092
|
+
path: "$.geoLocation." + propertyName,
|
|
17093
|
+
message: "is not allowed"
|
|
17094
|
+
});
|
|
17095
|
+
}
|
|
17096
|
+
requireString(json, propertyName, issues, parentPath = "$") {
|
|
17097
|
+
const value = json[propertyName];
|
|
17098
|
+
if (typeof value !== "string" || value.length === 0)
|
|
17099
|
+
issues.push({
|
|
17100
|
+
path: parentPath + "." + propertyName,
|
|
17101
|
+
message: "must be a non-empty string"
|
|
17102
|
+
});
|
|
17103
|
+
}
|
|
17104
|
+
requireConstantString(json, propertyName, expectedValue, issues) {
|
|
17105
|
+
if (json[propertyName] !== expectedValue)
|
|
17106
|
+
issues.push({
|
|
17107
|
+
path: "$." + propertyName,
|
|
17108
|
+
message: "must equal " + expectedValue
|
|
17109
|
+
});
|
|
17110
|
+
}
|
|
17111
|
+
normalizeAddress(address) {
|
|
17112
|
+
return {
|
|
17113
|
+
city: address.city ?? address.town,
|
|
17114
|
+
street: address.street,
|
|
17115
|
+
houseNumber: address.houseNumber,
|
|
17116
|
+
postalCode: address.postalCode ?? address.zipCode,
|
|
17117
|
+
country: address.country
|
|
17118
|
+
};
|
|
17119
|
+
}
|
|
17120
|
+
validationError(issues) {
|
|
17121
|
+
return {
|
|
17122
|
+
format: "ptb",
|
|
17123
|
+
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
17124
|
+
message: this.chargy.GetMultilanguageText("Invalid PTB OCMF container!"),
|
|
17125
|
+
certainty: 1,
|
|
17126
|
+
issues,
|
|
17127
|
+
errors: issues.map((issue) => CreateError(
|
|
17128
|
+
this.chargy.GetMultilanguageText(issue.path + " " + issue.message)
|
|
17129
|
+
))
|
|
17130
|
+
};
|
|
17131
|
+
}
|
|
17132
|
+
};
|
|
17133
|
+
|
|
16748
17134
|
// src/SAFE_XML.ts
|
|
16749
17135
|
var SAFEXML = class _SAFEXML {
|
|
16750
17136
|
chargy;
|
|
@@ -19977,7 +20363,9 @@ var Chargy = class {
|
|
|
19977
20363
|
if (IsAChargeTransparencyLiveLink(JSONContent)) {
|
|
19978
20364
|
JSONContent.timestamp ??= (/* @__PURE__ */ new Date()).toISOString();
|
|
19979
20365
|
processedFile.result = JSONContent;
|
|
19980
|
-
} else if (
|
|
20366
|
+
} else if (JSONContent["format"] === "ptb")
|
|
20367
|
+
processedFile.result = await new PTB(this).TryToParsePTBContainer(JSONContent);
|
|
20368
|
+
else if (isMandatoryString(JSONContext)) {
|
|
19981
20369
|
if (JSONContext.startsWith("https://open.charging.cloud/contexts/CTR+json"))
|
|
19982
20370
|
processedFile.result = JSONContent;
|
|
19983
20371
|
else if (JSONContext.startsWith("https://open.charging.cloud/contexts/publicKey+json"))
|
|
@@ -20450,6 +20838,6 @@ buffer/index.js:
|
|
|
20450
20838
|
*)
|
|
20451
20839
|
*/
|
|
20452
20840
|
|
|
20453
|
-
export { ACrypt, Alfen, AlfenCrypt01, BSMCrypt01, CanonicalJSONError, ChargeIT, ChargePoint, ChargePointCrypt01, IChargeTransparencyLiveLink_exports as ChargeTransparencyLiveLink, ChargeTransparencyLiveLinkContext, IChargeTransparencyRecord_exports as ChargeTransparencyRecord, Chargy, chargyInterfaces_exports as ChargyInterfaces, Clone, CloneCTR, ConcatenateBuffers, CreateDiv, CreateDiv2, CreateError, CreateWarning, CryptoAlgorithms, CryptoHashAlgorithms, DayOfWeek, DisplayPrefixes, EDL40, EDL40Crypt01, EDL40ValidationError, EDL40_OBIS, EDL40_SESSION_CONTEXT, EDL40_SIGNATURE_CONTEXT, EMHCrypt01, ErrorLevel, GDFCrypt01, IECCurves, IEncoding, InformationRelevance, InformationRelevanceToString, IsAChargeTransparencyLiveLink, IsAChargeTransparencyRecord, IsAPublicKey, IsAPublicKeyLookup, IsAPublicKeySignature, IsAPublicKeyXY, IsASessionCryptoResult, IsNullOrEmpty, JSONSignatureVerificationStatus, MENNEKES_EDL40_OBIS, MENNEKES_EDL40_XMLNS, Mennekes, MennekesCrypt01, OBIS2Hex, OBIS2MeasurementName, OBIS_RegExpr, OCMF, OCMFTransactionTypes, OCMFv1_x, OCPI, OIDInfo, PCDF, PCDFCrypt01, PCDFParseError, PCDFValidationError, PCDF_FIELD_ORDER, PCDF_PREFIX, ParseJSON_LD, PublicKeyFormats, IPublicKeyInfo_exports as PublicKeyInfo, SAFEXML, SessionVerificationResult, SetHex, SetInt8, SetText, SetText_withLength, SetTimestamp, SetTimestamp32, SetUInt32, SetUInt32_withCode, SetUInt64, SetUInt64D, SignMessage, SignatureFormats, TimeStatusTypes, UTC2human, VerificationResult, VerifyJSONMessageSignatures, WarningLevel, WhenNullOrEmpty, XMLContainer, asJSONArray, asJSONObject, asNumber, asString, base64ToBytes, buf2hex, buildEDL40Signature, buildIsaSignature, buildMennekesSignatureData, bytesToBase64, bytesToHex, canParseEDL40, canonicalJSONBytes, canonicalJSONStringify, cleanHex, closeFullscreen, createHexString, dateToMennekesLocalEpochSeconds, decodeSmlMessages, extractMennekesChargingProcesses, findEntryByObis, findGetListRes, firstKey, firstValue, getArrayElement, getArrayLikeElement, getDirectChildByLocalName, getDirectChildrenByLocalName, getElementsByLocalName, getFirstArrayElement, getInt16Bytes, getInt32Bytes, getInt64Bytes, getInt8Bytes, getLastArrayElement, getTrimmedTextContent, hashFile, hex2bin, hex32, hexToArrayBuffer, hexToBytes, intFromBytes, isEncodedValue, isGeoLocation, isI18NString, isICryptoResult, isIFileInfo, isISessionCryptoResult1, isISessionCryptoResult2, isJSONLDObject, isMandatoryArrayOfStrings, isMandatoryBoolean, isMandatoryDecimal, isMandatoryJSONArray, isMandatoryJSONObject, isMandatoryNumber, isMandatoryString, isMandatoryURL, isOIDInfo, isObject, isOptionalArrayOfStrings, isOptionalDecimal, isOptionalJSONArray, isOptionalJSONArrayError, isOptionalJSONArrayOk, isOptionalJSONObject, isOptionalNumber, isOptionalString, isOptionalStringArray, isOptionalStringOrOIDInfo, isOptionalURL, isPCDFText, isPublicKeySubject, isString, isStringArray, isStringOrOIDInfo, isStringOrStringArray, isaListNameContext, jsonPrettyPrinter, measurementName2human, normalizePCDFPublicKeyHex, normalizeXMLText, openFullscreen, pad, parseAndVerifyJSONSignatures, parseDescription, parseEDL40, parseHexString, parseMennekesXMLDocument, parseNumber, parseOBIS, parsePCDFDocument, parsePCDFPublicKey, parsePCDFSignature, parseSmlTime, parseUTC, readQRCodeTextFromImage, readQRCodeTextFromImageData, readTLV, secp224k1, setUILocale, sha256, sha256____, sha384, sha384____, sha512, sha512____, signJSONMessage, signMessage, stripPCDFControlCharacters, stripTransport, time2human, toArrayBuffer, toSessionVerificationResults, toUint8Array, transformEDL40Status, unquotePCDFText, validatePCDFFields, verifyEDL40Document, verifyJSONMessageSignatureResults, verifyJSONMessageSignatures, verifyJSONSignature, verifyJSONSignatureResult, verifyPCDFDocument };
|
|
20841
|
+
export { ACrypt, Alfen, AlfenCrypt01, BSMCrypt01, CanonicalJSONError, ChargeIT, ChargePoint, ChargePointCrypt01, IChargeTransparencyLiveLink_exports as ChargeTransparencyLiveLink, ChargeTransparencyLiveLinkContext, IChargeTransparencyRecord_exports as ChargeTransparencyRecord, Chargy, chargyInterfaces_exports as ChargyInterfaces, Clone, CloneCTR, ConcatenateBuffers, CreateDiv, CreateDiv2, CreateError, CreateWarning, CryptoAlgorithms, CryptoHashAlgorithms, DayOfWeek, DisplayPrefixes, EDL40, EDL40Crypt01, EDL40ValidationError, EDL40_OBIS, EDL40_SESSION_CONTEXT, EDL40_SIGNATURE_CONTEXT, EMHCrypt01, ErrorLevel, GDFCrypt01, IECCurves, IEncoding, InformationRelevance, InformationRelevanceToString, IsAChargeTransparencyLiveLink, IsAChargeTransparencyRecord, IsAPublicKey, IsAPublicKeyLookup, IsAPublicKeySignature, IsAPublicKeyXY, IsASessionCryptoResult, IsNullOrEmpty, JSONSignatureVerificationStatus, MENNEKES_EDL40_OBIS, MENNEKES_EDL40_XMLNS, Mennekes, MennekesCrypt01, OBIS2Hex, OBIS2MeasurementName, OBIS_RegExpr, OCMF, OCMFBonnTariffParseError, OCMFTransactionTypes, OCMFv1_x, OCPI, OIDInfo, PCDF, PCDFCrypt01, PCDFParseError, PCDFValidationError, PCDF_FIELD_ORDER, PCDF_PREFIX, PTB, ParseJSON_LD, PublicKeyFormats, IPublicKeyInfo_exports as PublicKeyInfo, SAFEXML, SessionVerificationResult, SetHex, SetInt8, SetText, SetText_withLength, SetTimestamp, SetTimestamp32, SetUInt32, SetUInt32_withCode, SetUInt64, SetUInt64D, SignMessage, SignatureFormats, TimeStatusTypes, UTC2human, VerificationResult, VerifyJSONMessageSignatures, WarningLevel, WhenNullOrEmpty, XMLContainer, asJSONArray, asJSONObject, asNumber, asString, base64ToBytes, buf2hex, buildEDL40Signature, buildIsaSignature, buildMennekesSignatureData, bytesToBase64, bytesToHex, canParseEDL40, canonicalJSONBytes, canonicalJSONStringify, cleanHex, closeFullscreen, createHexString, dateToMennekesLocalEpochSeconds, decodeSmlMessages, extractMennekesChargingProcesses, findEntryByObis, findGetListRes, firstKey, firstValue, getArrayElement, getArrayLikeElement, getDirectChildByLocalName, getDirectChildrenByLocalName, getElementsByLocalName, getFirstArrayElement, getInt16Bytes, getInt32Bytes, getInt64Bytes, getInt8Bytes, getLastArrayElement, getTrimmedTextContent, hashFile, hex2bin, hex32, hexToArrayBuffer, hexToBytes, intFromBytes, isEncodedValue, isGeoLocation, isI18NString, isICryptoResult, isIFileInfo, isISessionCryptoResult1, isISessionCryptoResult2, isJSONLDObject, isMandatoryArrayOfStrings, isMandatoryBoolean, isMandatoryDecimal, isMandatoryJSONArray, isMandatoryJSONObject, isMandatoryNumber, isMandatoryString, isMandatoryURL, isOIDInfo, isObject, isOptionalArrayOfStrings, isOptionalDecimal, isOptionalJSONArray, isOptionalJSONArrayError, isOptionalJSONArrayOk, isOptionalJSONObject, isOptionalNumber, isOptionalString, isOptionalStringArray, isOptionalStringOrOIDInfo, isOptionalURL, isPCDFText, isPublicKeySubject, isString, isStringArray, isStringOrOIDInfo, isStringOrStringArray, isaListNameContext, jsonPrettyPrinter, measurementName2human, normalizePCDFPublicKeyHex, normalizeXMLText, ocmfBonnTariffToChargingTariff, openFullscreen, pad, parseAndVerifyJSONSignatures, parseDescription, parseEDL40, parseHexString, parseMennekesXMLDocument, parseNumber, parseOBIS, parseOCMFBonnTariffText, parsePCDFDocument, parsePCDFPublicKey, parsePCDFSignature, parseSmlTime, parseUTC, readQRCodeTextFromImage, readQRCodeTextFromImageData, readTLV, secp224k1, setUILocale, sha256, sha256____, sha384, sha384____, sha512, sha512____, signJSONMessage, signMessage, stripPCDFControlCharacters, stripTransport, time2human, toArrayBuffer, toSessionVerificationResults, toUint8Array, transformEDL40Status, tryParseOCMFBonnTariffText, unquotePCDFText, validatePCDFFields, verifyEDL40Document, verifyJSONMessageSignatureResults, verifyJSONMessageSignatures, verifyJSONSignature, verifyJSONSignatureResult, verifyPCDFDocument };
|
|
20454
20842
|
//# sourceMappingURL=index.js.map
|
|
20455
20843
|
//# sourceMappingURL=index.js.map
|