@open-charging-cloud/chargy-core 0.6.1 → 0.6.3
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 +2 -2
- package/dist/ACrypt.d.ts +2 -2
- package/dist/ACrypt.d.ts.map +1 -1
- package/dist/Alfen.d.ts +6 -6
- package/dist/Alfen.d.ts.map +1 -1
- package/dist/BSMCrypt01.d.ts +8 -9
- package/dist/BSMCrypt01.d.ts.map +1 -1
- package/dist/EMHCrypt01.d.ts +8 -8
- package/dist/EMHCrypt01.d.ts.map +1 -1
- package/dist/GDFCrypt01.d.ts +8 -8
- package/dist/GDFCrypt01.d.ts.map +1 -1
- package/dist/Mennekes.d.ts +22 -22
- package/dist/Mennekes.d.ts.map +1 -1
- package/dist/OCMF.d.ts +25 -27
- package/dist/OCMF.d.ts.map +1 -1
- package/dist/OCPI.d.ts +2 -4
- package/dist/OCPI.d.ts.map +1 -1
- package/dist/PCDF.d.ts +1 -1
- package/dist/PCDF.d.ts.map +1 -1
- package/dist/QIDigital_DCC.d.ts +1 -1
- package/dist/QIDigital_DCC.d.ts.map +1 -1
- package/dist/QIDigital_DCoA.d.ts +1 -1
- package/dist/QIDigital_DCoA.d.ts.map +1 -1
- package/dist/QIDigital_DCoC.d.ts +1 -1
- package/dist/QIDigital_DCoC.d.ts.map +1 -1
- package/dist/SAFE_XML.d.ts +16 -16
- package/dist/SAFE_XML.d.ts.map +1 -1
- package/dist/XMLContainer.d.ts +2 -2
- package/dist/XMLContainer.d.ts.map +1 -1
- package/dist/browser/index.js +943 -895
- package/dist/browser/index.js.map +1 -1
- package/dist/chargeIT.d.ts +1 -3
- package/dist/chargeIT.d.ts.map +1 -1
- package/dist/chargePoint.d.ts +3 -3
- package/dist/chargePoint.d.ts.map +1 -1
- package/dist/chargy.d.ts +12 -12
- package/dist/chargy.d.ts.map +1 -1
- package/dist/chargyLib.d.ts +4 -0
- package/dist/chargyLib.d.ts.map +1 -1
- package/dist/interfaces/IChargeTransparencyRecord.d.ts +76 -76
- package/dist/interfaces/IChargeTransparencyRecord.d.ts.map +1 -1
- package/dist/interfaces/chargyInterfaces.d.ts +97 -107
- package/dist/interfaces/chargyInterfaces.d.ts.map +1 -1
- package/dist/node/index.js +943 -895
- package/dist/node/index.js.map +1 -1
- package/dist/pdfjs/browser.d.ts +2 -1
- package/dist/pdfjs/browser.d.ts.map +1 -1
- package/dist/qrCodeReader.d.ts.map +1 -1
- package/dist/secp224k1.d.ts +10 -11
- package/dist/secp224k1.d.ts.map +1 -1
- package/dist/verificationResults.d.ts +1 -1
- package/dist/verificationResults.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/node/index.js
CHANGED
|
@@ -8005,9 +8005,7 @@ var secp224k1 = class {
|
|
|
8005
8005
|
N = BigInt("0x010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7");
|
|
8006
8006
|
// Number of points in the field
|
|
8007
8007
|
Acurve = BigInt(0);
|
|
8008
|
-
//
|
|
8009
|
-
Bcurve = BigInt(5);
|
|
8010
|
-
// These two are defined on the elliptic curve. y^2 = x^3 + Acurve * x + Bcurve
|
|
8008
|
+
// Defined on the elliptic curve. y^2 = x^3 + Acurve * x + 5
|
|
8011
8009
|
Gx = BigInt("0xA1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C");
|
|
8012
8010
|
Gy = BigInt("0x7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5");
|
|
8013
8011
|
GPoint = [this.Gx, this.Gy];
|
|
@@ -8104,6 +8102,7 @@ var secp224k1 = class {
|
|
|
8104
8102
|
address: this.modulo(publicKey[1], this.Two) == this.One ? "03" + Px : "02" + Px
|
|
8105
8103
|
};
|
|
8106
8104
|
}
|
|
8105
|
+
return void 0;
|
|
8107
8106
|
}
|
|
8108
8107
|
};
|
|
8109
8108
|
|
|
@@ -8232,13 +8231,13 @@ function CreateError(message, level = "high" /* high */) {
|
|
|
8232
8231
|
};
|
|
8233
8232
|
}
|
|
8234
8233
|
function isISessionCryptoResult1(obj) {
|
|
8235
|
-
return
|
|
8234
|
+
return isObject(obj) && obj["status"] !== void 0;
|
|
8236
8235
|
}
|
|
8237
8236
|
function isISessionCryptoResult2(obj) {
|
|
8238
|
-
return
|
|
8237
|
+
return isObject(obj) && obj["status"] !== void 0 && obj["status"] !== "InvalidSessionFormat" /* InvalidSessionFormat */;
|
|
8239
8238
|
}
|
|
8240
8239
|
function isICryptoResult(obj) {
|
|
8241
|
-
return
|
|
8240
|
+
return isObject(obj) && obj["status"] !== void 0;
|
|
8242
8241
|
}
|
|
8243
8242
|
var InformationRelevance = /* @__PURE__ */ ((InformationRelevance2) => {
|
|
8244
8243
|
InformationRelevance2["Unknown"] = "Unknown";
|
|
@@ -8326,6 +8325,26 @@ function toArrayBuffer(data) {
|
|
|
8326
8325
|
function toUint8Array(data) {
|
|
8327
8326
|
return data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
8328
8327
|
}
|
|
8328
|
+
function getArrayElement(values, index, message = "Missing array element") {
|
|
8329
|
+
const value = values[index];
|
|
8330
|
+
if (value === void 0)
|
|
8331
|
+
throw new Error(message + " at index " + index.toString());
|
|
8332
|
+
return value;
|
|
8333
|
+
}
|
|
8334
|
+
function getFirstArrayElement(values, message = "Missing first array element") {
|
|
8335
|
+
return getArrayElement(values, 0, message);
|
|
8336
|
+
}
|
|
8337
|
+
function getLastArrayElement(values, message = "Missing last array element") {
|
|
8338
|
+
return getArrayElement(values, values.length - 1, message);
|
|
8339
|
+
}
|
|
8340
|
+
function getArrayLikeElement(values, index, message = "Missing array-like element") {
|
|
8341
|
+
if (index < 0 || index >= values.length)
|
|
8342
|
+
throw new Error(message + " at index " + index.toString());
|
|
8343
|
+
const value = values[index];
|
|
8344
|
+
if (value === void 0)
|
|
8345
|
+
throw new Error(message + " at index " + index.toString());
|
|
8346
|
+
return value;
|
|
8347
|
+
}
|
|
8329
8348
|
function normalizeXMLText(xmlText) {
|
|
8330
8349
|
return (xmlText ?? "").replace(/^\uFEFF/, "").replace(/\r\n?/g, "\n").replace(/>\s+</g, "><").trim();
|
|
8331
8350
|
}
|
|
@@ -8337,15 +8356,16 @@ function getDirectChildByLocalName(parent, localName) {
|
|
|
8337
8356
|
}
|
|
8338
8357
|
function getTrimmedTextContent(element) {
|
|
8339
8358
|
const text = element?.textContent.trim();
|
|
8340
|
-
return text && text.length > 0 ? text : void 0;
|
|
8359
|
+
return text != null && text.length > 0 ? text : void 0;
|
|
8341
8360
|
}
|
|
8342
8361
|
function parseDescription(parent) {
|
|
8343
8362
|
const descriptions = getDirectChildrenByLocalName(parent, "description");
|
|
8344
8363
|
const textMap = {};
|
|
8345
8364
|
for (const description of descriptions) {
|
|
8346
|
-
const
|
|
8365
|
+
const languageAttribute = description.getAttribute("language")?.trim();
|
|
8366
|
+
const language = languageAttribute != null && languageAttribute.length > 0 ? languageAttribute : "und";
|
|
8347
8367
|
const text = description.textContent.trim();
|
|
8348
|
-
if (text)
|
|
8368
|
+
if (text.length > 0)
|
|
8349
8369
|
textMap[language] = text;
|
|
8350
8370
|
}
|
|
8351
8371
|
return Object.keys(textMap).length > 0 ? textMap : void 0;
|
|
@@ -8381,12 +8401,14 @@ function ParseJSON_LD(Text, _Context = "") {
|
|
|
8381
8401
|
function firstKey(obj) {
|
|
8382
8402
|
for (const a in obj)
|
|
8383
8403
|
return a;
|
|
8404
|
+
return void 0;
|
|
8384
8405
|
}
|
|
8385
8406
|
function firstValue(obj) {
|
|
8386
8407
|
if (obj == void 0)
|
|
8387
8408
|
return void 0;
|
|
8388
8409
|
for (const a in obj)
|
|
8389
8410
|
return obj[a];
|
|
8411
|
+
return void 0;
|
|
8390
8412
|
}
|
|
8391
8413
|
var uiLocale = typeof window !== "undefined" ? window.navigator.language : "de";
|
|
8392
8414
|
function setUILocale(locale) {
|
|
@@ -8419,14 +8441,17 @@ function parseOBIS(OBIS) {
|
|
|
8419
8441
|
return `${String(media)}-${String(channel)}:${String(indicator)}.${String(mode)}.${String(quantities)}*${String(storage)}`;
|
|
8420
8442
|
}
|
|
8421
8443
|
var OBIS_RegExpr = new RegExp("((\\d+)\\-)?((\\d+):)?((\\d+)\\.)(\\d+)(\\.(\\d+))?(\\*(\\d+))?");
|
|
8444
|
+
function optionalOBISMatchValue(value) {
|
|
8445
|
+
return value ?? "0";
|
|
8446
|
+
}
|
|
8422
8447
|
function OBIS2Hex(OBIS) {
|
|
8423
8448
|
const OBISElements = OBIS.match(OBIS_RegExpr);
|
|
8424
|
-
return OBISElements == null ? "000000000000" : parseInt(OBISElements[2]).toString(16).padStart(2, "0") + // optional A
|
|
8425
|
-
parseInt(OBISElements[4]).toString(16).padStart(2, "0") + // optional B
|
|
8426
|
-
parseInt(OBISElements[6]).toString(16).padStart(2, "0") + // mandatory C
|
|
8427
|
-
parseInt(OBISElements[7]).toString(16).padStart(2, "0") + // mandatory D
|
|
8428
|
-
parseInt(OBISElements[9]).toString(16).padStart(2, "0") + // optional E
|
|
8429
|
-
parseInt(OBISElements[11]).toString(16).padStart(2, "0");
|
|
8449
|
+
return OBISElements == null ? "000000000000" : parseInt(optionalOBISMatchValue(OBISElements[2])).toString(16).padStart(2, "0") + // optional A
|
|
8450
|
+
parseInt(optionalOBISMatchValue(OBISElements[4])).toString(16).padStart(2, "0") + // optional B
|
|
8451
|
+
parseInt(optionalOBISMatchValue(OBISElements[6])).toString(16).padStart(2, "0") + // mandatory C
|
|
8452
|
+
parseInt(optionalOBISMatchValue(OBISElements[7])).toString(16).padStart(2, "0") + // mandatory D
|
|
8453
|
+
parseInt(optionalOBISMatchValue(OBISElements[9])).toString(16).padStart(2, "0") + // optional E
|
|
8454
|
+
parseInt(optionalOBISMatchValue(OBISElements[11])).toString(16).padStart(2, "0");
|
|
8430
8455
|
}
|
|
8431
8456
|
function OBIS2MeasurementName(OBISString) {
|
|
8432
8457
|
switch (OBISString) {
|
|
@@ -8469,15 +8494,15 @@ function measurementName2human(In) {
|
|
|
8469
8494
|
}
|
|
8470
8495
|
}
|
|
8471
8496
|
function IsNullOrEmpty(value) {
|
|
8472
|
-
return
|
|
8497
|
+
return value == null || value.length === 0;
|
|
8473
8498
|
}
|
|
8474
8499
|
function WhenNullOrEmpty(value, replacement) {
|
|
8475
|
-
if (
|
|
8500
|
+
if (value == null || value.length === 0)
|
|
8476
8501
|
return replacement;
|
|
8477
8502
|
return value;
|
|
8478
8503
|
}
|
|
8479
8504
|
function hex2bin(hex, Reverse) {
|
|
8480
|
-
if (Reverse) {
|
|
8505
|
+
if (Reverse === true) {
|
|
8481
8506
|
const reversed = [];
|
|
8482
8507
|
for (let i = 0; i < hex.length; i += 2)
|
|
8483
8508
|
reversed.push(hex.substring(i, i + 2));
|
|
@@ -8591,7 +8616,7 @@ function SetHex(dv, hex, offset, reverse) {
|
|
|
8591
8616
|
const bytes = parseHexString(hex);
|
|
8592
8617
|
const buffer = new ArrayBuffer(bytes.length);
|
|
8593
8618
|
const tv = new DataView(buffer);
|
|
8594
|
-
if (reverse)
|
|
8619
|
+
if (reverse === true)
|
|
8595
8620
|
bytes.reverse();
|
|
8596
8621
|
for (let i = 0; i < bytes.length; i++) {
|
|
8597
8622
|
dv.setUint8(offset + i, bytes[i] ?? 0);
|
|
@@ -8640,7 +8665,7 @@ function SetUInt32(dv, value, offset, reverse) {
|
|
|
8640
8665
|
const bytes = getInt32Bytes(value);
|
|
8641
8666
|
const buffer = new ArrayBuffer(bytes.length);
|
|
8642
8667
|
const tv = new DataView(buffer);
|
|
8643
|
-
if (reverse)
|
|
8668
|
+
if (reverse === true)
|
|
8644
8669
|
bytes.reverse();
|
|
8645
8670
|
for (let i = 0; i < bytes.length; i++) {
|
|
8646
8671
|
dv.setUint8(offset + i, bytes[i] ?? 0);
|
|
@@ -8652,7 +8677,7 @@ function SetUInt64(dv, value, offset, reverse) {
|
|
|
8652
8677
|
const bytes = getInt64Bytes(value);
|
|
8653
8678
|
const buffer = new ArrayBuffer(bytes.length);
|
|
8654
8679
|
const tv = new DataView(buffer);
|
|
8655
|
-
if (reverse)
|
|
8680
|
+
if (reverse === true)
|
|
8656
8681
|
bytes.reverse();
|
|
8657
8682
|
for (let i = 0; i < bytes.length; i++) {
|
|
8658
8683
|
dv.setUint8(offset + i, bytes[i] ?? 0);
|
|
@@ -8684,7 +8709,7 @@ function SetUInt32_withCode(dv, value, scale, obis, offset, reverse) {
|
|
|
8684
8709
|
const obisBytes = getInt8Bytes(obis);
|
|
8685
8710
|
const buffer = new ArrayBuffer(valueBytes.length + 2);
|
|
8686
8711
|
const tv = new DataView(buffer);
|
|
8687
|
-
if (reverse)
|
|
8712
|
+
if (reverse === true)
|
|
8688
8713
|
valueBytes.reverse();
|
|
8689
8714
|
for (let i = 0; i < valueBytes.length; i++) {
|
|
8690
8715
|
dv.setUint8(offset + i, valueBytes[i] ?? 0);
|
|
@@ -8747,8 +8772,7 @@ function CreateDiv2(ParentDiv, ChildClassName, ChildAInnerHTML, ChildBInnerHTML)
|
|
|
8747
8772
|
return childDiv;
|
|
8748
8773
|
}
|
|
8749
8774
|
function pad(text, paddingValue) {
|
|
8750
|
-
|
|
8751
|
-
text = "";
|
|
8775
|
+
text ??= "";
|
|
8752
8776
|
return (text + Array(2 * paddingValue).join("0")).substring(0, 2 * paddingValue);
|
|
8753
8777
|
}
|
|
8754
8778
|
async function sha256(message) {
|
|
@@ -8894,7 +8918,7 @@ function jsonPrettyPrinter(value, KeyLookup) {
|
|
|
8894
8918
|
value,
|
|
8895
8919
|
0,
|
|
8896
8920
|
"",
|
|
8897
|
-
KeyLookup ?? ((
|
|
8921
|
+
KeyLookup ?? ((_path, key) => key)
|
|
8898
8922
|
);
|
|
8899
8923
|
}
|
|
8900
8924
|
function _jsonPrettyPrinter(value, indentLevel, path, keyLookup) {
|
|
@@ -8973,13 +8997,15 @@ var ACrypt = class {
|
|
|
8973
8997
|
}
|
|
8974
8998
|
AddToVisualBuffer(valueHEX, bufferDiv, lineDiv) {
|
|
8975
8999
|
const newText = CreateDiv(bufferDiv, "entry", valueHEX);
|
|
9000
|
+
const lineId = getArrayLikeElement(lineDiv.children, 0, "Missing visual buffer line id");
|
|
9001
|
+
const lineHex = getArrayLikeElement(lineDiv.children, 1, "Missing visual buffer line hex");
|
|
8976
9002
|
newText.onmouseenter = function() {
|
|
8977
|
-
|
|
8978
|
-
|
|
9003
|
+
lineId.classList.add("overEntry");
|
|
9004
|
+
lineHex.classList.add("overEntry");
|
|
8979
9005
|
};
|
|
8980
9006
|
newText.onmouseleave = function() {
|
|
8981
|
-
|
|
8982
|
-
|
|
9007
|
+
lineId.classList.remove("overEntry");
|
|
9008
|
+
lineHex.classList.remove("overEntry");
|
|
8983
9009
|
};
|
|
8984
9010
|
lineDiv.onmouseenter = function() {
|
|
8985
9011
|
newText.classList.add("overEntry");
|
|
@@ -8995,7 +9021,7 @@ var Alfen = class {
|
|
|
8995
9021
|
this.chargy = chargy;
|
|
8996
9022
|
}
|
|
8997
9023
|
bufferToHex(buffer, Reverse) {
|
|
8998
|
-
return (Reverse ? Array.from(new Uint8Array(buffer)).reverse() : Array.from(new Uint8Array(buffer))).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
9024
|
+
return (Reverse === true ? Array.from(new Uint8Array(buffer)).reverse() : Array.from(new Uint8Array(buffer))).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
8999
9025
|
}
|
|
9000
9026
|
bufferToNumber(buffer) {
|
|
9001
9027
|
return parseInt(Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join(""), 16);
|
|
@@ -9030,28 +9056,29 @@ var Alfen = class {
|
|
|
9030
9056
|
signedValues = Content;
|
|
9031
9057
|
let previousTimestamp = "";
|
|
9032
9058
|
for (let i = 0; i < signedValues.length; i++) {
|
|
9033
|
-
const elements = signedValues
|
|
9034
|
-
if (elements
|
|
9059
|
+
const elements = getArrayElement(signedValues, i, "Missing Alfen signed value").split(";");
|
|
9060
|
+
if (elements.length != 6 && elements.length != 7)
|
|
9035
9061
|
return {
|
|
9036
9062
|
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
9037
9063
|
message: this.chargy.GetMultilanguageText("Invalid number of signed meter values!"),
|
|
9038
9064
|
certainty: 0
|
|
9039
9065
|
};
|
|
9040
|
-
const FormatId = elements
|
|
9041
|
-
const Type = elements
|
|
9042
|
-
const BlobVersion = elements
|
|
9043
|
-
const
|
|
9044
|
-
const
|
|
9045
|
-
const
|
|
9066
|
+
const FormatId = getArrayElement(elements, 0, "Missing Alfen format id");
|
|
9067
|
+
const Type = getArrayElement(elements, 1, "Missing Alfen type");
|
|
9068
|
+
const BlobVersion = getArrayElement(elements, 2, "Missing Alfen blob version");
|
|
9069
|
+
const publicKeyValue = getArrayElement(elements, 3, "Missing Alfen public key");
|
|
9070
|
+
const PublicKey = this.chargy.base32Decode(publicKeyValue, "RFC4648");
|
|
9071
|
+
const DataSet = this.chargy.base32Decode(getArrayElement(elements, 4, "Missing Alfen data set"), "RFC4648");
|
|
9072
|
+
const Signature = this.chargy.base32Decode(getArrayElement(elements, 5, "Missing Alfen signature"), "RFC4648");
|
|
9046
9073
|
if (common.PublicKey === "")
|
|
9047
|
-
common.PublicKey =
|
|
9048
|
-
else if (
|
|
9074
|
+
common.PublicKey = publicKeyValue;
|
|
9075
|
+
else if (publicKeyValue !== common.PublicKey)
|
|
9049
9076
|
return {
|
|
9050
9077
|
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
9051
9078
|
message: this.chargy.GetMultilanguageText("Inconsistent public keys!"),
|
|
9052
9079
|
certainty: 0
|
|
9053
9080
|
};
|
|
9054
|
-
if (FormatId !== "AP" || Type
|
|
9081
|
+
if (FormatId !== "AP" || Type.length !== 1 || BlobVersion.length !== 1 || BlobVersion !== "3" || PublicKey.byteLength !== 25 || DataSet.byteLength !== 82 || Signature.byteLength !== 48) {
|
|
9055
9082
|
return {
|
|
9056
9083
|
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
9057
9084
|
message: this.chargy.GetMultilanguageText("Invalid charging session format!"),
|
|
@@ -9168,14 +9195,8 @@ var Alfen = class {
|
|
|
9168
9195
|
const evseId = asString(containerInfos["EVSEId"]) ?? "DE*GEF*EVSE*CHARGY*1";
|
|
9169
9196
|
const chargingStationId = asString(containerInfos["ChargingStationId"]) ?? "DE*GEF*STATION*CHARGY*1";
|
|
9170
9197
|
const chargingSessionId = asString(chargingSession?.["@id"]);
|
|
9171
|
-
const firstDataSet = common.dataSets
|
|
9172
|
-
const lastDataSet = common.dataSets
|
|
9173
|
-
if (firstDataSet === void 0 || lastDataSet === void 0)
|
|
9174
|
-
return {
|
|
9175
|
-
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
9176
|
-
message: this.chargy.GetMultilanguageText("Invalid number of signed meter values!"),
|
|
9177
|
-
certainty: 0
|
|
9178
|
-
};
|
|
9198
|
+
const firstDataSet = getFirstArrayElement(common.dataSets, "Missing first Alfen data set");
|
|
9199
|
+
const lastDataSet = getLastArrayElement(common.dataSets, "Missing last Alfen data set");
|
|
9179
9200
|
const _CTR = {
|
|
9180
9201
|
"@id": chargingSessionId ?? common.InternalSessionId.toString(),
|
|
9181
9202
|
"@context": "https://open.charging.cloud/contexts/CTR+json",
|
|
@@ -9456,62 +9477,62 @@ var AlfenCrypt01 = class extends ACrypt {
|
|
|
9456
9477
|
}
|
|
9457
9478
|
return {};
|
|
9458
9479
|
}
|
|
9459
|
-
async ViewMeasurement(measurementValue,
|
|
9480
|
+
async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
|
|
9460
9481
|
const result = measurementValue.result;
|
|
9461
9482
|
{
|
|
9462
9483
|
introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "AlfenCrypt01").replace("{cryptoAlgorithm}", this.description);
|
|
9463
9484
|
}
|
|
9464
9485
|
{
|
|
9465
|
-
if (PlainTextDiv.parentElement
|
|
9466
|
-
PlainTextDiv.parentElement.children
|
|
9486
|
+
if (PlainTextDiv.parentElement) {
|
|
9487
|
+
getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = this.chargy.GetLocalizedMessage("Plain text") + " (320 Bytes, hex)";
|
|
9467
9488
|
}
|
|
9468
9489
|
PlainTextDiv.style.fontFamily = "";
|
|
9469
9490
|
PlainTextDiv.style.whiteSpace = "";
|
|
9470
9491
|
PlainTextDiv.style.maxHeight = "";
|
|
9471
9492
|
PlainTextDiv.style.overflowY = "";
|
|
9472
|
-
this.CreateLocalizedLine("Adapter Id", measurementValue.measurement.adapterId, result.adapterId
|
|
9473
|
-
this.CreateLocalizedLine("Adapter Firmware Version", measurementValue.measurement.adapterFWVersion, result.adapterFWVersion
|
|
9474
|
-
this.CreateLocalizedLine("Adapter Firmware Checksum", measurementValue.measurement.adapterFWChecksum, result.adapterFWChecksum
|
|
9475
|
-
this.CreateLocalizedLine("Meter number", measurementValue.measurement.energyMeterId, result.meterId
|
|
9493
|
+
this.CreateLocalizedLine("Adapter Id", measurementValue.measurement.adapterId, result.adapterId ?? "", infoDiv, PlainTextDiv);
|
|
9494
|
+
this.CreateLocalizedLine("Adapter Firmware Version", measurementValue.measurement.adapterFWVersion, result.adapterFWVersion ?? "", infoDiv, PlainTextDiv);
|
|
9495
|
+
this.CreateLocalizedLine("Adapter Firmware Checksum", measurementValue.measurement.adapterFWChecksum, result.adapterFWChecksum ?? "", infoDiv, PlainTextDiv);
|
|
9496
|
+
this.CreateLocalizedLine("Meter number", measurementValue.measurement.energyMeterId, result.meterId ?? "", infoDiv, PlainTextDiv);
|
|
9476
9497
|
this.CreateLocalizedLine(
|
|
9477
9498
|
"Meter status",
|
|
9478
9499
|
hex2bin(measurementValue.statusMeter, true) + " (" + measurementValue.statusMeter + ' hex)<br /><span class="statusInfos">' + this.DecodeMeterStatus(measurementValue.statusMeter).join("<br />") + "</span>",
|
|
9479
|
-
result.statusMeter
|
|
9500
|
+
result.statusMeter ?? "",
|
|
9480
9501
|
infoDiv,
|
|
9481
9502
|
PlainTextDiv
|
|
9482
9503
|
);
|
|
9483
9504
|
this.CreateLocalizedLine(
|
|
9484
9505
|
"Adapter status",
|
|
9485
9506
|
hex2bin(measurementValue.statusAdapter, true) + " (" + measurementValue.statusAdapter + ' hex)<br /><span class="statusInfos">' + this.DecodeAdapterStatus(measurementValue.statusAdapter).join("<br />") + "</span>",
|
|
9486
|
-
result.statusAdapter
|
|
9507
|
+
result.statusAdapter ?? "",
|
|
9487
9508
|
infoDiv,
|
|
9488
9509
|
PlainTextDiv
|
|
9489
9510
|
);
|
|
9490
|
-
this.CreateLocalizedLine("Seconds index", measurementValue.secondsIndex, result.secondsIndex
|
|
9491
|
-
this.CreateLocalizedLine("Timestamp", UTC2human(measurementValue.timestamp), result.timestamp
|
|
9492
|
-
this.CreateLocalizedLine("OBIS code", measurementValue.measurement.obis, result.obisId
|
|
9493
|
-
this.CreateLocalizedLine("Unit (encoded)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded
|
|
9494
|
-
this.CreateLocalizedLine("Scaling", measurementValue.measurement.scale, result.scalar
|
|
9495
|
-
this.CreateLocalizedLine("Measurement Value", measurementValue.value.toString() + " Wh", result.value
|
|
9496
|
-
this.CreateLocalizedLine("Authorization", (measurementValue.measurement.chargingSession?.authorizationStart["@id"] ?? "") + " hex", pad(result.uid, 20)
|
|
9497
|
-
this.CreateLocalizedLine("SessionId", measurementValue.measurement.chargingSession?.["@id"] ?? "", result.sessionId
|
|
9498
|
-
this.CreateLocalizedLine("Pagination counter", measurementValue.paginationId, result.paging
|
|
9511
|
+
this.CreateLocalizedLine("Seconds index", measurementValue.secondsIndex, result.secondsIndex ?? "", infoDiv, PlainTextDiv);
|
|
9512
|
+
this.CreateLocalizedLine("Timestamp", UTC2human(measurementValue.timestamp), result.timestamp ?? "", infoDiv, PlainTextDiv);
|
|
9513
|
+
this.CreateLocalizedLine("OBIS code", measurementValue.measurement.obis, result.obisId ?? "", infoDiv, PlainTextDiv);
|
|
9514
|
+
this.CreateLocalizedLine("Unit (encoded)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded ?? "", infoDiv, PlainTextDiv);
|
|
9515
|
+
this.CreateLocalizedLine("Scaling", measurementValue.measurement.scale, result.scalar ?? "", infoDiv, PlainTextDiv);
|
|
9516
|
+
this.CreateLocalizedLine("Measurement Value", measurementValue.value.toString() + " Wh", result.value ?? "", infoDiv, PlainTextDiv);
|
|
9517
|
+
this.CreateLocalizedLine("Authorization", (measurementValue.measurement.chargingSession?.authorizationStart["@id"] ?? "") + " hex", pad(result.uid, 20), infoDiv, PlainTextDiv);
|
|
9518
|
+
this.CreateLocalizedLine("SessionId", measurementValue.measurement.chargingSession?.["@id"] ?? "", result.sessionId ?? "", infoDiv, PlainTextDiv);
|
|
9519
|
+
this.CreateLocalizedLine("Pagination counter", measurementValue.paginationId, result.paging ?? "", infoDiv, PlainTextDiv);
|
|
9499
9520
|
}
|
|
9500
9521
|
{
|
|
9501
|
-
if (HashedPlainTextDiv.parentElement
|
|
9502
|
-
HashedPlainTextDiv.parentElement.children
|
|
9522
|
+
if (HashedPlainTextDiv.parentElement) {
|
|
9523
|
+
getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = this.chargy.GetLocalizedMessage("Hashed plain text") + " (SHA256, hex)";
|
|
9503
9524
|
}
|
|
9504
9525
|
const hashValueText = typeof result.hashValue === "string" ? result.hashValue : result.hashValue?.toString(16) ?? "";
|
|
9505
9526
|
HashedPlainTextDiv.innerHTML = hashValueText.match(/.{1,8}/g)?.join(" ") ?? "";
|
|
9506
9527
|
}
|
|
9507
|
-
if (result.publicKey && result.publicKey
|
|
9508
|
-
if (PublicKeyDiv.parentElement
|
|
9509
|
-
PublicKeyDiv.parentElement.children
|
|
9528
|
+
if (result.publicKey != null && result.publicKey.length > 0) {
|
|
9529
|
+
if (PublicKeyDiv.parentElement) {
|
|
9530
|
+
getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = this.chargy.GetLocalizedMessage("Public Key") + " (" + (result.publicKeyFormat != null && result.publicKeyFormat.length > 0 ? result.publicKeyFormat + ", " : "") + "base32)";
|
|
9510
9531
|
}
|
|
9511
9532
|
if (!IsNullOrEmpty(result.publicKey))
|
|
9512
9533
|
PublicKeyDiv.innerHTML = result.publicKey.match(/.{1,4}/g)?.join(" ") ?? "";
|
|
9513
9534
|
}
|
|
9514
|
-
if (PublicKeyDiv.parentElement
|
|
9535
|
+
if (PublicKeyDiv.parentElement?.children[3]) {
|
|
9515
9536
|
PublicKeyDiv.parentElement.children[3].innerHTML = "";
|
|
9516
9537
|
if (result.publicKeySignatures) {
|
|
9517
9538
|
for (const signature of result.publicKeySignatures) {
|
|
@@ -9530,14 +9551,14 @@ var AlfenCrypt01 = class extends ACrypt {
|
|
|
9530
9551
|
}
|
|
9531
9552
|
}
|
|
9532
9553
|
if (result.signature != null) {
|
|
9533
|
-
if (SignatureExpectedDiv.parentElement
|
|
9534
|
-
SignatureExpectedDiv.parentElement.children
|
|
9554
|
+
if (SignatureExpectedDiv.parentElement) {
|
|
9555
|
+
getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = this.chargy.GetLocalizedMessage("Expected signature") + " (" + (result.signature.format ?? "") + ", hex)";
|
|
9535
9556
|
}
|
|
9536
|
-
if (result.signature.r && result.signature.s) {
|
|
9557
|
+
if (result.signature.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0) {
|
|
9537
9558
|
const signatureR = result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
|
|
9538
9559
|
const signatureS = result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
|
|
9539
9560
|
SignatureExpectedDiv.innerHTML = "r: " + signatureR + "<br />s: " + signatureS;
|
|
9540
|
-
} else if (result.signature.value)
|
|
9561
|
+
} else if (result.signature.value != null && result.signature.value.length > 0)
|
|
9541
9562
|
SignatureExpectedDiv.innerHTML = result.signature.value.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
|
|
9542
9563
|
}
|
|
9543
9564
|
{
|
|
@@ -9779,10 +9800,14 @@ var BSMCrypt01 = class extends ACrypt {
|
|
|
9779
9800
|
throw new Error(`Invalid identification of signed meter value #${String(measurementCounter - 1)}!`);
|
|
9780
9801
|
const previousParts = previousId.split("-");
|
|
9781
9802
|
const currentParts = currentId.split("-");
|
|
9782
|
-
|
|
9803
|
+
const previousPrefix = previousParts.at(0);
|
|
9804
|
+
const previousCounter = previousParts.at(1);
|
|
9805
|
+
const currentPrefix = currentParts.at(0);
|
|
9806
|
+
const currentCounter = currentParts.at(1);
|
|
9807
|
+
if (previousParts.length !== 2 || currentParts.length !== 2 || previousPrefix !== currentPrefix || previousCounter === void 0 || currentCounter === void 0 || // parseInt returns NaN in case parsing fails which in turn does not match
|
|
9783
9808
|
// anything (not even NaN). This way we are checking that both counter values
|
|
9784
9809
|
// are numeric too.
|
|
9785
|
-
parseInt(
|
|
9810
|
+
parseInt(previousCounter, 10) >= parseInt(currentCounter, 10)) {
|
|
9786
9811
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeasurementIdP", measurementCounter)));
|
|
9787
9812
|
}
|
|
9788
9813
|
}
|
|
@@ -9820,7 +9845,7 @@ var BSMCrypt01 = class extends ACrypt {
|
|
|
9820
9845
|
precision: asNumber(displayedFormat?.["precision"])
|
|
9821
9846
|
};
|
|
9822
9847
|
});
|
|
9823
|
-
if (currentMeasurement["meterInfo"]) {
|
|
9848
|
+
if (currentMeasurement["meterInfo"] != null) {
|
|
9824
9849
|
const meterInfoObj2 = asJSONObject(currentMeasurement["meterInfo"]);
|
|
9825
9850
|
if (meterInfoObj2?.["firmwareVersion"] !== common.meterInfo_firmwareVersion)
|
|
9826
9851
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_FirmwareVersionP", measurementCounter)));
|
|
@@ -9828,42 +9853,42 @@ var BSMCrypt01 = class extends ACrypt {
|
|
|
9828
9853
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_PublicKeyP", measurementCounter)));
|
|
9829
9854
|
if (meterInfoObj2?.["meterId"] !== common.meterInfo_meterId)
|
|
9830
9855
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_MeterIdP", measurementCounter)));
|
|
9831
|
-
if (meterInfoObj2?.["meterId"] !== additionalValues.
|
|
9856
|
+
if (meterInfoObj2?.["meterId"] !== additionalValues.find((element) => element.measurandName === "MA1")?.value)
|
|
9832
9857
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_MeterIdP", measurementCounter)));
|
|
9833
9858
|
if (meterInfoObj2?.["manufacturer"] !== common.meterInfo_manufacturer)
|
|
9834
9859
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_ManufacturerP", measurementCounter)));
|
|
9835
9860
|
if (meterInfoObj2?.["type"] !== common.meterInfo_type)
|
|
9836
9861
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_TypeP", measurementCounter)));
|
|
9837
9862
|
}
|
|
9838
|
-
if (currentMeasurement["contract"]) {
|
|
9863
|
+
if (currentMeasurement["contract"] != null) {
|
|
9839
9864
|
const contractObj2 = asJSONObject(currentMeasurement["contract"]);
|
|
9840
|
-
if (additionalValues.filter((element) => element.measurandName?.startsWith("Meta") && asString(element.value)?.startsWith("contract-id:")).length == 0)
|
|
9865
|
+
if (additionalValues.filter((element) => element.measurandName?.startsWith("Meta") === true && asString(element.value)?.startsWith("contract-id:") === true).length == 0)
|
|
9841
9866
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_IdP", measurementCounter)));
|
|
9842
9867
|
if (contractObj2?.["id"] !== common.contract_id)
|
|
9843
9868
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_IdP", measurementCounter)));
|
|
9844
9869
|
if (contractObj2?.["type"] !== common.contract_type)
|
|
9845
9870
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_TypeP", measurementCounter)));
|
|
9846
|
-
const contractInfo = additionalValues.
|
|
9871
|
+
const contractInfo = additionalValues.find((element) => element.measurandName?.startsWith("Meta") === true && asString(element.value)?.startsWith("contract-id:") === true)?.value;
|
|
9847
9872
|
if (contractInfo != null) {
|
|
9848
|
-
if (contractObj2?.["type"] && contractInfo !== "contract-id: " + (common.contract_type ?? "-") + ":" + common.contract_id)
|
|
9873
|
+
if (contractObj2?.["type"] != null && contractInfo !== "contract-id: " + (common.contract_type ?? "-") + ":" + common.contract_id)
|
|
9849
9874
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_IdP", measurementCounter)));
|
|
9850
|
-
if (
|
|
9875
|
+
if (contractObj2?.["type"] == null && contractInfo !== "contract-id: " + common.contract_id)
|
|
9851
9876
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_IdP", measurementCounter)));
|
|
9852
9877
|
}
|
|
9853
9878
|
}
|
|
9854
9879
|
const rcrInAdditional = additionalValues.find((element) => element.measurandName == "RCR");
|
|
9855
9880
|
if (currentMeasurement["value"] == null)
|
|
9856
9881
|
throw new Error(`Missing value within signed meter value #${String(measurementCounter)}!`);
|
|
9857
|
-
if ((valueObj2?.["measurand"] || valueObj2?.["measuredValue"]) && rcrInAdditional === void 0)
|
|
9882
|
+
if ((valueObj2?.["measurand"] != null || valueObj2?.["measuredValue"] != null) && rcrInAdditional === void 0)
|
|
9858
9883
|
throw new Error(`Missing 'RCR' within the additional values of signed meter value #${String(measurementCounter)}!`);
|
|
9859
|
-
if (valueObj2?.["measurand"]) {
|
|
9884
|
+
if (valueObj2?.["measurand"] != null) {
|
|
9860
9885
|
const measurandObj2 = asJSONObject(valueObj2["measurand"]);
|
|
9861
9886
|
if (measurandObj2?.["id"] !== common.value_measurand_id || measurandObj2["id"] !== rcrInAdditional?.measurandId)
|
|
9862
9887
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_Measurand_IdentificationP", measurementCounter)));
|
|
9863
9888
|
if (measurandObj2?.["name"] !== common.value_measurand_name || measurandObj2["name"] !== rcrInAdditional?.measurandName)
|
|
9864
9889
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_Measurand_NameP", measurementCounter)));
|
|
9865
9890
|
}
|
|
9866
|
-
if (valueObj2?.["measuredValue"]) {
|
|
9891
|
+
if (valueObj2?.["measuredValue"] != null) {
|
|
9867
9892
|
if (measuredValueObj2?.["value"] !== rcrInAdditional?.value)
|
|
9868
9893
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValueP", measurementCounter)));
|
|
9869
9894
|
if (measuredValueObj2?.["scale"] !== common.value_measuredValue_scale || measuredValueObj2?.["scale"] !== rcrInAdditional?.scale)
|
|
@@ -9875,15 +9900,15 @@ var BSMCrypt01 = class extends ACrypt {
|
|
|
9875
9900
|
if (measuredValueObj2?.["valueType"] !== common.value_measuredValue_valueType || measuredValueObj2?.["valueType"] !== rcrInAdditional?.valueType)
|
|
9876
9901
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_TypeP", measurementCounter)));
|
|
9877
9902
|
}
|
|
9878
|
-
if (currentMeasurement["chargePoint"] && asJSONObject(currentMeasurement["chargePoint"])?.["softwareVersion"] !== common.chargePoint_softwareVersion)
|
|
9903
|
+
if (currentMeasurement["chargePoint"] != null && asJSONObject(currentMeasurement["chargePoint"])?.["softwareVersion"] !== common.chargePoint_softwareVersion)
|
|
9879
9904
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageText("Inconsistent_ChargingStation_FirmwareVersion")));
|
|
9880
|
-
const signedEVSEId = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") && asString(element.value)?.startsWith("evse-id:"));
|
|
9905
|
+
const signedEVSEId = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") === true && asString(element.value)?.startsWith("evse-id:") === true);
|
|
9881
9906
|
if (signedEVSEId.length == 1) {
|
|
9882
9907
|
const evse__id = (asString(signedEVSEId[0]?.value) ?? "").replace("evse-id:", "").trim();
|
|
9883
9908
|
if (evse__id !== "unknown" && ExpectedEVSEId !== evse__id)
|
|
9884
9909
|
currentErrors.push(CreateError(this.chargy.GetMultilanguageText("Inconsistent_EVSE_Identification")));
|
|
9885
9910
|
}
|
|
9886
|
-
const signedCSCSWVersion = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") && asString(element.value)?.startsWith("csc-sw-version:"));
|
|
9911
|
+
const signedCSCSWVersion = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") === true && asString(element.value)?.startsWith("csc-sw-version:") === true);
|
|
9887
9912
|
if (signedCSCSWVersion.length == 1) {
|
|
9888
9913
|
const csc_sw_version = asString(signedCSCSWVersion[0]?.value)?.replace("csc-sw-version:", "").trim() ?? null;
|
|
9889
9914
|
if (previousCscSwVersion !== null && previousCscSwVersion !== csc_sw_version)
|
|
@@ -9948,6 +9973,8 @@ var BSMCrypt01 = class extends ACrypt {
|
|
|
9948
9973
|
case "Evt":
|
|
9949
9974
|
Evt = asNumber(additionalValue.value) ?? NaN;
|
|
9950
9975
|
break;
|
|
9976
|
+
default:
|
|
9977
|
+
break;
|
|
9951
9978
|
}
|
|
9952
9979
|
}
|
|
9953
9980
|
const currentRCRValue = asNumber(RCR?.value) ?? NaN;
|
|
@@ -10010,18 +10037,17 @@ var BSMCrypt01 = class extends ACrypt {
|
|
|
10010
10037
|
});
|
|
10011
10038
|
}
|
|
10012
10039
|
const n = common.dataSets.length - 1;
|
|
10013
|
-
const firstDataSet = common.dataSets
|
|
10014
|
-
const lastDataSet = common.dataSets
|
|
10015
|
-
if (firstDataSet
|
|
10040
|
+
const firstDataSet = getFirstArrayElement(common.dataSets, "Missing first BSM data set");
|
|
10041
|
+
const lastDataSet = getArrayElement(common.dataSets, n, "Missing last BSM data set");
|
|
10042
|
+
if (firstDataSet.TypParsed !== "START" && firstDataSet.TypParsed !== "TURN ON")
|
|
10016
10043
|
throw new Error(this.chargy.GetLocalizedMessageWithParameter("Inconsistent_EnergyMeterValueP", 1));
|
|
10017
10044
|
for (let i = 1; i < common.dataSets.length - 1; i++) {
|
|
10018
10045
|
if (common.dataSets[i]?.TypParsed !== "CURRENT")
|
|
10019
10046
|
errors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_EnergyMeterValueP", measurementCounter + 1)));
|
|
10020
10047
|
}
|
|
10021
|
-
if (lastDataSet
|
|
10048
|
+
if (lastDataSet.TypParsed !== "END" && lastDataSet.TypParsed !== "TURN OFF")
|
|
10022
10049
|
throw new Error(this.chargy.GetLocalizedMessageWithParameter("Inconsistent_EnergyMeterValueP", n + 1));
|
|
10023
|
-
|
|
10024
|
-
CTR.chargingSessions = [];
|
|
10050
|
+
CTR.chargingSessions ??= [];
|
|
10025
10051
|
const ASN1_SignatureSchema = this.chargy.asn1.define("Signature", function() {
|
|
10026
10052
|
this.seq().obj(
|
|
10027
10053
|
this.key("r").int(),
|
|
@@ -10138,12 +10164,12 @@ var BSMCrypt01 = class extends ACrypt {
|
|
|
10138
10164
|
CTR.chargingSessions.push(session);
|
|
10139
10165
|
CTR["@id"] = common.meterInfo_meterId + "-" + String(firstDataSet.Epoch);
|
|
10140
10166
|
{
|
|
10141
|
-
const firstChargingSession = CTR.chargingSessions
|
|
10142
|
-
const lastChargingSession = CTR.chargingSessions
|
|
10143
|
-
if (
|
|
10167
|
+
const firstChargingSession = getFirstArrayElement(CTR.chargingSessions, "Missing first BSM charging session");
|
|
10168
|
+
const lastChargingSession = getLastArrayElement(CTR.chargingSessions, "Missing last BSM charging session");
|
|
10169
|
+
if (CTR.begin == void 0 || CTR.begin === "" || CTR.begin > firstChargingSession.begin) {
|
|
10144
10170
|
CTR.begin = firstChargingSession.begin;
|
|
10145
10171
|
}
|
|
10146
|
-
if (lastChargingSession
|
|
10172
|
+
if (lastChargingSession.end !== void 0) {
|
|
10147
10173
|
if (CTR.end == void 0 || CTR.end === "" || CTR.end < lastChargingSession.end)
|
|
10148
10174
|
CTR.end = lastChargingSession.end;
|
|
10149
10175
|
}
|
|
@@ -10315,58 +10341,63 @@ var BSMCrypt01 = class extends ACrypt {
|
|
|
10315
10341
|
}
|
|
10316
10342
|
return {};
|
|
10317
10343
|
}
|
|
10318
|
-
async ViewMeasurement(measurementValue,
|
|
10344
|
+
async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
|
|
10319
10345
|
if (measurementValue.measurement === void 0)
|
|
10320
10346
|
return new Error("Invalid measurement!");
|
|
10321
10347
|
const result = measurementValue.result;
|
|
10322
10348
|
introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "BSMCrypt01").replace("{cryptoAlgorithm}", this.description);
|
|
10323
|
-
if (PlainTextDiv.parentElement
|
|
10324
|
-
PlainTextDiv.parentElement.children
|
|
10349
|
+
if (PlainTextDiv.parentElement) {
|
|
10350
|
+
getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = "Plain text (" + measurementValue.result.ArraySize.toString() + " Bytes, hex)";
|
|
10325
10351
|
}
|
|
10326
10352
|
PlainTextDiv.style.fontFamily = "";
|
|
10327
10353
|
PlainTextDiv.style.whiteSpace = "";
|
|
10328
10354
|
PlainTextDiv.style.maxHeight = "";
|
|
10329
10355
|
PlainTextDiv.style.overflowY = "";
|
|
10330
|
-
this.CreateLine("Snapshot-Typ", this.ParseTyp(measurementValue.Typ), result.Typ
|
|
10331
|
-
this.CreateLine("RCR", (measurementValue.RCR * 10 ** measurementValue.RCR_SF).toString() + " " + measurementValue.RCR_Unit, result.RCR
|
|
10332
|
-
this.CreateLine("TotWhImp", (measurementValue.TotWhImp * 10 ** measurementValue.TotWhImp_SF).toString() + " " + measurementValue.TotWhImp_Unit, result.TotWhImp
|
|
10333
|
-
this.CreateLine("W", (measurementValue.W * 10 ** measurementValue.W_SF).toString() + " " + measurementValue.W_Unit, result.W
|
|
10334
|
-
this.CreateLine("MA1", measurementValue.MA1, result.MA1
|
|
10335
|
-
this.CreateLine("RCnt", measurementValue.RCnt, result.RCnt
|
|
10336
|
-
this.CreateLine("OS", measurementValue.OS, result.OS
|
|
10337
|
-
this.CreateLine("Zeitstempel", UTC2human(measurementValue.Epoch), result.Epoch
|
|
10338
|
-
this.CreateLine("TZO", measurementValue.TZO.toString() + " Minuten", result.TZO
|
|
10339
|
-
this.CreateLine("EpochSetCnt", measurementValue.EpochSetCnt, result.EpochSetCnt
|
|
10340
|
-
this.CreateLine("EpochSetOS", measurementValue.EpochSetOS, result.EpochSetOS
|
|
10341
|
-
this.CreateLine("DI", measurementValue.DI, result.DI
|
|
10342
|
-
this.CreateLine("DO", measurementValue.DO, result.DO
|
|
10343
|
-
this.CreateLine("Meta1", measurementValue.Meta1, result.Meta1
|
|
10344
|
-
this.CreateLine("Meta2", measurementValue.Meta2, result.Meta2
|
|
10345
|
-
this.CreateLine("Meta3", measurementValue.Meta3, result.Meta3
|
|
10346
|
-
this.CreateLine("Evt", this.ParseEvents(measurementValue.Evt).join("<br>"), result.Evt
|
|
10347
|
-
if (HashedPlainTextDiv.parentElement
|
|
10348
|
-
HashedPlainTextDiv.parentElement.children
|
|
10356
|
+
this.CreateLine("Snapshot-Typ", this.ParseTyp(measurementValue.Typ), result.Typ, infoDiv, PlainTextDiv);
|
|
10357
|
+
this.CreateLine("RCR", (measurementValue.RCR * 10 ** measurementValue.RCR_SF).toString() + " " + measurementValue.RCR_Unit, result.RCR, infoDiv, PlainTextDiv);
|
|
10358
|
+
this.CreateLine("TotWhImp", (measurementValue.TotWhImp * 10 ** measurementValue.TotWhImp_SF).toString() + " " + measurementValue.TotWhImp_Unit, result.TotWhImp, infoDiv, PlainTextDiv);
|
|
10359
|
+
this.CreateLine("W", (measurementValue.W * 10 ** measurementValue.W_SF).toString() + " " + measurementValue.W_Unit, result.W, infoDiv, PlainTextDiv);
|
|
10360
|
+
this.CreateLine("MA1", measurementValue.MA1, result.MA1, infoDiv, PlainTextDiv);
|
|
10361
|
+
this.CreateLine("RCnt", measurementValue.RCnt, result.RCnt, infoDiv, PlainTextDiv);
|
|
10362
|
+
this.CreateLine("OS", measurementValue.OS, result.OS, infoDiv, PlainTextDiv);
|
|
10363
|
+
this.CreateLine("Zeitstempel", UTC2human(measurementValue.Epoch), result.Epoch, infoDiv, PlainTextDiv);
|
|
10364
|
+
this.CreateLine("TZO", measurementValue.TZO.toString() + " Minuten", result.TZO, infoDiv, PlainTextDiv);
|
|
10365
|
+
this.CreateLine("EpochSetCnt", measurementValue.EpochSetCnt, result.EpochSetCnt, infoDiv, PlainTextDiv);
|
|
10366
|
+
this.CreateLine("EpochSetOS", measurementValue.EpochSetOS, result.EpochSetOS, infoDiv, PlainTextDiv);
|
|
10367
|
+
this.CreateLine("DI", measurementValue.DI, result.DI, infoDiv, PlainTextDiv);
|
|
10368
|
+
this.CreateLine("DO", measurementValue.DO, result.DO, infoDiv, PlainTextDiv);
|
|
10369
|
+
this.CreateLine("Meta1", measurementValue.Meta1, result.Meta1, infoDiv, PlainTextDiv);
|
|
10370
|
+
this.CreateLine("Meta2", measurementValue.Meta2, result.Meta2, infoDiv, PlainTextDiv);
|
|
10371
|
+
this.CreateLine("Meta3", measurementValue.Meta3, result.Meta3, infoDiv, PlainTextDiv);
|
|
10372
|
+
this.CreateLine("Evt", this.ParseEvents(measurementValue.Evt).join("<br>"), result.Evt, infoDiv, PlainTextDiv);
|
|
10373
|
+
if (HashedPlainTextDiv.parentElement) {
|
|
10374
|
+
getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = "Hashed plain text (SHA256, hex)";
|
|
10349
10375
|
}
|
|
10350
10376
|
HashedPlainTextDiv.innerHTML = result.sha256value?.match(/.{1,8}/g)?.join(" ") ?? "";
|
|
10351
10377
|
if (result.publicKey != null && result.publicKey != "") {
|
|
10352
|
-
if (PublicKeyDiv.parentElement
|
|
10353
|
-
PublicKeyDiv.parentElement.children
|
|
10378
|
+
if (PublicKeyDiv.parentElement) {
|
|
10379
|
+
getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = "Public Key (" + (result.publicKeyFormat != null && result.publicKeyFormat.length > 0 ? result.publicKeyFormat + ", " : "") + "hex)";
|
|
10354
10380
|
}
|
|
10355
10381
|
if (!IsNullOrEmpty(result.publicKey))
|
|
10356
10382
|
PublicKeyDiv.innerHTML = result.publicKey.startsWith("04") ? '<span class="leadingFour">04</span> ' + (result.publicKey.substring(2).match(/.{1,8}/g)?.join(" ") ?? "-") : result.publicKey.match(/.{1,8}/g)?.join(" ") ?? "-";
|
|
10357
|
-
|
|
10358
|
-
|
|
10383
|
+
const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
|
|
10384
|
+
if (publicKeySignatureContainer !== void 0) {
|
|
10385
|
+
publicKeySignatureContainer.innerHTML = "";
|
|
10359
10386
|
}
|
|
10360
10387
|
if (result.publicKeySignatures) {
|
|
10361
10388
|
for (const signature of result.publicKeySignatures) {
|
|
10362
10389
|
try {
|
|
10363
|
-
const signatureDiv =
|
|
10364
|
-
|
|
10390
|
+
const signatureDiv = publicKeySignatureContainer?.appendChild(document.createElement("div"));
|
|
10391
|
+
const chargingSession = measurementValue.measurement.chargingSession;
|
|
10392
|
+
const evse = chargingSession?.EVSE;
|
|
10393
|
+
const meter = evse?.meters.at(0);
|
|
10394
|
+
const publicKey = meter?.publicKeys?.at(0);
|
|
10395
|
+
if (signatureDiv != null && chargingSession != null && evse != null && meter != null && publicKey != null) {
|
|
10365
10396
|
signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
|
|
10366
|
-
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
|
|
10397
|
+
chargingSession.chargingStation,
|
|
10398
|
+
evse,
|
|
10399
|
+
meter,
|
|
10400
|
+
publicKey,
|
|
10370
10401
|
signature
|
|
10371
10402
|
);
|
|
10372
10403
|
}
|
|
@@ -10377,12 +10408,12 @@ var BSMCrypt01 = class extends ACrypt {
|
|
|
10377
10408
|
}
|
|
10378
10409
|
}
|
|
10379
10410
|
if (result.signature != null) {
|
|
10380
|
-
if (SignatureExpectedDiv.parentElement
|
|
10381
|
-
SignatureExpectedDiv.parentElement.children
|
|
10411
|
+
if (SignatureExpectedDiv.parentElement) {
|
|
10412
|
+
getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = "Erwartete Signatur (" + (result.signature.format ?? "") + ", hex)";
|
|
10382
10413
|
}
|
|
10383
|
-
if (result.signature.r && result.signature.s)
|
|
10414
|
+
if (result.signature.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0)
|
|
10384
10415
|
SignatureExpectedDiv.innerHTML = "r: " + (result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-") + "<br />s: " + (result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-");
|
|
10385
|
-
else if (result.signature.value)
|
|
10416
|
+
else if (result.signature.value != null && result.signature.value.length > 0)
|
|
10386
10417
|
SignatureExpectedDiv.innerHTML = result.signature.value.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
|
|
10387
10418
|
}
|
|
10388
10419
|
switch (result.status) {
|
|
@@ -10408,6 +10439,7 @@ var BSMCrypt01 = class extends ACrypt {
|
|
|
10408
10439
|
SignatureCheckDiv.innerHTML = '<i class="fas fa-times-circle"></i><div id="description">Ung\xFCltige Signatur</div>';
|
|
10409
10440
|
break;
|
|
10410
10441
|
}
|
|
10442
|
+
return void 0;
|
|
10411
10443
|
}
|
|
10412
10444
|
//#region Helper methods
|
|
10413
10445
|
PrefixConverter(input) {
|
|
@@ -10486,30 +10518,35 @@ var BSMCrypt01 = class extends ACrypt {
|
|
|
10486
10518
|
if ((value & 1 << 29) != 0) events.push("OEM 15");
|
|
10487
10519
|
return events;
|
|
10488
10520
|
}
|
|
10489
|
-
DecodeStatus(statusValue)
|
|
10490
|
-
|
|
10491
|
-
|
|
10492
|
-
|
|
10493
|
-
|
|
10494
|
-
|
|
10495
|
-
|
|
10496
|
-
|
|
10497
|
-
|
|
10498
|
-
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
|
|
10502
|
-
|
|
10503
|
-
|
|
10504
|
-
|
|
10505
|
-
|
|
10506
|
-
|
|
10507
|
-
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
|
|
10521
|
+
// private DecodeStatus(statusValue: string) : Array<string>
|
|
10522
|
+
// {
|
|
10523
|
+
// const statusArray:string[] = [];
|
|
10524
|
+
// try
|
|
10525
|
+
// {
|
|
10526
|
+
// const status = parseInt(statusValue);
|
|
10527
|
+
// if ((status & 1) == 1)
|
|
10528
|
+
// statusArray.push("Fehler erkannt");
|
|
10529
|
+
// if ((status & 2) == 2)
|
|
10530
|
+
// statusArray.push("Synchrone Messwertübermittlung");
|
|
10531
|
+
// // Bit 3 is reserved!
|
|
10532
|
+
// if ((status & 8) == 8)
|
|
10533
|
+
// statusArray.push("System-Uhr ist synchron");
|
|
10534
|
+
// else
|
|
10535
|
+
// statusArray.push("System-Uhr ist nicht synchron");
|
|
10536
|
+
// if ((status & 16) == 16)
|
|
10537
|
+
// statusArray.push("Rücklaufsperre aktiv");
|
|
10538
|
+
// if ((status & 32) == 32)
|
|
10539
|
+
// statusArray.push("Energierichtung -A");
|
|
10540
|
+
// if ((status & 64) == 64)
|
|
10541
|
+
// statusArray.push("Magnetfeld erkannt");
|
|
10542
|
+
// }
|
|
10543
|
+
// catch
|
|
10544
|
+
// {
|
|
10545
|
+
// statusArray.push("Invalid status!");
|
|
10546
|
+
// }
|
|
10547
|
+
// return statusArray;
|
|
10548
|
+
// }
|
|
10549
|
+
// //#endregion
|
|
10513
10550
|
};
|
|
10514
10551
|
|
|
10515
10552
|
// src/CanonicalJSON.ts
|
|
@@ -10909,7 +10946,7 @@ var EMHCrypt01 = class extends ACrypt {
|
|
|
10909
10946
|
measurementValue.result = cryptoResult;
|
|
10910
10947
|
return cryptoResult;
|
|
10911
10948
|
}
|
|
10912
|
-
if (measurementValue.measurement
|
|
10949
|
+
if (measurementValue.measurement?.chargingSession === void 0) {
|
|
10913
10950
|
return {
|
|
10914
10951
|
status: "InvalidMeasurement" /* InvalidMeasurement */
|
|
10915
10952
|
};
|
|
@@ -10948,9 +10985,10 @@ var EMHCrypt01 = class extends ACrypt {
|
|
|
10948
10985
|
cryptoResult.meter = meter;
|
|
10949
10986
|
if (meter.publicKeys != null && meter.publicKeys.length > 0) {
|
|
10950
10987
|
try {
|
|
10951
|
-
|
|
10952
|
-
cryptoResult.
|
|
10953
|
-
cryptoResult.
|
|
10988
|
+
const publicKey = meter.publicKeys.at(0);
|
|
10989
|
+
cryptoResult.publicKey = publicKey?.value?.toLowerCase();
|
|
10990
|
+
cryptoResult.publicKeyFormat = publicKey?.format;
|
|
10991
|
+
cryptoResult.publicKeySignatures = publicKey?.signatures;
|
|
10954
10992
|
try {
|
|
10955
10993
|
if (this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex").verify(
|
|
10956
10994
|
cryptoResult.sha256value,
|
|
@@ -10975,59 +11013,60 @@ var EMHCrypt01 = class extends ACrypt {
|
|
|
10975
11013
|
}
|
|
10976
11014
|
return {};
|
|
10977
11015
|
}
|
|
10978
|
-
async ViewMeasurement(measurementValue,
|
|
10979
|
-
if (measurementValue.measurement
|
|
11016
|
+
async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
|
|
11017
|
+
if (measurementValue.measurement?.chargingSession?.authorizationStart.timestamp === void 0) {
|
|
10980
11018
|
return new Error("Invalid measurement!");
|
|
10981
11019
|
}
|
|
10982
11020
|
const result = measurementValue.result;
|
|
10983
11021
|
introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "EMHCrypt01").replace("{cryptoAlgorithm}", this.description);
|
|
10984
11022
|
{
|
|
10985
|
-
if (PlainTextDiv.parentElement
|
|
10986
|
-
PlainTextDiv.parentElement.children
|
|
11023
|
+
if (PlainTextDiv.parentElement) {
|
|
11024
|
+
getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = "Plain text (320 Bytes, hex)";
|
|
10987
11025
|
}
|
|
10988
11026
|
PlainTextDiv.style.fontFamily = "";
|
|
10989
11027
|
PlainTextDiv.style.whiteSpace = "";
|
|
10990
11028
|
PlainTextDiv.style.maxHeight = "";
|
|
10991
11029
|
PlainTextDiv.style.overflowY = "";
|
|
10992
|
-
this.CreateLine("Z\xE4hlernummer", measurementValue.measurement.energyMeterId, result.meterId
|
|
10993
|
-
this.CreateLine("Zeitstempel", UTC2human(measurementValue.timestamp), result.timestamp
|
|
10994
|
-
this.CreateLine("Status", hex2bin(measurementValue.infoStatus) + " (" + measurementValue.infoStatus + ' hex)<br /><span class="statusInfos">' + this.DecodeStatus(measurementValue.infoStatus).join("<br />") + "</span>", result.infoStatus
|
|
10995
|
-
this.CreateLine("Sekundenindex", measurementValue.secondsIndex, result.secondsIndex
|
|
10996
|
-
this.CreateLine("Paginierungsz\xE4hler", parseInt(measurementValue.paginationId, 16), result.paginationId
|
|
10997
|
-
this.CreateLine("OBIS-Kennzahl", measurementValue.measurement.obis, result.obis
|
|
10998
|
-
this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded
|
|
10999
|
-
this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale
|
|
11000
|
-
this.CreateLine("Messwert", measurementValue.value.toString() + " Wh", result.value
|
|
11001
|
-
this.CreateLine("Logbuchindex", measurementValue.logBookIndex + " hex", result.logBookIndex
|
|
11002
|
-
this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128)
|
|
11003
|
-
this.CreateLine("Autorisierungszeitpunkt", UTC2human(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151)
|
|
11030
|
+
this.CreateLine("Z\xE4hlernummer", measurementValue.measurement.energyMeterId, result.meterId ?? "", infoDiv, PlainTextDiv);
|
|
11031
|
+
this.CreateLine("Zeitstempel", UTC2human(measurementValue.timestamp), result.timestamp ?? "", infoDiv, PlainTextDiv);
|
|
11032
|
+
this.CreateLine("Status", hex2bin(measurementValue.infoStatus) + " (" + measurementValue.infoStatus + ' hex)<br /><span class="statusInfos">' + this.DecodeStatus(measurementValue.infoStatus).join("<br />") + "</span>", result.infoStatus ?? "", infoDiv, PlainTextDiv);
|
|
11033
|
+
this.CreateLine("Sekundenindex", measurementValue.secondsIndex, result.secondsIndex ?? "", infoDiv, PlainTextDiv);
|
|
11034
|
+
this.CreateLine("Paginierungsz\xE4hler", parseInt(measurementValue.paginationId, 16), result.paginationId ?? "", infoDiv, PlainTextDiv);
|
|
11035
|
+
this.CreateLine("OBIS-Kennzahl", measurementValue.measurement.obis, result.obis ?? "", infoDiv, PlainTextDiv);
|
|
11036
|
+
this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded ?? "", infoDiv, PlainTextDiv);
|
|
11037
|
+
this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale ?? "", infoDiv, PlainTextDiv);
|
|
11038
|
+
this.CreateLine("Messwert", measurementValue.value.toString() + " Wh", result.value ?? "", infoDiv, PlainTextDiv);
|
|
11039
|
+
this.CreateLine("Logbuchindex", measurementValue.logBookIndex + " hex", result.logBookIndex ?? "", infoDiv, PlainTextDiv);
|
|
11040
|
+
this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128), infoDiv, PlainTextDiv);
|
|
11041
|
+
this.CreateLine("Autorisierungszeitpunkt", UTC2human(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151), infoDiv, PlainTextDiv);
|
|
11004
11042
|
}
|
|
11005
11043
|
{
|
|
11006
|
-
if (HashedPlainTextDiv.parentElement
|
|
11007
|
-
HashedPlainTextDiv.parentElement.children
|
|
11044
|
+
if (HashedPlainTextDiv.parentElement) {
|
|
11045
|
+
getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = "Hashed plain text (SHA256, 24 bytes, hex)";
|
|
11008
11046
|
}
|
|
11009
11047
|
HashedPlainTextDiv.innerHTML = result.sha256value?.match(/.{1,8}/g)?.join(" ") ?? "";
|
|
11010
11048
|
}
|
|
11011
11049
|
if (result.publicKey != null && result.publicKey != "") {
|
|
11012
|
-
if (PublicKeyDiv.parentElement
|
|
11013
|
-
PublicKeyDiv.parentElement.children
|
|
11050
|
+
if (PublicKeyDiv.parentElement) {
|
|
11051
|
+
getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = "Public Key (" + (result.publicKeyFormat != null && result.publicKeyFormat.length > 0 ? result.publicKeyFormat + ", " : "") + "hex)";
|
|
11014
11052
|
}
|
|
11015
11053
|
if (!IsNullOrEmpty(result.publicKey))
|
|
11016
11054
|
PublicKeyDiv.innerHTML = result.publicKey.startsWith("04") ? '<span class="leadingFour">04</span> ' + (result.publicKey.substring(2).match(/.{1,8}/g)?.join(" ") ?? "") : result.publicKey.match(/.{1,8}/g)?.join(" ") ?? "";
|
|
11017
|
-
|
|
11018
|
-
|
|
11055
|
+
const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
|
|
11056
|
+
if (publicKeySignatureContainer !== void 0) {
|
|
11057
|
+
publicKeySignatureContainer.innerHTML = "";
|
|
11019
11058
|
}
|
|
11020
11059
|
if (result.publicKeySignatures) {
|
|
11021
11060
|
for (const signature of result.publicKeySignatures) {
|
|
11022
11061
|
try {
|
|
11023
|
-
const signatureDiv =
|
|
11062
|
+
const signatureDiv = publicKeySignatureContainer?.appendChild(document.createElement("div"));
|
|
11024
11063
|
if (signatureDiv) {
|
|
11025
11064
|
signatureDiv.classList.add("signature");
|
|
11026
11065
|
signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
|
|
11027
11066
|
measurementValue.measurement.chargingSession.chargingStation,
|
|
11028
11067
|
measurementValue.measurement.chargingSession.EVSE,
|
|
11029
|
-
measurementValue.measurement.chargingSession.EVSE?.meters
|
|
11030
|
-
measurementValue.measurement.chargingSession.EVSE?.meters
|
|
11068
|
+
measurementValue.measurement.chargingSession.EVSE?.meters.at(0),
|
|
11069
|
+
measurementValue.measurement.chargingSession.EVSE?.meters.at(0)?.publicKeys?.at(0),
|
|
11031
11070
|
signature
|
|
11032
11071
|
);
|
|
11033
11072
|
signatureDiv.onclick = () => {
|
|
@@ -11041,12 +11080,12 @@ var EMHCrypt01 = class extends ACrypt {
|
|
|
11041
11080
|
}
|
|
11042
11081
|
}
|
|
11043
11082
|
if (result.signature != null) {
|
|
11044
|
-
if (SignatureExpectedDiv.parentElement
|
|
11045
|
-
SignatureExpectedDiv.parentElement.children
|
|
11083
|
+
if (SignatureExpectedDiv.parentElement) {
|
|
11084
|
+
getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = "Erwartete Signatur (" + (result.signature.format ?? "") + ", hex)";
|
|
11046
11085
|
}
|
|
11047
|
-
if (result.signature.r && result.signature.s)
|
|
11086
|
+
if (result.signature.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0)
|
|
11048
11087
|
SignatureExpectedDiv.innerHTML = "r: " + (result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") + "<br />s: " + (result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "");
|
|
11049
|
-
else if (result.signature.value)
|
|
11088
|
+
else if (result.signature.value != null && result.signature.value.length > 0)
|
|
11050
11089
|
SignatureExpectedDiv.innerHTML = result.signature.value.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
|
|
11051
11090
|
}
|
|
11052
11091
|
{
|
|
@@ -11074,6 +11113,7 @@ var EMHCrypt01 = class extends ACrypt {
|
|
|
11074
11113
|
break;
|
|
11075
11114
|
}
|
|
11076
11115
|
}
|
|
11116
|
+
return void 0;
|
|
11077
11117
|
}
|
|
11078
11118
|
//#region Helper methods
|
|
11079
11119
|
DecodeStatus(statusValue) {
|
|
@@ -11142,7 +11182,7 @@ var GDFCrypt01 = class extends ACrypt {
|
|
|
11142
11182
|
measurementValue.result = cryptoResult;
|
|
11143
11183
|
return cryptoResult;
|
|
11144
11184
|
}
|
|
11145
|
-
if (measurementValue.measurement
|
|
11185
|
+
if (measurementValue.measurement?.chargingSession === void 0) {
|
|
11146
11186
|
return {
|
|
11147
11187
|
status: "InvalidMeasurement" /* InvalidMeasurement */
|
|
11148
11188
|
};
|
|
@@ -11177,9 +11217,10 @@ var GDFCrypt01 = class extends ACrypt {
|
|
|
11177
11217
|
cryptoResult.meter = meter;
|
|
11178
11218
|
if (meter.publicKeys != null && meter.publicKeys.length > 0) {
|
|
11179
11219
|
try {
|
|
11180
|
-
|
|
11181
|
-
cryptoResult.
|
|
11182
|
-
cryptoResult.
|
|
11220
|
+
const publicKey = meter.publicKeys.at(0);
|
|
11221
|
+
cryptoResult.publicKey = publicKey?.value?.toLowerCase();
|
|
11222
|
+
cryptoResult.publicKeyFormat = publicKey?.format;
|
|
11223
|
+
cryptoResult.publicKeySignatures = publicKey?.signatures;
|
|
11183
11224
|
try {
|
|
11184
11225
|
if (this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex").verify(
|
|
11185
11226
|
cryptoResult.sha256value,
|
|
@@ -11204,54 +11245,55 @@ var GDFCrypt01 = class extends ACrypt {
|
|
|
11204
11245
|
}
|
|
11205
11246
|
return {};
|
|
11206
11247
|
}
|
|
11207
|
-
async ViewMeasurement(measurementValue,
|
|
11208
|
-
if (measurementValue.measurement
|
|
11248
|
+
async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
|
|
11249
|
+
if (measurementValue.measurement?.chargingSession?.authorizationStart.timestamp === void 0) {
|
|
11209
11250
|
return new Error("Invalid measurement!");
|
|
11210
11251
|
}
|
|
11211
11252
|
const result = measurementValue.result;
|
|
11212
11253
|
introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "GDFCrypt01").replace("{cryptoAlgorithm}", this.description);
|
|
11213
11254
|
{
|
|
11214
|
-
if (PlainTextDiv.parentElement
|
|
11215
|
-
PlainTextDiv.parentElement.children
|
|
11255
|
+
if (PlainTextDiv.parentElement) {
|
|
11256
|
+
getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = "Plain text (320 Bytes, hex)";
|
|
11216
11257
|
}
|
|
11217
11258
|
PlainTextDiv.style.fontFamily = "";
|
|
11218
11259
|
PlainTextDiv.style.whiteSpace = "";
|
|
11219
11260
|
PlainTextDiv.style.maxHeight = "";
|
|
11220
11261
|
PlainTextDiv.style.overflowY = "";
|
|
11221
|
-
this.CreateLine("Z\xE4hlernummer", measurementValue.measurement.energyMeterId, result.meterId
|
|
11222
|
-
this.CreateLine("Zeitstempel", UTC2human(measurementValue.timestamp), result.timestamp
|
|
11223
|
-
this.CreateLine("OBIS-Kennzahl", measurementValue.measurement.obis, result.obis
|
|
11224
|
-
this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded
|
|
11225
|
-
this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale
|
|
11226
|
-
this.CreateLine("Messwert", measurementValue.value.toString() + " Wh", result.value
|
|
11227
|
-
this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128)
|
|
11228
|
-
this.CreateLine("Autorisierungszeitpunkt", UTC2human(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151)
|
|
11262
|
+
this.CreateLine("Z\xE4hlernummer", measurementValue.measurement.energyMeterId, result.meterId ?? "", infoDiv, PlainTextDiv);
|
|
11263
|
+
this.CreateLine("Zeitstempel", UTC2human(measurementValue.timestamp), result.timestamp ?? "", infoDiv, PlainTextDiv);
|
|
11264
|
+
this.CreateLine("OBIS-Kennzahl", measurementValue.measurement.obis, result.obis ?? "", infoDiv, PlainTextDiv);
|
|
11265
|
+
this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded ?? "", infoDiv, PlainTextDiv);
|
|
11266
|
+
this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale ?? "", infoDiv, PlainTextDiv);
|
|
11267
|
+
this.CreateLine("Messwert", measurementValue.value.toString() + " Wh", result.value ?? "", infoDiv, PlainTextDiv);
|
|
11268
|
+
this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128), infoDiv, PlainTextDiv);
|
|
11269
|
+
this.CreateLine("Autorisierungszeitpunkt", UTC2human(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151), infoDiv, PlainTextDiv);
|
|
11229
11270
|
}
|
|
11230
11271
|
{
|
|
11231
|
-
if (HashedPlainTextDiv.parentElement
|
|
11232
|
-
HashedPlainTextDiv.parentElement.children
|
|
11272
|
+
if (HashedPlainTextDiv.parentElement) {
|
|
11273
|
+
getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = "Hashed plain text (SHA256, 24 bytes, hex)";
|
|
11233
11274
|
}
|
|
11234
11275
|
HashedPlainTextDiv.innerHTML = result.sha256value?.match(/.{1,8}/g)?.join(" ") ?? "";
|
|
11235
11276
|
}
|
|
11236
11277
|
if (result.publicKey != null && result.publicKey != "") {
|
|
11237
|
-
if (PublicKeyDiv.parentElement
|
|
11238
|
-
PublicKeyDiv.parentElement.children
|
|
11278
|
+
if (PublicKeyDiv.parentElement) {
|
|
11279
|
+
getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = "Public Key (" + (result.publicKeyFormat != null && result.publicKeyFormat.length > 0 ? result.publicKeyFormat + ", " : "") + "hex)";
|
|
11239
11280
|
}
|
|
11240
11281
|
if (!IsNullOrEmpty(result.publicKey))
|
|
11241
11282
|
PublicKeyDiv.innerHTML = result.publicKey.startsWith("04") ? '<span class="leadingFour">04</span> ' + (result.publicKey.substring(2).match(/.{1,8}/g)?.join(" ") ?? "") : result.publicKey.match(/.{1,8}/g)?.join(" ") ?? "";
|
|
11242
|
-
|
|
11243
|
-
|
|
11283
|
+
const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
|
|
11284
|
+
if (publicKeySignatureContainer !== void 0) {
|
|
11285
|
+
publicKeySignatureContainer.innerHTML = "";
|
|
11244
11286
|
}
|
|
11245
11287
|
if (result.publicKeySignatures) {
|
|
11246
11288
|
for (const signature of result.publicKeySignatures) {
|
|
11247
11289
|
try {
|
|
11248
|
-
const signatureDiv =
|
|
11290
|
+
const signatureDiv = publicKeySignatureContainer?.appendChild(document.createElement("div"));
|
|
11249
11291
|
if (signatureDiv != null)
|
|
11250
11292
|
signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
|
|
11251
11293
|
measurementValue.measurement.chargingSession.chargingStation,
|
|
11252
11294
|
measurementValue.measurement.chargingSession.EVSE,
|
|
11253
|
-
measurementValue.measurement.chargingSession.EVSE?.meters
|
|
11254
|
-
measurementValue.measurement.chargingSession.EVSE?.meters
|
|
11295
|
+
measurementValue.measurement.chargingSession.EVSE?.meters.at(0),
|
|
11296
|
+
measurementValue.measurement.chargingSession.EVSE?.meters.at(0)?.publicKeys?.at(0),
|
|
11255
11297
|
signature
|
|
11256
11298
|
);
|
|
11257
11299
|
} catch (exception) {
|
|
@@ -11261,12 +11303,12 @@ var GDFCrypt01 = class extends ACrypt {
|
|
|
11261
11303
|
}
|
|
11262
11304
|
}
|
|
11263
11305
|
if (result.signature != null) {
|
|
11264
|
-
if (SignatureExpectedDiv.parentElement
|
|
11265
|
-
SignatureExpectedDiv.parentElement.children
|
|
11306
|
+
if (SignatureExpectedDiv.parentElement) {
|
|
11307
|
+
getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = "Erwartete Signatur (" + (result.signature.format ?? "") + ", hex)";
|
|
11266
11308
|
}
|
|
11267
|
-
if (result.signature.r && result.signature.s)
|
|
11309
|
+
if (result.signature.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0)
|
|
11268
11310
|
SignatureExpectedDiv.innerHTML = "r: " + (result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") + "<br />s: " + (result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "");
|
|
11269
|
-
else if (result.signature.value)
|
|
11311
|
+
else if (result.signature.value != null && result.signature.value.length > 0)
|
|
11270
11312
|
SignatureExpectedDiv.innerHTML = result.signature.value.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
|
|
11271
11313
|
}
|
|
11272
11314
|
{
|
|
@@ -11294,6 +11336,7 @@ var GDFCrypt01 = class extends ACrypt {
|
|
|
11294
11336
|
break;
|
|
11295
11337
|
}
|
|
11296
11338
|
}
|
|
11339
|
+
return void 0;
|
|
11297
11340
|
}
|
|
11298
11341
|
};
|
|
11299
11342
|
var MENNEKES_EDL40_XMLNS = "http://www.mennekes.de/Mennekes.EdlVerification.xsd";
|
|
@@ -11540,7 +11583,7 @@ var MennekesCrypt01 = class extends ACrypt {
|
|
|
11540
11583
|
signedData.byteOffset + signedData.byteLength
|
|
11541
11584
|
);
|
|
11542
11585
|
cryptoResult.hashValue = (await sha256(new DataView(signedDataBuffer))).substring(0, 48);
|
|
11543
|
-
const publicKey = cleanHex(meter.publicKeys
|
|
11586
|
+
const publicKey = cleanHex(meter.publicKeys.at(0)?.value ?? measurement.publicKey);
|
|
11544
11587
|
if (publicKey.length !== 96)
|
|
11545
11588
|
return setResult("InvalidPublicKey" /* InvalidPublicKey */);
|
|
11546
11589
|
const result = this.curve192r1.keyFromPublic("04" + publicKey, "hex").verify(
|
|
@@ -11571,7 +11614,7 @@ var MennekesCrypt01 = class extends ACrypt {
|
|
|
11571
11614
|
PublicKeyDiv.innerHTML = result.publicKey?.match(/.{1,8}/g)?.join(" ") ?? "";
|
|
11572
11615
|
if (SignatureExpectedDiv.parentElement?.children[0])
|
|
11573
11616
|
SignatureExpectedDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Expected signature") + " (rs, hex)";
|
|
11574
|
-
SignatureExpectedDiv.innerHTML = result.signature?.r && result.signature.s ? "r: " + (result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") + "<br />s: " + (result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") : "";
|
|
11617
|
+
SignatureExpectedDiv.innerHTML = result.signature?.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0 ? "r: " + (result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") + "<br />s: " + (result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") : "";
|
|
11575
11618
|
SignatureCheckDiv.innerHTML = result.status === "ValidSignature" /* ValidSignature */ ? '<i class="fas fa-check-circle"></i><div id="description">' + this.chargy.GetLocalizedMessage("Valid signature") + "</div>" : '<i class="fas fa-times-circle"></i><div id="description">' + this.chargy.GetLocalizedMessage("Invalid signature") + "</div>";
|
|
11576
11619
|
return Promise.resolve(void 0);
|
|
11577
11620
|
}
|
|
@@ -11590,10 +11633,7 @@ function parseMennekesXMLDocument(XMLDocument) {
|
|
|
11590
11633
|
throw new Error("No Mennekes ChargingProcess element found!");
|
|
11591
11634
|
if (isLocalName(XMLDocument.documentElement, "ChargingProcess")) {
|
|
11592
11635
|
if (chargingProcesses.length > 1) {
|
|
11593
|
-
|
|
11594
|
-
if (chargingProcess != void 0)
|
|
11595
|
-
return chargingProcess;
|
|
11596
|
-
throw new Error("No Mennekes ChargingProcess found!");
|
|
11636
|
+
return getFirstArrayElement(chargingProcesses, "No Mennekes ChargingProcess found!");
|
|
11597
11637
|
}
|
|
11598
11638
|
}
|
|
11599
11639
|
return {
|
|
@@ -11716,8 +11756,8 @@ function toMennekesMeasurementValue(measurement) {
|
|
|
11716
11756
|
}
|
|
11717
11757
|
function validateMennekesLawConformity(measurementValues, chargy) {
|
|
11718
11758
|
const errors = new Array();
|
|
11719
|
-
const start = measurementValues
|
|
11720
|
-
const end = measurementValues
|
|
11759
|
+
const start = measurementValues.at(0);
|
|
11760
|
+
const end = measurementValues.at(-1);
|
|
11721
11761
|
if (start == null || end == null)
|
|
11722
11762
|
return [
|
|
11723
11763
|
CreateError(chargy.GetMultilanguageText("Mennekes EDL40 requires at least two measurement values."))
|
|
@@ -11847,9 +11887,9 @@ var OCMFv1_x = class extends ACrypt {
|
|
|
11847
11887
|
}
|
|
11848
11888
|
async VerifyMeasurement(measurementValue) {
|
|
11849
11889
|
measurementValue.method = this;
|
|
11850
|
-
return {
|
|
11890
|
+
return Promise.resolve({
|
|
11851
11891
|
status: measurementValue.result?.status ?? "Unvalidated" /* Unvalidated */
|
|
11852
|
-
};
|
|
11892
|
+
});
|
|
11853
11893
|
}
|
|
11854
11894
|
PayloadDictionary(Path, Key) {
|
|
11855
11895
|
if (Path === "RD") {
|
|
@@ -11919,7 +11959,7 @@ var OCMFv1_x = class extends ACrypt {
|
|
|
11919
11959
|
return Key;
|
|
11920
11960
|
}
|
|
11921
11961
|
}
|
|
11922
|
-
SignatureDictionary(
|
|
11962
|
+
SignatureDictionary(_Path, Key) {
|
|
11923
11963
|
switch (Key) {
|
|
11924
11964
|
case "SA":
|
|
11925
11965
|
return "Signature Algorithm";
|
|
@@ -11933,16 +11973,16 @@ var OCMFv1_x = class extends ACrypt {
|
|
|
11933
11973
|
return Key;
|
|
11934
11974
|
}
|
|
11935
11975
|
}
|
|
11936
|
-
async ViewMeasurement(measurementValue,
|
|
11976
|
+
async ViewMeasurement(measurementValue, _errorDiv, introDiv, _infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
|
|
11937
11977
|
if (!measurementValue.measurement || !measurementValue.ocmfDocument || !measurementValue.measurement.chargingSession) {
|
|
11938
11978
|
return new Error("Invalid measurement!");
|
|
11939
11979
|
}
|
|
11940
11980
|
{
|
|
11941
|
-
introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "OCMFCrypt01").replace("{cryptoAlgorithm}", measurementValue.ocmfDocument.publicKey && typeof measurementValue.ocmfDocument.publicKey !== "string" ? "(" + measurementValue.ocmfDocument.publicKey.algorithm + ") " : "");
|
|
11981
|
+
introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "OCMFCrypt01").replace("{cryptoAlgorithm}", measurementValue.ocmfDocument.publicKey != null && typeof measurementValue.ocmfDocument.publicKey !== "string" ? "(" + measurementValue.ocmfDocument.publicKey.algorithm + ") " : "");
|
|
11942
11982
|
}
|
|
11943
11983
|
{
|
|
11944
|
-
if (PlainTextDiv.parentElement
|
|
11945
|
-
PlainTextDiv.parentElement.children
|
|
11984
|
+
if (PlainTextDiv.parentElement) {
|
|
11985
|
+
getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = this.chargy.GetLocalizedMessage("Plain text") + " (OCMF|<" + this.chargy.GetLocalizedMessage("payload") + ">|<" + this.chargy.GetLocalizedMessage("signature") + ">)";
|
|
11946
11986
|
}
|
|
11947
11987
|
PlainTextDiv.innerText = "";
|
|
11948
11988
|
const compactValueDiv = document.createElement("div");
|
|
@@ -11974,29 +12014,30 @@ var OCMFv1_x = class extends ACrypt {
|
|
|
11974
12014
|
};
|
|
11975
12015
|
}
|
|
11976
12016
|
{
|
|
11977
|
-
if (HashedPlainTextDiv.parentElement
|
|
11978
|
-
HashedPlainTextDiv.parentElement.children
|
|
12017
|
+
if (HashedPlainTextDiv.parentElement) {
|
|
12018
|
+
getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed payload header").innerHTML = this.chargy.GetLocalizedMessage("Hashed payload") + " (" + measurementValue.ocmfDocument.hashAlgorithm + ")";
|
|
11979
12019
|
}
|
|
11980
12020
|
HashedPlainTextDiv.innerHTML = measurementValue.ocmfDocument.hashValue.match(/.{1,8}/g)?.join(" ") ?? "0x00000000000000000000000000000000000";
|
|
11981
12021
|
}
|
|
11982
|
-
if (measurementValue.ocmfDocument.publicKey) {
|
|
11983
|
-
if (PublicKeyDiv.parentElement
|
|
11984
|
-
PublicKeyDiv.parentElement.children
|
|
12022
|
+
if (measurementValue.ocmfDocument.publicKey != null) {
|
|
12023
|
+
if (PublicKeyDiv.parentElement) {
|
|
12024
|
+
getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = typeof measurementValue.ocmfDocument.publicKey === "string" ? this.chargy.GetLocalizedMessage("Public Key") : this.chargy.GetLocalizedMessage("Public Key") + " (" + measurementValue.ocmfDocument.publicKey.algorithm + ", " + measurementValue.ocmfDocument.publicKey.encoding + ")";
|
|
11985
12025
|
}
|
|
11986
12026
|
PublicKeyDiv.innerHTML = typeof measurementValue.ocmfDocument.publicKey === "string" ? measurementValue.ocmfDocument.publicKey : "der: " + (measurementValue.ocmfDocument.publicKey.value?.match(/.{1,8}/g)?.join(" ") ?? "-") + "<br /><br />x: " + (measurementValue.ocmfDocument.publicKey.x.match(/.{1,8}/g)?.join(" ") ?? "-") + "<br />y: " + (measurementValue.ocmfDocument.publicKey.y.match(/.{1,8}/g)?.join(" ") ?? "-");
|
|
11987
12027
|
}
|
|
11988
|
-
|
|
11989
|
-
|
|
12028
|
+
const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
|
|
12029
|
+
if (publicKeySignatureContainer !== void 0) {
|
|
12030
|
+
publicKeySignatureContainer.innerHTML = "";
|
|
11990
12031
|
const result = measurementValue.result;
|
|
11991
12032
|
if (result.publicKeySignatures) {
|
|
11992
12033
|
for (const signature of result.publicKeySignatures) {
|
|
11993
12034
|
try {
|
|
11994
|
-
const signatureDiv =
|
|
12035
|
+
const signatureDiv = publicKeySignatureContainer.appendChild(document.createElement("div"));
|
|
11995
12036
|
signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
|
|
11996
12037
|
measurementValue.measurement.chargingSession.chargingStation,
|
|
11997
12038
|
measurementValue.measurement.chargingSession.EVSE,
|
|
11998
|
-
measurementValue.measurement.chargingSession.EVSE?.meters
|
|
11999
|
-
measurementValue.measurement.chargingSession.EVSE?.meters
|
|
12039
|
+
measurementValue.measurement.chargingSession.EVSE?.meters.at(0),
|
|
12040
|
+
measurementValue.measurement.chargingSession.EVSE?.meters.at(0)?.publicKeys?.at(0),
|
|
12000
12041
|
signature
|
|
12001
12042
|
);
|
|
12002
12043
|
} catch {
|
|
@@ -12006,8 +12047,8 @@ var OCMFv1_x = class extends ACrypt {
|
|
|
12006
12047
|
}
|
|
12007
12048
|
}
|
|
12008
12049
|
if (measurementValue.ocmfDocument.signature.SD) {
|
|
12009
|
-
if (SignatureExpectedDiv.parentElement
|
|
12010
|
-
SignatureExpectedDiv.parentElement.children
|
|
12050
|
+
if (SignatureExpectedDiv.parentElement) {
|
|
12051
|
+
getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = this.chargy.GetLocalizedMessage("Expected signature") + " (rs, hex)";
|
|
12011
12052
|
}
|
|
12012
12053
|
SignatureExpectedDiv.innerHTML = "der: " + (measurementValue.ocmfDocument.signature.SD.match(/.{1,8}/g)?.join(" ") ?? "-") + "<br /><br />r: " + (measurementValue.ocmfDocument.signatureRS?.r?.toLowerCase().padStart(56, "0").match(/.{1,8}/g)?.join(" ") ?? "-") + "<br />s: " + (measurementValue.ocmfDocument.signatureRS?.s?.toLowerCase().padStart(56, "0").match(/.{1,8}/g)?.join(" ") ?? "-");
|
|
12013
12054
|
}
|
|
@@ -12030,6 +12071,7 @@ var OCMFv1_x = class extends ACrypt {
|
|
|
12030
12071
|
break;
|
|
12031
12072
|
}
|
|
12032
12073
|
}
|
|
12074
|
+
return void 0;
|
|
12033
12075
|
}
|
|
12034
12076
|
};
|
|
12035
12077
|
var OCMFTransactionTypes = /* @__PURE__ */ ((OCMFTransactionTypes2) => {
|
|
@@ -12062,268 +12104,270 @@ var OCMF = class {
|
|
|
12062
12104
|
const evseId = asString(containerInfos["EVSEId"]) ?? asString(evseInfo?.["@id"]) ?? "DE*GEF*EVSE*CHARGY*1";
|
|
12063
12105
|
const stationDescription = asJSONObject(chargingStationInfo?.["description"]);
|
|
12064
12106
|
const evseDescription = asJSONObject(evseInfo?.["description"]);
|
|
12065
|
-
const firstOCMDJSONDocument = OCMFJSONDocuments
|
|
12066
|
-
|
|
12067
|
-
|
|
12068
|
-
|
|
12069
|
-
|
|
12070
|
-
|
|
12071
|
-
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
|
|
12075
|
-
|
|
12076
|
-
|
|
12077
|
-
|
|
12078
|
-
|
|
12079
|
-
|
|
12080
|
-
|
|
12081
|
-
|
|
12082
|
-
|
|
12083
|
-
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
|
|
12087
|
-
|
|
12088
|
-
|
|
12089
|
-
|
|
12090
|
-
|
|
12091
|
-
|
|
12092
|
-
|
|
12093
|
-
|
|
12094
|
-
|
|
12095
|
-
|
|
12096
|
-
|
|
12097
|
-
|
|
12098
|
-
|
|
12099
|
-
|
|
12100
|
-
|
|
12101
|
-
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
|
|
12105
|
-
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
|
|
12112
|
-
|
|
12113
|
-
|
|
12114
|
-
|
|
12115
|
-
|
|
12116
|
-
|
|
12117
|
-
|
|
12118
|
-
|
|
12119
|
-
|
|
12120
|
-
|
|
12121
|
-
|
|
12107
|
+
const firstOCMDJSONDocument = getFirstArrayElement(OCMFJSONDocuments, "Missing first OCMF JSON document");
|
|
12108
|
+
const formatVersion = firstOCMDJSONDocument.payload.FV;
|
|
12109
|
+
const gatewayInformation = firstOCMDJSONDocument.payload.GI ?? firstOCMDJSONDocument.payload.VI;
|
|
12110
|
+
const gatewaySerial = firstOCMDJSONDocument.payload.GS;
|
|
12111
|
+
const gatewayVersion = firstOCMDJSONDocument.payload.GV ?? firstOCMDJSONDocument.payload.VV;
|
|
12112
|
+
const paging = firstOCMDJSONDocument.payload.PG;
|
|
12113
|
+
const meterVendor = firstOCMDJSONDocument.payload.MV;
|
|
12114
|
+
const meterModel = firstOCMDJSONDocument.payload.MM;
|
|
12115
|
+
const meterSerial = firstOCMDJSONDocument.payload.MS;
|
|
12116
|
+
const effectiveMeterSerial = meterSerial ?? gatewaySerial;
|
|
12117
|
+
const meterFirmware = firstOCMDJSONDocument.payload.MF;
|
|
12118
|
+
const identificationStatus = firstOCMDJSONDocument.payload.IS;
|
|
12119
|
+
const identificationLevel = firstOCMDJSONDocument.payload.IL;
|
|
12120
|
+
const identificationFlags = firstOCMDJSONDocument.payload.IF;
|
|
12121
|
+
const identificationType = firstOCMDJSONDocument.payload.IT;
|
|
12122
|
+
const identificationData = firstOCMDJSONDocument.payload.ID;
|
|
12123
|
+
const tariffText = firstOCMDJSONDocument.payload.TT;
|
|
12124
|
+
const controlerFirmwareVersion = firstOCMDJSONDocument.payload.CF;
|
|
12125
|
+
const lossCompensation = firstOCMDJSONDocument.payload.LC;
|
|
12126
|
+
const chargePointIdType = firstOCMDJSONDocument.payload.CT;
|
|
12127
|
+
const chargePointId = firstOCMDJSONDocument.payload.CI;
|
|
12128
|
+
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,
|
|
12129
|
+
// Charge Point and Public Key" section makes the serial-number fields conditionally
|
|
12130
|
+
// mandatory. KEBA KCP30 records identify the signing gateway via GS and omit MS.
|
|
12131
|
+
// Therefore we keep meterSerial and gatewaySerial separate, but require at least one
|
|
12132
|
+
// usable serial number for the CTR meter identity.
|
|
12133
|
+
isMandatoryString(effectiveMeterSerial) && isOptionalString(meterFirmware) && // OCMF 1.x uses boolean IS values. OCMF 0.1 SAFE reference data used status strings
|
|
12134
|
+
// such as "VERIFIED", so accept both forms and preserve the original value in the CTR.
|
|
12135
|
+
(isMandatoryBoolean(identificationStatus) || isMandatoryString(identificationStatus)) && isOptionalString(identificationLevel) && //chargyLib.isMandatoryArrayOfStrings (identificationFlags) &&
|
|
12136
|
+
isOptionalArrayOfStrings(identificationFlags) && // Note: Some vendors do not use this MANDATORY field!
|
|
12137
|
+
// IT is 1..1 in the user-assignment table for transaction records. Some OCMF 1.0
|
|
12138
|
+
// implementations omit it when no user is assigned (IS=false, ID empty). We tolerate
|
|
12139
|
+
// this vendor compatibility case instead of rejecting otherwise valid signatures.
|
|
12140
|
+
isOptionalString(identificationType) && isOptionalString(identificationData) && isOptionalString(tariffText) && isOptionalString(controlerFirmwareVersion) && isOptionalJSONObject(lossCompensation) && isOptionalString(chargePointIdType) && isOptionalString(chargePointId)) {
|
|
12141
|
+
const paginationPrefix = paging.length > 0 ? paging.charAt(0).toLowerCase() : null;
|
|
12142
|
+
const transactionType = paginationPrefix === "t" ? "transaction" /* transaction */ : paginationPrefix === "f" ? "fiscal" /* fiscal */ : "undefined" /* undefined */;
|
|
12143
|
+
const pagination = paging.length > 1 ? parseNumber(paging.substring(1)) : null;
|
|
12144
|
+
if (transactionType === "undefined" /* undefined */) return {
|
|
12145
|
+
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12146
|
+
message: this.chargy.GetMultilanguageText("The given OCMF data does not have a valid transaction type!"),
|
|
12147
|
+
certainty: 0
|
|
12148
|
+
};
|
|
12149
|
+
if (!isMandatoryNumber(pagination)) return {
|
|
12150
|
+
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12151
|
+
message: this.chargy.GetMultilanguageText("The given OCMF data does not have a valid pagination counter!"),
|
|
12152
|
+
certainty: 0
|
|
12153
|
+
};
|
|
12154
|
+
if (firstOCMDJSONDocument.payload.RD.length == 0) return {
|
|
12155
|
+
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12156
|
+
message: this.chargy.GetMultilanguageText("Each OCMF data set must have at least one meter reading!"),
|
|
12157
|
+
certainty: 0
|
|
12158
|
+
};
|
|
12159
|
+
const CTR = {
|
|
12160
|
+
"@id": "?",
|
|
12161
|
+
"@context": "https://open.charging.cloud/contexts/CTR+json",
|
|
12162
|
+
//"@context": [ "https://open.charging.cloud/contexts/CTR+json", "https://open.charging.cloud/contexts/CTR_OCMF+json" ],
|
|
12163
|
+
"begin": "?",
|
|
12164
|
+
"end": "?",
|
|
12165
|
+
"description": {
|
|
12166
|
+
"de": "Alle OCMF-Ladevorg\xE4nge"
|
|
12167
|
+
},
|
|
12168
|
+
"contract": {
|
|
12169
|
+
"@id": identificationData ?? "?",
|
|
12170
|
+
"type": identificationType ?? "?"
|
|
12171
|
+
},
|
|
12172
|
+
"ocmf": {
|
|
12173
|
+
"formatVersion": formatVersion,
|
|
12174
|
+
"gatewayInformation": gatewayInformation,
|
|
12175
|
+
"gatewaySerial": gatewaySerial,
|
|
12176
|
+
"gatewayVersion": gatewayVersion
|
|
12177
|
+
},
|
|
12178
|
+
// "chargingStationOperators": [{
|
|
12179
|
+
"chargingPools": [{
|
|
12180
|
+
"@id": "DE*GEF*POOL*CHARGY*1",
|
|
12181
|
+
"description": { "en": "GraphDefined CHARGY Virtual Charging Pool 1" },
|
|
12182
|
+
"chargingStations": [{
|
|
12183
|
+
"@id": chargingStationId,
|
|
12184
|
+
"description": stationDescription && Object.keys(stationDescription).length > 0 ? stationDescription : { "en": "GraphDefined CHARGY Virtual Charging Station 1" },
|
|
12185
|
+
"firmwareVersion": asString(chargingStationInfo?.["softwareVersion"]) ?? asString(chargingStationInfo?.["firmwareVersion"]),
|
|
12186
|
+
"geoLocation": asJSONObject(chargingStationInfo?.["geoLocation"]),
|
|
12187
|
+
"address": asJSONObject(chargingStationInfo?.["address"]),
|
|
12188
|
+
"EVSEs": [{
|
|
12189
|
+
"@id": evseId,
|
|
12190
|
+
"description": evseDescription && Object.keys(evseDescription).length > 0 ? evseDescription : { "en": "GraphDefined CHARGY Virtual EVSE 1" },
|
|
12191
|
+
"connectors": connectorInfo ? [{
|
|
12192
|
+
"type": asString(connectorInfo["type"]) ?? "",
|
|
12193
|
+
"looses": asNumber(connectorInfo["looses"]) ?? 0
|
|
12194
|
+
}] : void 0,
|
|
12195
|
+
"meters": [{
|
|
12196
|
+
"@id": effectiveMeterSerial,
|
|
12197
|
+
// The signed OCMF payload values always win,
|
|
12198
|
+
// the container infos only fill the gaps!
|
|
12199
|
+
"manufacturer": meterVendor ?? asString(energyMeterInfo?.["manufacturer"]),
|
|
12200
|
+
"manufacturerURL": asString(energyMeterInfo?.["manufacturerURL"]),
|
|
12201
|
+
"model": meterModel ?? asString(energyMeterInfo?.["model"]),
|
|
12202
|
+
"modelURL": asString(energyMeterInfo?.["modelURL"]),
|
|
12203
|
+
"hardwareVersion": asString(energyMeterInfo?.["hardwareVersion"]),
|
|
12204
|
+
"firmwareVersion": meterFirmware ?? asString(energyMeterInfo?.["firmwareVersion"]),
|
|
12205
|
+
"signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json",
|
|
12206
|
+
"publicKeys": [{
|
|
12207
|
+
"algorithm": "?",
|
|
12208
|
+
"encoding": "?",
|
|
12209
|
+
"format": "?",
|
|
12210
|
+
"value": "?"
|
|
12211
|
+
}]
|
|
12212
|
+
}]
|
|
12213
|
+
}]
|
|
12214
|
+
}]
|
|
12215
|
+
}],
|
|
12216
|
+
"chargingSessions": [{
|
|
12217
|
+
"@id": "1554181214441:-1965658344385548683:2",
|
|
12218
|
+
"@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/OCMFv1.0+json",
|
|
12122
12219
|
"begin": "?",
|
|
12123
12220
|
"end": "?",
|
|
12124
|
-
"
|
|
12125
|
-
|
|
12126
|
-
},
|
|
12127
|
-
"contract": {
|
|
12221
|
+
"EVSEId": evseId,
|
|
12222
|
+
"authorizationStart": {
|
|
12128
12223
|
"@id": identificationData ?? "?",
|
|
12129
|
-
"type": identificationType ?? "?"
|
|
12130
|
-
|
|
12131
|
-
|
|
12132
|
-
"
|
|
12133
|
-
|
|
12134
|
-
"gatewaySerial": gatewaySerial,
|
|
12135
|
-
"gatewayVersion": gatewayVersion
|
|
12224
|
+
"type": identificationType ?? "?",
|
|
12225
|
+
"identificationStatus": identificationStatus,
|
|
12226
|
+
"identificationLevel": identificationLevel,
|
|
12227
|
+
"identificationFlags": identificationFlags ?? []
|
|
12228
|
+
// Note: The OCMF documentation expects an empty array!
|
|
12136
12229
|
},
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
12141
|
-
|
|
12142
|
-
|
|
12143
|
-
|
|
12144
|
-
|
|
12145
|
-
|
|
12146
|
-
|
|
12147
|
-
|
|
12148
|
-
|
|
12149
|
-
|
|
12150
|
-
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
|
|
12154
|
-
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
|
|
12158
|
-
|
|
12159
|
-
|
|
12160
|
-
|
|
12161
|
-
|
|
12162
|
-
|
|
12163
|
-
|
|
12164
|
-
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12172
|
-
|
|
12173
|
-
|
|
12174
|
-
|
|
12175
|
-
|
|
12176
|
-
|
|
12177
|
-
|
|
12178
|
-
|
|
12179
|
-
|
|
12180
|
-
|
|
12181
|
-
|
|
12182
|
-
|
|
12183
|
-
|
|
12184
|
-
"
|
|
12185
|
-
|
|
12186
|
-
|
|
12187
|
-
|
|
12188
|
-
|
|
12189
|
-
|
|
12190
|
-
|
|
12191
|
-
|
|
12192
|
-
|
|
12193
|
-
|
|
12194
|
-
|
|
12195
|
-
|
|
12196
|
-
|
|
12197
|
-
|
|
12198
|
-
const time = effectiveReading.TM;
|
|
12199
|
-
const transaction = effectiveReading.TX;
|
|
12200
|
-
const readingValue = effectiveReading.RV;
|
|
12201
|
-
const readingIdentification = effectiveReading.RI;
|
|
12202
|
-
const readingUnit = effectiveReading.RU;
|
|
12203
|
-
const readingCurrentType = effectiveReading.RT;
|
|
12204
|
-
const cumulatedLoss = effectiveReading.CL;
|
|
12205
|
-
const errorFlags = effectiveReading.EF;
|
|
12206
|
-
const status = effectiveReading.ST;
|
|
12207
|
-
inheritedReading = effectiveReading;
|
|
12208
|
-
if (isMandatoryString(time) && isOptionalString(transaction) && isMandatoryDecimal(readingValue) && // Note: Some vendors use a JSON string here!
|
|
12209
|
-
isOptionalString(readingIdentification) && isMandatoryString(readingUnit) && isOptionalString(readingCurrentType) && isOptionalDecimal(cumulatedLoss) && isOptionalString(errorFlags) && isMandatoryString(status)) {
|
|
12210
|
-
const timeSplit = time.split(" ");
|
|
12211
|
-
if (timeSplit.length != 2) return {
|
|
12212
|
-
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12213
|
-
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time format!"),
|
|
12214
|
-
certainty: 0
|
|
12215
|
-
};
|
|
12216
|
-
const timeRegEx = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2},\d{3}[+-]\d{4}$/;
|
|
12217
|
-
const timeStamp = timeSplit[0];
|
|
12218
|
-
if (!isMandatoryString(timeStamp) || !timeRegEx.test(timeStamp)) return {
|
|
12219
|
-
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12220
|
-
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
|
|
12221
|
-
certainty: 0
|
|
12222
|
-
};
|
|
12223
|
-
const timeStampISO8601 = this.convertToISO8601(timeStamp);
|
|
12224
|
-
const timeSyncText = timeSplit[1];
|
|
12225
|
-
let timeSync = "unknown" /* unknown */;
|
|
12226
|
-
if (!isMandatoryString(timeSyncText) || !["U", "I", "S", "R"].includes(timeSyncText)) return {
|
|
12227
|
-
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12228
|
-
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
|
|
12229
|
-
certainty: 0
|
|
12230
|
-
};
|
|
12231
|
-
switch (timeSyncText) {
|
|
12232
|
-
case "U":
|
|
12233
|
-
timeSync = "unknown" /* unknown */;
|
|
12234
|
-
break;
|
|
12235
|
-
case "I":
|
|
12236
|
-
timeSync = "informative" /* informative */;
|
|
12237
|
-
break;
|
|
12238
|
-
case "S":
|
|
12239
|
-
timeSync = "syncronized" /* syncronized */;
|
|
12240
|
-
break;
|
|
12241
|
-
case "R":
|
|
12242
|
-
timeSync = "relative" /* relative */;
|
|
12243
|
-
break;
|
|
12244
|
-
default:
|
|
12245
|
-
return {
|
|
12246
|
-
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12247
|
-
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
|
|
12248
|
-
certainty: 0
|
|
12249
|
-
};
|
|
12250
|
-
}
|
|
12251
|
-
if (transaction && !["B", "C", "X", "E", "L", "R", "A", "P", "S", "T"].includes(transaction)) return {
|
|
12252
|
-
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12253
|
-
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid transaction type!"),
|
|
12254
|
-
certainty: 0
|
|
12255
|
-
};
|
|
12256
|
-
if (!["kWh", "Wh", "mOhm", "uOhm"].includes(readingUnit)) return {
|
|
12257
|
-
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12258
|
-
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid current type!"),
|
|
12259
|
-
certainty: 0
|
|
12260
|
-
};
|
|
12261
|
-
if (readingCurrentType && !["AC", "DC"].includes(readingCurrentType)) return {
|
|
12262
|
-
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12263
|
-
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid current type!"),
|
|
12264
|
-
certainty: 0
|
|
12265
|
-
};
|
|
12266
|
-
if (CTR.chargingSessions?.[0]?.begin === "?")
|
|
12267
|
-
CTR.chargingSessions[0].begin = timeStampISO8601;
|
|
12268
|
-
CTR.chargingSessions[0].end = timeStampISO8601;
|
|
12269
|
-
const measurementKey = [
|
|
12270
|
-
readingIdentification ?? "?",
|
|
12271
|
-
readingUnit,
|
|
12272
|
-
readingCurrentType ?? ""
|
|
12273
|
-
].join("|");
|
|
12274
|
-
let measurement = measurementsByKey.get(measurementKey);
|
|
12275
|
-
if (measurement == null) {
|
|
12276
|
-
measurement = {
|
|
12277
|
-
"name": OBIS2MeasurementName(readingIdentification ?? ""),
|
|
12278
|
-
"scale": 0,
|
|
12279
|
-
"energyMeterId": effectiveMeterSerial,
|
|
12280
|
-
"@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json",
|
|
12281
|
-
"obis": readingIdentification ?? "?",
|
|
12282
|
-
// OBIS: "1-b:1.8.0"
|
|
12283
|
-
"unit": readingUnit,
|
|
12284
|
-
// "kWh"
|
|
12285
|
-
"currentType": readingCurrentType,
|
|
12286
|
-
// "AC"
|
|
12287
|
-
"values": []
|
|
12230
|
+
"measurements": []
|
|
12231
|
+
}],
|
|
12232
|
+
"certainty": 1
|
|
12233
|
+
};
|
|
12234
|
+
const measurementsByKey = /* @__PURE__ */ new Map();
|
|
12235
|
+
for (const ocmfJSONDocument of OCMFJSONDocuments) {
|
|
12236
|
+
let inheritedReading = {};
|
|
12237
|
+
for (const reading of ocmfJSONDocument.payload.RD) {
|
|
12238
|
+
const effectiveReading = { ...inheritedReading, ...reading };
|
|
12239
|
+
const time = effectiveReading.TM;
|
|
12240
|
+
const transaction = effectiveReading.TX;
|
|
12241
|
+
const readingValue = effectiveReading.RV;
|
|
12242
|
+
const readingIdentification = effectiveReading.RI;
|
|
12243
|
+
const readingUnit = effectiveReading.RU;
|
|
12244
|
+
const readingCurrentType = effectiveReading.RT;
|
|
12245
|
+
const cumulatedLoss = effectiveReading.CL;
|
|
12246
|
+
const errorFlags = effectiveReading.EF;
|
|
12247
|
+
const status = effectiveReading.ST;
|
|
12248
|
+
inheritedReading = effectiveReading;
|
|
12249
|
+
if (isMandatoryString(time) && isOptionalString(transaction) && isMandatoryDecimal(readingValue) && // Note: Some vendors use a JSON string here!
|
|
12250
|
+
isOptionalString(readingIdentification) && isMandatoryString(readingUnit) && isOptionalString(readingCurrentType) && // chargyLib.isOptionalDecimal (cumulatedLoss) &&
|
|
12251
|
+
isOptionalString(errorFlags) && isMandatoryString(status)) {
|
|
12252
|
+
const timeSplit = time.split(" ");
|
|
12253
|
+
if (timeSplit.length != 2) return {
|
|
12254
|
+
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12255
|
+
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time format!"),
|
|
12256
|
+
certainty: 0
|
|
12257
|
+
};
|
|
12258
|
+
const timeRegEx = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2},\d{3}[+-]\d{4}$/;
|
|
12259
|
+
const timeStamp = timeSplit[0];
|
|
12260
|
+
if (!isMandatoryString(timeStamp) || !timeRegEx.test(timeStamp)) return {
|
|
12261
|
+
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12262
|
+
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
|
|
12263
|
+
certainty: 0
|
|
12264
|
+
};
|
|
12265
|
+
const timeStampISO8601 = this.convertToISO8601(timeStamp);
|
|
12266
|
+
const timeSyncText = timeSplit[1];
|
|
12267
|
+
let timeSync = "unknown" /* unknown */;
|
|
12268
|
+
if (!isMandatoryString(timeSyncText) || !["U", "I", "S", "R"].includes(timeSyncText)) return {
|
|
12269
|
+
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12270
|
+
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
|
|
12271
|
+
certainty: 0
|
|
12272
|
+
};
|
|
12273
|
+
switch (timeSyncText) {
|
|
12274
|
+
case "U":
|
|
12275
|
+
timeSync = "unknown" /* unknown */;
|
|
12276
|
+
break;
|
|
12277
|
+
case "I":
|
|
12278
|
+
timeSync = "informative" /* informative */;
|
|
12279
|
+
break;
|
|
12280
|
+
case "S":
|
|
12281
|
+
timeSync = "syncronized" /* syncronized */;
|
|
12282
|
+
break;
|
|
12283
|
+
case "R":
|
|
12284
|
+
timeSync = "relative" /* relative */;
|
|
12285
|
+
break;
|
|
12286
|
+
default:
|
|
12287
|
+
return {
|
|
12288
|
+
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12289
|
+
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
|
|
12290
|
+
certainty: 0
|
|
12288
12291
|
};
|
|
12289
|
-
measurementsByKey.set(measurementKey, measurement);
|
|
12290
|
-
CTR.chargingSessions[0].measurements.push(measurement);
|
|
12291
|
-
}
|
|
12292
|
-
measurement.values.push({
|
|
12293
|
-
"timestamp": timeStampISO8601,
|
|
12294
|
-
// "2019-06-26T08:57:44,337+0000"
|
|
12295
|
-
"timeSync": timeSync,
|
|
12296
|
-
// "U"|"I"|"S"|"R"
|
|
12297
|
-
"transaction": transaction,
|
|
12298
|
-
// "B"|"C"|"X"|"E"|"L"|"R"|"A"|"P"|"S"|"T"|null
|
|
12299
|
-
"value": new Decimal(readingValue),
|
|
12300
|
-
// 2935.6
|
|
12301
|
-
"transactionType": transactionType,
|
|
12302
|
-
// "T" ToDo: Serialize this to a string!
|
|
12303
|
-
"pagination": pagination,
|
|
12304
|
-
// "9289"
|
|
12305
|
-
"errorFlags": errorFlags,
|
|
12306
|
-
// ""
|
|
12307
|
-
"cumulatedLoss": cumulatedLoss ? new Decimal(cumulatedLoss) : void 0,
|
|
12308
|
-
"status": status,
|
|
12309
|
-
// "G"
|
|
12310
|
-
// "signatures": [{
|
|
12311
|
-
// "value": ocmfJSONDocument.signature["SD"]
|
|
12312
|
-
// }],
|
|
12313
|
-
"result": {
|
|
12314
|
-
"status": ocmfJSONDocument.validationStatus ?? "Unvalidated" /* Unvalidated */
|
|
12315
|
-
},
|
|
12316
|
-
"ocmfDocument": ocmfJSONDocument
|
|
12317
|
-
});
|
|
12318
12292
|
}
|
|
12293
|
+
if (transaction != null && transaction.length > 0 && !["B", "C", "X", "E", "L", "R", "A", "P", "S", "T"].includes(transaction)) return {
|
|
12294
|
+
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12295
|
+
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid transaction type!"),
|
|
12296
|
+
certainty: 0
|
|
12297
|
+
};
|
|
12298
|
+
if (!["kWh", "Wh", "mOhm", "uOhm"].includes(readingUnit)) return {
|
|
12299
|
+
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12300
|
+
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid current type!"),
|
|
12301
|
+
certainty: 0
|
|
12302
|
+
};
|
|
12303
|
+
if (readingCurrentType != null && readingCurrentType.length > 0 && !["AC", "DC"].includes(readingCurrentType)) return {
|
|
12304
|
+
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
12305
|
+
message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid current type!"),
|
|
12306
|
+
certainty: 0
|
|
12307
|
+
};
|
|
12308
|
+
if (CTR.chargingSessions?.[0]?.begin === "?")
|
|
12309
|
+
CTR.chargingSessions[0].begin = timeStampISO8601;
|
|
12310
|
+
if (CTR.chargingSessions?.[0] !== void 0)
|
|
12311
|
+
CTR.chargingSessions[0].end = timeStampISO8601;
|
|
12312
|
+
const measurementKey = [
|
|
12313
|
+
readingIdentification ?? "?",
|
|
12314
|
+
readingUnit,
|
|
12315
|
+
readingCurrentType ?? ""
|
|
12316
|
+
].join("|");
|
|
12317
|
+
let measurement = measurementsByKey.get(measurementKey);
|
|
12318
|
+
if (measurement == null) {
|
|
12319
|
+
measurement = {
|
|
12320
|
+
"name": OBIS2MeasurementName(readingIdentification ?? ""),
|
|
12321
|
+
"scale": 0,
|
|
12322
|
+
"energyMeterId": effectiveMeterSerial,
|
|
12323
|
+
"@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json",
|
|
12324
|
+
"obis": readingIdentification ?? "?",
|
|
12325
|
+
// OBIS: "1-b:1.8.0"
|
|
12326
|
+
"unit": readingUnit,
|
|
12327
|
+
// "kWh"
|
|
12328
|
+
"currentType": readingCurrentType,
|
|
12329
|
+
// "AC"
|
|
12330
|
+
"values": []
|
|
12331
|
+
};
|
|
12332
|
+
measurementsByKey.set(measurementKey, measurement);
|
|
12333
|
+
const firstChargingSession = CTR.chargingSessions?.[0];
|
|
12334
|
+
if (firstChargingSession !== void 0)
|
|
12335
|
+
firstChargingSession.measurements.push(measurement);
|
|
12336
|
+
}
|
|
12337
|
+
measurement.values.push({
|
|
12338
|
+
"timestamp": timeStampISO8601,
|
|
12339
|
+
// "2019-06-26T08:57:44,337+0000"
|
|
12340
|
+
"timeSync": timeSync,
|
|
12341
|
+
// "U"|"I"|"S"|"R"
|
|
12342
|
+
"transaction": transaction,
|
|
12343
|
+
// "B"|"C"|"X"|"E"|"L"|"R"|"A"|"P"|"S"|"T"|null
|
|
12344
|
+
"value": new Decimal(readingValue),
|
|
12345
|
+
// 2935.6
|
|
12346
|
+
"transactionType": transactionType,
|
|
12347
|
+
// "T" ToDo: Serialize this to a string!
|
|
12348
|
+
"pagination": pagination,
|
|
12349
|
+
// "9289"
|
|
12350
|
+
"errorFlags": errorFlags,
|
|
12351
|
+
// ""
|
|
12352
|
+
"cumulatedLoss": cumulatedLoss != null && cumulatedLoss !== 0 ? new Decimal(cumulatedLoss) : void 0,
|
|
12353
|
+
"status": status,
|
|
12354
|
+
// "G"
|
|
12355
|
+
// "signatures": [{
|
|
12356
|
+
// "value": ocmfJSONDocument.signature["SD"]
|
|
12357
|
+
// }],
|
|
12358
|
+
"result": {
|
|
12359
|
+
"status": ocmfJSONDocument.validationStatus ?? "Unvalidated" /* Unvalidated */
|
|
12360
|
+
},
|
|
12361
|
+
"ocmfDocument": ocmfJSONDocument
|
|
12362
|
+
});
|
|
12319
12363
|
}
|
|
12320
12364
|
}
|
|
12321
|
-
|
|
12322
|
-
|
|
12323
|
-
|
|
12324
|
-
|
|
12325
|
-
|
|
12326
|
-
|
|
12365
|
+
}
|
|
12366
|
+
CTR.status = OCMFJSONDocuments.every((ocmfJSONDocument) => ocmfJSONDocument.validationStatus === "ValidSignature" /* ValidSignature */) ? "ValidSignature" /* ValidSignature */ : "InvalidSignature" /* InvalidSignature */;
|
|
12367
|
+
if (CTR.chargingSessions != null && CTR.chargingSessions.length > 0 && CTR.chargingSessions[0]) {
|
|
12368
|
+
CTR.begin = CTR.chargingSessions[0].begin;
|
|
12369
|
+
CTR.end = CTR.chargingSessions[0].end;
|
|
12370
|
+
return CTR;
|
|
12327
12371
|
}
|
|
12328
12372
|
}
|
|
12329
12373
|
} catch (exception) {
|
|
@@ -12340,113 +12384,121 @@ var OCMF = class {
|
|
|
12340
12384
|
}
|
|
12341
12385
|
//#endregion
|
|
12342
12386
|
//#region (private) mergeOCMFSessions(CTRs)
|
|
12343
|
-
mergeOCMFSessions(CTRs)
|
|
12344
|
-
|
|
12345
|
-
|
|
12346
|
-
|
|
12347
|
-
|
|
12348
|
-
|
|
12349
|
-
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
|
|
12353
|
-
|
|
12354
|
-
|
|
12355
|
-
|
|
12356
|
-
|
|
12357
|
-
|
|
12358
|
-
|
|
12359
|
-
|
|
12360
|
-
|
|
12361
|
-
|
|
12362
|
-
|
|
12363
|
-
|
|
12364
|
-
|
|
12365
|
-
|
|
12366
|
-
|
|
12367
|
-
|
|
12368
|
-
|
|
12369
|
-
|
|
12370
|
-
|
|
12371
|
-
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
|
|
12376
|
-
|
|
12377
|
-
|
|
12378
|
-
|
|
12379
|
-
|
|
12380
|
-
|
|
12381
|
-
|
|
12382
|
-
|
|
12383
|
-
|
|
12384
|
-
|
|
12385
|
-
|
|
12386
|
-
|
|
12387
|
-
|
|
12388
|
-
|
|
12389
|
-
|
|
12390
|
-
|
|
12391
|
-
|
|
12392
|
-
|
|
12393
|
-
|
|
12394
|
-
|
|
12387
|
+
// private mergeOCMFSessions(CTRs: Array<IOCMFChargeTransparencyRecord>): IOCMFChargeTransparencyRecord
|
|
12388
|
+
// {
|
|
12389
|
+
// const mergedCTR:IOCMFChargeTransparencyRecord = {
|
|
12390
|
+
// "@id": "",
|
|
12391
|
+
// "@context": "",
|
|
12392
|
+
// certainty: 1
|
|
12393
|
+
// };
|
|
12394
|
+
// for (const ctr of CTRs)
|
|
12395
|
+
// {
|
|
12396
|
+
// if (mergedCTR["@id"] === "")
|
|
12397
|
+
// mergedCTR["@id"] = ctr["@id"];
|
|
12398
|
+
// if (mergedCTR["@context"] === "")
|
|
12399
|
+
// mergedCTR["@context"] = ctr["@context"];
|
|
12400
|
+
// if (!mergedCTR.begin || (mergedCTR.begin && ctr.begin && mergedCTR.begin > ctr.begin))
|
|
12401
|
+
// mergedCTR.begin = ctr.begin;
|
|
12402
|
+
// if (!mergedCTR.end || (mergedCTR.end && ctr.end && mergedCTR.end < ctr.end))
|
|
12403
|
+
// mergedCTR.end = ctr.end;
|
|
12404
|
+
// if (!mergedCTR.description)
|
|
12405
|
+
// mergedCTR.description = ctr.description;
|
|
12406
|
+
// //ToDo: Is this a really good idea? Or should we fail, whenever this information is different?
|
|
12407
|
+
// if (!mergedCTR.contract)
|
|
12408
|
+
// mergedCTR.contract = ctr.contract;
|
|
12409
|
+
// if (!mergedCTR.chargingStationOperators)
|
|
12410
|
+
// mergedCTR.chargingStationOperators = ctr.chargingStationOperators;
|
|
12411
|
+
// else if (ctr.chargingStationOperators)
|
|
12412
|
+
// for (const chargingStationOperator of ctr.chargingStationOperators)
|
|
12413
|
+
// mergedCTR.chargingStationOperators.push(chargingStationOperator);
|
|
12414
|
+
// if (!mergedCTR.chargingPools)
|
|
12415
|
+
// mergedCTR.chargingPools = ctr.chargingPools;
|
|
12416
|
+
// else if (ctr.chargingPools)
|
|
12417
|
+
// for (const chargingPool of ctr.chargingPools)
|
|
12418
|
+
// mergedCTR.chargingPools.push(chargingPool);
|
|
12419
|
+
// if (!mergedCTR.chargingStations)
|
|
12420
|
+
// mergedCTR.chargingStations = ctr.chargingStations;
|
|
12421
|
+
// else if (ctr.chargingStations)
|
|
12422
|
+
// for (const chargingStation of ctr.chargingStations)
|
|
12423
|
+
// mergedCTR.chargingStations.push(chargingStation);
|
|
12424
|
+
// // publicKeys
|
|
12425
|
+
// if (!mergedCTR.chargingSessions)
|
|
12426
|
+
// mergedCTR.chargingSessions = ctr.chargingSessions;
|
|
12427
|
+
// else if (ctr.chargingSessions)
|
|
12428
|
+
// for (const chargingSession of ctr.chargingSessions)
|
|
12429
|
+
// mergedCTR.chargingSessions.push(chargingSession);
|
|
12430
|
+
// if (!mergedCTR.eMobilityProviders)
|
|
12431
|
+
// mergedCTR.eMobilityProviders = ctr.eMobilityProviders;
|
|
12432
|
+
// else if (ctr.eMobilityProviders)
|
|
12433
|
+
// for (const eMobilityProvider of ctr.eMobilityProviders)
|
|
12434
|
+
// mergedCTR.eMobilityProviders.push(eMobilityProvider);
|
|
12435
|
+
// if (!mergedCTR.mediationServices)
|
|
12436
|
+
// mergedCTR.mediationServices = ctr.mediationServices;
|
|
12437
|
+
// else if (ctr.mediationServices)
|
|
12438
|
+
// for (const mediationService of ctr.mediationServices)
|
|
12439
|
+
// mergedCTR.mediationServices.push(mediationService);
|
|
12440
|
+
// }
|
|
12441
|
+
// return mergedCTR;
|
|
12442
|
+
// }
|
|
12395
12443
|
//#endregion
|
|
12396
12444
|
//#region (private) mergeChargeTransparencyRecords(CTRs)
|
|
12397
|
-
mergeChargeTransparencyRecords(CTRs)
|
|
12398
|
-
|
|
12399
|
-
|
|
12400
|
-
|
|
12401
|
-
|
|
12402
|
-
|
|
12403
|
-
|
|
12404
|
-
|
|
12405
|
-
|
|
12406
|
-
|
|
12407
|
-
|
|
12408
|
-
|
|
12409
|
-
|
|
12410
|
-
|
|
12411
|
-
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
|
|
12415
|
-
|
|
12416
|
-
|
|
12417
|
-
|
|
12418
|
-
|
|
12419
|
-
|
|
12420
|
-
|
|
12421
|
-
|
|
12422
|
-
|
|
12423
|
-
|
|
12424
|
-
|
|
12425
|
-
|
|
12426
|
-
|
|
12427
|
-
|
|
12428
|
-
|
|
12429
|
-
|
|
12430
|
-
|
|
12431
|
-
|
|
12432
|
-
|
|
12433
|
-
|
|
12434
|
-
|
|
12435
|
-
|
|
12436
|
-
|
|
12437
|
-
|
|
12438
|
-
|
|
12439
|
-
|
|
12440
|
-
|
|
12441
|
-
|
|
12442
|
-
|
|
12443
|
-
|
|
12444
|
-
|
|
12445
|
-
|
|
12446
|
-
|
|
12447
|
-
|
|
12448
|
-
|
|
12449
|
-
|
|
12445
|
+
// private mergeChargeTransparencyRecords(CTRs: Array<IOCMFChargeTransparencyRecord>): IOCMFChargeTransparencyRecord
|
|
12446
|
+
// {
|
|
12447
|
+
// const mergedCTR:IOCMFChargeTransparencyRecord = {
|
|
12448
|
+
// "@id": "",
|
|
12449
|
+
// "@context": "",
|
|
12450
|
+
// certainty: 1
|
|
12451
|
+
// };
|
|
12452
|
+
// for (const ctr of CTRs)
|
|
12453
|
+
// {
|
|
12454
|
+
// if (mergedCTR["@id"] === "")
|
|
12455
|
+
// mergedCTR["@id"] = ctr["@id"];
|
|
12456
|
+
// if (mergedCTR["@context"] === "")
|
|
12457
|
+
// mergedCTR["@context"] = ctr["@context"];
|
|
12458
|
+
// if (!mergedCTR.begin || (mergedCTR.begin && ctr.begin && mergedCTR.begin > ctr.begin))
|
|
12459
|
+
// mergedCTR.begin = ctr.begin;
|
|
12460
|
+
// if (!mergedCTR.end || (mergedCTR.end && ctr.end && mergedCTR.end < ctr.end))
|
|
12461
|
+
// mergedCTR.end = ctr.end;
|
|
12462
|
+
// if (!mergedCTR.description)
|
|
12463
|
+
// mergedCTR.description = ctr.description;
|
|
12464
|
+
// //ToDo: Is this a really good idea? Or should we fail, whenever this information is different?
|
|
12465
|
+
// if (!mergedCTR.contract)
|
|
12466
|
+
// mergedCTR.contract = ctr.contract;
|
|
12467
|
+
// if (!mergedCTR.chargingStationOperators)
|
|
12468
|
+
// mergedCTR.chargingStationOperators = ctr.chargingStationOperators;
|
|
12469
|
+
// else if (ctr.chargingStationOperators)
|
|
12470
|
+
// for (const chargingStationOperator of ctr.chargingStationOperators)
|
|
12471
|
+
// mergedCTR.chargingStationOperators.push(chargingStationOperator);
|
|
12472
|
+
// if (!mergedCTR.chargingPools)
|
|
12473
|
+
// mergedCTR.chargingPools = ctr.chargingPools;
|
|
12474
|
+
// else if (ctr.chargingPools)
|
|
12475
|
+
// for (const chargingPool of ctr.chargingPools)
|
|
12476
|
+
// mergedCTR.chargingPools.push(chargingPool);
|
|
12477
|
+
// if (!mergedCTR.chargingStations)
|
|
12478
|
+
// mergedCTR.chargingStations = ctr.chargingStations;
|
|
12479
|
+
// else if (ctr.chargingStations)
|
|
12480
|
+
// for (const chargingStation of ctr.chargingStations)
|
|
12481
|
+
// mergedCTR.chargingStations.push(chargingStation);
|
|
12482
|
+
// // publicKeys
|
|
12483
|
+
// if (!mergedCTR.chargingSessions)
|
|
12484
|
+
// mergedCTR.chargingSessions = ctr.chargingSessions;
|
|
12485
|
+
// else if (ctr.chargingSessions)
|
|
12486
|
+
// for (const chargingSession of ctr.chargingSessions)
|
|
12487
|
+
// mergedCTR.chargingSessions.push(chargingSession);
|
|
12488
|
+
// if (!mergedCTR.eMobilityProviders)
|
|
12489
|
+
// mergedCTR.eMobilityProviders = ctr.eMobilityProviders;
|
|
12490
|
+
// else if (ctr.eMobilityProviders)
|
|
12491
|
+
// for (const eMobilityProvider of ctr.eMobilityProviders)
|
|
12492
|
+
// mergedCTR.eMobilityProviders.push(eMobilityProvider);
|
|
12493
|
+
// if (!mergedCTR.mediationServices)
|
|
12494
|
+
// mergedCTR.mediationServices = ctr.mediationServices;
|
|
12495
|
+
// else if (ctr.mediationServices)
|
|
12496
|
+
// for (const mediationService of ctr.mediationServices)
|
|
12497
|
+
// mergedCTR.mediationServices.push(mediationService);
|
|
12498
|
+
// }
|
|
12499
|
+
// return mergedCTR;
|
|
12500
|
+
// }
|
|
12501
|
+
// //#endregion
|
|
12450
12502
|
//#region (private) validateOCMFSignature(OCMFJSONDocument, PublicKey, PublicKeyEncoding?)
|
|
12451
12503
|
async validateOCMFSignature(OCMFJSONDocument, PublicKey, PublicKeyEncoding) {
|
|
12452
12504
|
try {
|
|
@@ -12505,7 +12557,7 @@ var OCMF = class {
|
|
|
12505
12557
|
this.key("pubKey").bitstr()
|
|
12506
12558
|
);
|
|
12507
12559
|
});
|
|
12508
|
-
if (PublicKeyEncoding) {
|
|
12560
|
+
if (PublicKeyEncoding != null && PublicKeyEncoding.length > 0) {
|
|
12509
12561
|
switch (PublicKeyEncoding.toLowerCase()) {
|
|
12510
12562
|
case "hex":
|
|
12511
12563
|
publicKeyBytes = Buffer.from(OCMFJSONDocument.publicKey, "hex");
|
|
@@ -12533,11 +12585,12 @@ var OCMF = class {
|
|
|
12533
12585
|
publicKeyBytes = Buffer.from(OCMFJSONDocument.publicKey, "base64");
|
|
12534
12586
|
}
|
|
12535
12587
|
}
|
|
12536
|
-
if (
|
|
12588
|
+
if (publicKeyBytes == null) {
|
|
12537
12589
|
OCMFJSONDocument.validationStatus = "UnknownPublicKeyFormat" /* UnknownPublicKeyFormat */;
|
|
12538
12590
|
return OCMFJSONDocument.validationStatus;
|
|
12539
12591
|
}
|
|
12540
|
-
const
|
|
12592
|
+
const decodedPublicKeyASN1 = ECPoint.decode(publicKeyBytes, "der");
|
|
12593
|
+
const publicKeyASN1 = decodedPublicKeyASN1;
|
|
12541
12594
|
const coordinates = publicKeyASN1.pubKey.data.subarray(1);
|
|
12542
12595
|
const halfLength = coordinates.length / 2;
|
|
12543
12596
|
const publicKeyXY = {
|
|
@@ -12546,7 +12599,7 @@ var OCMF = class {
|
|
|
12546
12599
|
};
|
|
12547
12600
|
publicKey = curve.keyFromPublic(publicKeyXY, "hex");
|
|
12548
12601
|
OCMFJSONDocument.publicKey = {
|
|
12549
|
-
algorithm: OCMFJSONDocument.signature.SA ? OCMFJSONDocument.signature.SA.substring(
|
|
12602
|
+
algorithm: OCMFJSONDocument.signature.SA != null && OCMFJSONDocument.signature.SA.length > 0 ? OCMFJSONDocument.signature.SA.substring(
|
|
12550
12603
|
OCMFJSONDocument.signature.SA.indexOf("-") + 1,
|
|
12551
12604
|
OCMFJSONDocument.signature.SA.lastIndexOf("-")
|
|
12552
12605
|
) : "secp256r1",
|
|
@@ -12697,7 +12750,7 @@ var OCMF = class {
|
|
|
12697
12750
|
hashValue,
|
|
12698
12751
|
publicKey: PublicKey,
|
|
12699
12752
|
publicKeyEncoding: PublicKeyEncoding,
|
|
12700
|
-
validationStatus: validationStatus
|
|
12753
|
+
validationStatus: validationStatus ?? (PublicKey != null ? "Unvalidated" /* Unvalidated */ : "PublicKeyNotFound" /* PublicKeyNotFound */)
|
|
12701
12754
|
};
|
|
12702
12755
|
try {
|
|
12703
12756
|
const ECDSASignature = this.chargy.asn1.define("ECDSASignature", function() {
|
|
@@ -12719,7 +12772,8 @@ var OCMF = class {
|
|
|
12719
12772
|
default:
|
|
12720
12773
|
ocmfJSONDocument.validationStatus = "UnknownSignatureFormat" /* UnknownSignatureFormat */;
|
|
12721
12774
|
}
|
|
12722
|
-
const
|
|
12775
|
+
const decodedSignatureObj = ECDSASignature.decode(Buffer.from(ocmfJSONDocument.signature.SD, bufferEncoding), "der");
|
|
12776
|
+
const signatureObj = decodedSignatureObj;
|
|
12723
12777
|
ocmfJSONDocument.signatureRS = {
|
|
12724
12778
|
value: ocmfJSONDocument.signature.SD,
|
|
12725
12779
|
r: signatureObj.r.toString(16),
|
|
@@ -12728,7 +12782,7 @@ var OCMF = class {
|
|
|
12728
12782
|
} catch {
|
|
12729
12783
|
ocmfJSONDocument.validationStatus = "InvalidSignature" /* InvalidSignature */;
|
|
12730
12784
|
}
|
|
12731
|
-
if (PublicKey && ocmfJSONDocument.validationStatus === "Unvalidated" /* Unvalidated */)
|
|
12785
|
+
if (PublicKey != null && ocmfJSONDocument.validationStatus === "Unvalidated" /* Unvalidated */)
|
|
12732
12786
|
await this.validateOCMFSignature(
|
|
12733
12787
|
ocmfJSONDocument,
|
|
12734
12788
|
PublicKey,
|
|
@@ -12757,7 +12811,7 @@ var OCMF = class {
|
|
|
12757
12811
|
//#endregion
|
|
12758
12812
|
//#region TryToParseOCMFDocument (OCMFDocument, PublicKey?, PublicKeyEncoding?, ContainerInfos?)
|
|
12759
12813
|
async TryToParseOCMFDocument(OCMFDocument, PublicKey, PublicKeyEncoding, ContainerInfos) {
|
|
12760
|
-
return
|
|
12814
|
+
return this.TryToParseOCMFDocuments([OCMFDocument], PublicKey, PublicKeyEncoding, ContainerInfos);
|
|
12761
12815
|
}
|
|
12762
12816
|
//#endregion
|
|
12763
12817
|
//#region TryToParseOCMFDocuments(OCMFDocuments, PublicKey?, PublicKeyEncoding?, ContainerInfos?)
|
|
@@ -12777,7 +12831,8 @@ var OCMF = class {
|
|
|
12777
12831
|
if (typeof ocmfJSONDocuments !== "string") {
|
|
12778
12832
|
for (const ocmfJSONDocument of ocmfJSONDocuments) {
|
|
12779
12833
|
try {
|
|
12780
|
-
const groupingKey = (ocmfJSONDocument.payload.FV ?? "") + "|" + (ocmfJSONDocument.payload.GI ?? "") + "|" + (ocmfJSONDocument.payload.GS ?? "") + "|" + (ocmfJSONDocument.payload.GV ?? "") + "|" + (ocmfJSONDocument.payload.MV ?? "") + "|" + (ocmfJSONDocument.payload.MM ?? "") + "|" + (ocmfJSONDocument.payload.MS ?? "") + "|" + (ocmfJSONDocument.payload.MF ?? "") + "|" + (ocmfJSONDocument.payload.IS ? "1|" : "0|") + (ocmfJSONDocument.payload.IL ?? "") + "|" + (ocmfJSONDocument.payload.IF ?? "") + "|" +
|
|
12834
|
+
const groupingKey = (ocmfJSONDocument.payload.FV ?? "") + "|" + (ocmfJSONDocument.payload.GI ?? "") + "|" + (ocmfJSONDocument.payload.GS ?? "") + "|" + (ocmfJSONDocument.payload.GV ?? "") + "|" + (ocmfJSONDocument.payload.MV ?? "") + "|" + (ocmfJSONDocument.payload.MM ?? "") + "|" + (ocmfJSONDocument.payload.MS ?? "") + "|" + (ocmfJSONDocument.payload.MF ?? "") + "|" + (ocmfJSONDocument.payload.IS === true ? "1|" : "0|") + (ocmfJSONDocument.payload.IL ?? "") + "|" + //(ocmfJSONDocument.payload.IF ?? "") + "|" +
|
|
12835
|
+
(ocmfJSONDocument.payload.IT ?? "") + "|" + (ocmfJSONDocument.payload.ID ?? "") + "|" + (ocmfJSONDocument.payload.TT ?? "") + "|" + (ocmfJSONDocument.payload.CF ?? "") + "|" + (ocmfJSONDocument.payload.CT ?? "") + "|" + (ocmfJSONDocument.payload.CI ?? "");
|
|
12781
12836
|
if (!ocmfJSONDocumentGroups.has(groupingKey))
|
|
12782
12837
|
ocmfJSONDocumentGroups.set(groupingKey, new Array());
|
|
12783
12838
|
ocmfJSONDocumentGroups.get(groupingKey)?.push(ocmfJSONDocument);
|
|
@@ -12790,7 +12845,7 @@ var OCMF = class {
|
|
|
12790
12845
|
}
|
|
12791
12846
|
}
|
|
12792
12847
|
for (const ocmfJSONDocumentGroup of ocmfJSONDocumentGroups.values()) {
|
|
12793
|
-
if (PublicKey) {
|
|
12848
|
+
if (PublicKey != null) {
|
|
12794
12849
|
for (const ocmfJSONDocument of ocmfJSONDocumentGroup)
|
|
12795
12850
|
if (ocmfJSONDocument.validationStatus === "Unvalidated" /* Unvalidated */)
|
|
12796
12851
|
await this.validateOCMFSignature(ocmfJSONDocument, PublicKey);
|
|
@@ -12842,12 +12897,6 @@ var OCPI = class {
|
|
|
12842
12897
|
constructor(chargy) {
|
|
12843
12898
|
this.chargy = chargy;
|
|
12844
12899
|
}
|
|
12845
|
-
bufferToHex(buffer, Reverse) {
|
|
12846
|
-
return (Reverse ? Array.from(new Uint8Array(buffer)).reverse() : Array.from(new Uint8Array(buffer))).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
12847
|
-
}
|
|
12848
|
-
bufferToNumber(buffer) {
|
|
12849
|
-
return parseInt(Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join(""), 16);
|
|
12850
|
-
}
|
|
12851
12900
|
//#region tryToParseChargeITContainerFormat(SomeJSON)
|
|
12852
12901
|
// The chargeIT mobility data format does not always provide context information or format identifiers!
|
|
12853
12902
|
async tryToParseOCPIFormat(SomeJSON) {
|
|
@@ -12881,7 +12930,7 @@ var OCPI = class {
|
|
|
12881
12930
|
};
|
|
12882
12931
|
if (encoding_method === "OCMF" && isMandatoryJSONArray(signed_values) && signed_values.length > 0) {
|
|
12883
12932
|
const firstSignedData = asString(asJSONObject(signed_values[0])?.["signed_data"]);
|
|
12884
|
-
if (firstSignedData) {
|
|
12933
|
+
if (firstSignedData != null && firstSignedData.length > 0) {
|
|
12885
12934
|
const placeInfo = asJSONObject(SomeJSON["placeInfo"]);
|
|
12886
12935
|
const geoLocation = asJSONObject(placeInfo?.["geoLocation"]);
|
|
12887
12936
|
const address = asJSONObject(placeInfo?.["address"]);
|
|
@@ -12900,7 +12949,7 @@ var OCPI = class {
|
|
|
12900
12949
|
},
|
|
12901
12950
|
energyMeter: asJSONObject(SomeJSON["meterInfo"])
|
|
12902
12951
|
};
|
|
12903
|
-
return
|
|
12952
|
+
return new OCMF(this.chargy).TryToParseOCMFDocument(
|
|
12904
12953
|
firstSignedData,
|
|
12905
12954
|
asString(public_key),
|
|
12906
12955
|
encoding_method,
|
|
@@ -13218,9 +13267,9 @@ var OCPI = class {
|
|
|
13218
13267
|
],
|
|
13219
13268
|
certainty: 0
|
|
13220
13269
|
};
|
|
13221
|
-
if (smvContext?.startsWith("https://www.chargeit-mobility.com/contexts/bsm-ws36a-json"))
|
|
13270
|
+
if (smvContext?.startsWith("https://www.chargeit-mobility.com/contexts/bsm-ws36a-json") === true)
|
|
13222
13271
|
return new BSMCrypt01(this.chargy).tryToParseBSM_WS36aMeasurements(CTR, evseIdStr, asString(chargingStation_controllerSoftwareVersion) ?? null, signedMeterValues);
|
|
13223
|
-
if (smvContext?.startsWith("ALFEN"))
|
|
13272
|
+
if (smvContext?.startsWith("ALFEN") === true)
|
|
13224
13273
|
return new Alfen(this.chargy).TryToParseALFENFormat(
|
|
13225
13274
|
signedMeterValues.map((value) => asString(asJSONObject(value)?.["payload"]) ?? ""),
|
|
13226
13275
|
{
|
|
@@ -13367,9 +13416,9 @@ function parsePCDFDocument(input) {
|
|
|
13367
13416
|
}
|
|
13368
13417
|
const fields = {};
|
|
13369
13418
|
for (let i = 0; i < PCDF_FIELD_ORDER.length; i++) {
|
|
13370
|
-
const value = match
|
|
13371
|
-
const field = PCDF_FIELD_ORDER
|
|
13372
|
-
if (
|
|
13419
|
+
const value = getArrayElement(match, i + 1, "Missing PCDF field value");
|
|
13420
|
+
const field = getArrayElement(PCDF_FIELD_ORDER, i, "Missing PCDF field name");
|
|
13421
|
+
if (value.length === 0)
|
|
13373
13422
|
throw new PCDFParseError("MISSING_FIELDS", "Missing fields in the data tuple", field);
|
|
13374
13423
|
fields[field] = value;
|
|
13375
13424
|
}
|
|
@@ -13741,8 +13790,10 @@ function parsePCDFReadingValue(value, errors) {
|
|
|
13741
13790
|
errors.push("Session information is invalid");
|
|
13742
13791
|
return void 0;
|
|
13743
13792
|
}
|
|
13793
|
+
const integralPart = getArrayElement(match, 1, "Missing PCDF reading integral part");
|
|
13794
|
+
const fractionalPart = getArrayElement(match, 2, "Missing PCDF reading fractional part");
|
|
13744
13795
|
return {
|
|
13745
|
-
value: new Decimal(
|
|
13796
|
+
value: new Decimal(integralPart + "." + fractionalPart),
|
|
13746
13797
|
unit: "kWh"
|
|
13747
13798
|
};
|
|
13748
13799
|
}
|
|
@@ -13777,9 +13828,9 @@ function hexToBytes2(hex, errorMessage) {
|
|
|
13777
13828
|
}
|
|
13778
13829
|
function readDERLength(bytes, getOffset, setOffset) {
|
|
13779
13830
|
let offset = getOffset();
|
|
13780
|
-
|
|
13781
|
-
if (b == null)
|
|
13831
|
+
if (offset >= bytes.length)
|
|
13782
13832
|
throw new Error("Invalid signature");
|
|
13833
|
+
const b = getArrayElement(bytes, offset++, "Invalid signature");
|
|
13783
13834
|
if ((b & 128) === 0) {
|
|
13784
13835
|
setOffset(offset);
|
|
13785
13836
|
return b;
|
|
@@ -13789,9 +13840,9 @@ function readDERLength(bytes, getOffset, setOffset) {
|
|
|
13789
13840
|
throw new Error("Invalid signature");
|
|
13790
13841
|
let length = 0;
|
|
13791
13842
|
for (let i = 0; i < octets; i++) {
|
|
13792
|
-
|
|
13793
|
-
if (value == null)
|
|
13843
|
+
if (offset >= bytes.length)
|
|
13794
13844
|
throw new Error("Invalid signature");
|
|
13845
|
+
const value = getArrayElement(bytes, offset++, "Invalid signature");
|
|
13795
13846
|
length = (length << 8) + value;
|
|
13796
13847
|
}
|
|
13797
13848
|
setOffset(offset);
|
|
@@ -13820,30 +13871,33 @@ var SAFEXML = class _SAFEXML {
|
|
|
13820
13871
|
this.chargy = chargy;
|
|
13821
13872
|
}
|
|
13822
13873
|
static ParseChargingStationContext(XMLDocument) {
|
|
13823
|
-
const chargingStationElement = getElementsByLocalName(XMLDocument, "chargingStation")
|
|
13824
|
-
if (
|
|
13874
|
+
const chargingStationElement = getElementsByLocalName(XMLDocument, "chargingStation").at(0);
|
|
13875
|
+
if (chargingStationElement === void 0)
|
|
13825
13876
|
return {};
|
|
13826
|
-
const
|
|
13877
|
+
const chargingStationAttributeId = chargingStationElement.getAttribute("id")?.trim();
|
|
13878
|
+
const chargingStationId = chargingStationAttributeId != null && chargingStationAttributeId.length > 0 ? chargingStationAttributeId : getTrimmedTextContent(getDirectChildByLocalName(chargingStationElement, "id"));
|
|
13827
13879
|
const softwareVersion = getTrimmedTextContent(getDirectChildByLocalName(chargingStationElement, "softwareVersion"));
|
|
13828
13880
|
const geoLocationElement = getDirectChildByLocalName(chargingStationElement, "geoLocation");
|
|
13829
13881
|
const latitude = Number.parseFloat(getTrimmedTextContent(getDirectChildByLocalName(geoLocationElement ?? chargingStationElement, "latitude")) ?? "");
|
|
13830
13882
|
const longitude = Number.parseFloat(getTrimmedTextContent(getDirectChildByLocalName(geoLocationElement ?? chargingStationElement, "longitude")) ?? "");
|
|
13831
13883
|
const geoLocation = Number.isFinite(latitude) && Number.isFinite(longitude) ? { lat: latitude, lng: longitude } : void 0;
|
|
13832
|
-
if (getDirectChildByLocalName(chargingStationElement, "EVSEs"))
|
|
13884
|
+
if (getDirectChildByLocalName(chargingStationElement, "EVSEs") !== void 0)
|
|
13833
13885
|
throw new Error("The SAFE chargingStation XML element must contain EVSE directly and no EVSEs container element!");
|
|
13834
13886
|
const evseElements = getDirectChildrenByLocalName(chargingStationElement, "EVSE");
|
|
13835
13887
|
if (evseElements.length > 1)
|
|
13836
13888
|
throw new Error("The SAFE chargingStation XML element must not contain more than one EVSE element!");
|
|
13837
|
-
const evseElement = evseElements
|
|
13838
|
-
const
|
|
13839
|
-
const
|
|
13889
|
+
const evseElement = evseElements.at(0);
|
|
13890
|
+
const evseAttributeId = evseElement?.getAttribute("id")?.trim();
|
|
13891
|
+
const evseTextId = getTrimmedTextContent(getDirectChildByLocalName(evseElement ?? chargingStationElement, "id"));
|
|
13892
|
+
const evseId = evseAttributeId != null && evseAttributeId.length > 0 ? evseAttributeId : evseTextId ?? "";
|
|
13893
|
+
const connectorElements = evseElement !== void 0 ? getDirectChildrenByLocalName(evseElement, "connector") : [];
|
|
13840
13894
|
if (connectorElements.length > 1)
|
|
13841
13895
|
throw new Error("The SAFE EVSE XML element must not contain more than one connector element!");
|
|
13842
|
-
const connectorElement = connectorElements
|
|
13896
|
+
const connectorElement = connectorElements.at(0);
|
|
13843
13897
|
const connectorId = connectorElement?.getAttribute("id")?.trim();
|
|
13844
13898
|
const connectorType = getTrimmedTextContent(getDirectChildByLocalName(connectorElement ?? evseElement ?? chargingStationElement, "type"));
|
|
13845
|
-
const connector = connectorType ? { "@id": connectorId, type: connectorType, looses: 0 } : void 0;
|
|
13846
|
-
const parsedEVSE = evseElement ? {
|
|
13899
|
+
const connector = connectorType != null && connectorType.length > 0 ? { "@id": connectorId, type: connectorType, looses: 0 } : void 0;
|
|
13900
|
+
const parsedEVSE = evseElement !== void 0 ? {
|
|
13847
13901
|
"@id": evseId,
|
|
13848
13902
|
"description": parseDescription(evseElement),
|
|
13849
13903
|
"meters": [],
|
|
@@ -14008,8 +14062,8 @@ var XMLContainer = class {
|
|
|
14008
14062
|
if (values.length == 1) {
|
|
14009
14063
|
const valueList = values[0]?.querySelectorAll("signedMeterValue");
|
|
14010
14064
|
if (valueList != null && valueList.length >= 1) {
|
|
14011
|
-
for (
|
|
14012
|
-
const publicKey =
|
|
14065
|
+
for (const valueElement of valueList) {
|
|
14066
|
+
const publicKey = valueElement.querySelector("publicKey");
|
|
14013
14067
|
if (publicKey != null) {
|
|
14014
14068
|
const publicKeyEncoding = publicKey.attributes.getNamedItem("encoding")?.value.trim().toLowerCase() ?? "";
|
|
14015
14069
|
let publicKeyValue = publicKey.textContent.trim();
|
|
@@ -14049,7 +14103,7 @@ var XMLContainer = class {
|
|
|
14049
14103
|
certainty: 0
|
|
14050
14104
|
};
|
|
14051
14105
|
}
|
|
14052
|
-
const meterValueSignature =
|
|
14106
|
+
const meterValueSignature = valueElement.querySelector("meterValueSignature");
|
|
14053
14107
|
if (meterValueSignature != null) {
|
|
14054
14108
|
const meterValueSignatureEncoding = meterValueSignature.attributes.getNamedItem("encoding")?.value.trim().toLowerCase() ?? "";
|
|
14055
14109
|
let meterValueSignatureValue = meterValueSignature.textContent.trim();
|
|
@@ -14082,7 +14136,7 @@ var XMLContainer = class {
|
|
|
14082
14136
|
};
|
|
14083
14137
|
common.meterValueSignatures.push(meterValueSignatureValue);
|
|
14084
14138
|
}
|
|
14085
|
-
const signatureMethod =
|
|
14139
|
+
const signatureMethod = valueElement.querySelector("signatureMethod")?.textContent.trim().toLowerCase() ?? "";
|
|
14086
14140
|
if (common.signatureMethod == "")
|
|
14087
14141
|
common.signatureMethod = signatureMethod;
|
|
14088
14142
|
else if (common.signatureMethod != signatureMethod)
|
|
@@ -14091,7 +14145,7 @@ var XMLContainer = class {
|
|
|
14091
14145
|
message: this.chargy.GetMultilanguageText("Invalid mixture of different signature methods within the given XML container!"),
|
|
14092
14146
|
certainty: 0
|
|
14093
14147
|
};
|
|
14094
|
-
const encodingMethod =
|
|
14148
|
+
const encodingMethod = valueElement.querySelector("encodingMethod")?.textContent.trim().toLowerCase() ?? "";
|
|
14095
14149
|
if (common.encodingMethod == "")
|
|
14096
14150
|
common.encodingMethod = encodingMethod;
|
|
14097
14151
|
else if (common.encodingMethod != encodingMethod)
|
|
@@ -14100,7 +14154,7 @@ var XMLContainer = class {
|
|
|
14100
14154
|
message: this.chargy.GetMultilanguageText("Invalid mixture of different signed data formats within the given XML container!"),
|
|
14101
14155
|
certainty: 0
|
|
14102
14156
|
};
|
|
14103
|
-
const encodedMeterValue =
|
|
14157
|
+
const encodedMeterValue = valueElement.querySelector("encodedMeterValue");
|
|
14104
14158
|
if (encodedMeterValue != null) {
|
|
14105
14159
|
const signedDataEncoding = encodedMeterValue.attributes.getNamedItem("encoding")?.value.trim() ?? "";
|
|
14106
14160
|
let signedDataValue = encodedMeterValue.textContent.trim();
|
|
@@ -14161,12 +14215,6 @@ var ChargeIT = class {
|
|
|
14161
14215
|
constructor(chargy) {
|
|
14162
14216
|
this.chargy = chargy;
|
|
14163
14217
|
}
|
|
14164
|
-
bufferToHex(buffer, Reverse) {
|
|
14165
|
-
return (Reverse ? Array.from(new Uint8Array(buffer)).reverse() : Array.from(new Uint8Array(buffer))).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
14166
|
-
}
|
|
14167
|
-
bufferToNumber(buffer) {
|
|
14168
|
-
return parseInt(Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join(""), 16);
|
|
14169
|
-
}
|
|
14170
14218
|
//#region TryToParseOldChargeITMeterValuesFormat(CTR, evseId, address, geoLocation, signedMeterValues)
|
|
14171
14219
|
TryToParseOldChargeITMeterValuesFormat(CTR, evseId, address, geoLocation, signedMeterValues) {
|
|
14172
14220
|
const CTRArray = new Array();
|
|
@@ -14266,14 +14314,8 @@ var ChargeIT = class {
|
|
|
14266
14314
|
});
|
|
14267
14315
|
}
|
|
14268
14316
|
}
|
|
14269
|
-
const firstMeterValue = CTRArray
|
|
14270
|
-
const lastMeterValue = CTRArray
|
|
14271
|
-
if (firstMeterValue === void 0 || lastMeterValue === void 0)
|
|
14272
|
-
return {
|
|
14273
|
-
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
14274
|
-
message: this.chargy.GetMultilanguageText("UnknownOrInvalidChargingSessionFormat"),
|
|
14275
|
-
certainty: 0
|
|
14276
|
-
};
|
|
14317
|
+
const firstMeterValue = getFirstArrayElement(CTRArray, "Missing first chargeIT meter value");
|
|
14318
|
+
const lastMeterValue = getLastArrayElement(CTRArray, "Missing last chargeIT meter value");
|
|
14277
14319
|
CTR["@id"] = lastMeterValue["transactionId"];
|
|
14278
14320
|
CTR.begin = this.chargy.moment.unix(firstMeterValue["measuredValue"]["timestampLocal"]["timestamp"]).utc().format();
|
|
14279
14321
|
CTR.end = this.chargy.moment.unix(lastMeterValue["measuredValue"]["timestampLocal"]["timestamp"]).utc().format();
|
|
@@ -14503,7 +14545,6 @@ var ChargeIT = class {
|
|
|
14503
14545
|
if (consistent) {
|
|
14504
14546
|
if (signedMeterValueContext === "https://www.lichtblick.de/contexts/bsm-ws36a-json-v0" || signedMeterValueContext === "https://www.lichtblick.de/contexts/bsm-ws36a-json-v1" || signedMeterValueContext === "https://www.eneco.com/contexts/bsm-ws36a-json-v0" || signedMeterValueContext === "https://www.eneco.com/contexts/bsm-ws36a-json-v1" || signedMeterValueContext === "https://www.chargeit-mobility.com/contexts/bsm-ws36a-json-v0" || signedMeterValueContext === "https://www.chargeit-mobility.com/contexts/bsm-ws36a-json-v1") {
|
|
14505
14547
|
} else if (signedMeterValueContext.startsWith("ALFEN")) {
|
|
14506
|
-
} else if (containerFormat === oldChargeITContainerFormat) {
|
|
14507
14548
|
} else if (signedMeterValueContext === oldChargeITMeterValueFormat) {
|
|
14508
14549
|
let measurementCounter = 0;
|
|
14509
14550
|
for (const signedMeterValue of signedMeterValues) {
|
|
@@ -14619,10 +14660,10 @@ var ChargeIT = class {
|
|
|
14619
14660
|
}
|
|
14620
14661
|
}
|
|
14621
14662
|
const chargePoint = signedMeterValue["chargePoint"];
|
|
14622
|
-
if (!isMandatoryJSONObject(chargePoint)) {
|
|
14663
|
+
if (chargePoint !== void 0 && !isMandatoryJSONObject(chargePoint)) {
|
|
14623
14664
|
errors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("MissingOrInvalid_SignedMeterValue_ChargePointInformationP", measurementCounter)));
|
|
14624
14665
|
secondaryErrors += 1;
|
|
14625
|
-
} else {
|
|
14666
|
+
} else if (isMandatoryJSONObject(chargePoint)) {
|
|
14626
14667
|
if (!isMandatoryString(chargePoint["softwareVersion"]))
|
|
14627
14668
|
errors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("MissingOrInvalid_SignedMeterValue_ChargePointInformation_SoftwareVersionP", measurementCounter)));
|
|
14628
14669
|
}
|
|
@@ -14770,19 +14811,17 @@ var ChargeIT = class {
|
|
|
14770
14811
|
}
|
|
14771
14812
|
);
|
|
14772
14813
|
}
|
|
14773
|
-
if (
|
|
14774
|
-
|
|
14775
|
-
|
|
14776
|
-
|
|
14777
|
-
|
|
14778
|
-
|
|
14779
|
-
|
|
14780
|
-
|
|
14781
|
-
address: { "street": address_street, "postalCode": address_zipCode, "city": address_town, "country": address_country }
|
|
14782
|
-
}
|
|
14814
|
+
if (asJSONObject(signedMeterValues[0])?.["format"] == "ALFEN")
|
|
14815
|
+
return new Alfen(this.chargy).TryToParseALFENFormat(
|
|
14816
|
+
signedMeterValues.map((value) => asString(asJSONObject(value)?.["payload"]) ?? ""),
|
|
14817
|
+
{
|
|
14818
|
+
EVSEId: evseId,
|
|
14819
|
+
chargingStation: {
|
|
14820
|
+
geoLocation: { "lat": geoLocation_lat, "lng": geoLocation_lon },
|
|
14821
|
+
address: { "street": address_street, "postalCode": address_zipCode, "city": address_town, "country": address_country }
|
|
14783
14822
|
}
|
|
14784
|
-
|
|
14785
|
-
|
|
14823
|
+
}
|
|
14824
|
+
);
|
|
14786
14825
|
if (signedMeterValueContext === oldChargeITMeterValueFormat)
|
|
14787
14826
|
return this.TryToParseOldChargeITMeterValuesFormat(
|
|
14788
14827
|
CTR,
|
|
@@ -14972,8 +15011,6 @@ var ChargeIT = class {
|
|
|
14972
15011
|
errors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("MissingOrInvalid_SignedMeterValue_MeterInfo_MeterIdP", 1)));
|
|
14973
15012
|
}
|
|
14974
15013
|
if (isMandatoryJSONArray(chargingTariffs)) {
|
|
14975
|
-
for (let i = 0; i < chargingTariffs.length; i++) {
|
|
14976
|
-
}
|
|
14977
15014
|
}
|
|
14978
15015
|
if (totalCosts) {
|
|
14979
15016
|
if (!isMandatoryNumber(totalCosts_total))
|
|
@@ -15126,9 +15163,9 @@ var ChargeIT = class {
|
|
|
15126
15163
|
],
|
|
15127
15164
|
certainty: 0
|
|
15128
15165
|
};
|
|
15129
|
-
if (smvContext?.startsWith("https://www.chargeit-mobility.com/contexts/bsm-ws36a-json"))
|
|
15166
|
+
if (smvContext?.startsWith("https://www.chargeit-mobility.com/contexts/bsm-ws36a-json") === true)
|
|
15130
15167
|
return new BSMCrypt01(this.chargy).tryToParseBSM_WS36aMeasurements(CTR, evseIdStr, asString(chargingStation_controllerSoftwareVersion) ?? null, signedMeterValues);
|
|
15131
|
-
if (smvContext?.startsWith("ALFEN"))
|
|
15168
|
+
if (smvContext?.startsWith("ALFEN") === true)
|
|
15132
15169
|
return new Alfen(this.chargy).TryToParseALFENFormat(
|
|
15133
15170
|
signedMeterValues.map((value) => asString(asJSONObject(value)?.["payload"]) ?? ""),
|
|
15134
15171
|
{
|
|
@@ -15231,10 +15268,8 @@ var ChargePoint = class {
|
|
|
15231
15268
|
if (startTimeUTC !== void 0 && (parkingEnd === void 0 || startTimeUTC > parkingEnd))
|
|
15232
15269
|
parkingEnd = endTimeUTC;
|
|
15233
15270
|
}
|
|
15234
|
-
|
|
15235
|
-
|
|
15236
|
-
if (chargingEnd === void 0)
|
|
15237
|
-
chargingEnd = parkingEnd;
|
|
15271
|
+
chargingStart ??= parkingStart;
|
|
15272
|
+
chargingEnd ??= parkingEnd;
|
|
15238
15273
|
let sessionStart = parkingStart !== void 0 && (chargingStart === void 0 || parkingStart < chargingStart) ? parkingStart : chargingStart;
|
|
15239
15274
|
if (sessionStart === void 0 && parkingStart !== void 0)
|
|
15240
15275
|
sessionStart = parkingStart;
|
|
@@ -15383,7 +15418,7 @@ var ChargePoint = class {
|
|
|
15383
15418
|
"status": "Unvalidated" /* Unvalidated */
|
|
15384
15419
|
};
|
|
15385
15420
|
if (parking && parking.length > 0 && CTR.chargingSessions && CTR.chargingSessions.length > 0) {
|
|
15386
|
-
const chargingSession = CTR.chargingSessions
|
|
15421
|
+
const chargingSession = getFirstArrayElement(CTR.chargingSessions, "Missing ChargePoint charging session");
|
|
15387
15422
|
chargingSession.parking = [];
|
|
15388
15423
|
for (const parkingItem of parking) {
|
|
15389
15424
|
const parkingObj = asJSONObject(parkingItem);
|
|
@@ -15679,6 +15714,8 @@ var ChargePointCrypt01 = class extends ACrypt {
|
|
|
15679
15714
|
case "InvalidSignature" /* InvalidSignature */:
|
|
15680
15715
|
currentResult.status = "InvalidStartValue" /* InvalidStartValue */;
|
|
15681
15716
|
break;
|
|
15717
|
+
default:
|
|
15718
|
+
break;
|
|
15682
15719
|
}
|
|
15683
15720
|
} else if (i == measurement.values.length - 1) {
|
|
15684
15721
|
switch (currentResult.status) {
|
|
@@ -15691,6 +15728,8 @@ var ChargePointCrypt01 = class extends ACrypt {
|
|
|
15691
15728
|
case "InvalidSignature" /* InvalidSignature */:
|
|
15692
15729
|
currentResult.status = "InvalidStopValue" /* InvalidStopValue */;
|
|
15693
15730
|
break;
|
|
15731
|
+
default:
|
|
15732
|
+
break;
|
|
15694
15733
|
}
|
|
15695
15734
|
} else {
|
|
15696
15735
|
switch (currentResult.status) {
|
|
@@ -15703,6 +15742,8 @@ var ChargePointCrypt01 = class extends ACrypt {
|
|
|
15703
15742
|
case "InvalidSignature" /* InvalidSignature */:
|
|
15704
15743
|
currentResult.status = "InvalidStopValue" /* InvalidStopValue */;
|
|
15705
15744
|
break;
|
|
15745
|
+
default:
|
|
15746
|
+
break;
|
|
15706
15747
|
}
|
|
15707
15748
|
}
|
|
15708
15749
|
}
|
|
@@ -15732,9 +15773,9 @@ var ChargePointCrypt01 = class extends ACrypt {
|
|
|
15732
15773
|
const cryptoResult = {
|
|
15733
15774
|
status: "NoOperation" /* NoOperation */
|
|
15734
15775
|
};
|
|
15735
|
-
return
|
|
15776
|
+
return Promise.resolve(setResult("NoOperation" /* NoOperation */));
|
|
15736
15777
|
}
|
|
15737
|
-
async ViewMeasurement(measurementValue,
|
|
15778
|
+
async ViewMeasurement(measurementValue, _errorDiv, introDiv, _infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
|
|
15738
15779
|
if (measurementValue.measurement?.chargingSession === void 0)
|
|
15739
15780
|
return new Error("Invalid measurement!");
|
|
15740
15781
|
const chargingSession = measurementValue.measurement.chargingSession;
|
|
@@ -15742,8 +15783,8 @@ var ChargePointCrypt01 = class extends ACrypt {
|
|
|
15742
15783
|
const algorithmName = typeof chargingSession.publicKey?.algorithm === "object" ? chargingSession.publicKey.algorithm.name : chargingSession.publicKey?.algorithm ?? "";
|
|
15743
15784
|
const algorithmType = typeof chargingSession.publicKey?.type === "object" ? chargingSession.publicKey.type.name : chargingSession.publicKey?.type;
|
|
15744
15785
|
introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "ChargePointCrypt01").replace("{cryptoAlgorithm}", algorithmName);
|
|
15745
|
-
if (PlainTextDiv.parentElement
|
|
15746
|
-
PlainTextDiv.parentElement.children
|
|
15786
|
+
if (PlainTextDiv.parentElement) {
|
|
15787
|
+
getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = "Plain text (secrrct)";
|
|
15747
15788
|
}
|
|
15748
15789
|
PlainTextDiv.innerText = atob(chargingSession.original ?? "");
|
|
15749
15790
|
PlainTextDiv.style.fontFamily = "monospace";
|
|
@@ -15765,22 +15806,23 @@ var ChargePointCrypt01 = class extends ACrypt {
|
|
|
15765
15806
|
hashInfo = "(SHA512, 512 Bits, hex)";
|
|
15766
15807
|
break;
|
|
15767
15808
|
}
|
|
15768
|
-
if (HashedPlainTextDiv.parentElement
|
|
15769
|
-
HashedPlainTextDiv.parentElement.children
|
|
15809
|
+
if (HashedPlainTextDiv.parentElement) {
|
|
15810
|
+
getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = "Hashed plain text " + hashInfo;
|
|
15770
15811
|
}
|
|
15771
15812
|
HashedPlainTextDiv.innerHTML = chargingSession.hashValue?.match(/.{1,8}/g)?.join(" ") ?? "0x00000000000000000000000000000000000";
|
|
15772
15813
|
if (chargingSession.publicKey != null) {
|
|
15773
|
-
if (PublicKeyDiv.parentElement
|
|
15774
|
-
PublicKeyDiv.parentElement.children
|
|
15814
|
+
if (PublicKeyDiv.parentElement) {
|
|
15815
|
+
getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = "Public Key (" + (algorithmType != null && algorithmType.length > 0 ? algorithmType + ", " : "") + (algorithmName.length > 0 ? algorithmName + ", " : "") + "hex)";
|
|
15775
15816
|
}
|
|
15776
15817
|
PublicKeyDiv.innerHTML = chargingSession.publicKey.value.startsWith("04") ? '<span class="leadingFour">04</span> ' + (chargingSession.publicKey.value.substring(2).match(/.{1,8}/g)?.join(" ") ?? "") : chargingSession.publicKey.value.match(/.{1,8}/g)?.join(" ") ?? "";
|
|
15777
|
-
|
|
15778
|
-
|
|
15818
|
+
const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
|
|
15819
|
+
if (publicKeySignatureContainer !== void 0) {
|
|
15820
|
+
publicKeySignatureContainer.innerHTML = "";
|
|
15779
15821
|
}
|
|
15780
15822
|
if (result.publicKeySignatures) {
|
|
15781
15823
|
for (const signature of result.publicKeySignatures) {
|
|
15782
15824
|
try {
|
|
15783
|
-
const signatureDiv =
|
|
15825
|
+
const signatureDiv = publicKeySignatureContainer?.appendChild(document.createElement("div"));
|
|
15784
15826
|
if (signatureDiv != null)
|
|
15785
15827
|
signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
|
|
15786
15828
|
measurementValue.measurement.chargingSession.chargingStation,
|
|
@@ -15795,8 +15837,8 @@ var ChargePointCrypt01 = class extends ACrypt {
|
|
|
15795
15837
|
}
|
|
15796
15838
|
}
|
|
15797
15839
|
if (chargingSession.signature != null) {
|
|
15798
|
-
if (SignatureExpectedDiv.parentElement
|
|
15799
|
-
SignatureExpectedDiv.parentElement.children
|
|
15840
|
+
if (SignatureExpectedDiv.parentElement) {
|
|
15841
|
+
getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = "Erwartete Signatur (secrrct.sign, rs, hex)";
|
|
15800
15842
|
}
|
|
15801
15843
|
if (typeof chargingSession.signature != "string")
|
|
15802
15844
|
SignatureExpectedDiv.innerHTML = "r: " + (chargingSession.signature.r?.toLowerCase().padStart(56, "0").match(/.{1,8}/g)?.join(" ") ?? "") + "<br />s: " + (chargingSession.signature.s?.toLowerCase().padStart(56, "0").match(/.{1,8}/g)?.join(" ") ?? "");
|
|
@@ -15828,6 +15870,7 @@ var ChargePointCrypt01 = class extends ACrypt {
|
|
|
15828
15870
|
break;
|
|
15829
15871
|
}
|
|
15830
15872
|
}
|
|
15873
|
+
return void 0;
|
|
15831
15874
|
}
|
|
15832
15875
|
};
|
|
15833
15876
|
|
|
@@ -15848,8 +15891,7 @@ function IsAChargeTransparencyRecord(data) {
|
|
|
15848
15891
|
function IsASessionCryptoResult(data) {
|
|
15849
15892
|
if (!isMandatoryJSONObject(data))
|
|
15850
15893
|
return false;
|
|
15851
|
-
|
|
15852
|
-
return sessionCryptoResult.status !== void 0;
|
|
15894
|
+
return true;
|
|
15853
15895
|
}
|
|
15854
15896
|
function CloneCTR(CTR) {
|
|
15855
15897
|
const clonedCTR = JSON.parse(JSON.stringify(CTR));
|
|
@@ -16025,8 +16067,10 @@ async function imageDataFromNodeCanvas(data) {
|
|
|
16025
16067
|
if (!isCanvasModule(canvasLib))
|
|
16026
16068
|
return void 0;
|
|
16027
16069
|
const image = await canvasLib.loadImage(Buffer$1.from(toUint8Array(data)));
|
|
16028
|
-
const
|
|
16029
|
-
const
|
|
16070
|
+
const naturalWidth = image.naturalWidth ?? 0;
|
|
16071
|
+
const naturalHeight = image.naturalHeight ?? 0;
|
|
16072
|
+
const width = naturalWidth > 0 ? naturalWidth : image.width;
|
|
16073
|
+
const height = naturalHeight > 0 ? naturalHeight : image.height;
|
|
16030
16074
|
if (width <= 0 || height <= 0)
|
|
16031
16075
|
return void 0;
|
|
16032
16076
|
const canvas = canvasLib.createCanvas(width, height);
|
|
@@ -16097,22 +16141,22 @@ async function importOptionalNodeModule(moduleName) {
|
|
|
16097
16141
|
}
|
|
16098
16142
|
async function readQRCodeTextFromImage(data, mimeType) {
|
|
16099
16143
|
const imageDataSources = typeof document === "undefined" ? [
|
|
16100
|
-
() => imageDataFromNodeCanvas(data),
|
|
16101
|
-
() => imageDataFromPNGOrJPEG(data, mimeType),
|
|
16102
|
-
() => imageDataFromBrowserCanvas(data, mimeType),
|
|
16103
|
-
() => imageDataFromBrowserImageElement(data, mimeType)
|
|
16144
|
+
async () => imageDataFromNodeCanvas(data),
|
|
16145
|
+
async () => imageDataFromPNGOrJPEG(data, mimeType),
|
|
16146
|
+
async () => imageDataFromBrowserCanvas(data, mimeType),
|
|
16147
|
+
async () => imageDataFromBrowserImageElement(data, mimeType)
|
|
16104
16148
|
] : [
|
|
16105
|
-
() => imageDataFromBrowserCanvas(data, mimeType),
|
|
16106
|
-
() => imageDataFromBrowserImageElement(data, mimeType),
|
|
16107
|
-
() => imageDataFromNodeCanvas(data),
|
|
16108
|
-
() => imageDataFromPNGOrJPEG(data, mimeType)
|
|
16149
|
+
async () => imageDataFromBrowserCanvas(data, mimeType),
|
|
16150
|
+
async () => imageDataFromBrowserImageElement(data, mimeType),
|
|
16151
|
+
async () => imageDataFromNodeCanvas(data),
|
|
16152
|
+
async () => imageDataFromPNGOrJPEG(data, mimeType)
|
|
16109
16153
|
];
|
|
16110
16154
|
for (const imageDataSource of imageDataSources) {
|
|
16111
16155
|
const imageData = await imageDataSource();
|
|
16112
16156
|
if (imageData == null)
|
|
16113
16157
|
continue;
|
|
16114
16158
|
const qrText = readQRCodeTextFromImageData(imageData);
|
|
16115
|
-
if (qrText && qrText.length > 0)
|
|
16159
|
+
if (qrText != null && qrText.length > 0)
|
|
16116
16160
|
return qrText;
|
|
16117
16161
|
}
|
|
16118
16162
|
return void 0;
|
|
@@ -16125,7 +16169,7 @@ function readQRCodeTextFromImageData(imageData) {
|
|
|
16125
16169
|
{ inversionAttempts: "attemptBoth" }
|
|
16126
16170
|
);
|
|
16127
16171
|
const qrText = qrCode?.data.trim();
|
|
16128
|
-
return qrText && qrText.length > 0 ? qrText : void 0;
|
|
16172
|
+
return qrText != null && qrText.length > 0 ? qrText : void 0;
|
|
16129
16173
|
}
|
|
16130
16174
|
|
|
16131
16175
|
// src/pdfjs/node.ts
|
|
@@ -16146,6 +16190,11 @@ var validationRules_default = {
|
|
|
16146
16190
|
}
|
|
16147
16191
|
}
|
|
16148
16192
|
};
|
|
16193
|
+
function isPdfAttachment(value) {
|
|
16194
|
+
if (!isMandatoryJSONObject(value))
|
|
16195
|
+
return false;
|
|
16196
|
+
return typeof value["filename"] === "string" && (value["content"] instanceof ArrayBuffer || ArrayBuffer.isView(value["content"]));
|
|
16197
|
+
}
|
|
16149
16198
|
var Chargy = class {
|
|
16150
16199
|
//#region Data
|
|
16151
16200
|
i18n;
|
|
@@ -16162,8 +16211,6 @@ var Chargy = class {
|
|
|
16162
16211
|
EVSEs = new Array();
|
|
16163
16212
|
meters = new Array();
|
|
16164
16213
|
chargingSessions = new Array();
|
|
16165
|
-
eMobilityProviders = new Array();
|
|
16166
|
-
mediationServices = new Array();
|
|
16167
16214
|
currentCTR = {};
|
|
16168
16215
|
internalCTR = {};
|
|
16169
16216
|
//#endregion
|
|
@@ -16177,41 +16224,55 @@ var Chargy = class {
|
|
|
16177
16224
|
this.showPKIDetails = ShowPKIDetails;
|
|
16178
16225
|
this.validationRules = validationRules;
|
|
16179
16226
|
}
|
|
16180
|
-
|
|
16181
|
-
|
|
16227
|
+
fileNameWithoutExtension(fileName) {
|
|
16228
|
+
const lastSeparator = Math.max(fileName.lastIndexOf("/"), fileName.lastIndexOf("\\"));
|
|
16229
|
+
const lastDot = fileName.lastIndexOf(".");
|
|
16230
|
+
if (lastDot > lastSeparator)
|
|
16231
|
+
return fileName.substring(0, lastDot);
|
|
16232
|
+
return fileName;
|
|
16182
16233
|
}
|
|
16183
|
-
|
|
16184
|
-
|
|
16185
|
-
|
|
16186
|
-
|
|
16187
|
-
|
|
16188
|
-
|
|
16234
|
+
tryExtractChargeTransparencyTextFromURL(qrText) {
|
|
16235
|
+
if (!qrText.startsWith("http://") && !qrText.startsWith("https://"))
|
|
16236
|
+
return qrText;
|
|
16237
|
+
try {
|
|
16238
|
+
const url = new URL(qrText);
|
|
16239
|
+
const candidates = [
|
|
16240
|
+
url.hash.startsWith("#") ? url.hash.substring(1) : url.hash,
|
|
16241
|
+
url.searchParams.get("data"),
|
|
16242
|
+
url.searchParams.get("content"),
|
|
16243
|
+
url.searchParams.get("ctr"),
|
|
16244
|
+
url.searchParams.get("record"),
|
|
16245
|
+
url.searchParams.get("payload"),
|
|
16246
|
+
url.searchParams.get("q")
|
|
16247
|
+
];
|
|
16248
|
+
for (const candidate of candidates) {
|
|
16249
|
+
const decodedCandidate = candidate != null ? decodeURIComponent(candidate).trim() : "";
|
|
16250
|
+
if (decodedCandidate.startsWith("<?xml") || decodedCandidate.startsWith("<values") || decodedCandidate.startsWith("{") || decodedCandidate.startsWith("[") || decodedCandidate.startsWith("OCMF") || decodedCandidate.startsWith("AP;")) {
|
|
16251
|
+
return decodedCandidate;
|
|
16252
|
+
}
|
|
16189
16253
|
}
|
|
16254
|
+
} catch {
|
|
16255
|
+
console.log("Invalid URL in QR code: " + qrText);
|
|
16190
16256
|
}
|
|
16191
|
-
return
|
|
16257
|
+
return qrText;
|
|
16192
16258
|
}
|
|
16193
|
-
|
|
16194
|
-
|
|
16195
|
-
|
|
16196
|
-
|
|
16197
|
-
|
|
16259
|
+
tryExtractSignedDataTextFromXML(qrText) {
|
|
16260
|
+
const trimmedQRCodeText = qrText.trim();
|
|
16261
|
+
if (!trimmedQRCodeText.startsWith("<?xml") && !trimmedQRCodeText.startsWith("<"))
|
|
16262
|
+
return qrText;
|
|
16263
|
+
try {
|
|
16264
|
+
const xmlDocument = new DOMParser().parseFromString(trimmedQRCodeText, "text/xml");
|
|
16265
|
+
const signedDataValues = getElementsByLocalName(xmlDocument, "signedData").filter((signedData) => (signedData.getAttribute("format") ?? "").trim().toLowerCase() === "alfen").map((signedData) => signedData.textContent.trim()).filter((signedData) => signedData.startsWith("AP;"));
|
|
16266
|
+
if (signedDataValues.length > 0)
|
|
16267
|
+
return signedDataValues.join("\n");
|
|
16268
|
+
} catch {
|
|
16269
|
+
console.log("Error parsing XML content from QR code: " + qrText);
|
|
16198
16270
|
}
|
|
16199
|
-
|
|
16200
|
-
if (english !== void 0)
|
|
16201
|
-
return english;
|
|
16202
|
-
return Object.values(Text).find((value) => value !== void 0);
|
|
16203
|
-
}
|
|
16204
|
-
CompleteMultilanguageText(Text, fallbackText) {
|
|
16205
|
-
const result = {
|
|
16206
|
-
...Text ?? {}
|
|
16207
|
-
};
|
|
16208
|
-
const fallback = this.FindBestMultilanguageText(result) ?? fallbackText;
|
|
16209
|
-
for (const language of this.uiLanguages)
|
|
16210
|
-
result[language] ??= fallback;
|
|
16211
|
-
return result;
|
|
16271
|
+
return qrText;
|
|
16212
16272
|
}
|
|
16273
|
+
//#region Public key methods...
|
|
16213
16274
|
PublicKeyIdFromFileName(fileName) {
|
|
16214
|
-
return (fileName.
|
|
16275
|
+
return (fileName.includes(".") ? fileName.substring(0, fileName.indexOf(".")) : fileName).replace(/[-_]?public[-_]?key/i, "");
|
|
16215
16276
|
}
|
|
16216
16277
|
TryToParseDERPublicKey(keyId, publicKeyBuffer) {
|
|
16217
16278
|
const ASN1_OIDs = this.asn1.define("OIDs", function() {
|
|
@@ -16292,66 +16353,13 @@ var Chargy = class {
|
|
|
16292
16353
|
return textContent.replace(/\s+/g, "");
|
|
16293
16354
|
return void 0;
|
|
16294
16355
|
}
|
|
16356
|
+
//#endregion
|
|
16357
|
+
//#region QR code image files...
|
|
16295
16358
|
isSupportedQRCodeImageFile(fileInfo, mimeType) {
|
|
16296
16359
|
const mimeTypeToCheck = (mimeType ?? fileInfo.type ?? "").toLowerCase();
|
|
16297
16360
|
const fileName = fileInfo.name.toLowerCase();
|
|
16298
16361
|
return mimeTypeToCheck === "image/png" || mimeTypeToCheck === "image/jpeg" || mimeTypeToCheck === "image/jpg" || mimeTypeToCheck === "image/gif" || mimeTypeToCheck === "image/webp" || mimeTypeToCheck === "image/bmp" || mimeTypeToCheck === "image/svg+xml" || fileName.endsWith(".png") || fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") || fileName.endsWith(".gif") || fileName.endsWith(".webp") || fileName.endsWith(".bmp") || fileName.endsWith(".svg");
|
|
16299
16362
|
}
|
|
16300
|
-
fileNameWithoutExtension(fileName) {
|
|
16301
|
-
const lastSeparator = Math.max(fileName.lastIndexOf("/"), fileName.lastIndexOf("\\"));
|
|
16302
|
-
const lastDot = fileName.lastIndexOf(".");
|
|
16303
|
-
if (lastDot > lastSeparator)
|
|
16304
|
-
return fileName.substring(0, lastDot);
|
|
16305
|
-
return fileName;
|
|
16306
|
-
}
|
|
16307
|
-
textFileNameForQRCodeContent(fileName, qrText) {
|
|
16308
|
-
const trimmedQRCodeText = qrText.trimStart();
|
|
16309
|
-
const baseFileName = this.fileNameWithoutExtension(fileName);
|
|
16310
|
-
if (trimmedQRCodeText.startsWith("<?xml") || trimmedQRCodeText.startsWith("<"))
|
|
16311
|
-
return baseFileName + ".xml";
|
|
16312
|
-
if (trimmedQRCodeText.startsWith("{") || trimmedQRCodeText.startsWith("["))
|
|
16313
|
-
return baseFileName + ".json";
|
|
16314
|
-
return baseFileName + ".txt";
|
|
16315
|
-
}
|
|
16316
|
-
tryExtractChargeTransparencyTextFromURL(qrText) {
|
|
16317
|
-
if (!qrText.startsWith("http://") && !qrText.startsWith("https://"))
|
|
16318
|
-
return qrText;
|
|
16319
|
-
try {
|
|
16320
|
-
const url = new URL(qrText);
|
|
16321
|
-
const candidates = [
|
|
16322
|
-
url.hash.startsWith("#") ? url.hash.substring(1) : url.hash,
|
|
16323
|
-
url.searchParams.get("data"),
|
|
16324
|
-
url.searchParams.get("content"),
|
|
16325
|
-
url.searchParams.get("ctr"),
|
|
16326
|
-
url.searchParams.get("record"),
|
|
16327
|
-
url.searchParams.get("payload"),
|
|
16328
|
-
url.searchParams.get("q")
|
|
16329
|
-
];
|
|
16330
|
-
for (const candidate of candidates) {
|
|
16331
|
-
const decodedCandidate = candidate != null ? decodeURIComponent(candidate).trim() : "";
|
|
16332
|
-
if (decodedCandidate.startsWith("<?xml") || decodedCandidate.startsWith("<values") || decodedCandidate.startsWith("{") || decodedCandidate.startsWith("[") || decodedCandidate.startsWith("OCMF") || decodedCandidate.startsWith("AP;")) {
|
|
16333
|
-
return decodedCandidate;
|
|
16334
|
-
}
|
|
16335
|
-
}
|
|
16336
|
-
} catch {
|
|
16337
|
-
console.log("Invalid URL in QR code: " + qrText);
|
|
16338
|
-
}
|
|
16339
|
-
return qrText;
|
|
16340
|
-
}
|
|
16341
|
-
tryExtractSignedDataTextFromXML(qrText) {
|
|
16342
|
-
const trimmedQRCodeText = qrText.trim();
|
|
16343
|
-
if (!trimmedQRCodeText.startsWith("<?xml") && !trimmedQRCodeText.startsWith("<"))
|
|
16344
|
-
return qrText;
|
|
16345
|
-
try {
|
|
16346
|
-
const xmlDocument = new DOMParser().parseFromString(trimmedQRCodeText, "text/xml");
|
|
16347
|
-
const signedDataValues = getElementsByLocalName(xmlDocument, "signedData").filter((signedData) => (signedData.getAttribute("format") ?? "").trim().toLowerCase() === "alfen").map((signedData) => signedData.textContent.trim()).filter((signedData) => signedData.startsWith("AP;"));
|
|
16348
|
-
if (signedDataValues.length > 0)
|
|
16349
|
-
return signedDataValues.join("\n");
|
|
16350
|
-
} catch {
|
|
16351
|
-
console.log("Error parsing XML content from QR code: " + qrText);
|
|
16352
|
-
}
|
|
16353
|
-
return qrText;
|
|
16354
|
-
}
|
|
16355
16363
|
async expandQRCodeImageFiles(FileInfos) {
|
|
16356
16364
|
const expandedFileInfos = new Array();
|
|
16357
16365
|
for (const fileInfo of FileInfos) {
|
|
@@ -16383,7 +16391,50 @@ var Chargy = class {
|
|
|
16383
16391
|
}
|
|
16384
16392
|
return expandedFileInfos;
|
|
16385
16393
|
}
|
|
16386
|
-
|
|
16394
|
+
textFileNameForQRCodeContent(fileName, qrText) {
|
|
16395
|
+
const trimmedQRCodeText = qrText.trimStart();
|
|
16396
|
+
const baseFileName = this.fileNameWithoutExtension(fileName);
|
|
16397
|
+
if (trimmedQRCodeText.startsWith("<?xml") || trimmedQRCodeText.startsWith("<"))
|
|
16398
|
+
return baseFileName + ".xml";
|
|
16399
|
+
if (trimmedQRCodeText.startsWith("{") || trimmedQRCodeText.startsWith("["))
|
|
16400
|
+
return baseFileName + ".json";
|
|
16401
|
+
return baseFileName + ".txt";
|
|
16402
|
+
}
|
|
16403
|
+
//#endregion
|
|
16404
|
+
//#region i18n...
|
|
16405
|
+
SetUILanguages(UILanguages) {
|
|
16406
|
+
this.uiLanguages = this.NormalizeUILanguages(UILanguages);
|
|
16407
|
+
}
|
|
16408
|
+
NormalizeUILanguages(UILanguages) {
|
|
16409
|
+
const languages = new Array();
|
|
16410
|
+
for (const language of UILanguages) {
|
|
16411
|
+
const normalized = language.trim();
|
|
16412
|
+
if (normalized.length > 0 && !languages.includes(normalized)) {
|
|
16413
|
+
languages.push(normalized);
|
|
16414
|
+
}
|
|
16415
|
+
}
|
|
16416
|
+
return languages.length > 0 ? languages : ["en"];
|
|
16417
|
+
}
|
|
16418
|
+
FindBestMultilanguageText(Text) {
|
|
16419
|
+
for (const language of this.uiLanguages) {
|
|
16420
|
+
const localLanguage = Text[language];
|
|
16421
|
+
if (localLanguage !== void 0)
|
|
16422
|
+
return localLanguage;
|
|
16423
|
+
}
|
|
16424
|
+
const english = Text["en"];
|
|
16425
|
+
if (english !== void 0)
|
|
16426
|
+
return english;
|
|
16427
|
+
return Object.values(Text).find((value) => value !== void 0);
|
|
16428
|
+
}
|
|
16429
|
+
CompleteMultilanguageText(Text, fallbackText) {
|
|
16430
|
+
const result = {
|
|
16431
|
+
...Text ?? {}
|
|
16432
|
+
};
|
|
16433
|
+
const fallback = this.FindBestMultilanguageText(result) ?? fallbackText;
|
|
16434
|
+
for (const language of this.uiLanguages)
|
|
16435
|
+
result[language] ??= fallback;
|
|
16436
|
+
return result;
|
|
16437
|
+
}
|
|
16387
16438
|
GetLocalizedMessage(Text) {
|
|
16388
16439
|
const multiLanguage = this.i18n[Text];
|
|
16389
16440
|
if (multiLanguage !== void 0) {
|
|
@@ -16417,6 +16468,14 @@ var Chargy = class {
|
|
|
16417
16468
|
}
|
|
16418
16469
|
return this.CompleteMultilanguageText(parameterizedText, Text.replace("%p", String(Parameter)));
|
|
16419
16470
|
}
|
|
16471
|
+
getLocalizedText(data) {
|
|
16472
|
+
if (data == null)
|
|
16473
|
+
return void 0;
|
|
16474
|
+
const bestLanguage = this.FindBestMultilanguageText(data);
|
|
16475
|
+
if (bestLanguage == null)
|
|
16476
|
+
return void 0;
|
|
16477
|
+
return data[bestLanguage];
|
|
16478
|
+
}
|
|
16420
16479
|
//#endregion
|
|
16421
16480
|
//#region GetDevices...
|
|
16422
16481
|
GetChargingPool = (Id) => {
|
|
@@ -16567,7 +16626,7 @@ var Chargy = class {
|
|
|
16567
16626
|
if (compressedFiles.length == 0)
|
|
16568
16627
|
continue;
|
|
16569
16628
|
archiveFound = true;
|
|
16570
|
-
if (compressedFiles.length == 1
|
|
16629
|
+
if (compressedFiles.length == 1) {
|
|
16571
16630
|
expandedFileInfos.push({
|
|
16572
16631
|
name: FileInfo.name.substring(0, FileInfo.name.lastIndexOf(".")),
|
|
16573
16632
|
data: compressedFiles[0]?.data
|
|
@@ -16604,9 +16663,12 @@ var Chargy = class {
|
|
|
16604
16663
|
}
|
|
16605
16664
|
if (dataFile.length > 0 && signatureFile.length > 0) {
|
|
16606
16665
|
try {
|
|
16607
|
-
|
|
16608
|
-
|
|
16609
|
-
|
|
16666
|
+
const parsedCTRFile = JSON.parse(dataFile);
|
|
16667
|
+
if (!isMandatoryJSONObject(parsedCTRFile))
|
|
16668
|
+
throw new Error("Invalid chargepoint 'secrrct' JSON file!");
|
|
16669
|
+
CTRfile = parsedCTRFile;
|
|
16670
|
+
CTRfile["original"] = btoa(dataFile);
|
|
16671
|
+
CTRfile["signature"] = signatureFile;
|
|
16610
16672
|
expandedFileInfos.push({
|
|
16611
16673
|
name: FileInfo.name,
|
|
16612
16674
|
data: new TextEncoder().encode(JSON.stringify(CTRfile))
|
|
@@ -16645,11 +16707,10 @@ var Chargy = class {
|
|
|
16645
16707
|
} while (archiveFound);
|
|
16646
16708
|
return expandedFileInfos;
|
|
16647
16709
|
}
|
|
16648
|
-
//#endregion
|
|
16649
16710
|
async extractArchive(fileName, data, mimeType) {
|
|
16650
16711
|
const archiveData = this.toUint8Array(data);
|
|
16651
16712
|
if (mimeType === "application/zip")
|
|
16652
|
-
return
|
|
16713
|
+
return this.extractZipArchive(archiveData);
|
|
16653
16714
|
if (mimeType === "application/x-tar")
|
|
16654
16715
|
return this.extractTarArchive(archiveData);
|
|
16655
16716
|
if (mimeType === "application/gzip") {
|
|
@@ -16688,7 +16749,7 @@ var Chargy = class {
|
|
|
16688
16749
|
break;
|
|
16689
16750
|
const prefix = this.readTarString(header, 345, 155);
|
|
16690
16751
|
const path = prefix.length > 0 ? prefix + "/" + name : name;
|
|
16691
|
-
const typeFlag = String.fromCharCode(header
|
|
16752
|
+
const typeFlag = String.fromCharCode(getArrayElement(header, 156, "Missing tar header type flag"));
|
|
16692
16753
|
const dataStart = offset + 512;
|
|
16693
16754
|
const dataEnd = dataStart + size;
|
|
16694
16755
|
if (dataEnd > data.byteLength)
|
|
@@ -16784,6 +16845,7 @@ var Chargy = class {
|
|
|
16784
16845
|
const value = this.readTarString(data, offset, length).replace(/\0/g, "").trim();
|
|
16785
16846
|
return value.length > 0 ? parseInt(value, 8) : 0;
|
|
16786
16847
|
}
|
|
16848
|
+
//#endregion
|
|
16787
16849
|
//#region DetectAndConvertContentFormat(FileInfos)
|
|
16788
16850
|
async DetectAndConvertContentFormat(FileInfos) {
|
|
16789
16851
|
if (FileInfos.length == 0) return {
|
|
@@ -16797,45 +16859,48 @@ var Chargy = class {
|
|
|
16797
16859
|
for (const fileInfo of FileInfos) {
|
|
16798
16860
|
if (fileInfo.type === "application/pdf" || fileInfo.name.endsWith(".pdf")) {
|
|
16799
16861
|
const pdfjsLib = await importPdfJs();
|
|
16800
|
-
const pdfDocument = fileInfo.data ? await pdfjsLib.getDocument({ data: fileInfo.data }).promise : fileInfo.path ? await pdfjsLib.getDocument({ url: fileInfo.path }).promise : null;
|
|
16801
|
-
if (pdfDocument) {
|
|
16862
|
+
const pdfDocument = fileInfo.data ? await pdfjsLib.getDocument({ data: fileInfo.data }).promise : fileInfo.path != null && fileInfo.path.length > 0 ? await pdfjsLib.getDocument({ url: fileInfo.path }).promise : null;
|
|
16863
|
+
if (pdfDocument !== null) {
|
|
16802
16864
|
try {
|
|
16803
|
-
const
|
|
16804
|
-
|
|
16805
|
-
|
|
16806
|
-
|
|
16807
|
-
|
|
16808
|
-
|
|
16809
|
-
|
|
16810
|
-
|
|
16811
|
-
|
|
16812
|
-
|
|
16813
|
-
|
|
16814
|
-
|
|
16815
|
-
|
|
16816
|
-
|
|
16817
|
-
|
|
16818
|
-
|
|
16819
|
-
|
|
16820
|
-
|
|
16821
|
-
|
|
16822
|
-
|
|
16823
|
-
|
|
16824
|
-
|
|
16825
|
-
|
|
16826
|
-
|
|
16827
|
-
|
|
16828
|
-
|
|
16829
|
-
|
|
16830
|
-
|
|
16831
|
-
|
|
16832
|
-
|
|
16833
|
-
|
|
16834
|
-
|
|
16835
|
-
|
|
16836
|
-
|
|
16837
|
-
|
|
16838
|
-
|
|
16865
|
+
const attachmentsUnknown = await pdfDocument.getAttachments();
|
|
16866
|
+
if (isMandatoryJSONObject(attachmentsUnknown))
|
|
16867
|
+
Object.values(attachmentsUnknown).forEach((attachmentUnknown) => {
|
|
16868
|
+
if (!isPdfAttachment(attachmentUnknown))
|
|
16869
|
+
return;
|
|
16870
|
+
const attachment = attachmentUnknown;
|
|
16871
|
+
if (attachment.filename.endsWith(".chargy"))
|
|
16872
|
+
expandedFiles.push({
|
|
16873
|
+
name: attachment.filename,
|
|
16874
|
+
path: FileInfos[0]?.path,
|
|
16875
|
+
type: "application/chargy",
|
|
16876
|
+
data: attachment.content,
|
|
16877
|
+
info: "A CHARGY file extracted from a PDF/A-3 or newer attachment"
|
|
16878
|
+
});
|
|
16879
|
+
else if (attachment.filename.endsWith(".xml"))
|
|
16880
|
+
expandedFiles.push({
|
|
16881
|
+
name: attachment.filename,
|
|
16882
|
+
path: FileInfos[0]?.path,
|
|
16883
|
+
type: "application/xml",
|
|
16884
|
+
data: attachment.content,
|
|
16885
|
+
info: "A XML file extracted from a PDF/A-3 or newer attachment"
|
|
16886
|
+
});
|
|
16887
|
+
else if (attachment.filename.endsWith(".json"))
|
|
16888
|
+
expandedFiles.push({
|
|
16889
|
+
name: attachment.filename,
|
|
16890
|
+
path: FileInfos[0]?.path,
|
|
16891
|
+
type: "application/json",
|
|
16892
|
+
data: attachment.content,
|
|
16893
|
+
info: "A JSON file extracted from a PDF/A-3 or newer attachment"
|
|
16894
|
+
});
|
|
16895
|
+
else if (attachment.filename.endsWith(".csv"))
|
|
16896
|
+
expandedFiles.push({
|
|
16897
|
+
name: attachment.filename,
|
|
16898
|
+
path: FileInfos[0]?.path,
|
|
16899
|
+
type: "text/csv",
|
|
16900
|
+
data: attachment.content,
|
|
16901
|
+
info: "A CSV file extracted from a PDF/A-3 or newer attachment"
|
|
16902
|
+
});
|
|
16903
|
+
});
|
|
16839
16904
|
} catch (error) {
|
|
16840
16905
|
console.error(`Error extracting PDF/A-3 attachments: ${String(error)}`);
|
|
16841
16906
|
}
|
|
@@ -16881,7 +16946,7 @@ var Chargy = class {
|
|
|
16881
16946
|
break;
|
|
16882
16947
|
}
|
|
16883
16948
|
processedFile.result = await new SAFEXML(this).tryToParseSAFEXML(XMLDocument);
|
|
16884
|
-
if (processedFile.result.status && processedFile.result.status !== "Unvalidated" /* Unvalidated */ && getElementsByLocalName(XMLDocument, "chargingStation").length === 0) {
|
|
16949
|
+
if (processedFile.result.status != null && processedFile.result.status !== "Unvalidated" /* Unvalidated */ && getElementsByLocalName(XMLDocument, "chargingStation").length === 0) {
|
|
16885
16950
|
processedFile.result = new XMLContainer(this).tryToParseXMLContainer(XMLDocument);
|
|
16886
16951
|
}
|
|
16887
16952
|
break;
|
|
@@ -16965,8 +17030,7 @@ var Chargy = class {
|
|
|
16965
17030
|
if (isMandatoryJSONObject(JSONContent)) {
|
|
16966
17031
|
const JSONContext = JSONContent["@context"];
|
|
16967
17032
|
if (IsAChargeTransparencyLiveLink(JSONContent)) {
|
|
16968
|
-
|
|
16969
|
-
JSONContent.timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
17033
|
+
JSONContent.timestamp ??= (/* @__PURE__ */ new Date()).toISOString();
|
|
16970
17034
|
processedFile.result = JSONContent;
|
|
16971
17035
|
} else if (isMandatoryString(JSONContext)) {
|
|
16972
17036
|
if (JSONContext.startsWith("https://open.charging.cloud/contexts/CTR+json"))
|
|
@@ -17010,25 +17074,18 @@ var Chargy = class {
|
|
|
17010
17074
|
processedFiles.push(processedFile);
|
|
17011
17075
|
}
|
|
17012
17076
|
if (processedFiles.length == 1) {
|
|
17013
|
-
const processedFile = processedFiles
|
|
17014
|
-
if (processedFile)
|
|
17015
|
-
|
|
17016
|
-
|
|
17017
|
-
if (IsAChargeTransparencyLiveLink(processedFile.result))
|
|
17018
|
-
return processedFile.result;
|
|
17019
|
-
if (IsAPublicKeyLookup(processedFile.result))
|
|
17020
|
-
return {
|
|
17021
|
-
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
17022
|
-
message: this.GetMultilanguageText("UnknownOrInvalidChargeTransparencyRecord"),
|
|
17023
|
-
certainty: 0
|
|
17024
|
-
};
|
|
17077
|
+
const processedFile = getFirstArrayElement(processedFiles, "Missing processed file");
|
|
17078
|
+
if (IsAChargeTransparencyRecord(processedFile.result))
|
|
17079
|
+
return this.processChargeTransparencyRecord(processedFile.result);
|
|
17080
|
+
if (IsAChargeTransparencyLiveLink(processedFile.result))
|
|
17025
17081
|
return processedFile.result;
|
|
17026
|
-
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
|
|
17030
|
-
|
|
17031
|
-
|
|
17082
|
+
if (IsAPublicKeyLookup(processedFile.result))
|
|
17083
|
+
return {
|
|
17084
|
+
status: "InvalidSessionFormat" /* InvalidSessionFormat */,
|
|
17085
|
+
message: this.GetMultilanguageText("UnknownOrInvalidChargeTransparencyRecord"),
|
|
17086
|
+
certainty: 0
|
|
17087
|
+
};
|
|
17088
|
+
return processedFile.result;
|
|
17032
17089
|
} else if (processedFiles.length > 1) {
|
|
17033
17090
|
const mergedCTR = {
|
|
17034
17091
|
"@id": "",
|
|
@@ -17042,14 +17099,12 @@ var Chargy = class {
|
|
|
17042
17099
|
mergedCTR["@id"] = processedFileResult["@id"];
|
|
17043
17100
|
if (mergedCTR["@context"] === "")
|
|
17044
17101
|
mergedCTR["@context"] = processedFileResult["@context"];
|
|
17045
|
-
if (
|
|
17102
|
+
if (processedFileResult.begin != null && processedFileResult.begin.length > 0 && (mergedCTR.begin == null || mergedCTR.begin.length === 0 || mergedCTR.begin > processedFileResult.begin))
|
|
17046
17103
|
mergedCTR.begin = processedFileResult.begin;
|
|
17047
|
-
if (
|
|
17104
|
+
if (processedFileResult.end != null && processedFileResult.end.length > 0 && (mergedCTR.end == null || mergedCTR.end.length === 0 || mergedCTR.end < processedFileResult.end))
|
|
17048
17105
|
mergedCTR.end = processedFileResult.end;
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
if (!mergedCTR.contract)
|
|
17052
|
-
mergedCTR.contract = processedFileResult.contract;
|
|
17106
|
+
mergedCTR.description ??= processedFileResult.description;
|
|
17107
|
+
mergedCTR.contract ??= processedFileResult.contract;
|
|
17053
17108
|
if (!mergedCTR.chargingStationOperators)
|
|
17054
17109
|
mergedCTR.chargingStationOperators = processedFileResult.chargingStationOperators;
|
|
17055
17110
|
else if (processedFileResult.chargingStationOperators)
|
|
@@ -17081,17 +17136,14 @@ var Chargy = class {
|
|
|
17081
17136
|
for (const mediationService of processedFileResult.mediationServices)
|
|
17082
17137
|
mergedCTR.mediationServices.push(mediationService);
|
|
17083
17138
|
} else if (IsAPublicKeyInfo(processedFileResult)) {
|
|
17084
|
-
|
|
17085
|
-
mergedCTR.publicKeys = new Array();
|
|
17139
|
+
mergedCTR.publicKeys ??= new Array();
|
|
17086
17140
|
mergedCTR.publicKeys.push(processedFileResult);
|
|
17087
17141
|
} else if (IsAPublicKeyLookup(processedFileResult)) {
|
|
17088
|
-
|
|
17089
|
-
mergedCTR.publicKeys = new Array();
|
|
17142
|
+
mergedCTR.publicKeys ??= new Array();
|
|
17090
17143
|
for (const publicKey of processedFileResult.publicKeys)
|
|
17091
17144
|
mergedCTR.publicKeys.push(publicKey);
|
|
17092
17145
|
} else {
|
|
17093
|
-
|
|
17094
|
-
mergedCTR.invalidDataSets = new Array();
|
|
17146
|
+
mergedCTR.invalidDataSets ??= new Array();
|
|
17095
17147
|
mergedCTR.invalidDataSets.push(processedFile);
|
|
17096
17148
|
}
|
|
17097
17149
|
}
|
|
@@ -17119,8 +17171,6 @@ var Chargy = class {
|
|
|
17119
17171
|
this.EVSEs = [];
|
|
17120
17172
|
this.meters = [];
|
|
17121
17173
|
this.chargingSessions = [];
|
|
17122
|
-
this.eMobilityProviders = [];
|
|
17123
|
-
this.mediationServices = [];
|
|
17124
17174
|
try {
|
|
17125
17175
|
this.internalCTR = CloneCTR(CTR);
|
|
17126
17176
|
this.currentCTR = CTR;
|
|
@@ -17247,9 +17297,9 @@ var Chargy = class {
|
|
|
17247
17297
|
if (measurement.name !== "ENERGY_TOTAL" || measurement.values.length < 2) {
|
|
17248
17298
|
continue;
|
|
17249
17299
|
}
|
|
17250
|
-
const firstValue2 = measurement.values
|
|
17251
|
-
const lastValue = measurement.values
|
|
17252
|
-
if (firstValue2
|
|
17300
|
+
const firstValue2 = measurement.values.at(0);
|
|
17301
|
+
const lastValue = measurement.values.at(-1);
|
|
17302
|
+
if (firstValue2 === void 0 || lastValue === void 0) {
|
|
17253
17303
|
continue;
|
|
17254
17304
|
}
|
|
17255
17305
|
const firstValueKWh = this.measurementValueInKWh(measurement, firstValue2);
|
|
@@ -17398,14 +17448,12 @@ var Chargy = class {
|
|
|
17398
17448
|
mergedCTR["@id"] = ctr["@id"];
|
|
17399
17449
|
if (mergedCTR["@context"] === "")
|
|
17400
17450
|
mergedCTR["@context"] = ctr["@context"];
|
|
17401
|
-
if (
|
|
17451
|
+
if (ctr.begin != null && ctr.begin.length > 0 && (mergedCTR.begin == null || mergedCTR.begin.length === 0 || mergedCTR.begin > ctr.begin))
|
|
17402
17452
|
mergedCTR.begin = ctr.begin;
|
|
17403
|
-
if (
|
|
17453
|
+
if (ctr.end != null && ctr.end.length > 0 && (mergedCTR.end == null || mergedCTR.end.length === 0 || mergedCTR.end < ctr.end))
|
|
17404
17454
|
mergedCTR.end = ctr.end;
|
|
17405
|
-
|
|
17406
|
-
|
|
17407
|
-
if (!mergedCTR.contract)
|
|
17408
|
-
mergedCTR.contract = ctr.contract;
|
|
17455
|
+
mergedCTR.description ??= ctr.description;
|
|
17456
|
+
mergedCTR.contract ??= ctr.contract;
|
|
17409
17457
|
if (!mergedCTR.chargingStationOperators)
|
|
17410
17458
|
mergedCTR.chargingStationOperators = ctr.chargingStationOperators;
|
|
17411
17459
|
else if (ctr.chargingStationOperators)
|
|
@@ -17453,6 +17501,6 @@ function toSessionVerificationResults(CTR, noRecordsMessage = { "en": "No charge
|
|
|
17453
17501
|
};
|
|
17454
17502
|
}
|
|
17455
17503
|
|
|
17456
|
-
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, CryptoAlgorithms, CryptoHashAlgorithms, DayOfWeek, DisplayPrefixes, EMHCrypt01, ErrorLevel, GDFCrypt01, IECCurves, IEncoding, InformationRelevance, InformationRelevanceToString, IsAChargeTransparencyLiveLink, IsAChargeTransparencyRecord, IsAPublicKeyInfo, IsAPublicKeyLookup, IsASessionCryptoResult, IsNullOrEmpty, JSONSignatureVerificationStatus, MENNEKES_EDL40_OBIS, MENNEKES_EDL40_XMLNS, Mennekes, MennekesCrypt01, OBIS2Hex, OBIS2MeasurementName, OBIS_RegExpr, OCMF, OCMFTransactionTypes, OCMFv1_x, OCPI, 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, buf2hex, buildMennekesSignatureData, bytesToHex2 as bytesToHex, canonicalJSONBytes, canonicalJSONStringify, cleanHex, closeFullscreen, createHexString, dateToMennekesLocalEpochSeconds, extractMennekesChargingProcesses, firstKey, firstValue, getDirectChildByLocalName, getDirectChildrenByLocalName, getElementsByLocalName, getInt16Bytes, getInt32Bytes, getInt64Bytes, getInt8Bytes, getTrimmedTextContent, hashFile, hex2bin, hex32, hexToArrayBuffer, hexToBytes, intFromBytes, isGeoLocation, isICryptoResult, isIFileInfo, isIPublicKeyXY, isISessionCryptoResult1, isISessionCryptoResult2, isJSONLDObject, isMandatoryArrayOfStrings, isMandatoryBoolean, isMandatoryDecimal, isMandatoryJSONArray, isMandatoryJSONObject, isMandatoryNumber, isMandatoryString, isMandatoryURL, isMultilanguageText, isOIDInfo, isObject, isOptionalArrayOfStrings, isOptionalDecimal, isOptionalJSONArray, isOptionalJSONArrayError, isOptionalJSONArrayOk, isOptionalJSONObject, isOptionalNumber, isOptionalString, isOptionalURL, isPCDFText, isString, isStringArray, isStringOrOIDInfo, isStringOrStringArray, jsonPrettyPrinter, measurementName2human, normalizePCDFPublicKeyHex, normalizeXMLText, openFullscreen, pad, parseAndVerifyJSONSignatures, parseDescription, parseHexString, parseMennekesXMLDocument, parseNumber, parseOBIS, parsePCDFDocument, parsePCDFPublicKey, parsePCDFSignature, parseUTC, readQRCodeTextFromImage, readQRCodeTextFromImageData, secp224k1, setUILocale, sha256, sha384, sha512, signJSONMessage, signMessage, stripPCDFControlCharacters, time2human, toArrayBuffer, toSessionVerificationResults, toUint8Array, unquotePCDFText, validatePCDFFields, verifyJSONMessageSignatureResults, verifyJSONMessageSignatures, verifyJSONSignature, verifyJSONSignatureResult, verifyPCDFDocument };
|
|
17504
|
+
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, CryptoAlgorithms, CryptoHashAlgorithms, DayOfWeek, DisplayPrefixes, EMHCrypt01, ErrorLevel, GDFCrypt01, IECCurves, IEncoding, InformationRelevance, InformationRelevanceToString, IsAChargeTransparencyLiveLink, IsAChargeTransparencyRecord, IsAPublicKeyInfo, IsAPublicKeyLookup, IsASessionCryptoResult, IsNullOrEmpty, JSONSignatureVerificationStatus, MENNEKES_EDL40_OBIS, MENNEKES_EDL40_XMLNS, Mennekes, MennekesCrypt01, OBIS2Hex, OBIS2MeasurementName, OBIS_RegExpr, OCMF, OCMFTransactionTypes, OCMFv1_x, OCPI, 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, buf2hex, buildMennekesSignatureData, bytesToHex2 as bytesToHex, canonicalJSONBytes, canonicalJSONStringify, cleanHex, closeFullscreen, createHexString, dateToMennekesLocalEpochSeconds, extractMennekesChargingProcesses, firstKey, firstValue, getArrayElement, getArrayLikeElement, getDirectChildByLocalName, getDirectChildrenByLocalName, getElementsByLocalName, getFirstArrayElement, getInt16Bytes, getInt32Bytes, getInt64Bytes, getInt8Bytes, getLastArrayElement, getTrimmedTextContent, hashFile, hex2bin, hex32, hexToArrayBuffer, hexToBytes, intFromBytes, isGeoLocation, isICryptoResult, isIFileInfo, isIPublicKeyXY, isISessionCryptoResult1, isISessionCryptoResult2, isJSONLDObject, isMandatoryArrayOfStrings, isMandatoryBoolean, isMandatoryDecimal, isMandatoryJSONArray, isMandatoryJSONObject, isMandatoryNumber, isMandatoryString, isMandatoryURL, isMultilanguageText, isOIDInfo, isObject, isOptionalArrayOfStrings, isOptionalDecimal, isOptionalJSONArray, isOptionalJSONArrayError, isOptionalJSONArrayOk, isOptionalJSONObject, isOptionalNumber, isOptionalString, isOptionalURL, isPCDFText, isString, isStringArray, isStringOrOIDInfo, isStringOrStringArray, jsonPrettyPrinter, measurementName2human, normalizePCDFPublicKeyHex, normalizeXMLText, openFullscreen, pad, parseAndVerifyJSONSignatures, parseDescription, parseHexString, parseMennekesXMLDocument, parseNumber, parseOBIS, parsePCDFDocument, parsePCDFPublicKey, parsePCDFSignature, parseUTC, readQRCodeTextFromImage, readQRCodeTextFromImageData, secp224k1, setUILocale, sha256, sha384, sha512, signJSONMessage, signMessage, stripPCDFControlCharacters, time2human, toArrayBuffer, toSessionVerificationResults, toUint8Array, unquotePCDFText, validatePCDFFields, verifyJSONMessageSignatureResults, verifyJSONMessageSignatures, verifyJSONSignature, verifyJSONSignatureResult, verifyPCDFDocument };
|
|
17457
17505
|
//# sourceMappingURL=index.js.map
|
|
17458
17506
|
//# sourceMappingURL=index.js.map
|