@open-charging-cloud/chargy-core 0.6.1 → 0.6.2

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.
Files changed (53) hide show
  1. package/README.md +2 -2
  2. package/dist/ACrypt.d.ts +2 -2
  3. package/dist/ACrypt.d.ts.map +1 -1
  4. package/dist/Alfen.d.ts +6 -6
  5. package/dist/Alfen.d.ts.map +1 -1
  6. package/dist/BSMCrypt01.d.ts +8 -9
  7. package/dist/BSMCrypt01.d.ts.map +1 -1
  8. package/dist/EMHCrypt01.d.ts +8 -8
  9. package/dist/EMHCrypt01.d.ts.map +1 -1
  10. package/dist/GDFCrypt01.d.ts +8 -8
  11. package/dist/GDFCrypt01.d.ts.map +1 -1
  12. package/dist/Mennekes.d.ts +22 -22
  13. package/dist/Mennekes.d.ts.map +1 -1
  14. package/dist/OCMF.d.ts +25 -27
  15. package/dist/OCMF.d.ts.map +1 -1
  16. package/dist/OCPI.d.ts +2 -4
  17. package/dist/OCPI.d.ts.map +1 -1
  18. package/dist/PCDF.d.ts +1 -1
  19. package/dist/PCDF.d.ts.map +1 -1
  20. package/dist/QIDigital_DCC.d.ts +1 -1
  21. package/dist/QIDigital_DCC.d.ts.map +1 -1
  22. package/dist/QIDigital_DCoA.d.ts +1 -1
  23. package/dist/QIDigital_DCoA.d.ts.map +1 -1
  24. package/dist/QIDigital_DCoC.d.ts +1 -1
  25. package/dist/QIDigital_DCoC.d.ts.map +1 -1
  26. package/dist/SAFE_XML.d.ts +16 -16
  27. package/dist/SAFE_XML.d.ts.map +1 -1
  28. package/dist/XMLContainer.d.ts +2 -2
  29. package/dist/XMLContainer.d.ts.map +1 -1
  30. package/dist/browser/index.js +847 -811
  31. package/dist/browser/index.js.map +1 -1
  32. package/dist/chargeIT.d.ts +1 -3
  33. package/dist/chargeIT.d.ts.map +1 -1
  34. package/dist/chargePoint.d.ts +3 -3
  35. package/dist/chargePoint.d.ts.map +1 -1
  36. package/dist/chargy.d.ts +3 -4
  37. package/dist/chargy.d.ts.map +1 -1
  38. package/dist/chargyLib.d.ts +4 -0
  39. package/dist/chargyLib.d.ts.map +1 -1
  40. package/dist/interfaces/IChargeTransparencyRecord.d.ts +76 -76
  41. package/dist/interfaces/IChargeTransparencyRecord.d.ts.map +1 -1
  42. package/dist/interfaces/chargyInterfaces.d.ts +97 -107
  43. package/dist/interfaces/chargyInterfaces.d.ts.map +1 -1
  44. package/dist/node/index.js +847 -811
  45. package/dist/node/index.js.map +1 -1
  46. package/dist/pdfjs/browser.d.ts +2 -1
  47. package/dist/pdfjs/browser.d.ts.map +1 -1
  48. package/dist/qrCodeReader.d.ts.map +1 -1
  49. package/dist/secp224k1.d.ts +10 -11
  50. package/dist/secp224k1.d.ts.map +1 -1
  51. package/dist/verificationResults.d.ts +1 -1
  52. package/dist/verificationResults.d.ts.map +1 -1
  53. package/package.json +3 -3
@@ -9768,9 +9768,7 @@ var secp224k1 = class {
9768
9768
  N = BigInt("0x010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7");
9769
9769
  // Number of points in the field
9770
9770
  Acurve = BigInt(0);
9771
- // These two are defined on the elliptic curve. y^2 = x^3 + Acurve * x + Bcurve
9772
- Bcurve = BigInt(5);
9773
- // These two are defined on the elliptic curve. y^2 = x^3 + Acurve * x + Bcurve
9771
+ // Defined on the elliptic curve. y^2 = x^3 + Acurve * x + 5
9774
9772
  Gx = BigInt("0xA1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C");
9775
9773
  Gy = BigInt("0x7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5");
9776
9774
  GPoint = [this.Gx, this.Gy];
@@ -9867,6 +9865,7 @@ var secp224k1 = class {
9867
9865
  address: this.modulo(publicKey[1], this.Two) == this.One ? "03" + Px : "02" + Px
9868
9866
  };
9869
9867
  }
9868
+ return void 0;
9870
9869
  }
9871
9870
  };
9872
9871
 
@@ -9995,13 +9994,13 @@ function CreateError(message, level = "high" /* high */) {
9995
9994
  };
9996
9995
  }
9997
9996
  function isISessionCryptoResult1(obj) {
9998
- return typeof obj === "object" && obj !== null && obj.status !== void 0;
9997
+ return isObject(obj) && obj["status"] !== void 0;
9999
9998
  }
10000
9999
  function isISessionCryptoResult2(obj) {
10001
- return typeof obj === "object" && obj !== null && obj.status !== void 0 && obj.status !== "InvalidSessionFormat" /* InvalidSessionFormat */;
10000
+ return isObject(obj) && obj["status"] !== void 0 && obj["status"] !== "InvalidSessionFormat" /* InvalidSessionFormat */;
10002
10001
  }
10003
10002
  function isICryptoResult(obj) {
10004
- return typeof obj === "object" && obj !== null && obj.status !== void 0;
10003
+ return isObject(obj) && obj["status"] !== void 0;
10005
10004
  }
10006
10005
  var InformationRelevance = /* @__PURE__ */ ((InformationRelevance2) => {
10007
10006
  InformationRelevance2["Unknown"] = "Unknown";
@@ -10089,6 +10088,26 @@ function toArrayBuffer(data) {
10089
10088
  function toUint8Array(data) {
10090
10089
  return data instanceof Uint8Array ? data : new Uint8Array(data);
10091
10090
  }
10091
+ function getArrayElement(values, index, message = "Missing array element") {
10092
+ const value = values[index];
10093
+ if (value === void 0)
10094
+ throw new Error(message + " at index " + index.toString());
10095
+ return value;
10096
+ }
10097
+ function getFirstArrayElement(values, message = "Missing first array element") {
10098
+ return getArrayElement(values, 0, message);
10099
+ }
10100
+ function getLastArrayElement(values, message = "Missing last array element") {
10101
+ return getArrayElement(values, values.length - 1, message);
10102
+ }
10103
+ function getArrayLikeElement(values, index, message = "Missing array-like element") {
10104
+ if (index < 0 || index >= values.length)
10105
+ throw new Error(message + " at index " + index.toString());
10106
+ const value = values[index];
10107
+ if (value === void 0)
10108
+ throw new Error(message + " at index " + index.toString());
10109
+ return value;
10110
+ }
10092
10111
  function normalizeXMLText(xmlText) {
10093
10112
  return (xmlText ?? "").replace(/^\uFEFF/, "").replace(/\r\n?/g, "\n").replace(/>\s+</g, "><").trim();
10094
10113
  }
@@ -10100,15 +10119,16 @@ function getDirectChildByLocalName(parent, localName) {
10100
10119
  }
10101
10120
  function getTrimmedTextContent(element) {
10102
10121
  const text = element?.textContent.trim();
10103
- return text && text.length > 0 ? text : void 0;
10122
+ return text != null && text.length > 0 ? text : void 0;
10104
10123
  }
10105
10124
  function parseDescription(parent) {
10106
10125
  const descriptions = getDirectChildrenByLocalName(parent, "description");
10107
10126
  const textMap = {};
10108
10127
  for (const description of descriptions) {
10109
- const language = description.getAttribute("language")?.trim() || "und";
10128
+ const languageAttribute = description.getAttribute("language")?.trim();
10129
+ const language = languageAttribute != null && languageAttribute.length > 0 ? languageAttribute : "und";
10110
10130
  const text = description.textContent.trim();
10111
- if (text)
10131
+ if (text.length > 0)
10112
10132
  textMap[language] = text;
10113
10133
  }
10114
10134
  return Object.keys(textMap).length > 0 ? textMap : void 0;
@@ -10144,12 +10164,14 @@ function ParseJSON_LD(Text, _Context = "") {
10144
10164
  function firstKey(obj) {
10145
10165
  for (const a in obj)
10146
10166
  return a;
10167
+ return void 0;
10147
10168
  }
10148
10169
  function firstValue(obj) {
10149
10170
  if (obj == void 0)
10150
10171
  return void 0;
10151
10172
  for (const a in obj)
10152
10173
  return obj[a];
10174
+ return void 0;
10153
10175
  }
10154
10176
  var uiLocale = typeof window !== "undefined" ? window.navigator.language : "de";
10155
10177
  function setUILocale(locale) {
@@ -10182,14 +10204,17 @@ function parseOBIS(OBIS) {
10182
10204
  return `${String(media)}-${String(channel)}:${String(indicator)}.${String(mode)}.${String(quantities)}*${String(storage)}`;
10183
10205
  }
10184
10206
  var OBIS_RegExpr = new RegExp("((\\d+)\\-)?((\\d+):)?((\\d+)\\.)(\\d+)(\\.(\\d+))?(\\*(\\d+))?");
10207
+ function optionalOBISMatchValue(value) {
10208
+ return value ?? "0";
10209
+ }
10185
10210
  function OBIS2Hex(OBIS) {
10186
10211
  const OBISElements = OBIS.match(OBIS_RegExpr);
10187
- return OBISElements == null ? "000000000000" : parseInt(OBISElements[2]).toString(16).padStart(2, "0") + // optional A
10188
- parseInt(OBISElements[4]).toString(16).padStart(2, "0") + // optional B
10189
- parseInt(OBISElements[6]).toString(16).padStart(2, "0") + // mandatory C
10190
- parseInt(OBISElements[7]).toString(16).padStart(2, "0") + // mandatory D
10191
- parseInt(OBISElements[9]).toString(16).padStart(2, "0") + // optional E
10192
- parseInt(OBISElements[11]).toString(16).padStart(2, "0");
10212
+ return OBISElements == null ? "000000000000" : parseInt(optionalOBISMatchValue(OBISElements[2])).toString(16).padStart(2, "0") + // optional A
10213
+ parseInt(optionalOBISMatchValue(OBISElements[4])).toString(16).padStart(2, "0") + // optional B
10214
+ parseInt(optionalOBISMatchValue(OBISElements[6])).toString(16).padStart(2, "0") + // mandatory C
10215
+ parseInt(optionalOBISMatchValue(OBISElements[7])).toString(16).padStart(2, "0") + // mandatory D
10216
+ parseInt(optionalOBISMatchValue(OBISElements[9])).toString(16).padStart(2, "0") + // optional E
10217
+ parseInt(optionalOBISMatchValue(OBISElements[11])).toString(16).padStart(2, "0");
10193
10218
  }
10194
10219
  function OBIS2MeasurementName(OBISString) {
10195
10220
  switch (OBISString) {
@@ -10232,15 +10257,15 @@ function measurementName2human(In) {
10232
10257
  }
10233
10258
  }
10234
10259
  function IsNullOrEmpty(value) {
10235
- return !value;
10260
+ return value == null || value.length === 0;
10236
10261
  }
10237
10262
  function WhenNullOrEmpty(value, replacement) {
10238
- if (!value)
10263
+ if (value == null || value.length === 0)
10239
10264
  return replacement;
10240
10265
  return value;
10241
10266
  }
10242
10267
  function hex2bin(hex, Reverse) {
10243
- if (Reverse) {
10268
+ if (Reverse === true) {
10244
10269
  const reversed = [];
10245
10270
  for (let i = 0; i < hex.length; i += 2)
10246
10271
  reversed.push(hex.substring(i, i + 2));
@@ -10354,7 +10379,7 @@ function SetHex(dv, hex, offset, reverse) {
10354
10379
  const bytes = parseHexString(hex);
10355
10380
  const buffer = new ArrayBuffer(bytes.length);
10356
10381
  const tv = new DataView(buffer);
10357
- if (reverse)
10382
+ if (reverse === true)
10358
10383
  bytes.reverse();
10359
10384
  for (let i = 0; i < bytes.length; i++) {
10360
10385
  dv.setUint8(offset + i, bytes[i] ?? 0);
@@ -10403,7 +10428,7 @@ function SetUInt32(dv, value, offset, reverse) {
10403
10428
  const bytes = getInt32Bytes(value);
10404
10429
  const buffer = new ArrayBuffer(bytes.length);
10405
10430
  const tv = new DataView(buffer);
10406
- if (reverse)
10431
+ if (reverse === true)
10407
10432
  bytes.reverse();
10408
10433
  for (let i = 0; i < bytes.length; i++) {
10409
10434
  dv.setUint8(offset + i, bytes[i] ?? 0);
@@ -10415,7 +10440,7 @@ function SetUInt64(dv, value, offset, reverse) {
10415
10440
  const bytes = getInt64Bytes(value);
10416
10441
  const buffer = new ArrayBuffer(bytes.length);
10417
10442
  const tv = new DataView(buffer);
10418
- if (reverse)
10443
+ if (reverse === true)
10419
10444
  bytes.reverse();
10420
10445
  for (let i = 0; i < bytes.length; i++) {
10421
10446
  dv.setUint8(offset + i, bytes[i] ?? 0);
@@ -10447,7 +10472,7 @@ function SetUInt32_withCode(dv, value, scale, obis, offset, reverse) {
10447
10472
  const obisBytes = getInt8Bytes(obis);
10448
10473
  const buffer = new ArrayBuffer(valueBytes.length + 2);
10449
10474
  const tv = new DataView(buffer);
10450
- if (reverse)
10475
+ if (reverse === true)
10451
10476
  valueBytes.reverse();
10452
10477
  for (let i = 0; i < valueBytes.length; i++) {
10453
10478
  dv.setUint8(offset + i, valueBytes[i] ?? 0);
@@ -10510,8 +10535,7 @@ function CreateDiv2(ParentDiv, ChildClassName, ChildAInnerHTML, ChildBInnerHTML)
10510
10535
  return childDiv;
10511
10536
  }
10512
10537
  function pad(text, paddingValue) {
10513
- if (text == void 0)
10514
- text = "";
10538
+ text ??= "";
10515
10539
  return (text + Array(2 * paddingValue).join("0")).substring(0, 2 * paddingValue);
10516
10540
  }
10517
10541
  async function sha256(message) {
@@ -10657,7 +10681,7 @@ function jsonPrettyPrinter(value, KeyLookup) {
10657
10681
  value,
10658
10682
  0,
10659
10683
  "",
10660
- KeyLookup ?? ((path, key) => key)
10684
+ KeyLookup ?? ((_path, key) => key)
10661
10685
  );
10662
10686
  }
10663
10687
  function _jsonPrettyPrinter(value, indentLevel, path, keyLookup) {
@@ -10736,13 +10760,15 @@ var ACrypt = class {
10736
10760
  }
10737
10761
  AddToVisualBuffer(valueHEX, bufferDiv, lineDiv) {
10738
10762
  const newText = CreateDiv(bufferDiv, "entry", valueHEX);
10763
+ const lineId = getArrayLikeElement(lineDiv.children, 0, "Missing visual buffer line id");
10764
+ const lineHex = getArrayLikeElement(lineDiv.children, 1, "Missing visual buffer line hex");
10739
10765
  newText.onmouseenter = function() {
10740
- lineDiv.children[0]?.classList.add("overEntry");
10741
- lineDiv.children[1]?.classList.add("overEntry");
10766
+ lineId.classList.add("overEntry");
10767
+ lineHex.classList.add("overEntry");
10742
10768
  };
10743
10769
  newText.onmouseleave = function() {
10744
- lineDiv.children[0]?.classList.remove("overEntry");
10745
- lineDiv.children[1]?.classList.remove("overEntry");
10770
+ lineId.classList.remove("overEntry");
10771
+ lineHex.classList.remove("overEntry");
10746
10772
  };
10747
10773
  lineDiv.onmouseenter = function() {
10748
10774
  newText.classList.add("overEntry");
@@ -10758,7 +10784,7 @@ var Alfen = class {
10758
10784
  this.chargy = chargy;
10759
10785
  }
10760
10786
  bufferToHex(buffer, Reverse) {
10761
- return (Reverse ? Array.from(new Uint8Array(buffer)).reverse() : Array.from(new Uint8Array(buffer))).map((b) => b.toString(16).padStart(2, "0")).join("");
10787
+ return (Reverse === true ? Array.from(new Uint8Array(buffer)).reverse() : Array.from(new Uint8Array(buffer))).map((b) => b.toString(16).padStart(2, "0")).join("");
10762
10788
  }
10763
10789
  bufferToNumber(buffer) {
10764
10790
  return parseInt(Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join(""), 16);
@@ -10793,28 +10819,29 @@ var Alfen = class {
10793
10819
  signedValues = Content;
10794
10820
  let previousTimestamp = "";
10795
10821
  for (let i = 0; i < signedValues.length; i++) {
10796
- const elements = signedValues[i]?.split(";");
10797
- if (elements?.length != 6 && elements?.length != 7)
10822
+ const elements = getArrayElement(signedValues, i, "Missing Alfen signed value").split(";");
10823
+ if (elements.length != 6 && elements.length != 7)
10798
10824
  return {
10799
10825
  status: "InvalidSessionFormat" /* InvalidSessionFormat */,
10800
10826
  message: this.chargy.GetMultilanguageText("Invalid number of signed meter values!"),
10801
10827
  certainty: 0
10802
10828
  };
10803
- const FormatId = elements[0];
10804
- const Type = elements[1];
10805
- const BlobVersion = elements[2];
10806
- const PublicKey = this.chargy.base32Decode(elements[3] ?? "", "RFC4648");
10807
- const DataSet = this.chargy.base32Decode(elements[4] ?? "", "RFC4648");
10808
- const Signature = this.chargy.base32Decode(elements[5] ?? "", "RFC4648");
10829
+ const FormatId = getArrayElement(elements, 0, "Missing Alfen format id");
10830
+ const Type = getArrayElement(elements, 1, "Missing Alfen type");
10831
+ const BlobVersion = getArrayElement(elements, 2, "Missing Alfen blob version");
10832
+ const publicKeyValue = getArrayElement(elements, 3, "Missing Alfen public key");
10833
+ const PublicKey = this.chargy.base32Decode(publicKeyValue, "RFC4648");
10834
+ const DataSet = this.chargy.base32Decode(getArrayElement(elements, 4, "Missing Alfen data set"), "RFC4648");
10835
+ const Signature = this.chargy.base32Decode(getArrayElement(elements, 5, "Missing Alfen signature"), "RFC4648");
10809
10836
  if (common.PublicKey === "")
10810
- common.PublicKey = elements[3] ?? "";
10811
- else if (elements[3] !== common.PublicKey)
10837
+ common.PublicKey = publicKeyValue;
10838
+ else if (publicKeyValue !== common.PublicKey)
10812
10839
  return {
10813
10840
  status: "InvalidSessionFormat" /* InvalidSessionFormat */,
10814
10841
  message: this.chargy.GetMultilanguageText("Inconsistent public keys!"),
10815
10842
  certainty: 0
10816
10843
  };
10817
- if (FormatId !== "AP" || Type?.length !== 1 || BlobVersion?.length !== 1 || BlobVersion !== "3" || PublicKey.byteLength !== 25 || DataSet.byteLength !== 82 || Signature.byteLength !== 48) {
10844
+ if (FormatId !== "AP" || Type.length !== 1 || BlobVersion.length !== 1 || BlobVersion !== "3" || PublicKey.byteLength !== 25 || DataSet.byteLength !== 82 || Signature.byteLength !== 48) {
10818
10845
  return {
10819
10846
  status: "InvalidSessionFormat" /* InvalidSessionFormat */,
10820
10847
  message: this.chargy.GetMultilanguageText("Invalid charging session format!"),
@@ -10931,14 +10958,8 @@ var Alfen = class {
10931
10958
  const evseId = asString(containerInfos["EVSEId"]) ?? "DE*GEF*EVSE*CHARGY*1";
10932
10959
  const chargingStationId = asString(containerInfos["ChargingStationId"]) ?? "DE*GEF*STATION*CHARGY*1";
10933
10960
  const chargingSessionId = asString(chargingSession?.["@id"]);
10934
- const firstDataSet = common.dataSets[0];
10935
- const lastDataSet = common.dataSets[common.dataSets.length - 1];
10936
- if (firstDataSet === void 0 || lastDataSet === void 0)
10937
- return {
10938
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
10939
- message: this.chargy.GetMultilanguageText("Invalid number of signed meter values!"),
10940
- certainty: 0
10941
- };
10961
+ const firstDataSet = getFirstArrayElement(common.dataSets, "Missing first Alfen data set");
10962
+ const lastDataSet = getLastArrayElement(common.dataSets, "Missing last Alfen data set");
10942
10963
  const _CTR = {
10943
10964
  "@id": chargingSessionId ?? common.InternalSessionId.toString(),
10944
10965
  "@context": "https://open.charging.cloud/contexts/CTR+json",
@@ -11219,62 +11240,62 @@ var AlfenCrypt01 = class extends ACrypt {
11219
11240
  }
11220
11241
  return {};
11221
11242
  }
11222
- async ViewMeasurement(measurementValue, errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
11243
+ async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
11223
11244
  const result = measurementValue.result;
11224
11245
  {
11225
11246
  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);
11226
11247
  }
11227
11248
  {
11228
- if (PlainTextDiv.parentElement && PlainTextDiv.parentElement.children[0]) {
11229
- PlainTextDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Plain text") + " (320 Bytes, hex)";
11249
+ if (PlainTextDiv.parentElement) {
11250
+ getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = this.chargy.GetLocalizedMessage("Plain text") + " (320 Bytes, hex)";
11230
11251
  }
11231
11252
  PlainTextDiv.style.fontFamily = "";
11232
11253
  PlainTextDiv.style.whiteSpace = "";
11233
11254
  PlainTextDiv.style.maxHeight = "";
11234
11255
  PlainTextDiv.style.overflowY = "";
11235
- this.CreateLocalizedLine("Adapter Id", measurementValue.measurement.adapterId, result.adapterId || "", infoDiv, PlainTextDiv);
11236
- this.CreateLocalizedLine("Adapter Firmware Version", measurementValue.measurement.adapterFWVersion, result.adapterFWVersion || "", infoDiv, PlainTextDiv);
11237
- this.CreateLocalizedLine("Adapter Firmware Checksum", measurementValue.measurement.adapterFWChecksum, result.adapterFWChecksum || "", infoDiv, PlainTextDiv);
11238
- this.CreateLocalizedLine("Meter number", measurementValue.measurement.energyMeterId, result.meterId || "", infoDiv, PlainTextDiv);
11256
+ this.CreateLocalizedLine("Adapter Id", measurementValue.measurement.adapterId, result.adapterId ?? "", infoDiv, PlainTextDiv);
11257
+ this.CreateLocalizedLine("Adapter Firmware Version", measurementValue.measurement.adapterFWVersion, result.adapterFWVersion ?? "", infoDiv, PlainTextDiv);
11258
+ this.CreateLocalizedLine("Adapter Firmware Checksum", measurementValue.measurement.adapterFWChecksum, result.adapterFWChecksum ?? "", infoDiv, PlainTextDiv);
11259
+ this.CreateLocalizedLine("Meter number", measurementValue.measurement.energyMeterId, result.meterId ?? "", infoDiv, PlainTextDiv);
11239
11260
  this.CreateLocalizedLine(
11240
11261
  "Meter status",
11241
11262
  hex2bin(measurementValue.statusMeter, true) + " (" + measurementValue.statusMeter + ' hex)<br /><span class="statusInfos">' + this.DecodeMeterStatus(measurementValue.statusMeter).join("<br />") + "</span>",
11242
- result.statusMeter || "",
11263
+ result.statusMeter ?? "",
11243
11264
  infoDiv,
11244
11265
  PlainTextDiv
11245
11266
  );
11246
11267
  this.CreateLocalizedLine(
11247
11268
  "Adapter status",
11248
11269
  hex2bin(measurementValue.statusAdapter, true) + " (" + measurementValue.statusAdapter + ' hex)<br /><span class="statusInfos">' + this.DecodeAdapterStatus(measurementValue.statusAdapter).join("<br />") + "</span>",
11249
- result.statusAdapter || "",
11270
+ result.statusAdapter ?? "",
11250
11271
  infoDiv,
11251
11272
  PlainTextDiv
11252
11273
  );
11253
- this.CreateLocalizedLine("Seconds index", measurementValue.secondsIndex, result.secondsIndex || "", infoDiv, PlainTextDiv);
11254
- this.CreateLocalizedLine("Timestamp", UTC2human(measurementValue.timestamp), result.timestamp || "", infoDiv, PlainTextDiv);
11255
- this.CreateLocalizedLine("OBIS code", measurementValue.measurement.obis, result.obisId || "", infoDiv, PlainTextDiv);
11256
- this.CreateLocalizedLine("Unit (encoded)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded || "", infoDiv, PlainTextDiv);
11257
- this.CreateLocalizedLine("Scaling", measurementValue.measurement.scale, result.scalar || "", infoDiv, PlainTextDiv);
11258
- this.CreateLocalizedLine("Measurement Value", measurementValue.value.toString() + " Wh", result.value || "", infoDiv, PlainTextDiv);
11259
- this.CreateLocalizedLine("Authorization", (measurementValue.measurement.chargingSession?.authorizationStart["@id"] ?? "") + " hex", pad(result.uid, 20) || "", infoDiv, PlainTextDiv);
11260
- this.CreateLocalizedLine("SessionId", measurementValue.measurement.chargingSession?.["@id"] ?? "", result.sessionId || "", infoDiv, PlainTextDiv);
11261
- this.CreateLocalizedLine("Pagination counter", measurementValue.paginationId, result.paging || "", infoDiv, PlainTextDiv);
11274
+ this.CreateLocalizedLine("Seconds index", measurementValue.secondsIndex, result.secondsIndex ?? "", infoDiv, PlainTextDiv);
11275
+ this.CreateLocalizedLine("Timestamp", UTC2human(measurementValue.timestamp), result.timestamp ?? "", infoDiv, PlainTextDiv);
11276
+ this.CreateLocalizedLine("OBIS code", measurementValue.measurement.obis, result.obisId ?? "", infoDiv, PlainTextDiv);
11277
+ this.CreateLocalizedLine("Unit (encoded)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded ?? "", infoDiv, PlainTextDiv);
11278
+ this.CreateLocalizedLine("Scaling", measurementValue.measurement.scale, result.scalar ?? "", infoDiv, PlainTextDiv);
11279
+ this.CreateLocalizedLine("Measurement Value", measurementValue.value.toString() + " Wh", result.value ?? "", infoDiv, PlainTextDiv);
11280
+ this.CreateLocalizedLine("Authorization", (measurementValue.measurement.chargingSession?.authorizationStart["@id"] ?? "") + " hex", pad(result.uid, 20), infoDiv, PlainTextDiv);
11281
+ this.CreateLocalizedLine("SessionId", measurementValue.measurement.chargingSession?.["@id"] ?? "", result.sessionId ?? "", infoDiv, PlainTextDiv);
11282
+ this.CreateLocalizedLine("Pagination counter", measurementValue.paginationId, result.paging ?? "", infoDiv, PlainTextDiv);
11262
11283
  }
11263
11284
  {
11264
- if (HashedPlainTextDiv.parentElement && HashedPlainTextDiv.parentElement.children[0]) {
11265
- HashedPlainTextDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Hashed plain text") + " (SHA256, hex)";
11285
+ if (HashedPlainTextDiv.parentElement) {
11286
+ getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = this.chargy.GetLocalizedMessage("Hashed plain text") + " (SHA256, hex)";
11266
11287
  }
11267
11288
  const hashValueText = typeof result.hashValue === "string" ? result.hashValue : result.hashValue?.toString(16) ?? "";
11268
11289
  HashedPlainTextDiv.innerHTML = hashValueText.match(/.{1,8}/g)?.join(" ") ?? "";
11269
11290
  }
11270
- if (result.publicKey && result.publicKey != "") {
11271
- if (PublicKeyDiv.parentElement && PublicKeyDiv.parentElement.children[0]) {
11272
- PublicKeyDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Public Key") + " (" + (result.publicKeyFormat ? result.publicKeyFormat + ", " : "") + "base32)";
11291
+ if (result.publicKey != null && result.publicKey.length > 0) {
11292
+ if (PublicKeyDiv.parentElement) {
11293
+ 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)";
11273
11294
  }
11274
11295
  if (!IsNullOrEmpty(result.publicKey))
11275
11296
  PublicKeyDiv.innerHTML = result.publicKey.match(/.{1,4}/g)?.join(" ") ?? "";
11276
11297
  }
11277
- if (PublicKeyDiv.parentElement && PublicKeyDiv.parentElement.children[3]) {
11298
+ if (PublicKeyDiv.parentElement?.children[3]) {
11278
11299
  PublicKeyDiv.parentElement.children[3].innerHTML = "";
11279
11300
  if (result.publicKeySignatures) {
11280
11301
  for (const signature of result.publicKeySignatures) {
@@ -11293,14 +11314,14 @@ var AlfenCrypt01 = class extends ACrypt {
11293
11314
  }
11294
11315
  }
11295
11316
  if (result.signature != null) {
11296
- if (SignatureExpectedDiv.parentElement && SignatureExpectedDiv.parentElement.children[0]) {
11297
- SignatureExpectedDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Expected signature") + " (" + (result.signature.format ?? "") + ", hex)";
11317
+ if (SignatureExpectedDiv.parentElement) {
11318
+ getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = this.chargy.GetLocalizedMessage("Expected signature") + " (" + (result.signature.format ?? "") + ", hex)";
11298
11319
  }
11299
- if (result.signature.r && result.signature.s) {
11320
+ if (result.signature.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0) {
11300
11321
  const signatureR = result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
11301
11322
  const signatureS = result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
11302
11323
  SignatureExpectedDiv.innerHTML = "r: " + signatureR + "<br />s: " + signatureS;
11303
- } else if (result.signature.value)
11324
+ } else if (result.signature.value != null && result.signature.value.length > 0)
11304
11325
  SignatureExpectedDiv.innerHTML = result.signature.value.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
11305
11326
  }
11306
11327
  {
@@ -11542,10 +11563,14 @@ var BSMCrypt01 = class extends ACrypt {
11542
11563
  throw new Error(`Invalid identification of signed meter value #${String(measurementCounter - 1)}!`);
11543
11564
  const previousParts = previousId.split("-");
11544
11565
  const currentParts = currentId.split("-");
11545
- if (previousParts.length !== 2 || currentParts.length !== 2 || previousParts[0] !== currentParts[0] || previousParts[1] === void 0 || currentParts[1] === void 0 || // parseInt returns NaN in case parsing fails which in turn does not match
11566
+ const previousPrefix = previousParts.at(0);
11567
+ const previousCounter = previousParts.at(1);
11568
+ const currentPrefix = currentParts.at(0);
11569
+ const currentCounter = currentParts.at(1);
11570
+ 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
11546
11571
  // anything (not even NaN). This way we are checking that both counter values
11547
11572
  // are numeric too.
11548
- parseInt(previousParts[1], 10) >= parseInt(currentParts[1], 10)) {
11573
+ parseInt(previousCounter, 10) >= parseInt(currentCounter, 10)) {
11549
11574
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeasurementIdP", measurementCounter)));
11550
11575
  }
11551
11576
  }
@@ -11583,7 +11608,7 @@ var BSMCrypt01 = class extends ACrypt {
11583
11608
  precision: asNumber(displayedFormat?.["precision"])
11584
11609
  };
11585
11610
  });
11586
- if (currentMeasurement["meterInfo"]) {
11611
+ if (currentMeasurement["meterInfo"] != null) {
11587
11612
  const meterInfoObj2 = asJSONObject(currentMeasurement["meterInfo"]);
11588
11613
  if (meterInfoObj2?.["firmwareVersion"] !== common.meterInfo_firmwareVersion)
11589
11614
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_FirmwareVersionP", measurementCounter)));
@@ -11591,42 +11616,42 @@ var BSMCrypt01 = class extends ACrypt {
11591
11616
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_PublicKeyP", measurementCounter)));
11592
11617
  if (meterInfoObj2?.["meterId"] !== common.meterInfo_meterId)
11593
11618
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_MeterIdP", measurementCounter)));
11594
- if (meterInfoObj2?.["meterId"] !== additionalValues.filter((element) => element.measurandName === "MA1")[0]?.value)
11619
+ if (meterInfoObj2?.["meterId"] !== additionalValues.find((element) => element.measurandName === "MA1")?.value)
11595
11620
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_MeterIdP", measurementCounter)));
11596
11621
  if (meterInfoObj2?.["manufacturer"] !== common.meterInfo_manufacturer)
11597
11622
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_ManufacturerP", measurementCounter)));
11598
11623
  if (meterInfoObj2?.["type"] !== common.meterInfo_type)
11599
11624
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_TypeP", measurementCounter)));
11600
11625
  }
11601
- if (currentMeasurement["contract"]) {
11626
+ if (currentMeasurement["contract"] != null) {
11602
11627
  const contractObj2 = asJSONObject(currentMeasurement["contract"]);
11603
- if (additionalValues.filter((element) => element.measurandName?.startsWith("Meta") && asString(element.value)?.startsWith("contract-id:")).length == 0)
11628
+ if (additionalValues.filter((element) => element.measurandName?.startsWith("Meta") === true && asString(element.value)?.startsWith("contract-id:") === true).length == 0)
11604
11629
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_IdP", measurementCounter)));
11605
11630
  if (contractObj2?.["id"] !== common.contract_id)
11606
11631
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_IdP", measurementCounter)));
11607
11632
  if (contractObj2?.["type"] !== common.contract_type)
11608
11633
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_TypeP", measurementCounter)));
11609
- const contractInfo = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") && asString(element.value)?.startsWith("contract-id:"))[0]?.value;
11634
+ const contractInfo = additionalValues.find((element) => element.measurandName?.startsWith("Meta") === true && asString(element.value)?.startsWith("contract-id:") === true)?.value;
11610
11635
  if (contractInfo != null) {
11611
- if (contractObj2?.["type"] && contractInfo !== "contract-id: " + (common.contract_type ?? "-") + ":" + common.contract_id)
11636
+ if (contractObj2?.["type"] != null && contractInfo !== "contract-id: " + (common.contract_type ?? "-") + ":" + common.contract_id)
11612
11637
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_IdP", measurementCounter)));
11613
- if (!contractObj2?.["type"] && contractInfo !== "contract-id: " + common.contract_id)
11638
+ if (contractObj2?.["type"] == null && contractInfo !== "contract-id: " + common.contract_id)
11614
11639
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_IdP", measurementCounter)));
11615
11640
  }
11616
11641
  }
11617
11642
  const rcrInAdditional = additionalValues.find((element) => element.measurandName == "RCR");
11618
11643
  if (currentMeasurement["value"] == null)
11619
11644
  throw new Error(`Missing value within signed meter value #${String(measurementCounter)}!`);
11620
- if ((valueObj2?.["measurand"] || valueObj2?.["measuredValue"]) && rcrInAdditional === void 0)
11645
+ if ((valueObj2?.["measurand"] != null || valueObj2?.["measuredValue"] != null) && rcrInAdditional === void 0)
11621
11646
  throw new Error(`Missing 'RCR' within the additional values of signed meter value #${String(measurementCounter)}!`);
11622
- if (valueObj2?.["measurand"]) {
11647
+ if (valueObj2?.["measurand"] != null) {
11623
11648
  const measurandObj2 = asJSONObject(valueObj2["measurand"]);
11624
11649
  if (measurandObj2?.["id"] !== common.value_measurand_id || measurandObj2["id"] !== rcrInAdditional?.measurandId)
11625
11650
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_Measurand_IdentificationP", measurementCounter)));
11626
11651
  if (measurandObj2?.["name"] !== common.value_measurand_name || measurandObj2["name"] !== rcrInAdditional?.measurandName)
11627
11652
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_Measurand_NameP", measurementCounter)));
11628
11653
  }
11629
- if (valueObj2?.["measuredValue"]) {
11654
+ if (valueObj2?.["measuredValue"] != null) {
11630
11655
  if (measuredValueObj2?.["value"] !== rcrInAdditional?.value)
11631
11656
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValueP", measurementCounter)));
11632
11657
  if (measuredValueObj2?.["scale"] !== common.value_measuredValue_scale || measuredValueObj2?.["scale"] !== rcrInAdditional?.scale)
@@ -11638,15 +11663,15 @@ var BSMCrypt01 = class extends ACrypt {
11638
11663
  if (measuredValueObj2?.["valueType"] !== common.value_measuredValue_valueType || measuredValueObj2?.["valueType"] !== rcrInAdditional?.valueType)
11639
11664
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_TypeP", measurementCounter)));
11640
11665
  }
11641
- if (currentMeasurement["chargePoint"] && asJSONObject(currentMeasurement["chargePoint"])?.["softwareVersion"] !== common.chargePoint_softwareVersion)
11666
+ if (currentMeasurement["chargePoint"] != null && asJSONObject(currentMeasurement["chargePoint"])?.["softwareVersion"] !== common.chargePoint_softwareVersion)
11642
11667
  currentErrors.push(CreateError(this.chargy.GetMultilanguageText("Inconsistent_ChargingStation_FirmwareVersion")));
11643
- const signedEVSEId = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") && asString(element.value)?.startsWith("evse-id:"));
11668
+ const signedEVSEId = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") === true && asString(element.value)?.startsWith("evse-id:") === true);
11644
11669
  if (signedEVSEId.length == 1) {
11645
11670
  const evse__id = (asString(signedEVSEId[0]?.value) ?? "").replace("evse-id:", "").trim();
11646
11671
  if (evse__id !== "unknown" && ExpectedEVSEId !== evse__id)
11647
11672
  currentErrors.push(CreateError(this.chargy.GetMultilanguageText("Inconsistent_EVSE_Identification")));
11648
11673
  }
11649
- const signedCSCSWVersion = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") && asString(element.value)?.startsWith("csc-sw-version:"));
11674
+ const signedCSCSWVersion = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") === true && asString(element.value)?.startsWith("csc-sw-version:") === true);
11650
11675
  if (signedCSCSWVersion.length == 1) {
11651
11676
  const csc_sw_version = asString(signedCSCSWVersion[0]?.value)?.replace("csc-sw-version:", "").trim() ?? null;
11652
11677
  if (previousCscSwVersion !== null && previousCscSwVersion !== csc_sw_version)
@@ -11711,6 +11736,8 @@ var BSMCrypt01 = class extends ACrypt {
11711
11736
  case "Evt":
11712
11737
  Evt = asNumber(additionalValue.value) ?? NaN;
11713
11738
  break;
11739
+ default:
11740
+ break;
11714
11741
  }
11715
11742
  }
11716
11743
  const currentRCRValue = asNumber(RCR?.value) ?? NaN;
@@ -11773,18 +11800,17 @@ var BSMCrypt01 = class extends ACrypt {
11773
11800
  });
11774
11801
  }
11775
11802
  const n = common.dataSets.length - 1;
11776
- const firstDataSet = common.dataSets[0];
11777
- const lastDataSet = common.dataSets[n];
11778
- if (firstDataSet === void 0 || firstDataSet.TypParsed !== "START" && firstDataSet.TypParsed !== "TURN ON")
11803
+ const firstDataSet = getFirstArrayElement(common.dataSets, "Missing first BSM data set");
11804
+ const lastDataSet = getArrayElement(common.dataSets, n, "Missing last BSM data set");
11805
+ if (firstDataSet.TypParsed !== "START" && firstDataSet.TypParsed !== "TURN ON")
11779
11806
  throw new Error(this.chargy.GetLocalizedMessageWithParameter("Inconsistent_EnergyMeterValueP", 1));
11780
11807
  for (let i = 1; i < common.dataSets.length - 1; i++) {
11781
11808
  if (common.dataSets[i]?.TypParsed !== "CURRENT")
11782
11809
  errors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_EnergyMeterValueP", measurementCounter + 1)));
11783
11810
  }
11784
- if (lastDataSet === void 0 || lastDataSet.TypParsed !== "END" && lastDataSet.TypParsed !== "TURN OFF")
11811
+ if (lastDataSet.TypParsed !== "END" && lastDataSet.TypParsed !== "TURN OFF")
11785
11812
  throw new Error(this.chargy.GetLocalizedMessageWithParameter("Inconsistent_EnergyMeterValueP", n + 1));
11786
- if (CTR.chargingSessions == null)
11787
- CTR.chargingSessions = [];
11813
+ CTR.chargingSessions ??= [];
11788
11814
  const ASN1_SignatureSchema = this.chargy.asn1.define("Signature", function() {
11789
11815
  this.seq().obj(
11790
11816
  this.key("r").int(),
@@ -11901,12 +11927,12 @@ var BSMCrypt01 = class extends ACrypt {
11901
11927
  CTR.chargingSessions.push(session);
11902
11928
  CTR["@id"] = common.meterInfo_meterId + "-" + String(firstDataSet.Epoch);
11903
11929
  {
11904
- const firstChargingSession = CTR.chargingSessions[0];
11905
- const lastChargingSession = CTR.chargingSessions[CTR.chargingSessions.length - 1];
11906
- if (firstChargingSession !== void 0 && (CTR.begin == void 0 || CTR.begin === "" || CTR.begin > firstChargingSession.begin)) {
11930
+ const firstChargingSession = getFirstArrayElement(CTR.chargingSessions, "Missing first BSM charging session");
11931
+ const lastChargingSession = getLastArrayElement(CTR.chargingSessions, "Missing last BSM charging session");
11932
+ if (CTR.begin == void 0 || CTR.begin === "" || CTR.begin > firstChargingSession.begin) {
11907
11933
  CTR.begin = firstChargingSession.begin;
11908
11934
  }
11909
- if (lastChargingSession?.end !== void 0) {
11935
+ if (lastChargingSession.end !== void 0) {
11910
11936
  if (CTR.end == void 0 || CTR.end === "" || CTR.end < lastChargingSession.end)
11911
11937
  CTR.end = lastChargingSession.end;
11912
11938
  }
@@ -12078,58 +12104,63 @@ var BSMCrypt01 = class extends ACrypt {
12078
12104
  }
12079
12105
  return {};
12080
12106
  }
12081
- async ViewMeasurement(measurementValue, errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
12107
+ async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
12082
12108
  if (measurementValue.measurement === void 0)
12083
12109
  return new Error("Invalid measurement!");
12084
12110
  const result = measurementValue.result;
12085
12111
  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);
12086
- if (PlainTextDiv.parentElement != void 0 && PlainTextDiv.parentElement.children[0] != void 0) {
12087
- PlainTextDiv.parentElement.children[0].innerHTML = "Plain text (" + measurementValue.result.ArraySize.toString() + " Bytes, hex)";
12112
+ if (PlainTextDiv.parentElement) {
12113
+ getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = "Plain text (" + measurementValue.result.ArraySize.toString() + " Bytes, hex)";
12088
12114
  }
12089
12115
  PlainTextDiv.style.fontFamily = "";
12090
12116
  PlainTextDiv.style.whiteSpace = "";
12091
12117
  PlainTextDiv.style.maxHeight = "";
12092
12118
  PlainTextDiv.style.overflowY = "";
12093
- this.CreateLine("Snapshot-Typ", this.ParseTyp(measurementValue.Typ), result.Typ || "", infoDiv, PlainTextDiv);
12094
- this.CreateLine("RCR", (measurementValue.RCR * 10 ** measurementValue.RCR_SF).toString() + " " + measurementValue.RCR_Unit, result.RCR || "", infoDiv, PlainTextDiv);
12095
- this.CreateLine("TotWhImp", (measurementValue.TotWhImp * 10 ** measurementValue.TotWhImp_SF).toString() + " " + measurementValue.TotWhImp_Unit, result.TotWhImp || "", infoDiv, PlainTextDiv);
12096
- this.CreateLine("W", (measurementValue.W * 10 ** measurementValue.W_SF).toString() + " " + measurementValue.W_Unit, result.W || "", infoDiv, PlainTextDiv);
12097
- this.CreateLine("MA1", measurementValue.MA1, result.MA1 || "", infoDiv, PlainTextDiv);
12098
- this.CreateLine("RCnt", measurementValue.RCnt, result.RCnt || "", infoDiv, PlainTextDiv);
12099
- this.CreateLine("OS", measurementValue.OS, result.OS || "", infoDiv, PlainTextDiv);
12100
- this.CreateLine("Zeitstempel", UTC2human(measurementValue.Epoch), result.Epoch || "", infoDiv, PlainTextDiv);
12101
- this.CreateLine("TZO", measurementValue.TZO.toString() + " Minuten", result.TZO || "", infoDiv, PlainTextDiv);
12102
- this.CreateLine("EpochSetCnt", measurementValue.EpochSetCnt, result.EpochSetCnt || "", infoDiv, PlainTextDiv);
12103
- this.CreateLine("EpochSetOS", measurementValue.EpochSetOS, result.EpochSetOS || "", infoDiv, PlainTextDiv);
12104
- this.CreateLine("DI", measurementValue.DI, result.DI || "", infoDiv, PlainTextDiv);
12105
- this.CreateLine("DO", measurementValue.DO, result.DO || "", infoDiv, PlainTextDiv);
12106
- this.CreateLine("Meta1", measurementValue.Meta1, result.Meta1 || "", infoDiv, PlainTextDiv);
12107
- this.CreateLine("Meta2", measurementValue.Meta2, result.Meta2 || "", infoDiv, PlainTextDiv);
12108
- this.CreateLine("Meta3", measurementValue.Meta3, result.Meta3 || "", infoDiv, PlainTextDiv);
12109
- this.CreateLine("Evt", this.ParseEvents(measurementValue.Evt).join("<br>"), result.Evt || "", infoDiv, PlainTextDiv);
12110
- if (HashedPlainTextDiv.parentElement != void 0 && HashedPlainTextDiv.parentElement.children[0] != void 0) {
12111
- HashedPlainTextDiv.parentElement.children[0].innerHTML = "Hashed plain text (SHA256, hex)";
12119
+ this.CreateLine("Snapshot-Typ", this.ParseTyp(measurementValue.Typ), result.Typ, infoDiv, PlainTextDiv);
12120
+ this.CreateLine("RCR", (measurementValue.RCR * 10 ** measurementValue.RCR_SF).toString() + " " + measurementValue.RCR_Unit, result.RCR, infoDiv, PlainTextDiv);
12121
+ this.CreateLine("TotWhImp", (measurementValue.TotWhImp * 10 ** measurementValue.TotWhImp_SF).toString() + " " + measurementValue.TotWhImp_Unit, result.TotWhImp, infoDiv, PlainTextDiv);
12122
+ this.CreateLine("W", (measurementValue.W * 10 ** measurementValue.W_SF).toString() + " " + measurementValue.W_Unit, result.W, infoDiv, PlainTextDiv);
12123
+ this.CreateLine("MA1", measurementValue.MA1, result.MA1, infoDiv, PlainTextDiv);
12124
+ this.CreateLine("RCnt", measurementValue.RCnt, result.RCnt, infoDiv, PlainTextDiv);
12125
+ this.CreateLine("OS", measurementValue.OS, result.OS, infoDiv, PlainTextDiv);
12126
+ this.CreateLine("Zeitstempel", UTC2human(measurementValue.Epoch), result.Epoch, infoDiv, PlainTextDiv);
12127
+ this.CreateLine("TZO", measurementValue.TZO.toString() + " Minuten", result.TZO, infoDiv, PlainTextDiv);
12128
+ this.CreateLine("EpochSetCnt", measurementValue.EpochSetCnt, result.EpochSetCnt, infoDiv, PlainTextDiv);
12129
+ this.CreateLine("EpochSetOS", measurementValue.EpochSetOS, result.EpochSetOS, infoDiv, PlainTextDiv);
12130
+ this.CreateLine("DI", measurementValue.DI, result.DI, infoDiv, PlainTextDiv);
12131
+ this.CreateLine("DO", measurementValue.DO, result.DO, infoDiv, PlainTextDiv);
12132
+ this.CreateLine("Meta1", measurementValue.Meta1, result.Meta1, infoDiv, PlainTextDiv);
12133
+ this.CreateLine("Meta2", measurementValue.Meta2, result.Meta2, infoDiv, PlainTextDiv);
12134
+ this.CreateLine("Meta3", measurementValue.Meta3, result.Meta3, infoDiv, PlainTextDiv);
12135
+ this.CreateLine("Evt", this.ParseEvents(measurementValue.Evt).join("<br>"), result.Evt, infoDiv, PlainTextDiv);
12136
+ if (HashedPlainTextDiv.parentElement) {
12137
+ getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = "Hashed plain text (SHA256, hex)";
12112
12138
  }
12113
12139
  HashedPlainTextDiv.innerHTML = result.sha256value?.match(/.{1,8}/g)?.join(" ") ?? "";
12114
12140
  if (result.publicKey != null && result.publicKey != "") {
12115
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[0] != void 0) {
12116
- PublicKeyDiv.parentElement.children[0].innerHTML = "Public Key (" + (result.publicKeyFormat ? result.publicKeyFormat + ", " : "") + "hex)";
12141
+ if (PublicKeyDiv.parentElement) {
12142
+ getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = "Public Key (" + (result.publicKeyFormat != null && result.publicKeyFormat.length > 0 ? result.publicKeyFormat + ", " : "") + "hex)";
12117
12143
  }
12118
12144
  if (!IsNullOrEmpty(result.publicKey))
12119
12145
  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(" ") ?? "-";
12120
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[3] != void 0) {
12121
- PublicKeyDiv.parentElement.children[3].innerHTML = "";
12146
+ const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
12147
+ if (publicKeySignatureContainer !== void 0) {
12148
+ publicKeySignatureContainer.innerHTML = "";
12122
12149
  }
12123
12150
  if (result.publicKeySignatures) {
12124
12151
  for (const signature of result.publicKeySignatures) {
12125
12152
  try {
12126
- const signatureDiv = PublicKeyDiv.parentElement?.children[3]?.appendChild(document.createElement("div"));
12127
- if (signatureDiv != null && measurementValue.measurement.chargingSession != null && measurementValue.measurement.chargingSession.EVSE != null && measurementValue.measurement.chargingSession.EVSE.meters.length > 0 && measurementValue.measurement.chargingSession.EVSE.meters[0] != null && measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys != null && measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys.length > 0) {
12153
+ const signatureDiv = publicKeySignatureContainer?.appendChild(document.createElement("div"));
12154
+ const chargingSession = measurementValue.measurement.chargingSession;
12155
+ const evse = chargingSession?.EVSE;
12156
+ const meter = evse?.meters.at(0);
12157
+ const publicKey = meter?.publicKeys?.at(0);
12158
+ if (signatureDiv != null && chargingSession != null && evse != null && meter != null && publicKey != null) {
12128
12159
  signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
12129
- measurementValue.measurement.chargingSession.chargingStation,
12130
- measurementValue.measurement.chargingSession.EVSE,
12131
- measurementValue.measurement.chargingSession.EVSE.meters[0],
12132
- measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys[0],
12160
+ chargingSession.chargingStation,
12161
+ evse,
12162
+ meter,
12163
+ publicKey,
12133
12164
  signature
12134
12165
  );
12135
12166
  }
@@ -12140,12 +12171,12 @@ var BSMCrypt01 = class extends ACrypt {
12140
12171
  }
12141
12172
  }
12142
12173
  if (result.signature != null) {
12143
- if (SignatureExpectedDiv.parentElement != void 0 && SignatureExpectedDiv.parentElement.children[0] != void 0) {
12144
- SignatureExpectedDiv.parentElement.children[0].innerHTML = "Erwartete Signatur (" + (result.signature.format || "") + ", hex)";
12174
+ if (SignatureExpectedDiv.parentElement) {
12175
+ getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = "Erwartete Signatur (" + (result.signature.format ?? "") + ", hex)";
12145
12176
  }
12146
- if (result.signature.r && result.signature.s)
12177
+ if (result.signature.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0)
12147
12178
  SignatureExpectedDiv.innerHTML = "r: " + (result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-") + "<br />s: " + (result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-");
12148
- else if (result.signature.value)
12179
+ else if (result.signature.value != null && result.signature.value.length > 0)
12149
12180
  SignatureExpectedDiv.innerHTML = result.signature.value.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
12150
12181
  }
12151
12182
  switch (result.status) {
@@ -12171,6 +12202,7 @@ var BSMCrypt01 = class extends ACrypt {
12171
12202
  SignatureCheckDiv.innerHTML = '<i class="fas fa-times-circle"></i><div id="description">Ung\xFCltige Signatur</div>';
12172
12203
  break;
12173
12204
  }
12205
+ return void 0;
12174
12206
  }
12175
12207
  //#region Helper methods
12176
12208
  PrefixConverter(input) {
@@ -12249,30 +12281,35 @@ var BSMCrypt01 = class extends ACrypt {
12249
12281
  if ((value & 1 << 29) != 0) events.push("OEM 15");
12250
12282
  return events;
12251
12283
  }
12252
- DecodeStatus(statusValue) {
12253
- const statusArray = [];
12254
- try {
12255
- const status = parseInt(statusValue);
12256
- if ((status & 1) == 1)
12257
- statusArray.push("Fehler erkannt");
12258
- if ((status & 2) == 2)
12259
- statusArray.push("Synchrone Messwert\xFCbermittlung");
12260
- if ((status & 8) == 8)
12261
- statusArray.push("System-Uhr ist synchron");
12262
- else
12263
- statusArray.push("System-Uhr ist nicht synchron");
12264
- if ((status & 16) == 16)
12265
- statusArray.push("R\xFCcklaufsperre aktiv");
12266
- if ((status & 32) == 32)
12267
- statusArray.push("Energierichtung -A");
12268
- if ((status & 64) == 64)
12269
- statusArray.push("Magnetfeld erkannt");
12270
- } catch {
12271
- statusArray.push("Invalid status!");
12272
- }
12273
- return statusArray;
12274
- }
12275
- //#endregion
12284
+ // private DecodeStatus(statusValue: string) : Array<string>
12285
+ // {
12286
+ // const statusArray:string[] = [];
12287
+ // try
12288
+ // {
12289
+ // const status = parseInt(statusValue);
12290
+ // if ((status & 1) == 1)
12291
+ // statusArray.push("Fehler erkannt");
12292
+ // if ((status & 2) == 2)
12293
+ // statusArray.push("Synchrone Messwertübermittlung");
12294
+ // // Bit 3 is reserved!
12295
+ // if ((status & 8) == 8)
12296
+ // statusArray.push("System-Uhr ist synchron");
12297
+ // else
12298
+ // statusArray.push("System-Uhr ist nicht synchron");
12299
+ // if ((status & 16) == 16)
12300
+ // statusArray.push("Rücklaufsperre aktiv");
12301
+ // if ((status & 32) == 32)
12302
+ // statusArray.push("Energierichtung -A");
12303
+ // if ((status & 64) == 64)
12304
+ // statusArray.push("Magnetfeld erkannt");
12305
+ // }
12306
+ // catch
12307
+ // {
12308
+ // statusArray.push("Invalid status!");
12309
+ // }
12310
+ // return statusArray;
12311
+ // }
12312
+ // //#endregion
12276
12313
  };
12277
12314
 
12278
12315
  // src/CanonicalJSON.ts
@@ -12672,7 +12709,7 @@ var EMHCrypt01 = class extends ACrypt {
12672
12709
  measurementValue.result = cryptoResult;
12673
12710
  return cryptoResult;
12674
12711
  }
12675
- if (measurementValue.measurement === void 0 || measurementValue.measurement.chargingSession === void 0) {
12712
+ if (measurementValue.measurement?.chargingSession === void 0) {
12676
12713
  return {
12677
12714
  status: "InvalidMeasurement" /* InvalidMeasurement */
12678
12715
  };
@@ -12711,9 +12748,10 @@ var EMHCrypt01 = class extends ACrypt {
12711
12748
  cryptoResult.meter = meter;
12712
12749
  if (meter.publicKeys != null && meter.publicKeys.length > 0) {
12713
12750
  try {
12714
- cryptoResult.publicKey = meter.publicKeys[0]?.value?.toLowerCase();
12715
- cryptoResult.publicKeyFormat = meter.publicKeys[0]?.format;
12716
- cryptoResult.publicKeySignatures = meter.publicKeys[0]?.signatures;
12751
+ const publicKey = meter.publicKeys.at(0);
12752
+ cryptoResult.publicKey = publicKey?.value?.toLowerCase();
12753
+ cryptoResult.publicKeyFormat = publicKey?.format;
12754
+ cryptoResult.publicKeySignatures = publicKey?.signatures;
12717
12755
  try {
12718
12756
  if (this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex").verify(
12719
12757
  cryptoResult.sha256value,
@@ -12738,59 +12776,60 @@ var EMHCrypt01 = class extends ACrypt {
12738
12776
  }
12739
12777
  return {};
12740
12778
  }
12741
- async ViewMeasurement(measurementValue, errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
12742
- if (measurementValue.measurement === void 0 || measurementValue.measurement.chargingSession === void 0 || measurementValue.measurement.chargingSession.authorizationStart.timestamp === void 0) {
12779
+ async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
12780
+ if (measurementValue.measurement?.chargingSession?.authorizationStart.timestamp === void 0) {
12743
12781
  return new Error("Invalid measurement!");
12744
12782
  }
12745
12783
  const result = measurementValue.result;
12746
12784
  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);
12747
12785
  {
12748
- if (PlainTextDiv.parentElement != void 0 && PlainTextDiv.parentElement.children[0] != void 0) {
12749
- PlainTextDiv.parentElement.children[0].innerHTML = "Plain text (320 Bytes, hex)";
12786
+ if (PlainTextDiv.parentElement) {
12787
+ getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = "Plain text (320 Bytes, hex)";
12750
12788
  }
12751
12789
  PlainTextDiv.style.fontFamily = "";
12752
12790
  PlainTextDiv.style.whiteSpace = "";
12753
12791
  PlainTextDiv.style.maxHeight = "";
12754
12792
  PlainTextDiv.style.overflowY = "";
12755
- this.CreateLine("Z\xE4hlernummer", measurementValue.measurement.energyMeterId, result.meterId || "", infoDiv, PlainTextDiv);
12756
- this.CreateLine("Zeitstempel", UTC2human(measurementValue.timestamp), result.timestamp || "", infoDiv, PlainTextDiv);
12757
- this.CreateLine("Status", hex2bin(measurementValue.infoStatus) + " (" + measurementValue.infoStatus + ' hex)<br /><span class="statusInfos">' + this.DecodeStatus(measurementValue.infoStatus).join("<br />") + "</span>", result.infoStatus || "", infoDiv, PlainTextDiv);
12758
- this.CreateLine("Sekundenindex", measurementValue.secondsIndex, result.secondsIndex || "", infoDiv, PlainTextDiv);
12759
- this.CreateLine("Paginierungsz\xE4hler", parseInt(measurementValue.paginationId, 16), result.paginationId || "", infoDiv, PlainTextDiv);
12760
- this.CreateLine("OBIS-Kennzahl", measurementValue.measurement.obis, result.obis || "", infoDiv, PlainTextDiv);
12761
- this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded || "", infoDiv, PlainTextDiv);
12762
- this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale || "", infoDiv, PlainTextDiv);
12763
- this.CreateLine("Messwert", measurementValue.value.toString() + " Wh", result.value || "", infoDiv, PlainTextDiv);
12764
- this.CreateLine("Logbuchindex", measurementValue.logBookIndex + " hex", result.logBookIndex || "", infoDiv, PlainTextDiv);
12765
- this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128) || "", infoDiv, PlainTextDiv);
12766
- this.CreateLine("Autorisierungszeitpunkt", UTC2human(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151) || "", infoDiv, PlainTextDiv);
12793
+ this.CreateLine("Z\xE4hlernummer", measurementValue.measurement.energyMeterId, result.meterId ?? "", infoDiv, PlainTextDiv);
12794
+ this.CreateLine("Zeitstempel", UTC2human(measurementValue.timestamp), result.timestamp ?? "", infoDiv, PlainTextDiv);
12795
+ this.CreateLine("Status", hex2bin(measurementValue.infoStatus) + " (" + measurementValue.infoStatus + ' hex)<br /><span class="statusInfos">' + this.DecodeStatus(measurementValue.infoStatus).join("<br />") + "</span>", result.infoStatus ?? "", infoDiv, PlainTextDiv);
12796
+ this.CreateLine("Sekundenindex", measurementValue.secondsIndex, result.secondsIndex ?? "", infoDiv, PlainTextDiv);
12797
+ this.CreateLine("Paginierungsz\xE4hler", parseInt(measurementValue.paginationId, 16), result.paginationId ?? "", infoDiv, PlainTextDiv);
12798
+ this.CreateLine("OBIS-Kennzahl", measurementValue.measurement.obis, result.obis ?? "", infoDiv, PlainTextDiv);
12799
+ this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded ?? "", infoDiv, PlainTextDiv);
12800
+ this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale ?? "", infoDiv, PlainTextDiv);
12801
+ this.CreateLine("Messwert", measurementValue.value.toString() + " Wh", result.value ?? "", infoDiv, PlainTextDiv);
12802
+ this.CreateLine("Logbuchindex", measurementValue.logBookIndex + " hex", result.logBookIndex ?? "", infoDiv, PlainTextDiv);
12803
+ this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128), infoDiv, PlainTextDiv);
12804
+ this.CreateLine("Autorisierungszeitpunkt", UTC2human(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151), infoDiv, PlainTextDiv);
12767
12805
  }
12768
12806
  {
12769
- if (HashedPlainTextDiv.parentElement != void 0 && HashedPlainTextDiv.parentElement.children[0] != void 0) {
12770
- HashedPlainTextDiv.parentElement.children[0].innerHTML = "Hashed plain text (SHA256, 24 bytes, hex)";
12807
+ if (HashedPlainTextDiv.parentElement) {
12808
+ getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = "Hashed plain text (SHA256, 24 bytes, hex)";
12771
12809
  }
12772
12810
  HashedPlainTextDiv.innerHTML = result.sha256value?.match(/.{1,8}/g)?.join(" ") ?? "";
12773
12811
  }
12774
12812
  if (result.publicKey != null && result.publicKey != "") {
12775
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[0] != void 0) {
12776
- PublicKeyDiv.parentElement.children[0].innerHTML = "Public Key (" + (result.publicKeyFormat ? result.publicKeyFormat + ", " : "") + "hex)";
12813
+ if (PublicKeyDiv.parentElement) {
12814
+ getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = "Public Key (" + (result.publicKeyFormat != null && result.publicKeyFormat.length > 0 ? result.publicKeyFormat + ", " : "") + "hex)";
12777
12815
  }
12778
12816
  if (!IsNullOrEmpty(result.publicKey))
12779
12817
  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(" ") ?? "";
12780
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[3] != void 0) {
12781
- PublicKeyDiv.parentElement.children[3].innerHTML = "";
12818
+ const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
12819
+ if (publicKeySignatureContainer !== void 0) {
12820
+ publicKeySignatureContainer.innerHTML = "";
12782
12821
  }
12783
12822
  if (result.publicKeySignatures) {
12784
12823
  for (const signature of result.publicKeySignatures) {
12785
12824
  try {
12786
- const signatureDiv = PublicKeyDiv.parentElement?.children[3]?.appendChild(document.createElement("div"));
12825
+ const signatureDiv = publicKeySignatureContainer?.appendChild(document.createElement("div"));
12787
12826
  if (signatureDiv) {
12788
12827
  signatureDiv.classList.add("signature");
12789
12828
  signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
12790
12829
  measurementValue.measurement.chargingSession.chargingStation,
12791
12830
  measurementValue.measurement.chargingSession.EVSE,
12792
- measurementValue.measurement.chargingSession.EVSE?.meters[0],
12793
- measurementValue.measurement.chargingSession.EVSE?.meters[0]?.publicKeys?.[0],
12831
+ measurementValue.measurement.chargingSession.EVSE?.meters.at(0),
12832
+ measurementValue.measurement.chargingSession.EVSE?.meters.at(0)?.publicKeys?.at(0),
12794
12833
  signature
12795
12834
  );
12796
12835
  signatureDiv.onclick = () => {
@@ -12804,12 +12843,12 @@ var EMHCrypt01 = class extends ACrypt {
12804
12843
  }
12805
12844
  }
12806
12845
  if (result.signature != null) {
12807
- if (SignatureExpectedDiv.parentElement != void 0 && SignatureExpectedDiv.parentElement.children[0] != void 0) {
12808
- SignatureExpectedDiv.parentElement.children[0].innerHTML = "Erwartete Signatur (" + (result.signature.format || "") + ", hex)";
12846
+ if (SignatureExpectedDiv.parentElement) {
12847
+ getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = "Erwartete Signatur (" + (result.signature.format ?? "") + ", hex)";
12809
12848
  }
12810
- if (result.signature.r && result.signature.s)
12849
+ if (result.signature.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0)
12811
12850
  SignatureExpectedDiv.innerHTML = "r: " + (result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") + "<br />s: " + (result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "");
12812
- else if (result.signature.value)
12851
+ else if (result.signature.value != null && result.signature.value.length > 0)
12813
12852
  SignatureExpectedDiv.innerHTML = result.signature.value.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
12814
12853
  }
12815
12854
  {
@@ -12837,6 +12876,7 @@ var EMHCrypt01 = class extends ACrypt {
12837
12876
  break;
12838
12877
  }
12839
12878
  }
12879
+ return void 0;
12840
12880
  }
12841
12881
  //#region Helper methods
12842
12882
  DecodeStatus(statusValue) {
@@ -12905,7 +12945,7 @@ var GDFCrypt01 = class extends ACrypt {
12905
12945
  measurementValue.result = cryptoResult;
12906
12946
  return cryptoResult;
12907
12947
  }
12908
- if (measurementValue.measurement === void 0 || measurementValue.measurement.chargingSession === void 0) {
12948
+ if (measurementValue.measurement?.chargingSession === void 0) {
12909
12949
  return {
12910
12950
  status: "InvalidMeasurement" /* InvalidMeasurement */
12911
12951
  };
@@ -12940,9 +12980,10 @@ var GDFCrypt01 = class extends ACrypt {
12940
12980
  cryptoResult.meter = meter;
12941
12981
  if (meter.publicKeys != null && meter.publicKeys.length > 0) {
12942
12982
  try {
12943
- cryptoResult.publicKey = meter.publicKeys[0]?.value?.toLowerCase();
12944
- cryptoResult.publicKeyFormat = meter.publicKeys[0]?.format;
12945
- cryptoResult.publicKeySignatures = meter.publicKeys[0]?.signatures;
12983
+ const publicKey = meter.publicKeys.at(0);
12984
+ cryptoResult.publicKey = publicKey?.value?.toLowerCase();
12985
+ cryptoResult.publicKeyFormat = publicKey?.format;
12986
+ cryptoResult.publicKeySignatures = publicKey?.signatures;
12946
12987
  try {
12947
12988
  if (this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex").verify(
12948
12989
  cryptoResult.sha256value,
@@ -12967,54 +13008,55 @@ var GDFCrypt01 = class extends ACrypt {
12967
13008
  }
12968
13009
  return {};
12969
13010
  }
12970
- async ViewMeasurement(measurementValue, errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
12971
- if (measurementValue.measurement === void 0 || measurementValue.measurement.chargingSession === void 0 || measurementValue.measurement.chargingSession.authorizationStart.timestamp === void 0) {
13011
+ async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
13012
+ if (measurementValue.measurement?.chargingSession?.authorizationStart.timestamp === void 0) {
12972
13013
  return new Error("Invalid measurement!");
12973
13014
  }
12974
13015
  const result = measurementValue.result;
12975
13016
  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);
12976
13017
  {
12977
- if (PlainTextDiv.parentElement != void 0 && PlainTextDiv.parentElement.children[0] != void 0) {
12978
- PlainTextDiv.parentElement.children[0].innerHTML = "Plain text (320 Bytes, hex)";
13018
+ if (PlainTextDiv.parentElement) {
13019
+ getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = "Plain text (320 Bytes, hex)";
12979
13020
  }
12980
13021
  PlainTextDiv.style.fontFamily = "";
12981
13022
  PlainTextDiv.style.whiteSpace = "";
12982
13023
  PlainTextDiv.style.maxHeight = "";
12983
13024
  PlainTextDiv.style.overflowY = "";
12984
- this.CreateLine("Z\xE4hlernummer", measurementValue.measurement.energyMeterId, result.meterId || "", infoDiv, PlainTextDiv);
12985
- this.CreateLine("Zeitstempel", UTC2human(measurementValue.timestamp), result.timestamp || "", infoDiv, PlainTextDiv);
12986
- this.CreateLine("OBIS-Kennzahl", measurementValue.measurement.obis, result.obis || "", infoDiv, PlainTextDiv);
12987
- this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded || "", infoDiv, PlainTextDiv);
12988
- this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale || "", infoDiv, PlainTextDiv);
12989
- this.CreateLine("Messwert", measurementValue.value.toString() + " Wh", result.value || "", infoDiv, PlainTextDiv);
12990
- this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128) || "", infoDiv, PlainTextDiv);
12991
- this.CreateLine("Autorisierungszeitpunkt", UTC2human(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151) || "", infoDiv, PlainTextDiv);
13025
+ this.CreateLine("Z\xE4hlernummer", measurementValue.measurement.energyMeterId, result.meterId ?? "", infoDiv, PlainTextDiv);
13026
+ this.CreateLine("Zeitstempel", UTC2human(measurementValue.timestamp), result.timestamp ?? "", infoDiv, PlainTextDiv);
13027
+ this.CreateLine("OBIS-Kennzahl", measurementValue.measurement.obis, result.obis ?? "", infoDiv, PlainTextDiv);
13028
+ this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded ?? "", infoDiv, PlainTextDiv);
13029
+ this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale ?? "", infoDiv, PlainTextDiv);
13030
+ this.CreateLine("Messwert", measurementValue.value.toString() + " Wh", result.value ?? "", infoDiv, PlainTextDiv);
13031
+ this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128), infoDiv, PlainTextDiv);
13032
+ this.CreateLine("Autorisierungszeitpunkt", UTC2human(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151), infoDiv, PlainTextDiv);
12992
13033
  }
12993
13034
  {
12994
- if (HashedPlainTextDiv.parentElement != void 0 && HashedPlainTextDiv.parentElement.children[0] != void 0) {
12995
- HashedPlainTextDiv.parentElement.children[0].innerHTML = "Hashed plain text (SHA256, 24 bytes, hex)";
13035
+ if (HashedPlainTextDiv.parentElement) {
13036
+ getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = "Hashed plain text (SHA256, 24 bytes, hex)";
12996
13037
  }
12997
13038
  HashedPlainTextDiv.innerHTML = result.sha256value?.match(/.{1,8}/g)?.join(" ") ?? "";
12998
13039
  }
12999
13040
  if (result.publicKey != null && result.publicKey != "") {
13000
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[0] != void 0) {
13001
- PublicKeyDiv.parentElement.children[0].innerHTML = "Public Key (" + (result.publicKeyFormat ? result.publicKeyFormat + ", " : "") + "hex)";
13041
+ if (PublicKeyDiv.parentElement) {
13042
+ getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = "Public Key (" + (result.publicKeyFormat != null && result.publicKeyFormat.length > 0 ? result.publicKeyFormat + ", " : "") + "hex)";
13002
13043
  }
13003
13044
  if (!IsNullOrEmpty(result.publicKey))
13004
13045
  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(" ") ?? "";
13005
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[3] != void 0) {
13006
- PublicKeyDiv.parentElement.children[3].innerHTML = "";
13046
+ const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
13047
+ if (publicKeySignatureContainer !== void 0) {
13048
+ publicKeySignatureContainer.innerHTML = "";
13007
13049
  }
13008
13050
  if (result.publicKeySignatures) {
13009
13051
  for (const signature of result.publicKeySignatures) {
13010
13052
  try {
13011
- const signatureDiv = PublicKeyDiv.parentElement?.children[3]?.appendChild(document.createElement("div"));
13053
+ const signatureDiv = publicKeySignatureContainer?.appendChild(document.createElement("div"));
13012
13054
  if (signatureDiv != null)
13013
13055
  signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
13014
13056
  measurementValue.measurement.chargingSession.chargingStation,
13015
13057
  measurementValue.measurement.chargingSession.EVSE,
13016
- measurementValue.measurement.chargingSession.EVSE?.meters[0],
13017
- measurementValue.measurement.chargingSession.EVSE?.meters[0]?.publicKeys?.[0],
13058
+ measurementValue.measurement.chargingSession.EVSE?.meters.at(0),
13059
+ measurementValue.measurement.chargingSession.EVSE?.meters.at(0)?.publicKeys?.at(0),
13018
13060
  signature
13019
13061
  );
13020
13062
  } catch (exception) {
@@ -13024,12 +13066,12 @@ var GDFCrypt01 = class extends ACrypt {
13024
13066
  }
13025
13067
  }
13026
13068
  if (result.signature != null) {
13027
- if (SignatureExpectedDiv.parentElement != void 0 && SignatureExpectedDiv.parentElement.children[0] != void 0) {
13028
- SignatureExpectedDiv.parentElement.children[0].innerHTML = "Erwartete Signatur (" + (result.signature.format || "") + ", hex)";
13069
+ if (SignatureExpectedDiv.parentElement) {
13070
+ getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = "Erwartete Signatur (" + (result.signature.format ?? "") + ", hex)";
13029
13071
  }
13030
- if (result.signature.r && result.signature.s)
13072
+ if (result.signature.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0)
13031
13073
  SignatureExpectedDiv.innerHTML = "r: " + (result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") + "<br />s: " + (result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "");
13032
- else if (result.signature.value)
13074
+ else if (result.signature.value != null && result.signature.value.length > 0)
13033
13075
  SignatureExpectedDiv.innerHTML = result.signature.value.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
13034
13076
  }
13035
13077
  {
@@ -13057,6 +13099,7 @@ var GDFCrypt01 = class extends ACrypt {
13057
13099
  break;
13058
13100
  }
13059
13101
  }
13102
+ return void 0;
13060
13103
  }
13061
13104
  };
13062
13105
  var MENNEKES_EDL40_XMLNS = "http://www.mennekes.de/Mennekes.EdlVerification.xsd";
@@ -13303,7 +13346,7 @@ var MennekesCrypt01 = class extends ACrypt {
13303
13346
  signedData.byteOffset + signedData.byteLength
13304
13347
  );
13305
13348
  cryptoResult.hashValue = (await sha256(new DataView(signedDataBuffer))).substring(0, 48);
13306
- const publicKey = cleanHex(meter.publicKeys[0]?.value ?? measurement.publicKey);
13349
+ const publicKey = cleanHex(meter.publicKeys.at(0)?.value ?? measurement.publicKey);
13307
13350
  if (publicKey.length !== 96)
13308
13351
  return setResult("InvalidPublicKey" /* InvalidPublicKey */);
13309
13352
  const result = this.curve192r1.keyFromPublic("04" + publicKey, "hex").verify(
@@ -13334,7 +13377,7 @@ var MennekesCrypt01 = class extends ACrypt {
13334
13377
  PublicKeyDiv.innerHTML = result.publicKey?.match(/.{1,8}/g)?.join(" ") ?? "";
13335
13378
  if (SignatureExpectedDiv.parentElement?.children[0])
13336
13379
  SignatureExpectedDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Expected signature") + " (rs, hex)";
13337
- 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(" ") ?? "") : "";
13380
+ 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(" ") ?? "") : "";
13338
13381
  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>";
13339
13382
  return Promise.resolve(void 0);
13340
13383
  }
@@ -13353,10 +13396,7 @@ function parseMennekesXMLDocument(XMLDocument) {
13353
13396
  throw new Error("No Mennekes ChargingProcess element found!");
13354
13397
  if (isLocalName(XMLDocument.documentElement, "ChargingProcess")) {
13355
13398
  if (chargingProcesses.length > 1) {
13356
- const chargingProcess = chargingProcesses[0];
13357
- if (chargingProcess != void 0)
13358
- return chargingProcess;
13359
- throw new Error("No Mennekes ChargingProcess found!");
13399
+ return getFirstArrayElement(chargingProcesses, "No Mennekes ChargingProcess found!");
13360
13400
  }
13361
13401
  }
13362
13402
  return {
@@ -13479,8 +13519,8 @@ function toMennekesMeasurementValue(measurement) {
13479
13519
  }
13480
13520
  function validateMennekesLawConformity(measurementValues, chargy) {
13481
13521
  const errors = new Array();
13482
- const start = measurementValues[0];
13483
- const end = measurementValues[measurementValues.length - 1];
13522
+ const start = measurementValues.at(0);
13523
+ const end = measurementValues.at(-1);
13484
13524
  if (start == null || end == null)
13485
13525
  return [
13486
13526
  CreateError(chargy.GetMultilanguageText("Mennekes EDL40 requires at least two measurement values."))
@@ -13610,9 +13650,9 @@ var OCMFv1_x = class extends ACrypt {
13610
13650
  }
13611
13651
  async VerifyMeasurement(measurementValue) {
13612
13652
  measurementValue.method = this;
13613
- return {
13653
+ return Promise.resolve({
13614
13654
  status: measurementValue.result?.status ?? "Unvalidated" /* Unvalidated */
13615
- };
13655
+ });
13616
13656
  }
13617
13657
  PayloadDictionary(Path, Key) {
13618
13658
  if (Path === "RD") {
@@ -13682,7 +13722,7 @@ var OCMFv1_x = class extends ACrypt {
13682
13722
  return Key;
13683
13723
  }
13684
13724
  }
13685
- SignatureDictionary(Path, Key) {
13725
+ SignatureDictionary(_Path, Key) {
13686
13726
  switch (Key) {
13687
13727
  case "SA":
13688
13728
  return "Signature Algorithm";
@@ -13696,16 +13736,16 @@ var OCMFv1_x = class extends ACrypt {
13696
13736
  return Key;
13697
13737
  }
13698
13738
  }
13699
- async ViewMeasurement(measurementValue, errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
13739
+ async ViewMeasurement(measurementValue, _errorDiv, introDiv, _infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
13700
13740
  if (!measurementValue.measurement || !measurementValue.ocmfDocument || !measurementValue.measurement.chargingSession) {
13701
13741
  return new Error("Invalid measurement!");
13702
13742
  }
13703
13743
  {
13704
- 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 + ") " : "");
13744
+ 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 + ") " : "");
13705
13745
  }
13706
13746
  {
13707
- if (PlainTextDiv.parentElement && PlainTextDiv.parentElement.children[0]) {
13708
- PlainTextDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Plain text") + " (OCMF|&lt;" + this.chargy.GetLocalizedMessage("payload") + "&gt;|&lt;" + this.chargy.GetLocalizedMessage("signature") + "&gt;)";
13747
+ if (PlainTextDiv.parentElement) {
13748
+ getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = this.chargy.GetLocalizedMessage("Plain text") + " (OCMF|&lt;" + this.chargy.GetLocalizedMessage("payload") + "&gt;|&lt;" + this.chargy.GetLocalizedMessage("signature") + "&gt;)";
13709
13749
  }
13710
13750
  PlainTextDiv.innerText = "";
13711
13751
  const compactValueDiv = document.createElement("div");
@@ -13737,29 +13777,30 @@ var OCMFv1_x = class extends ACrypt {
13737
13777
  };
13738
13778
  }
13739
13779
  {
13740
- if (HashedPlainTextDiv.parentElement && HashedPlainTextDiv.parentElement.children[0]) {
13741
- HashedPlainTextDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Hashed payload") + " (" + measurementValue.ocmfDocument.hashAlgorithm + ")";
13780
+ if (HashedPlainTextDiv.parentElement) {
13781
+ getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed payload header").innerHTML = this.chargy.GetLocalizedMessage("Hashed payload") + " (" + measurementValue.ocmfDocument.hashAlgorithm + ")";
13742
13782
  }
13743
13783
  HashedPlainTextDiv.innerHTML = measurementValue.ocmfDocument.hashValue.match(/.{1,8}/g)?.join(" ") ?? "0x00000000000000000000000000000000000";
13744
13784
  }
13745
- if (measurementValue.ocmfDocument.publicKey) {
13746
- if (PublicKeyDiv.parentElement && PublicKeyDiv.parentElement.children[0]) {
13747
- PublicKeyDiv.parentElement.children[0].innerHTML = typeof measurementValue.ocmfDocument.publicKey === "string" ? this.chargy.GetLocalizedMessage("Public Key") : this.chargy.GetLocalizedMessage("Public Key") + " (" + measurementValue.ocmfDocument.publicKey.algorithm + ", " + measurementValue.ocmfDocument.publicKey.encoding + ")";
13785
+ if (measurementValue.ocmfDocument.publicKey != null) {
13786
+ if (PublicKeyDiv.parentElement) {
13787
+ 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 + ")";
13748
13788
  }
13749
13789
  PublicKeyDiv.innerHTML = typeof measurementValue.ocmfDocument.publicKey === "string" ? measurementValue.ocmfDocument.publicKey : "der: " + (measurementValue.ocmfDocument.publicKey.value?.match(/.{1,8}/g)?.join(" ") ?? "-") + "<br /><br />x:&nbsp;&nbsp; " + (measurementValue.ocmfDocument.publicKey.x.match(/.{1,8}/g)?.join(" ") ?? "-") + "<br />y:&nbsp;&nbsp; " + (measurementValue.ocmfDocument.publicKey.y.match(/.{1,8}/g)?.join(" ") ?? "-");
13750
13790
  }
13751
- if (PublicKeyDiv.parentElement && PublicKeyDiv.parentElement.children[3]) {
13752
- PublicKeyDiv.parentElement.children[3].innerHTML = "";
13791
+ const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
13792
+ if (publicKeySignatureContainer !== void 0) {
13793
+ publicKeySignatureContainer.innerHTML = "";
13753
13794
  const result = measurementValue.result;
13754
13795
  if (result.publicKeySignatures) {
13755
13796
  for (const signature of result.publicKeySignatures) {
13756
13797
  try {
13757
- const signatureDiv = PublicKeyDiv.parentElement.children[3].appendChild(document.createElement("div"));
13798
+ const signatureDiv = publicKeySignatureContainer.appendChild(document.createElement("div"));
13758
13799
  signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
13759
13800
  measurementValue.measurement.chargingSession.chargingStation,
13760
13801
  measurementValue.measurement.chargingSession.EVSE,
13761
- measurementValue.measurement.chargingSession.EVSE?.meters[0],
13762
- measurementValue.measurement.chargingSession.EVSE?.meters[0]?.publicKeys?.[0],
13802
+ measurementValue.measurement.chargingSession.EVSE?.meters.at(0),
13803
+ measurementValue.measurement.chargingSession.EVSE?.meters.at(0)?.publicKeys?.at(0),
13763
13804
  signature
13764
13805
  );
13765
13806
  } catch {
@@ -13769,8 +13810,8 @@ var OCMFv1_x = class extends ACrypt {
13769
13810
  }
13770
13811
  }
13771
13812
  if (measurementValue.ocmfDocument.signature.SD) {
13772
- if (SignatureExpectedDiv.parentElement && SignatureExpectedDiv.parentElement.children[0]) {
13773
- SignatureExpectedDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Expected signature") + " (rs, hex)";
13813
+ if (SignatureExpectedDiv.parentElement) {
13814
+ getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = this.chargy.GetLocalizedMessage("Expected signature") + " (rs, hex)";
13774
13815
  }
13775
13816
  SignatureExpectedDiv.innerHTML = "der: " + (measurementValue.ocmfDocument.signature.SD.match(/.{1,8}/g)?.join(" ") ?? "-") + "<br /><br />r:&nbsp;&nbsp; " + (measurementValue.ocmfDocument.signatureRS?.r?.toLowerCase().padStart(56, "0").match(/.{1,8}/g)?.join(" ") ?? "-") + "<br />s:&nbsp;&nbsp; " + (measurementValue.ocmfDocument.signatureRS?.s?.toLowerCase().padStart(56, "0").match(/.{1,8}/g)?.join(" ") ?? "-");
13776
13817
  }
@@ -13793,6 +13834,7 @@ var OCMFv1_x = class extends ACrypt {
13793
13834
  break;
13794
13835
  }
13795
13836
  }
13837
+ return void 0;
13796
13838
  }
13797
13839
  };
13798
13840
  var OCMFTransactionTypes = /* @__PURE__ */ ((OCMFTransactionTypes2) => {
@@ -13825,268 +13867,270 @@ var OCMF = class {
13825
13867
  const evseId = asString(containerInfos["EVSEId"]) ?? asString(evseInfo?.["@id"]) ?? "DE*GEF*EVSE*CHARGY*1";
13826
13868
  const stationDescription = asJSONObject(chargingStationInfo?.["description"]);
13827
13869
  const evseDescription = asJSONObject(evseInfo?.["description"]);
13828
- const firstOCMDJSONDocument = OCMFJSONDocuments[0];
13829
- if (firstOCMDJSONDocument != void 0) {
13830
- const formatVersion = firstOCMDJSONDocument.payload.FV;
13831
- const gatewayInformation = firstOCMDJSONDocument.payload.GI ?? firstOCMDJSONDocument.payload.VI;
13832
- const gatewaySerial = firstOCMDJSONDocument.payload.GS;
13833
- const gatewayVersion = firstOCMDJSONDocument.payload.GV ?? firstOCMDJSONDocument.payload.VV;
13834
- const paging = firstOCMDJSONDocument.payload.PG;
13835
- const meterVendor = firstOCMDJSONDocument.payload.MV;
13836
- const meterModel = firstOCMDJSONDocument.payload.MM;
13837
- const meterSerial = firstOCMDJSONDocument.payload.MS;
13838
- const effectiveMeterSerial = meterSerial ?? gatewaySerial;
13839
- const meterFirmware = firstOCMDJSONDocument.payload.MF;
13840
- const identificationStatus = firstOCMDJSONDocument.payload.IS;
13841
- const identificationLevel = firstOCMDJSONDocument.payload.IL;
13842
- const identificationFlags = firstOCMDJSONDocument.payload.IF;
13843
- const identificationType = firstOCMDJSONDocument.payload.IT;
13844
- const identificationData = firstOCMDJSONDocument.payload.ID;
13845
- const tariffText = firstOCMDJSONDocument.payload.TT;
13846
- const controlerFirmwareVersion = firstOCMDJSONDocument.payload.CF;
13847
- const lossCompensation = firstOCMDJSONDocument.payload.LC;
13848
- const chargePointIdType = firstOCMDJSONDocument.payload.CT;
13849
- const chargePointId = firstOCMDJSONDocument.payload.CI;
13850
- 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,
13851
- // Charge Point and Public Key" section makes the serial-number fields conditionally
13852
- // mandatory. KEBA KCP30 records identify the signing gateway via GS and omit MS.
13853
- // Therefore we keep meterSerial and gatewaySerial separate, but require at least one
13854
- // usable serial number for the CTR meter identity.
13855
- isMandatoryString(effectiveMeterSerial) && isOptionalString(meterFirmware) && // OCMF 1.x uses boolean IS values. OCMF 0.1 SAFE reference data used status strings
13856
- // such as "VERIFIED", so accept both forms and preserve the original value in the CTR.
13857
- (isMandatoryBoolean(identificationStatus) || isMandatoryString(identificationStatus)) && isOptionalString(identificationLevel) && //chargyLib.isMandatoryArrayOfStrings (identificationFlags) &&
13858
- isOptionalArrayOfStrings(identificationFlags) && // Note: Some vendors do not use this MANDATORY field!
13859
- // IT is 1..1 in the user-assignment table for transaction records. Some OCMF 1.0
13860
- // implementations omit it when no user is assigned (IS=false, ID empty). We tolerate
13861
- // this vendor compatibility case instead of rejecting otherwise valid signatures.
13862
- isOptionalString(identificationType) && isOptionalString(identificationData) && isOptionalString(tariffText) && isOptionalString(controlerFirmwareVersion) && isOptionalJSONObject(lossCompensation) && isOptionalString(chargePointIdType) && isOptionalString(chargePointId)) {
13863
- const paginationPrefix = paging.length > 0 ? paging[0]?.toLowerCase() : null;
13864
- const transactionType = paginationPrefix === "t" ? "transaction" /* transaction */ : paginationPrefix === "f" ? "fiscal" /* fiscal */ : "undefined" /* undefined */;
13865
- const pagination = paging.length > 1 ? parseNumber(paging.substring(1)) : null;
13866
- if (transactionType === "undefined" /* undefined */) return {
13867
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
13868
- message: this.chargy.GetMultilanguageText("The given OCMF data does not have a valid transaction type!"),
13869
- certainty: 0
13870
- };
13871
- if (!isMandatoryNumber(pagination)) return {
13872
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
13873
- message: this.chargy.GetMultilanguageText("The given OCMF data does not have a valid pagination counter!"),
13874
- certainty: 0
13875
- };
13876
- if (firstOCMDJSONDocument.payload.RD.length == 0) return {
13877
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
13878
- message: this.chargy.GetMultilanguageText("Each OCMF data set must have at least one meter reading!"),
13879
- certainty: 0
13880
- };
13881
- const CTR = {
13882
- "@id": "?",
13883
- "@context": "https://open.charging.cloud/contexts/CTR+json",
13884
- //"@context": [ "https://open.charging.cloud/contexts/CTR+json", "https://open.charging.cloud/contexts/CTR_OCMF+json" ],
13870
+ const firstOCMDJSONDocument = getFirstArrayElement(OCMFJSONDocuments, "Missing first OCMF JSON document");
13871
+ const formatVersion = firstOCMDJSONDocument.payload.FV;
13872
+ const gatewayInformation = firstOCMDJSONDocument.payload.GI ?? firstOCMDJSONDocument.payload.VI;
13873
+ const gatewaySerial = firstOCMDJSONDocument.payload.GS;
13874
+ const gatewayVersion = firstOCMDJSONDocument.payload.GV ?? firstOCMDJSONDocument.payload.VV;
13875
+ const paging = firstOCMDJSONDocument.payload.PG;
13876
+ const meterVendor = firstOCMDJSONDocument.payload.MV;
13877
+ const meterModel = firstOCMDJSONDocument.payload.MM;
13878
+ const meterSerial = firstOCMDJSONDocument.payload.MS;
13879
+ const effectiveMeterSerial = meterSerial ?? gatewaySerial;
13880
+ const meterFirmware = firstOCMDJSONDocument.payload.MF;
13881
+ const identificationStatus = firstOCMDJSONDocument.payload.IS;
13882
+ const identificationLevel = firstOCMDJSONDocument.payload.IL;
13883
+ const identificationFlags = firstOCMDJSONDocument.payload.IF;
13884
+ const identificationType = firstOCMDJSONDocument.payload.IT;
13885
+ const identificationData = firstOCMDJSONDocument.payload.ID;
13886
+ const tariffText = firstOCMDJSONDocument.payload.TT;
13887
+ const controlerFirmwareVersion = firstOCMDJSONDocument.payload.CF;
13888
+ const lossCompensation = firstOCMDJSONDocument.payload.LC;
13889
+ const chargePointIdType = firstOCMDJSONDocument.payload.CT;
13890
+ const chargePointId = firstOCMDJSONDocument.payload.CI;
13891
+ 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,
13892
+ // Charge Point and Public Key" section makes the serial-number fields conditionally
13893
+ // mandatory. KEBA KCP30 records identify the signing gateway via GS and omit MS.
13894
+ // Therefore we keep meterSerial and gatewaySerial separate, but require at least one
13895
+ // usable serial number for the CTR meter identity.
13896
+ isMandatoryString(effectiveMeterSerial) && isOptionalString(meterFirmware) && // OCMF 1.x uses boolean IS values. OCMF 0.1 SAFE reference data used status strings
13897
+ // such as "VERIFIED", so accept both forms and preserve the original value in the CTR.
13898
+ (isMandatoryBoolean(identificationStatus) || isMandatoryString(identificationStatus)) && isOptionalString(identificationLevel) && //chargyLib.isMandatoryArrayOfStrings (identificationFlags) &&
13899
+ isOptionalArrayOfStrings(identificationFlags) && // Note: Some vendors do not use this MANDATORY field!
13900
+ // IT is 1..1 in the user-assignment table for transaction records. Some OCMF 1.0
13901
+ // implementations omit it when no user is assigned (IS=false, ID empty). We tolerate
13902
+ // this vendor compatibility case instead of rejecting otherwise valid signatures.
13903
+ isOptionalString(identificationType) && isOptionalString(identificationData) && isOptionalString(tariffText) && isOptionalString(controlerFirmwareVersion) && isOptionalJSONObject(lossCompensation) && isOptionalString(chargePointIdType) && isOptionalString(chargePointId)) {
13904
+ const paginationPrefix = paging.length > 0 ? paging.charAt(0).toLowerCase() : null;
13905
+ const transactionType = paginationPrefix === "t" ? "transaction" /* transaction */ : paginationPrefix === "f" ? "fiscal" /* fiscal */ : "undefined" /* undefined */;
13906
+ const pagination = paging.length > 1 ? parseNumber(paging.substring(1)) : null;
13907
+ if (transactionType === "undefined" /* undefined */) return {
13908
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
13909
+ message: this.chargy.GetMultilanguageText("The given OCMF data does not have a valid transaction type!"),
13910
+ certainty: 0
13911
+ };
13912
+ if (!isMandatoryNumber(pagination)) return {
13913
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
13914
+ message: this.chargy.GetMultilanguageText("The given OCMF data does not have a valid pagination counter!"),
13915
+ certainty: 0
13916
+ };
13917
+ if (firstOCMDJSONDocument.payload.RD.length == 0) return {
13918
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
13919
+ message: this.chargy.GetMultilanguageText("Each OCMF data set must have at least one meter reading!"),
13920
+ certainty: 0
13921
+ };
13922
+ const CTR = {
13923
+ "@id": "?",
13924
+ "@context": "https://open.charging.cloud/contexts/CTR+json",
13925
+ //"@context": [ "https://open.charging.cloud/contexts/CTR+json", "https://open.charging.cloud/contexts/CTR_OCMF+json" ],
13926
+ "begin": "?",
13927
+ "end": "?",
13928
+ "description": {
13929
+ "de": "Alle OCMF-Ladevorg\xE4nge"
13930
+ },
13931
+ "contract": {
13932
+ "@id": identificationData ?? "?",
13933
+ "type": identificationType ?? "?"
13934
+ },
13935
+ "ocmf": {
13936
+ "formatVersion": formatVersion,
13937
+ "gatewayInformation": gatewayInformation,
13938
+ "gatewaySerial": gatewaySerial,
13939
+ "gatewayVersion": gatewayVersion
13940
+ },
13941
+ // "chargingStationOperators": [{
13942
+ "chargingPools": [{
13943
+ "@id": "DE*GEF*POOL*CHARGY*1",
13944
+ "description": { "en": "GraphDefined CHARGY Virtual Charging Pool 1" },
13945
+ "chargingStations": [{
13946
+ "@id": chargingStationId,
13947
+ "description": stationDescription && Object.keys(stationDescription).length > 0 ? stationDescription : { "en": "GraphDefined CHARGY Virtual Charging Station 1" },
13948
+ "firmwareVersion": asString(chargingStationInfo?.["softwareVersion"]) ?? asString(chargingStationInfo?.["firmwareVersion"]),
13949
+ "geoLocation": asJSONObject(chargingStationInfo?.["geoLocation"]),
13950
+ "address": asJSONObject(chargingStationInfo?.["address"]),
13951
+ "EVSEs": [{
13952
+ "@id": evseId,
13953
+ "description": evseDescription && Object.keys(evseDescription).length > 0 ? evseDescription : { "en": "GraphDefined CHARGY Virtual EVSE 1" },
13954
+ "connectors": connectorInfo ? [{
13955
+ "type": asString(connectorInfo["type"]) ?? "",
13956
+ "looses": asNumber(connectorInfo["looses"]) ?? 0
13957
+ }] : void 0,
13958
+ "meters": [{
13959
+ "@id": effectiveMeterSerial,
13960
+ // The signed OCMF payload values always win,
13961
+ // the container infos only fill the gaps!
13962
+ "manufacturer": meterVendor ?? asString(energyMeterInfo?.["manufacturer"]),
13963
+ "manufacturerURL": asString(energyMeterInfo?.["manufacturerURL"]),
13964
+ "model": meterModel ?? asString(energyMeterInfo?.["model"]),
13965
+ "modelURL": asString(energyMeterInfo?.["modelURL"]),
13966
+ "hardwareVersion": asString(energyMeterInfo?.["hardwareVersion"]),
13967
+ "firmwareVersion": meterFirmware ?? asString(energyMeterInfo?.["firmwareVersion"]),
13968
+ "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json",
13969
+ "publicKeys": [{
13970
+ "algorithm": "?",
13971
+ "encoding": "?",
13972
+ "format": "?",
13973
+ "value": "?"
13974
+ }]
13975
+ }]
13976
+ }]
13977
+ }]
13978
+ }],
13979
+ "chargingSessions": [{
13980
+ "@id": "1554181214441:-1965658344385548683:2",
13981
+ "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/OCMFv1.0+json",
13885
13982
  "begin": "?",
13886
13983
  "end": "?",
13887
- "description": {
13888
- "de": "Alle OCMF-Ladevorg\xE4nge"
13889
- },
13890
- "contract": {
13984
+ "EVSEId": evseId,
13985
+ "authorizationStart": {
13891
13986
  "@id": identificationData ?? "?",
13892
- "type": identificationType ?? "?"
13893
- },
13894
- "ocmf": {
13895
- "formatVersion": formatVersion,
13896
- "gatewayInformation": gatewayInformation,
13897
- "gatewaySerial": gatewaySerial,
13898
- "gatewayVersion": gatewayVersion
13987
+ "type": identificationType ?? "?",
13988
+ "identificationStatus": identificationStatus,
13989
+ "identificationLevel": identificationLevel,
13990
+ "identificationFlags": identificationFlags ?? []
13991
+ // Note: The OCMF documentation expects an empty array!
13899
13992
  },
13900
- // "chargingStationOperators": [{
13901
- "chargingPools": [{
13902
- "@id": "DE*GEF*POOL*CHARGY*1",
13903
- "description": { "en": "GraphDefined CHARGY Virtual Charging Pool 1" },
13904
- "chargingStations": [{
13905
- "@id": chargingStationId,
13906
- "description": stationDescription && Object.keys(stationDescription).length > 0 ? stationDescription : { "en": "GraphDefined CHARGY Virtual Charging Station 1" },
13907
- "firmwareVersion": asString(chargingStationInfo?.["softwareVersion"]) ?? asString(chargingStationInfo?.["firmwareVersion"]),
13908
- "geoLocation": asJSONObject(chargingStationInfo?.["geoLocation"]),
13909
- "address": asJSONObject(chargingStationInfo?.["address"]),
13910
- "EVSEs": [{
13911
- "@id": evseId,
13912
- "description": evseDescription && Object.keys(evseDescription).length > 0 ? evseDescription : { "en": "GraphDefined CHARGY Virtual EVSE 1" },
13913
- "connectors": connectorInfo ? [{
13914
- "type": asString(connectorInfo["type"]) ?? "",
13915
- "looses": asNumber(connectorInfo["looses"]) ?? 0
13916
- }] : void 0,
13917
- "meters": [{
13918
- "@id": effectiveMeterSerial,
13919
- // The signed OCMF payload values always win,
13920
- // the container infos only fill the gaps!
13921
- "manufacturer": meterVendor ?? asString(energyMeterInfo?.["manufacturer"]),
13922
- "manufacturerURL": asString(energyMeterInfo?.["manufacturerURL"]),
13923
- "model": meterModel ?? asString(energyMeterInfo?.["model"]),
13924
- "modelURL": asString(energyMeterInfo?.["modelURL"]),
13925
- "hardwareVersion": asString(energyMeterInfo?.["hardwareVersion"]),
13926
- "firmwareVersion": meterFirmware ?? asString(energyMeterInfo?.["firmwareVersion"]),
13927
- "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json",
13928
- "publicKeys": [{
13929
- "algorithm": "?",
13930
- "encoding": "?",
13931
- "format": "?",
13932
- "value": "?"
13933
- }]
13934
- }]
13935
- }]
13936
- }]
13937
- }],
13938
- "chargingSessions": [{
13939
- "@id": "1554181214441:-1965658344385548683:2",
13940
- "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/OCMFv1.0+json",
13941
- "begin": "?",
13942
- "end": "?",
13943
- "EVSEId": evseId,
13944
- "authorizationStart": {
13945
- "@id": identificationData ?? "?",
13946
- "type": identificationType ?? "?",
13947
- "identificationStatus": identificationStatus,
13948
- "identificationLevel": identificationLevel,
13949
- "identificationFlags": identificationFlags ?? []
13950
- // Note: The OCMF documentation expects an empty array!
13951
- },
13952
- "measurements": []
13953
- }],
13954
- "certainty": 1
13955
- };
13956
- const measurementsByKey = /* @__PURE__ */ new Map();
13957
- for (const ocmfJSONDocument of OCMFJSONDocuments) {
13958
- let inheritedReading = {};
13959
- for (const reading of ocmfJSONDocument.payload.RD) {
13960
- const effectiveReading = { ...inheritedReading, ...reading };
13961
- const time = effectiveReading.TM;
13962
- const transaction = effectiveReading.TX;
13963
- const readingValue = effectiveReading.RV;
13964
- const readingIdentification = effectiveReading.RI;
13965
- const readingUnit = effectiveReading.RU;
13966
- const readingCurrentType = effectiveReading.RT;
13967
- const cumulatedLoss = effectiveReading.CL;
13968
- const errorFlags = effectiveReading.EF;
13969
- const status = effectiveReading.ST;
13970
- inheritedReading = effectiveReading;
13971
- if (isMandatoryString(time) && isOptionalString(transaction) && isMandatoryDecimal(readingValue) && // Note: Some vendors use a JSON string here!
13972
- isOptionalString(readingIdentification) && isMandatoryString(readingUnit) && isOptionalString(readingCurrentType) && isOptionalDecimal(cumulatedLoss) && isOptionalString(errorFlags) && isMandatoryString(status)) {
13973
- const timeSplit = time.split(" ");
13974
- if (timeSplit.length != 2) return {
13975
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
13976
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time format!"),
13977
- certainty: 0
13978
- };
13979
- const timeRegEx = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2},\d{3}[+-]\d{4}$/;
13980
- const timeStamp = timeSplit[0];
13981
- if (!isMandatoryString(timeStamp) || !timeRegEx.test(timeStamp)) return {
13982
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
13983
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
13984
- certainty: 0
13985
- };
13986
- const timeStampISO8601 = this.convertToISO8601(timeStamp);
13987
- const timeSyncText = timeSplit[1];
13988
- let timeSync = "unknown" /* unknown */;
13989
- if (!isMandatoryString(timeSyncText) || !["U", "I", "S", "R"].includes(timeSyncText)) return {
13990
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
13991
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
13992
- certainty: 0
13993
- };
13994
- switch (timeSyncText) {
13995
- case "U":
13996
- timeSync = "unknown" /* unknown */;
13997
- break;
13998
- case "I":
13999
- timeSync = "informative" /* informative */;
14000
- break;
14001
- case "S":
14002
- timeSync = "syncronized" /* syncronized */;
14003
- break;
14004
- case "R":
14005
- timeSync = "relative" /* relative */;
14006
- break;
14007
- default:
14008
- return {
14009
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
14010
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
14011
- certainty: 0
14012
- };
14013
- }
14014
- if (transaction && !["B", "C", "X", "E", "L", "R", "A", "P", "S", "T"].includes(transaction)) return {
14015
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
14016
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid transaction type!"),
14017
- certainty: 0
14018
- };
14019
- if (!["kWh", "Wh", "mOhm", "uOhm"].includes(readingUnit)) return {
14020
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
14021
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid current type!"),
14022
- certainty: 0
14023
- };
14024
- if (readingCurrentType && !["AC", "DC"].includes(readingCurrentType)) return {
14025
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
14026
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid current type!"),
14027
- certainty: 0
14028
- };
14029
- if (CTR.chargingSessions?.[0]?.begin === "?")
14030
- CTR.chargingSessions[0].begin = timeStampISO8601;
14031
- CTR.chargingSessions[0].end = timeStampISO8601;
14032
- const measurementKey = [
14033
- readingIdentification ?? "?",
14034
- readingUnit,
14035
- readingCurrentType ?? ""
14036
- ].join("|");
14037
- let measurement = measurementsByKey.get(measurementKey);
14038
- if (measurement == null) {
14039
- measurement = {
14040
- "name": OBIS2MeasurementName(readingIdentification ?? ""),
14041
- "scale": 0,
14042
- "energyMeterId": effectiveMeterSerial,
14043
- "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json",
14044
- "obis": readingIdentification ?? "?",
14045
- // OBIS: "1-b:1.8.0"
14046
- "unit": readingUnit,
14047
- // "kWh"
14048
- "currentType": readingCurrentType,
14049
- // "AC"
14050
- "values": []
13993
+ "measurements": []
13994
+ }],
13995
+ "certainty": 1
13996
+ };
13997
+ const measurementsByKey = /* @__PURE__ */ new Map();
13998
+ for (const ocmfJSONDocument of OCMFJSONDocuments) {
13999
+ let inheritedReading = {};
14000
+ for (const reading of ocmfJSONDocument.payload.RD) {
14001
+ const effectiveReading = { ...inheritedReading, ...reading };
14002
+ const time = effectiveReading.TM;
14003
+ const transaction = effectiveReading.TX;
14004
+ const readingValue = effectiveReading.RV;
14005
+ const readingIdentification = effectiveReading.RI;
14006
+ const readingUnit = effectiveReading.RU;
14007
+ const readingCurrentType = effectiveReading.RT;
14008
+ const cumulatedLoss = effectiveReading.CL;
14009
+ const errorFlags = effectiveReading.EF;
14010
+ const status = effectiveReading.ST;
14011
+ inheritedReading = effectiveReading;
14012
+ if (isMandatoryString(time) && isOptionalString(transaction) && isMandatoryDecimal(readingValue) && // Note: Some vendors use a JSON string here!
14013
+ isOptionalString(readingIdentification) && isMandatoryString(readingUnit) && isOptionalString(readingCurrentType) && // chargyLib.isOptionalDecimal (cumulatedLoss) &&
14014
+ isOptionalString(errorFlags) && isMandatoryString(status)) {
14015
+ const timeSplit = time.split(" ");
14016
+ if (timeSplit.length != 2) return {
14017
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
14018
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time format!"),
14019
+ certainty: 0
14020
+ };
14021
+ const timeRegEx = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2},\d{3}[+-]\d{4}$/;
14022
+ const timeStamp = timeSplit[0];
14023
+ if (!isMandatoryString(timeStamp) || !timeRegEx.test(timeStamp)) return {
14024
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
14025
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
14026
+ certainty: 0
14027
+ };
14028
+ const timeStampISO8601 = this.convertToISO8601(timeStamp);
14029
+ const timeSyncText = timeSplit[1];
14030
+ let timeSync = "unknown" /* unknown */;
14031
+ if (!isMandatoryString(timeSyncText) || !["U", "I", "S", "R"].includes(timeSyncText)) return {
14032
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
14033
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
14034
+ certainty: 0
14035
+ };
14036
+ switch (timeSyncText) {
14037
+ case "U":
14038
+ timeSync = "unknown" /* unknown */;
14039
+ break;
14040
+ case "I":
14041
+ timeSync = "informative" /* informative */;
14042
+ break;
14043
+ case "S":
14044
+ timeSync = "syncronized" /* syncronized */;
14045
+ break;
14046
+ case "R":
14047
+ timeSync = "relative" /* relative */;
14048
+ break;
14049
+ default:
14050
+ return {
14051
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
14052
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
14053
+ certainty: 0
14051
14054
  };
14052
- measurementsByKey.set(measurementKey, measurement);
14053
- CTR.chargingSessions[0].measurements.push(measurement);
14054
- }
14055
- measurement.values.push({
14056
- "timestamp": timeStampISO8601,
14057
- // "2019-06-26T08:57:44,337+0000"
14058
- "timeSync": timeSync,
14059
- // "U"|"I"|"S"|"R"
14060
- "transaction": transaction,
14061
- // "B"|"C"|"X"|"E"|"L"|"R"|"A"|"P"|"S"|"T"|null
14062
- "value": new Decimal(readingValue),
14063
- // 2935.6
14064
- "transactionType": transactionType,
14065
- // "T" ToDo: Serialize this to a string!
14066
- "pagination": pagination,
14067
- // "9289"
14068
- "errorFlags": errorFlags,
14069
- // ""
14070
- "cumulatedLoss": cumulatedLoss ? new Decimal(cumulatedLoss) : void 0,
14071
- "status": status,
14072
- // "G"
14073
- // "signatures": [{
14074
- // "value": ocmfJSONDocument.signature["SD"]
14075
- // }],
14076
- "result": {
14077
- "status": ocmfJSONDocument.validationStatus ?? "Unvalidated" /* Unvalidated */
14078
- },
14079
- "ocmfDocument": ocmfJSONDocument
14080
- });
14081
14055
  }
14056
+ if (transaction != null && transaction.length > 0 && !["B", "C", "X", "E", "L", "R", "A", "P", "S", "T"].includes(transaction)) return {
14057
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
14058
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid transaction type!"),
14059
+ certainty: 0
14060
+ };
14061
+ if (!["kWh", "Wh", "mOhm", "uOhm"].includes(readingUnit)) return {
14062
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
14063
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid current type!"),
14064
+ certainty: 0
14065
+ };
14066
+ if (readingCurrentType != null && readingCurrentType.length > 0 && !["AC", "DC"].includes(readingCurrentType)) return {
14067
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
14068
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid current type!"),
14069
+ certainty: 0
14070
+ };
14071
+ if (CTR.chargingSessions?.[0]?.begin === "?")
14072
+ CTR.chargingSessions[0].begin = timeStampISO8601;
14073
+ if (CTR.chargingSessions?.[0] !== void 0)
14074
+ CTR.chargingSessions[0].end = timeStampISO8601;
14075
+ const measurementKey = [
14076
+ readingIdentification ?? "?",
14077
+ readingUnit,
14078
+ readingCurrentType ?? ""
14079
+ ].join("|");
14080
+ let measurement = measurementsByKey.get(measurementKey);
14081
+ if (measurement == null) {
14082
+ measurement = {
14083
+ "name": OBIS2MeasurementName(readingIdentification ?? ""),
14084
+ "scale": 0,
14085
+ "energyMeterId": effectiveMeterSerial,
14086
+ "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json",
14087
+ "obis": readingIdentification ?? "?",
14088
+ // OBIS: "1-b:1.8.0"
14089
+ "unit": readingUnit,
14090
+ // "kWh"
14091
+ "currentType": readingCurrentType,
14092
+ // "AC"
14093
+ "values": []
14094
+ };
14095
+ measurementsByKey.set(measurementKey, measurement);
14096
+ const firstChargingSession = CTR.chargingSessions?.[0];
14097
+ if (firstChargingSession !== void 0)
14098
+ firstChargingSession.measurements.push(measurement);
14099
+ }
14100
+ measurement.values.push({
14101
+ "timestamp": timeStampISO8601,
14102
+ // "2019-06-26T08:57:44,337+0000"
14103
+ "timeSync": timeSync,
14104
+ // "U"|"I"|"S"|"R"
14105
+ "transaction": transaction,
14106
+ // "B"|"C"|"X"|"E"|"L"|"R"|"A"|"P"|"S"|"T"|null
14107
+ "value": new Decimal(readingValue),
14108
+ // 2935.6
14109
+ "transactionType": transactionType,
14110
+ // "T" ToDo: Serialize this to a string!
14111
+ "pagination": pagination,
14112
+ // "9289"
14113
+ "errorFlags": errorFlags,
14114
+ // ""
14115
+ "cumulatedLoss": cumulatedLoss != null && cumulatedLoss !== 0 ? new Decimal(cumulatedLoss) : void 0,
14116
+ "status": status,
14117
+ // "G"
14118
+ // "signatures": [{
14119
+ // "value": ocmfJSONDocument.signature["SD"]
14120
+ // }],
14121
+ "result": {
14122
+ "status": ocmfJSONDocument.validationStatus ?? "Unvalidated" /* Unvalidated */
14123
+ },
14124
+ "ocmfDocument": ocmfJSONDocument
14125
+ });
14082
14126
  }
14083
14127
  }
14084
- CTR.status = OCMFJSONDocuments.every((ocmfJSONDocument) => ocmfJSONDocument.validationStatus === "ValidSignature" /* ValidSignature */) ? "ValidSignature" /* ValidSignature */ : "InvalidSignature" /* InvalidSignature */;
14085
- if (CTR.chargingSessions != null && CTR.chargingSessions.length > 0 && CTR.chargingSessions[0] != null) {
14086
- CTR.begin = CTR.chargingSessions[0].begin;
14087
- CTR.end = CTR.chargingSessions[0].end;
14088
- return CTR;
14089
- }
14128
+ }
14129
+ CTR.status = OCMFJSONDocuments.every((ocmfJSONDocument) => ocmfJSONDocument.validationStatus === "ValidSignature" /* ValidSignature */) ? "ValidSignature" /* ValidSignature */ : "InvalidSignature" /* InvalidSignature */;
14130
+ if (CTR.chargingSessions != null && CTR.chargingSessions.length > 0 && CTR.chargingSessions[0]) {
14131
+ CTR.begin = CTR.chargingSessions[0].begin;
14132
+ CTR.end = CTR.chargingSessions[0].end;
14133
+ return CTR;
14090
14134
  }
14091
14135
  }
14092
14136
  } catch (exception) {
@@ -14103,113 +14147,121 @@ var OCMF = class {
14103
14147
  }
14104
14148
  //#endregion
14105
14149
  //#region (private) mergeOCMFSessions(CTRs)
14106
- mergeOCMFSessions(CTRs) {
14107
- const mergedCTR = {
14108
- "@id": "",
14109
- "@context": "",
14110
- certainty: 1
14111
- };
14112
- for (const ctr of CTRs) {
14113
- if (mergedCTR["@id"] === "")
14114
- mergedCTR["@id"] = ctr["@id"];
14115
- if (mergedCTR["@context"] === "")
14116
- mergedCTR["@context"] = ctr["@context"];
14117
- if (!mergedCTR.begin || mergedCTR.begin && ctr.begin && mergedCTR.begin > ctr.begin)
14118
- mergedCTR.begin = ctr.begin;
14119
- if (!mergedCTR.end || mergedCTR.end && ctr.end && mergedCTR.end < ctr.end)
14120
- mergedCTR.end = ctr.end;
14121
- if (!mergedCTR.description)
14122
- mergedCTR.description = ctr.description;
14123
- if (!mergedCTR.contract)
14124
- mergedCTR.contract = ctr.contract;
14125
- if (!mergedCTR.chargingStationOperators)
14126
- mergedCTR.chargingStationOperators = ctr.chargingStationOperators;
14127
- else if (ctr.chargingStationOperators)
14128
- for (const chargingStationOperator of ctr.chargingStationOperators)
14129
- mergedCTR.chargingStationOperators.push(chargingStationOperator);
14130
- if (!mergedCTR.chargingPools)
14131
- mergedCTR.chargingPools = ctr.chargingPools;
14132
- else if (ctr.chargingPools)
14133
- for (const chargingPool of ctr.chargingPools)
14134
- mergedCTR.chargingPools.push(chargingPool);
14135
- if (!mergedCTR.chargingStations)
14136
- mergedCTR.chargingStations = ctr.chargingStations;
14137
- else if (ctr.chargingStations)
14138
- for (const chargingStation of ctr.chargingStations)
14139
- mergedCTR.chargingStations.push(chargingStation);
14140
- if (!mergedCTR.chargingSessions)
14141
- mergedCTR.chargingSessions = ctr.chargingSessions;
14142
- else if (ctr.chargingSessions)
14143
- for (const chargingSession of ctr.chargingSessions)
14144
- mergedCTR.chargingSessions.push(chargingSession);
14145
- if (!mergedCTR.eMobilityProviders)
14146
- mergedCTR.eMobilityProviders = ctr.eMobilityProviders;
14147
- else if (ctr.eMobilityProviders)
14148
- for (const eMobilityProvider of ctr.eMobilityProviders)
14149
- mergedCTR.eMobilityProviders.push(eMobilityProvider);
14150
- if (!mergedCTR.mediationServices)
14151
- mergedCTR.mediationServices = ctr.mediationServices;
14152
- else if (ctr.mediationServices)
14153
- for (const mediationService of ctr.mediationServices)
14154
- mergedCTR.mediationServices.push(mediationService);
14155
- }
14156
- return mergedCTR;
14157
- }
14150
+ // private mergeOCMFSessions(CTRs: Array<IOCMFChargeTransparencyRecord>): IOCMFChargeTransparencyRecord
14151
+ // {
14152
+ // const mergedCTR:IOCMFChargeTransparencyRecord = {
14153
+ // "@id": "",
14154
+ // "@context": "",
14155
+ // certainty: 1
14156
+ // };
14157
+ // for (const ctr of CTRs)
14158
+ // {
14159
+ // if (mergedCTR["@id"] === "")
14160
+ // mergedCTR["@id"] = ctr["@id"];
14161
+ // if (mergedCTR["@context"] === "")
14162
+ // mergedCTR["@context"] = ctr["@context"];
14163
+ // if (!mergedCTR.begin || (mergedCTR.begin && ctr.begin && mergedCTR.begin > ctr.begin))
14164
+ // mergedCTR.begin = ctr.begin;
14165
+ // if (!mergedCTR.end || (mergedCTR.end && ctr.end && mergedCTR.end < ctr.end))
14166
+ // mergedCTR.end = ctr.end;
14167
+ // if (!mergedCTR.description)
14168
+ // mergedCTR.description = ctr.description;
14169
+ // //ToDo: Is this a really good idea? Or should we fail, whenever this information is different?
14170
+ // if (!mergedCTR.contract)
14171
+ // mergedCTR.contract = ctr.contract;
14172
+ // if (!mergedCTR.chargingStationOperators)
14173
+ // mergedCTR.chargingStationOperators = ctr.chargingStationOperators;
14174
+ // else if (ctr.chargingStationOperators)
14175
+ // for (const chargingStationOperator of ctr.chargingStationOperators)
14176
+ // mergedCTR.chargingStationOperators.push(chargingStationOperator);
14177
+ // if (!mergedCTR.chargingPools)
14178
+ // mergedCTR.chargingPools = ctr.chargingPools;
14179
+ // else if (ctr.chargingPools)
14180
+ // for (const chargingPool of ctr.chargingPools)
14181
+ // mergedCTR.chargingPools.push(chargingPool);
14182
+ // if (!mergedCTR.chargingStations)
14183
+ // mergedCTR.chargingStations = ctr.chargingStations;
14184
+ // else if (ctr.chargingStations)
14185
+ // for (const chargingStation of ctr.chargingStations)
14186
+ // mergedCTR.chargingStations.push(chargingStation);
14187
+ // // publicKeys
14188
+ // if (!mergedCTR.chargingSessions)
14189
+ // mergedCTR.chargingSessions = ctr.chargingSessions;
14190
+ // else if (ctr.chargingSessions)
14191
+ // for (const chargingSession of ctr.chargingSessions)
14192
+ // mergedCTR.chargingSessions.push(chargingSession);
14193
+ // if (!mergedCTR.eMobilityProviders)
14194
+ // mergedCTR.eMobilityProviders = ctr.eMobilityProviders;
14195
+ // else if (ctr.eMobilityProviders)
14196
+ // for (const eMobilityProvider of ctr.eMobilityProviders)
14197
+ // mergedCTR.eMobilityProviders.push(eMobilityProvider);
14198
+ // if (!mergedCTR.mediationServices)
14199
+ // mergedCTR.mediationServices = ctr.mediationServices;
14200
+ // else if (ctr.mediationServices)
14201
+ // for (const mediationService of ctr.mediationServices)
14202
+ // mergedCTR.mediationServices.push(mediationService);
14203
+ // }
14204
+ // return mergedCTR;
14205
+ // }
14158
14206
  //#endregion
14159
14207
  //#region (private) mergeChargeTransparencyRecords(CTRs)
14160
- mergeChargeTransparencyRecords(CTRs) {
14161
- const mergedCTR = {
14162
- "@id": "",
14163
- "@context": "",
14164
- certainty: 1
14165
- };
14166
- for (const ctr of CTRs) {
14167
- if (mergedCTR["@id"] === "")
14168
- mergedCTR["@id"] = ctr["@id"];
14169
- if (mergedCTR["@context"] === "")
14170
- mergedCTR["@context"] = ctr["@context"];
14171
- if (!mergedCTR.begin || mergedCTR.begin && ctr.begin && mergedCTR.begin > ctr.begin)
14172
- mergedCTR.begin = ctr.begin;
14173
- if (!mergedCTR.end || mergedCTR.end && ctr.end && mergedCTR.end < ctr.end)
14174
- mergedCTR.end = ctr.end;
14175
- if (!mergedCTR.description)
14176
- mergedCTR.description = ctr.description;
14177
- if (!mergedCTR.contract)
14178
- mergedCTR.contract = ctr.contract;
14179
- if (!mergedCTR.chargingStationOperators)
14180
- mergedCTR.chargingStationOperators = ctr.chargingStationOperators;
14181
- else if (ctr.chargingStationOperators)
14182
- for (const chargingStationOperator of ctr.chargingStationOperators)
14183
- mergedCTR.chargingStationOperators.push(chargingStationOperator);
14184
- if (!mergedCTR.chargingPools)
14185
- mergedCTR.chargingPools = ctr.chargingPools;
14186
- else if (ctr.chargingPools)
14187
- for (const chargingPool of ctr.chargingPools)
14188
- mergedCTR.chargingPools.push(chargingPool);
14189
- if (!mergedCTR.chargingStations)
14190
- mergedCTR.chargingStations = ctr.chargingStations;
14191
- else if (ctr.chargingStations)
14192
- for (const chargingStation of ctr.chargingStations)
14193
- mergedCTR.chargingStations.push(chargingStation);
14194
- if (!mergedCTR.chargingSessions)
14195
- mergedCTR.chargingSessions = ctr.chargingSessions;
14196
- else if (ctr.chargingSessions)
14197
- for (const chargingSession of ctr.chargingSessions)
14198
- mergedCTR.chargingSessions.push(chargingSession);
14199
- if (!mergedCTR.eMobilityProviders)
14200
- mergedCTR.eMobilityProviders = ctr.eMobilityProviders;
14201
- else if (ctr.eMobilityProviders)
14202
- for (const eMobilityProvider of ctr.eMobilityProviders)
14203
- mergedCTR.eMobilityProviders.push(eMobilityProvider);
14204
- if (!mergedCTR.mediationServices)
14205
- mergedCTR.mediationServices = ctr.mediationServices;
14206
- else if (ctr.mediationServices)
14207
- for (const mediationService of ctr.mediationServices)
14208
- mergedCTR.mediationServices.push(mediationService);
14209
- }
14210
- return mergedCTR;
14211
- }
14212
- //#endregion
14208
+ // private mergeChargeTransparencyRecords(CTRs: Array<IOCMFChargeTransparencyRecord>): IOCMFChargeTransparencyRecord
14209
+ // {
14210
+ // const mergedCTR:IOCMFChargeTransparencyRecord = {
14211
+ // "@id": "",
14212
+ // "@context": "",
14213
+ // certainty: 1
14214
+ // };
14215
+ // for (const ctr of CTRs)
14216
+ // {
14217
+ // if (mergedCTR["@id"] === "")
14218
+ // mergedCTR["@id"] = ctr["@id"];
14219
+ // if (mergedCTR["@context"] === "")
14220
+ // mergedCTR["@context"] = ctr["@context"];
14221
+ // if (!mergedCTR.begin || (mergedCTR.begin && ctr.begin && mergedCTR.begin > ctr.begin))
14222
+ // mergedCTR.begin = ctr.begin;
14223
+ // if (!mergedCTR.end || (mergedCTR.end && ctr.end && mergedCTR.end < ctr.end))
14224
+ // mergedCTR.end = ctr.end;
14225
+ // if (!mergedCTR.description)
14226
+ // mergedCTR.description = ctr.description;
14227
+ // //ToDo: Is this a really good idea? Or should we fail, whenever this information is different?
14228
+ // if (!mergedCTR.contract)
14229
+ // mergedCTR.contract = ctr.contract;
14230
+ // if (!mergedCTR.chargingStationOperators)
14231
+ // mergedCTR.chargingStationOperators = ctr.chargingStationOperators;
14232
+ // else if (ctr.chargingStationOperators)
14233
+ // for (const chargingStationOperator of ctr.chargingStationOperators)
14234
+ // mergedCTR.chargingStationOperators.push(chargingStationOperator);
14235
+ // if (!mergedCTR.chargingPools)
14236
+ // mergedCTR.chargingPools = ctr.chargingPools;
14237
+ // else if (ctr.chargingPools)
14238
+ // for (const chargingPool of ctr.chargingPools)
14239
+ // mergedCTR.chargingPools.push(chargingPool);
14240
+ // if (!mergedCTR.chargingStations)
14241
+ // mergedCTR.chargingStations = ctr.chargingStations;
14242
+ // else if (ctr.chargingStations)
14243
+ // for (const chargingStation of ctr.chargingStations)
14244
+ // mergedCTR.chargingStations.push(chargingStation);
14245
+ // // publicKeys
14246
+ // if (!mergedCTR.chargingSessions)
14247
+ // mergedCTR.chargingSessions = ctr.chargingSessions;
14248
+ // else if (ctr.chargingSessions)
14249
+ // for (const chargingSession of ctr.chargingSessions)
14250
+ // mergedCTR.chargingSessions.push(chargingSession);
14251
+ // if (!mergedCTR.eMobilityProviders)
14252
+ // mergedCTR.eMobilityProviders = ctr.eMobilityProviders;
14253
+ // else if (ctr.eMobilityProviders)
14254
+ // for (const eMobilityProvider of ctr.eMobilityProviders)
14255
+ // mergedCTR.eMobilityProviders.push(eMobilityProvider);
14256
+ // if (!mergedCTR.mediationServices)
14257
+ // mergedCTR.mediationServices = ctr.mediationServices;
14258
+ // else if (ctr.mediationServices)
14259
+ // for (const mediationService of ctr.mediationServices)
14260
+ // mergedCTR.mediationServices.push(mediationService);
14261
+ // }
14262
+ // return mergedCTR;
14263
+ // }
14264
+ // //#endregion
14213
14265
  //#region (private) validateOCMFSignature(OCMFJSONDocument, PublicKey, PublicKeyEncoding?)
14214
14266
  async validateOCMFSignature(OCMFJSONDocument, PublicKey, PublicKeyEncoding) {
14215
14267
  try {
@@ -14268,7 +14320,7 @@ var OCMF = class {
14268
14320
  this.key("pubKey").bitstr()
14269
14321
  );
14270
14322
  });
14271
- if (PublicKeyEncoding) {
14323
+ if (PublicKeyEncoding != null && PublicKeyEncoding.length > 0) {
14272
14324
  switch (PublicKeyEncoding.toLowerCase()) {
14273
14325
  case "hex":
14274
14326
  publicKeyBytes = Buffer.from(OCMFJSONDocument.publicKey, "hex");
@@ -14296,11 +14348,12 @@ var OCMF = class {
14296
14348
  publicKeyBytes = Buffer.from(OCMFJSONDocument.publicKey, "base64");
14297
14349
  }
14298
14350
  }
14299
- if (!publicKeyBytes) {
14351
+ if (publicKeyBytes == null) {
14300
14352
  OCMFJSONDocument.validationStatus = "UnknownPublicKeyFormat" /* UnknownPublicKeyFormat */;
14301
14353
  return OCMFJSONDocument.validationStatus;
14302
14354
  }
14303
- const publicKeyASN1 = ECPoint.decode(publicKeyBytes, "der");
14355
+ const decodedPublicKeyASN1 = ECPoint.decode(publicKeyBytes, "der");
14356
+ const publicKeyASN1 = decodedPublicKeyASN1;
14304
14357
  const coordinates = publicKeyASN1.pubKey.data.subarray(1);
14305
14358
  const halfLength = coordinates.length / 2;
14306
14359
  const publicKeyXY = {
@@ -14309,7 +14362,7 @@ var OCMF = class {
14309
14362
  };
14310
14363
  publicKey = curve.keyFromPublic(publicKeyXY, "hex");
14311
14364
  OCMFJSONDocument.publicKey = {
14312
- algorithm: OCMFJSONDocument.signature.SA ? OCMFJSONDocument.signature.SA.substring(
14365
+ algorithm: OCMFJSONDocument.signature.SA != null && OCMFJSONDocument.signature.SA.length > 0 ? OCMFJSONDocument.signature.SA.substring(
14313
14366
  OCMFJSONDocument.signature.SA.indexOf("-") + 1,
14314
14367
  OCMFJSONDocument.signature.SA.lastIndexOf("-")
14315
14368
  ) : "secp256r1",
@@ -14460,7 +14513,7 @@ var OCMF = class {
14460
14513
  hashValue,
14461
14514
  publicKey: PublicKey,
14462
14515
  publicKeyEncoding: PublicKeyEncoding,
14463
- validationStatus: validationStatus ? validationStatus : PublicKey ? "Unvalidated" /* Unvalidated */ : "PublicKeyNotFound" /* PublicKeyNotFound */
14516
+ validationStatus: validationStatus ?? (PublicKey != null ? "Unvalidated" /* Unvalidated */ : "PublicKeyNotFound" /* PublicKeyNotFound */)
14464
14517
  };
14465
14518
  try {
14466
14519
  const ECDSASignature = this.chargy.asn1.define("ECDSASignature", function() {
@@ -14482,7 +14535,8 @@ var OCMF = class {
14482
14535
  default:
14483
14536
  ocmfJSONDocument.validationStatus = "UnknownSignatureFormat" /* UnknownSignatureFormat */;
14484
14537
  }
14485
- const signatureObj = ECDSASignature.decode(Buffer.from(ocmfJSONDocument.signature.SD, bufferEncoding), "der");
14538
+ const decodedSignatureObj = ECDSASignature.decode(Buffer.from(ocmfJSONDocument.signature.SD, bufferEncoding), "der");
14539
+ const signatureObj = decodedSignatureObj;
14486
14540
  ocmfJSONDocument.signatureRS = {
14487
14541
  value: ocmfJSONDocument.signature.SD,
14488
14542
  r: signatureObj.r.toString(16),
@@ -14491,7 +14545,7 @@ var OCMF = class {
14491
14545
  } catch {
14492
14546
  ocmfJSONDocument.validationStatus = "InvalidSignature" /* InvalidSignature */;
14493
14547
  }
14494
- if (PublicKey && ocmfJSONDocument.validationStatus === "Unvalidated" /* Unvalidated */)
14548
+ if (PublicKey != null && ocmfJSONDocument.validationStatus === "Unvalidated" /* Unvalidated */)
14495
14549
  await this.validateOCMFSignature(
14496
14550
  ocmfJSONDocument,
14497
14551
  PublicKey,
@@ -14520,7 +14574,7 @@ var OCMF = class {
14520
14574
  //#endregion
14521
14575
  //#region TryToParseOCMFDocument (OCMFDocument, PublicKey?, PublicKeyEncoding?, ContainerInfos?)
14522
14576
  async TryToParseOCMFDocument(OCMFDocument, PublicKey, PublicKeyEncoding, ContainerInfos) {
14523
- return await this.TryToParseOCMFDocuments([OCMFDocument], PublicKey, PublicKeyEncoding, ContainerInfos);
14577
+ return this.TryToParseOCMFDocuments([OCMFDocument], PublicKey, PublicKeyEncoding, ContainerInfos);
14524
14578
  }
14525
14579
  //#endregion
14526
14580
  //#region TryToParseOCMFDocuments(OCMFDocuments, PublicKey?, PublicKeyEncoding?, ContainerInfos?)
@@ -14540,7 +14594,8 @@ var OCMF = class {
14540
14594
  if (typeof ocmfJSONDocuments !== "string") {
14541
14595
  for (const ocmfJSONDocument of ocmfJSONDocuments) {
14542
14596
  try {
14543
- 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 ?? "") + "|" + (ocmfJSONDocument.payload.IT ?? "") + "|" + (ocmfJSONDocument.payload.ID ?? "") + "|" + (ocmfJSONDocument.payload.TT ?? "") + "|" + (ocmfJSONDocument.payload.CF ?? "") + "|" + (ocmfJSONDocument.payload.CT ?? "") + "|" + (ocmfJSONDocument.payload.CI ?? "");
14597
+ 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 ?? "") + "|" +
14598
+ (ocmfJSONDocument.payload.IT ?? "") + "|" + (ocmfJSONDocument.payload.ID ?? "") + "|" + (ocmfJSONDocument.payload.TT ?? "") + "|" + (ocmfJSONDocument.payload.CF ?? "") + "|" + (ocmfJSONDocument.payload.CT ?? "") + "|" + (ocmfJSONDocument.payload.CI ?? "");
14544
14599
  if (!ocmfJSONDocumentGroups.has(groupingKey))
14545
14600
  ocmfJSONDocumentGroups.set(groupingKey, new Array());
14546
14601
  ocmfJSONDocumentGroups.get(groupingKey)?.push(ocmfJSONDocument);
@@ -14553,7 +14608,7 @@ var OCMF = class {
14553
14608
  }
14554
14609
  }
14555
14610
  for (const ocmfJSONDocumentGroup of ocmfJSONDocumentGroups.values()) {
14556
- if (PublicKey) {
14611
+ if (PublicKey != null) {
14557
14612
  for (const ocmfJSONDocument of ocmfJSONDocumentGroup)
14558
14613
  if (ocmfJSONDocument.validationStatus === "Unvalidated" /* Unvalidated */)
14559
14614
  await this.validateOCMFSignature(ocmfJSONDocument, PublicKey);
@@ -14605,12 +14660,6 @@ var OCPI = class {
14605
14660
  constructor(chargy) {
14606
14661
  this.chargy = chargy;
14607
14662
  }
14608
- bufferToHex(buffer, Reverse) {
14609
- return (Reverse ? Array.from(new Uint8Array(buffer)).reverse() : Array.from(new Uint8Array(buffer))).map((b) => b.toString(16).padStart(2, "0")).join("");
14610
- }
14611
- bufferToNumber(buffer) {
14612
- return parseInt(Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join(""), 16);
14613
- }
14614
14663
  //#region tryToParseChargeITContainerFormat(SomeJSON)
14615
14664
  // The chargeIT mobility data format does not always provide context information or format identifiers!
14616
14665
  async tryToParseOCPIFormat(SomeJSON) {
@@ -14644,7 +14693,7 @@ var OCPI = class {
14644
14693
  };
14645
14694
  if (encoding_method === "OCMF" && isMandatoryJSONArray(signed_values) && signed_values.length > 0) {
14646
14695
  const firstSignedData = asString(asJSONObject(signed_values[0])?.["signed_data"]);
14647
- if (firstSignedData) {
14696
+ if (firstSignedData != null && firstSignedData.length > 0) {
14648
14697
  const placeInfo = asJSONObject(SomeJSON["placeInfo"]);
14649
14698
  const geoLocation = asJSONObject(placeInfo?.["geoLocation"]);
14650
14699
  const address = asJSONObject(placeInfo?.["address"]);
@@ -14663,7 +14712,7 @@ var OCPI = class {
14663
14712
  },
14664
14713
  energyMeter: asJSONObject(SomeJSON["meterInfo"])
14665
14714
  };
14666
- return await new OCMF(this.chargy).TryToParseOCMFDocument(
14715
+ return new OCMF(this.chargy).TryToParseOCMFDocument(
14667
14716
  firstSignedData,
14668
14717
  asString(public_key),
14669
14718
  encoding_method,
@@ -14981,9 +15030,9 @@ var OCPI = class {
14981
15030
  ],
14982
15031
  certainty: 0
14983
15032
  };
14984
- if (smvContext?.startsWith("https://www.chargeit-mobility.com/contexts/bsm-ws36a-json"))
15033
+ if (smvContext?.startsWith("https://www.chargeit-mobility.com/contexts/bsm-ws36a-json") === true)
14985
15034
  return new BSMCrypt01(this.chargy).tryToParseBSM_WS36aMeasurements(CTR, evseIdStr, asString(chargingStation_controllerSoftwareVersion) ?? null, signedMeterValues);
14986
- if (smvContext?.startsWith("ALFEN"))
15035
+ if (smvContext?.startsWith("ALFEN") === true)
14987
15036
  return new Alfen(this.chargy).TryToParseALFENFormat(
14988
15037
  signedMeterValues.map((value) => asString(asJSONObject(value)?.["payload"]) ?? ""),
14989
15038
  {
@@ -15130,9 +15179,9 @@ function parsePCDFDocument(input) {
15130
15179
  }
15131
15180
  const fields = {};
15132
15181
  for (let i = 0; i < PCDF_FIELD_ORDER.length; i++) {
15133
- const value = match[i + 1];
15134
- const field = PCDF_FIELD_ORDER[i];
15135
- if (field == null || value == null)
15182
+ const value = getArrayElement(match, i + 1, "Missing PCDF field value");
15183
+ const field = getArrayElement(PCDF_FIELD_ORDER, i, "Missing PCDF field name");
15184
+ if (value.length === 0)
15136
15185
  throw new PCDFParseError("MISSING_FIELDS", "Missing fields in the data tuple", field);
15137
15186
  fields[field] = value;
15138
15187
  }
@@ -15504,8 +15553,10 @@ function parsePCDFReadingValue(value, errors) {
15504
15553
  errors.push("Session information is invalid");
15505
15554
  return void 0;
15506
15555
  }
15556
+ const integralPart = getArrayElement(match, 1, "Missing PCDF reading integral part");
15557
+ const fractionalPart = getArrayElement(match, 2, "Missing PCDF reading fractional part");
15507
15558
  return {
15508
- value: new Decimal(String(match[1]) + "." + String(match[2])),
15559
+ value: new Decimal(integralPart + "." + fractionalPart),
15509
15560
  unit: "kWh"
15510
15561
  };
15511
15562
  }
@@ -15540,9 +15591,9 @@ function hexToBytes2(hex, errorMessage) {
15540
15591
  }
15541
15592
  function readDERLength(bytes, getOffset, setOffset) {
15542
15593
  let offset = getOffset();
15543
- const b = bytes[offset++];
15544
- if (b == null)
15594
+ if (offset >= bytes.length)
15545
15595
  throw new Error("Invalid signature");
15596
+ const b = getArrayElement(bytes, offset++, "Invalid signature");
15546
15597
  if ((b & 128) === 0) {
15547
15598
  setOffset(offset);
15548
15599
  return b;
@@ -15552,9 +15603,9 @@ function readDERLength(bytes, getOffset, setOffset) {
15552
15603
  throw new Error("Invalid signature");
15553
15604
  let length = 0;
15554
15605
  for (let i = 0; i < octets; i++) {
15555
- const value = bytes[offset++];
15556
- if (value == null)
15606
+ if (offset >= bytes.length)
15557
15607
  throw new Error("Invalid signature");
15608
+ const value = getArrayElement(bytes, offset++, "Invalid signature");
15558
15609
  length = (length << 8) + value;
15559
15610
  }
15560
15611
  setOffset(offset);
@@ -15583,30 +15634,33 @@ var SAFEXML = class _SAFEXML {
15583
15634
  this.chargy = chargy;
15584
15635
  }
15585
15636
  static ParseChargingStationContext(XMLDocument) {
15586
- const chargingStationElement = getElementsByLocalName(XMLDocument, "chargingStation")[0];
15587
- if (!chargingStationElement)
15637
+ const chargingStationElement = getElementsByLocalName(XMLDocument, "chargingStation").at(0);
15638
+ if (chargingStationElement === void 0)
15588
15639
  return {};
15589
- const chargingStationId = chargingStationElement.getAttribute("id")?.trim() || getTrimmedTextContent(getDirectChildByLocalName(chargingStationElement, "id"));
15640
+ const chargingStationAttributeId = chargingStationElement.getAttribute("id")?.trim();
15641
+ const chargingStationId = chargingStationAttributeId != null && chargingStationAttributeId.length > 0 ? chargingStationAttributeId : getTrimmedTextContent(getDirectChildByLocalName(chargingStationElement, "id"));
15590
15642
  const softwareVersion = getTrimmedTextContent(getDirectChildByLocalName(chargingStationElement, "softwareVersion"));
15591
15643
  const geoLocationElement = getDirectChildByLocalName(chargingStationElement, "geoLocation");
15592
15644
  const latitude = Number.parseFloat(getTrimmedTextContent(getDirectChildByLocalName(geoLocationElement ?? chargingStationElement, "latitude")) ?? "");
15593
15645
  const longitude = Number.parseFloat(getTrimmedTextContent(getDirectChildByLocalName(geoLocationElement ?? chargingStationElement, "longitude")) ?? "");
15594
15646
  const geoLocation = Number.isFinite(latitude) && Number.isFinite(longitude) ? { lat: latitude, lng: longitude } : void 0;
15595
- if (getDirectChildByLocalName(chargingStationElement, "EVSEs"))
15647
+ if (getDirectChildByLocalName(chargingStationElement, "EVSEs") !== void 0)
15596
15648
  throw new Error("The SAFE chargingStation XML element must contain EVSE directly and no EVSEs container element!");
15597
15649
  const evseElements = getDirectChildrenByLocalName(chargingStationElement, "EVSE");
15598
15650
  if (evseElements.length > 1)
15599
15651
  throw new Error("The SAFE chargingStation XML element must not contain more than one EVSE element!");
15600
- const evseElement = evseElements[0];
15601
- const evseId = evseElement?.getAttribute("id")?.trim() || getTrimmedTextContent(getDirectChildByLocalName(evseElement ?? chargingStationElement, "id")) || "";
15602
- const connectorElements = evseElement ? getDirectChildrenByLocalName(evseElement, "connector") : [];
15652
+ const evseElement = evseElements.at(0);
15653
+ const evseAttributeId = evseElement?.getAttribute("id")?.trim();
15654
+ const evseTextId = getTrimmedTextContent(getDirectChildByLocalName(evseElement ?? chargingStationElement, "id"));
15655
+ const evseId = evseAttributeId != null && evseAttributeId.length > 0 ? evseAttributeId : evseTextId ?? "";
15656
+ const connectorElements = evseElement !== void 0 ? getDirectChildrenByLocalName(evseElement, "connector") : [];
15603
15657
  if (connectorElements.length > 1)
15604
15658
  throw new Error("The SAFE EVSE XML element must not contain more than one connector element!");
15605
- const connectorElement = connectorElements[0];
15659
+ const connectorElement = connectorElements.at(0);
15606
15660
  const connectorId = connectorElement?.getAttribute("id")?.trim();
15607
15661
  const connectorType = getTrimmedTextContent(getDirectChildByLocalName(connectorElement ?? evseElement ?? chargingStationElement, "type"));
15608
- const connector = connectorType ? { "@id": connectorId, type: connectorType, looses: 0 } : void 0;
15609
- const parsedEVSE = evseElement ? {
15662
+ const connector = connectorType != null && connectorType.length > 0 ? { "@id": connectorId, type: connectorType, looses: 0 } : void 0;
15663
+ const parsedEVSE = evseElement !== void 0 ? {
15610
15664
  "@id": evseId,
15611
15665
  "description": parseDescription(evseElement),
15612
15666
  "meters": [],
@@ -15771,8 +15825,8 @@ var XMLContainer = class {
15771
15825
  if (values.length == 1) {
15772
15826
  const valueList = values[0]?.querySelectorAll("signedMeterValue");
15773
15827
  if (valueList != null && valueList.length >= 1) {
15774
- for (let i = 0; i < valueList.length; i++) {
15775
- const publicKey = valueList[i]?.querySelector("publicKey");
15828
+ for (const valueElement of valueList) {
15829
+ const publicKey = valueElement.querySelector("publicKey");
15776
15830
  if (publicKey != null) {
15777
15831
  const publicKeyEncoding = publicKey.attributes.getNamedItem("encoding")?.value.trim().toLowerCase() ?? "";
15778
15832
  let publicKeyValue = publicKey.textContent.trim();
@@ -15812,7 +15866,7 @@ var XMLContainer = class {
15812
15866
  certainty: 0
15813
15867
  };
15814
15868
  }
15815
- const meterValueSignature = valueList[i]?.querySelector("meterValueSignature");
15869
+ const meterValueSignature = valueElement.querySelector("meterValueSignature");
15816
15870
  if (meterValueSignature != null) {
15817
15871
  const meterValueSignatureEncoding = meterValueSignature.attributes.getNamedItem("encoding")?.value.trim().toLowerCase() ?? "";
15818
15872
  let meterValueSignatureValue = meterValueSignature.textContent.trim();
@@ -15845,7 +15899,7 @@ var XMLContainer = class {
15845
15899
  };
15846
15900
  common.meterValueSignatures.push(meterValueSignatureValue);
15847
15901
  }
15848
- const signatureMethod = valueList[i]?.querySelector("signatureMethod")?.textContent.trim().toLowerCase() ?? "";
15902
+ const signatureMethod = valueElement.querySelector("signatureMethod")?.textContent.trim().toLowerCase() ?? "";
15849
15903
  if (common.signatureMethod == "")
15850
15904
  common.signatureMethod = signatureMethod;
15851
15905
  else if (common.signatureMethod != signatureMethod)
@@ -15854,7 +15908,7 @@ var XMLContainer = class {
15854
15908
  message: this.chargy.GetMultilanguageText("Invalid mixture of different signature methods within the given XML container!"),
15855
15909
  certainty: 0
15856
15910
  };
15857
- const encodingMethod = valueList[i]?.querySelector("encodingMethod")?.textContent.trim().toLowerCase() ?? "";
15911
+ const encodingMethod = valueElement.querySelector("encodingMethod")?.textContent.trim().toLowerCase() ?? "";
15858
15912
  if (common.encodingMethod == "")
15859
15913
  common.encodingMethod = encodingMethod;
15860
15914
  else if (common.encodingMethod != encodingMethod)
@@ -15863,7 +15917,7 @@ var XMLContainer = class {
15863
15917
  message: this.chargy.GetMultilanguageText("Invalid mixture of different signed data formats within the given XML container!"),
15864
15918
  certainty: 0
15865
15919
  };
15866
- const encodedMeterValue = valueList[i]?.querySelector("encodedMeterValue");
15920
+ const encodedMeterValue = valueElement.querySelector("encodedMeterValue");
15867
15921
  if (encodedMeterValue != null) {
15868
15922
  const signedDataEncoding = encodedMeterValue.attributes.getNamedItem("encoding")?.value.trim() ?? "";
15869
15923
  let signedDataValue = encodedMeterValue.textContent.trim();
@@ -15924,12 +15978,6 @@ var ChargeIT = class {
15924
15978
  constructor(chargy) {
15925
15979
  this.chargy = chargy;
15926
15980
  }
15927
- bufferToHex(buffer, Reverse) {
15928
- return (Reverse ? Array.from(new Uint8Array(buffer)).reverse() : Array.from(new Uint8Array(buffer))).map((b) => b.toString(16).padStart(2, "0")).join("");
15929
- }
15930
- bufferToNumber(buffer) {
15931
- return parseInt(Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join(""), 16);
15932
- }
15933
15981
  //#region TryToParseOldChargeITMeterValuesFormat(CTR, evseId, address, geoLocation, signedMeterValues)
15934
15982
  TryToParseOldChargeITMeterValuesFormat(CTR, evseId, address, geoLocation, signedMeterValues) {
15935
15983
  const CTRArray = new Array();
@@ -16029,14 +16077,8 @@ var ChargeIT = class {
16029
16077
  });
16030
16078
  }
16031
16079
  }
16032
- const firstMeterValue = CTRArray[0];
16033
- const lastMeterValue = CTRArray[CTRArray.length - 1];
16034
- if (firstMeterValue === void 0 || lastMeterValue === void 0)
16035
- return {
16036
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
16037
- message: this.chargy.GetMultilanguageText("UnknownOrInvalidChargingSessionFormat"),
16038
- certainty: 0
16039
- };
16080
+ const firstMeterValue = getFirstArrayElement(CTRArray, "Missing first chargeIT meter value");
16081
+ const lastMeterValue = getLastArrayElement(CTRArray, "Missing last chargeIT meter value");
16040
16082
  CTR["@id"] = lastMeterValue["transactionId"];
16041
16083
  CTR.begin = this.chargy.moment.unix(firstMeterValue["measuredValue"]["timestampLocal"]["timestamp"]).utc().format();
16042
16084
  CTR.end = this.chargy.moment.unix(lastMeterValue["measuredValue"]["timestampLocal"]["timestamp"]).utc().format();
@@ -16266,7 +16308,6 @@ var ChargeIT = class {
16266
16308
  if (consistent) {
16267
16309
  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") {
16268
16310
  } else if (signedMeterValueContext.startsWith("ALFEN")) {
16269
- } else if (containerFormat === oldChargeITContainerFormat) {
16270
16311
  } else if (signedMeterValueContext === oldChargeITMeterValueFormat) {
16271
16312
  let measurementCounter = 0;
16272
16313
  for (const signedMeterValue of signedMeterValues) {
@@ -16382,10 +16423,10 @@ var ChargeIT = class {
16382
16423
  }
16383
16424
  }
16384
16425
  const chargePoint = signedMeterValue["chargePoint"];
16385
- if (!isMandatoryJSONObject(chargePoint)) {
16426
+ if (chargePoint !== void 0 && !isMandatoryJSONObject(chargePoint)) {
16386
16427
  errors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("MissingOrInvalid_SignedMeterValue_ChargePointInformationP", measurementCounter)));
16387
16428
  secondaryErrors += 1;
16388
- } else {
16429
+ } else if (isMandatoryJSONObject(chargePoint)) {
16389
16430
  if (!isMandatoryString(chargePoint["softwareVersion"]))
16390
16431
  errors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("MissingOrInvalid_SignedMeterValue_ChargePointInformation_SoftwareVersionP", measurementCounter)));
16391
16432
  }
@@ -16533,19 +16574,17 @@ var ChargeIT = class {
16533
16574
  }
16534
16575
  );
16535
16576
  }
16536
- if (containerFormat === oldChargeITContainerFormat) {
16537
- if (asJSONObject(signedMeterValues[0])?.["format"] == "ALFEN")
16538
- return new Alfen(this.chargy).TryToParseALFENFormat(
16539
- signedMeterValues.map((value) => asString(asJSONObject(value)?.["payload"]) ?? ""),
16540
- {
16541
- EVSEId: evseId,
16542
- chargingStation: {
16543
- geoLocation: { "lat": geoLocation_lat, "lng": geoLocation_lon },
16544
- address: { "street": address_street, "postalCode": address_zipCode, "city": address_town, "country": address_country }
16545
- }
16577
+ if (asJSONObject(signedMeterValues[0])?.["format"] == "ALFEN")
16578
+ return new Alfen(this.chargy).TryToParseALFENFormat(
16579
+ signedMeterValues.map((value) => asString(asJSONObject(value)?.["payload"]) ?? ""),
16580
+ {
16581
+ EVSEId: evseId,
16582
+ chargingStation: {
16583
+ geoLocation: { "lat": geoLocation_lat, "lng": geoLocation_lon },
16584
+ address: { "street": address_street, "postalCode": address_zipCode, "city": address_town, "country": address_country }
16546
16585
  }
16547
- );
16548
- }
16586
+ }
16587
+ );
16549
16588
  if (signedMeterValueContext === oldChargeITMeterValueFormat)
16550
16589
  return this.TryToParseOldChargeITMeterValuesFormat(
16551
16590
  CTR,
@@ -16735,8 +16774,6 @@ var ChargeIT = class {
16735
16774
  errors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("MissingOrInvalid_SignedMeterValue_MeterInfo_MeterIdP", 1)));
16736
16775
  }
16737
16776
  if (isMandatoryJSONArray(chargingTariffs)) {
16738
- for (let i = 0; i < chargingTariffs.length; i++) {
16739
- }
16740
16777
  }
16741
16778
  if (totalCosts) {
16742
16779
  if (!isMandatoryNumber(totalCosts_total))
@@ -16889,9 +16926,9 @@ var ChargeIT = class {
16889
16926
  ],
16890
16927
  certainty: 0
16891
16928
  };
16892
- if (smvContext?.startsWith("https://www.chargeit-mobility.com/contexts/bsm-ws36a-json"))
16929
+ if (smvContext?.startsWith("https://www.chargeit-mobility.com/contexts/bsm-ws36a-json") === true)
16893
16930
  return new BSMCrypt01(this.chargy).tryToParseBSM_WS36aMeasurements(CTR, evseIdStr, asString(chargingStation_controllerSoftwareVersion) ?? null, signedMeterValues);
16894
- if (smvContext?.startsWith("ALFEN"))
16931
+ if (smvContext?.startsWith("ALFEN") === true)
16895
16932
  return new Alfen(this.chargy).TryToParseALFENFormat(
16896
16933
  signedMeterValues.map((value) => asString(asJSONObject(value)?.["payload"]) ?? ""),
16897
16934
  {
@@ -16994,10 +17031,8 @@ var ChargePoint = class {
16994
17031
  if (startTimeUTC !== void 0 && (parkingEnd === void 0 || startTimeUTC > parkingEnd))
16995
17032
  parkingEnd = endTimeUTC;
16996
17033
  }
16997
- if (chargingStart === void 0)
16998
- chargingStart = parkingStart;
16999
- if (chargingEnd === void 0)
17000
- chargingEnd = parkingEnd;
17034
+ chargingStart ??= parkingStart;
17035
+ chargingEnd ??= parkingEnd;
17001
17036
  let sessionStart = parkingStart !== void 0 && (chargingStart === void 0 || parkingStart < chargingStart) ? parkingStart : chargingStart;
17002
17037
  if (sessionStart === void 0 && parkingStart !== void 0)
17003
17038
  sessionStart = parkingStart;
@@ -17146,7 +17181,7 @@ var ChargePoint = class {
17146
17181
  "status": "Unvalidated" /* Unvalidated */
17147
17182
  };
17148
17183
  if (parking && parking.length > 0 && CTR.chargingSessions && CTR.chargingSessions.length > 0) {
17149
- const chargingSession = CTR.chargingSessions[0];
17184
+ const chargingSession = getFirstArrayElement(CTR.chargingSessions, "Missing ChargePoint charging session");
17150
17185
  chargingSession.parking = [];
17151
17186
  for (const parkingItem of parking) {
17152
17187
  const parkingObj = asJSONObject(parkingItem);
@@ -17442,6 +17477,8 @@ var ChargePointCrypt01 = class extends ACrypt {
17442
17477
  case "InvalidSignature" /* InvalidSignature */:
17443
17478
  currentResult.status = "InvalidStartValue" /* InvalidStartValue */;
17444
17479
  break;
17480
+ default:
17481
+ break;
17445
17482
  }
17446
17483
  } else if (i == measurement.values.length - 1) {
17447
17484
  switch (currentResult.status) {
@@ -17454,6 +17491,8 @@ var ChargePointCrypt01 = class extends ACrypt {
17454
17491
  case "InvalidSignature" /* InvalidSignature */:
17455
17492
  currentResult.status = "InvalidStopValue" /* InvalidStopValue */;
17456
17493
  break;
17494
+ default:
17495
+ break;
17457
17496
  }
17458
17497
  } else {
17459
17498
  switch (currentResult.status) {
@@ -17466,6 +17505,8 @@ var ChargePointCrypt01 = class extends ACrypt {
17466
17505
  case "InvalidSignature" /* InvalidSignature */:
17467
17506
  currentResult.status = "InvalidStopValue" /* InvalidStopValue */;
17468
17507
  break;
17508
+ default:
17509
+ break;
17469
17510
  }
17470
17511
  }
17471
17512
  }
@@ -17495,9 +17536,9 @@ var ChargePointCrypt01 = class extends ACrypt {
17495
17536
  const cryptoResult = {
17496
17537
  status: "NoOperation" /* NoOperation */
17497
17538
  };
17498
- return await Promise.resolve(setResult("NoOperation" /* NoOperation */));
17539
+ return Promise.resolve(setResult("NoOperation" /* NoOperation */));
17499
17540
  }
17500
- async ViewMeasurement(measurementValue, errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
17541
+ async ViewMeasurement(measurementValue, _errorDiv, introDiv, _infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
17501
17542
  if (measurementValue.measurement?.chargingSession === void 0)
17502
17543
  return new Error("Invalid measurement!");
17503
17544
  const chargingSession = measurementValue.measurement.chargingSession;
@@ -17505,8 +17546,8 @@ var ChargePointCrypt01 = class extends ACrypt {
17505
17546
  const algorithmName = typeof chargingSession.publicKey?.algorithm === "object" ? chargingSession.publicKey.algorithm.name : chargingSession.publicKey?.algorithm ?? "";
17506
17547
  const algorithmType = typeof chargingSession.publicKey?.type === "object" ? chargingSession.publicKey.type.name : chargingSession.publicKey?.type;
17507
17548
  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);
17508
- if (PlainTextDiv.parentElement != void 0 && PlainTextDiv.parentElement.children[0] != void 0) {
17509
- PlainTextDiv.parentElement.children[0].innerHTML = "Plain text (secrrct)";
17549
+ if (PlainTextDiv.parentElement) {
17550
+ getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = "Plain text (secrrct)";
17510
17551
  }
17511
17552
  PlainTextDiv.innerText = atob(chargingSession.original ?? "");
17512
17553
  PlainTextDiv.style.fontFamily = "monospace";
@@ -17528,22 +17569,23 @@ var ChargePointCrypt01 = class extends ACrypt {
17528
17569
  hashInfo = "(SHA512, 512 Bits, hex)";
17529
17570
  break;
17530
17571
  }
17531
- if (HashedPlainTextDiv.parentElement != void 0 && HashedPlainTextDiv.parentElement.children[0] != void 0) {
17532
- HashedPlainTextDiv.parentElement.children[0].innerHTML = "Hashed plain text " + hashInfo;
17572
+ if (HashedPlainTextDiv.parentElement) {
17573
+ getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = "Hashed plain text " + hashInfo;
17533
17574
  }
17534
17575
  HashedPlainTextDiv.innerHTML = chargingSession.hashValue?.match(/.{1,8}/g)?.join(" ") ?? "0x00000000000000000000000000000000000";
17535
17576
  if (chargingSession.publicKey != null) {
17536
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[0] != void 0) {
17537
- PublicKeyDiv.parentElement.children[0].innerHTML = "Public Key (" + (algorithmType ? algorithmType + ", " : "") + (algorithmName ? algorithmName + ", " : "") + "hex)";
17577
+ if (PublicKeyDiv.parentElement) {
17578
+ getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = "Public Key (" + (algorithmType != null && algorithmType.length > 0 ? algorithmType + ", " : "") + (algorithmName.length > 0 ? algorithmName + ", " : "") + "hex)";
17538
17579
  }
17539
17580
  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(" ") ?? "";
17540
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[3] != void 0) {
17541
- PublicKeyDiv.parentElement.children[3].innerHTML = "";
17581
+ const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
17582
+ if (publicKeySignatureContainer !== void 0) {
17583
+ publicKeySignatureContainer.innerHTML = "";
17542
17584
  }
17543
17585
  if (result.publicKeySignatures) {
17544
17586
  for (const signature of result.publicKeySignatures) {
17545
17587
  try {
17546
- const signatureDiv = PublicKeyDiv.parentElement?.children[3]?.appendChild(document.createElement("div"));
17588
+ const signatureDiv = publicKeySignatureContainer?.appendChild(document.createElement("div"));
17547
17589
  if (signatureDiv != null)
17548
17590
  signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
17549
17591
  measurementValue.measurement.chargingSession.chargingStation,
@@ -17558,8 +17600,8 @@ var ChargePointCrypt01 = class extends ACrypt {
17558
17600
  }
17559
17601
  }
17560
17602
  if (chargingSession.signature != null) {
17561
- if (SignatureExpectedDiv.parentElement != void 0 && SignatureExpectedDiv.parentElement.children[0] != void 0) {
17562
- SignatureExpectedDiv.parentElement.children[0].innerHTML = "Erwartete Signatur (secrrct.sign, rs, hex)";
17603
+ if (SignatureExpectedDiv.parentElement) {
17604
+ getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = "Erwartete Signatur (secrrct.sign, rs, hex)";
17563
17605
  }
17564
17606
  if (typeof chargingSession.signature != "string")
17565
17607
  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(" ") ?? "");
@@ -17591,6 +17633,7 @@ var ChargePointCrypt01 = class extends ACrypt {
17591
17633
  break;
17592
17634
  }
17593
17635
  }
17636
+ return void 0;
17594
17637
  }
17595
17638
  };
17596
17639
 
@@ -17614,8 +17657,7 @@ function IsAChargeTransparencyRecord(data) {
17614
17657
  function IsASessionCryptoResult(data) {
17615
17658
  if (!isMandatoryJSONObject(data))
17616
17659
  return false;
17617
- const sessionCryptoResult = data;
17618
- return sessionCryptoResult.status !== void 0;
17660
+ return true;
17619
17661
  }
17620
17662
  function CloneCTR(CTR) {
17621
17663
  const clonedCTR = JSON.parse(JSON.stringify(CTR));
@@ -17794,8 +17836,10 @@ async function imageDataFromNodeCanvas(data) {
17794
17836
  if (!isCanvasModule(canvasLib))
17795
17837
  return void 0;
17796
17838
  const image = await canvasLib.loadImage(import_buffer.Buffer.from(toUint8Array(data)));
17797
- const width = image.naturalWidth || image.width;
17798
- const height = image.naturalHeight || image.height;
17839
+ const naturalWidth = image.naturalWidth ?? 0;
17840
+ const naturalHeight = image.naturalHeight ?? 0;
17841
+ const width = naturalWidth > 0 ? naturalWidth : image.width;
17842
+ const height = naturalHeight > 0 ? naturalHeight : image.height;
17799
17843
  if (width <= 0 || height <= 0)
17800
17844
  return void 0;
17801
17845
  const canvas = canvasLib.createCanvas(width, height);
@@ -17866,22 +17910,22 @@ async function importOptionalNodeModule(moduleName) {
17866
17910
  }
17867
17911
  async function readQRCodeTextFromImage(data, mimeType) {
17868
17912
  const imageDataSources = typeof document === "undefined" ? [
17869
- () => imageDataFromNodeCanvas(data),
17870
- () => imageDataFromPNGOrJPEG(data, mimeType),
17871
- () => imageDataFromBrowserCanvas(data, mimeType),
17872
- () => imageDataFromBrowserImageElement(data, mimeType)
17913
+ async () => imageDataFromNodeCanvas(data),
17914
+ async () => imageDataFromPNGOrJPEG(data, mimeType),
17915
+ async () => imageDataFromBrowserCanvas(data, mimeType),
17916
+ async () => imageDataFromBrowserImageElement(data, mimeType)
17873
17917
  ] : [
17874
- () => imageDataFromBrowserCanvas(data, mimeType),
17875
- () => imageDataFromBrowserImageElement(data, mimeType),
17876
- () => imageDataFromNodeCanvas(data),
17877
- () => imageDataFromPNGOrJPEG(data, mimeType)
17918
+ async () => imageDataFromBrowserCanvas(data, mimeType),
17919
+ async () => imageDataFromBrowserImageElement(data, mimeType),
17920
+ async () => imageDataFromNodeCanvas(data),
17921
+ async () => imageDataFromPNGOrJPEG(data, mimeType)
17878
17922
  ];
17879
17923
  for (const imageDataSource of imageDataSources) {
17880
17924
  const imageData = await imageDataSource();
17881
17925
  if (imageData == null)
17882
17926
  continue;
17883
17927
  const qrText = readQRCodeTextFromImageData(imageData);
17884
- if (qrText && qrText.length > 0)
17928
+ if (qrText != null && qrText.length > 0)
17885
17929
  return qrText;
17886
17930
  }
17887
17931
  return void 0;
@@ -17894,7 +17938,7 @@ function readQRCodeTextFromImageData(imageData) {
17894
17938
  { inversionAttempts: "attemptBoth" }
17895
17939
  );
17896
17940
  const qrText = qrCode?.data.trim();
17897
- return qrText && qrText.length > 0 ? qrText : void 0;
17941
+ return qrText != null && qrText.length > 0 ? qrText : void 0;
17898
17942
  }
17899
17943
 
17900
17944
  // src/pdfjs/browser.ts
@@ -17915,6 +17959,11 @@ var validationRules_default = {
17915
17959
  }
17916
17960
  }
17917
17961
  };
17962
+ function isPdfAttachment(value) {
17963
+ if (!isMandatoryJSONObject(value))
17964
+ return false;
17965
+ return typeof value["filename"] === "string" && (value["content"] instanceof ArrayBuffer || ArrayBuffer.isView(value["content"]));
17966
+ }
17918
17967
  var Chargy = class {
17919
17968
  //#region Data
17920
17969
  i18n;
@@ -17931,8 +17980,6 @@ var Chargy = class {
17931
17980
  EVSEs = new Array();
17932
17981
  meters = new Array();
17933
17982
  chargingSessions = new Array();
17934
- eMobilityProviders = new Array();
17935
- mediationServices = new Array();
17936
17983
  currentCTR = {};
17937
17984
  internalCTR = {};
17938
17985
  //#endregion
@@ -17980,7 +18027,7 @@ var Chargy = class {
17980
18027
  return result;
17981
18028
  }
17982
18029
  PublicKeyIdFromFileName(fileName) {
17983
- return (fileName.indexOf(".") > -1 ? fileName.substring(0, fileName.indexOf(".")) : fileName).replace(/[-_]?public[-_]?key/i, "");
18030
+ return (fileName.includes(".") ? fileName.substring(0, fileName.indexOf(".")) : fileName).replace(/[-_]?public[-_]?key/i, "");
17984
18031
  }
17985
18032
  TryToParseDERPublicKey(keyId, publicKeyBuffer) {
17986
18033
  const ASN1_OIDs = this.asn1.define("OIDs", function() {
@@ -18336,7 +18383,7 @@ var Chargy = class {
18336
18383
  if (compressedFiles.length == 0)
18337
18384
  continue;
18338
18385
  archiveFound = true;
18339
- if (compressedFiles.length == 1 && compressedFiles[0]?.path == null) {
18386
+ if (compressedFiles.length == 1) {
18340
18387
  expandedFileInfos.push({
18341
18388
  name: FileInfo.name.substring(0, FileInfo.name.lastIndexOf(".")),
18342
18389
  data: compressedFiles[0]?.data
@@ -18373,9 +18420,12 @@ var Chargy = class {
18373
18420
  }
18374
18421
  if (dataFile.length > 0 && signatureFile.length > 0) {
18375
18422
  try {
18376
- CTRfile = JSON.parse(dataFile);
18377
- CTRfile.original = btoa(dataFile);
18378
- CTRfile.signature = signatureFile;
18423
+ const parsedCTRFile = JSON.parse(dataFile);
18424
+ if (!isMandatoryJSONObject(parsedCTRFile))
18425
+ throw new Error("Invalid chargepoint 'secrrct' JSON file!");
18426
+ CTRfile = parsedCTRFile;
18427
+ CTRfile["original"] = btoa(dataFile);
18428
+ CTRfile["signature"] = signatureFile;
18379
18429
  expandedFileInfos.push({
18380
18430
  name: FileInfo.name,
18381
18431
  data: new TextEncoder().encode(JSON.stringify(CTRfile))
@@ -18418,7 +18468,7 @@ var Chargy = class {
18418
18468
  async extractArchive(fileName, data, mimeType) {
18419
18469
  const archiveData = this.toUint8Array(data);
18420
18470
  if (mimeType === "application/zip")
18421
- return await this.extractZipArchive(archiveData);
18471
+ return this.extractZipArchive(archiveData);
18422
18472
  if (mimeType === "application/x-tar")
18423
18473
  return this.extractTarArchive(archiveData);
18424
18474
  if (mimeType === "application/gzip") {
@@ -18457,7 +18507,7 @@ var Chargy = class {
18457
18507
  break;
18458
18508
  const prefix = this.readTarString(header, 345, 155);
18459
18509
  const path = prefix.length > 0 ? prefix + "/" + name : name;
18460
- const typeFlag = String.fromCharCode(header[156] ?? 0);
18510
+ const typeFlag = String.fromCharCode(getArrayElement(header, 156, "Missing tar header type flag"));
18461
18511
  const dataStart = offset + 512;
18462
18512
  const dataEnd = dataStart + size;
18463
18513
  if (dataEnd > data.byteLength)
@@ -18566,45 +18616,48 @@ var Chargy = class {
18566
18616
  for (const fileInfo of FileInfos) {
18567
18617
  if (fileInfo.type === "application/pdf" || fileInfo.name.endsWith(".pdf")) {
18568
18618
  const pdfjsLib = await importPdfJs();
18569
- const pdfDocument = fileInfo.data ? await pdfjsLib.getDocument({ data: fileInfo.data }).promise : fileInfo.path ? await pdfjsLib.getDocument({ url: fileInfo.path }).promise : null;
18570
- if (pdfDocument) {
18619
+ 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;
18620
+ if (pdfDocument !== null) {
18571
18621
  try {
18572
- const attachments = await pdfDocument.getAttachments();
18573
- Object.keys(attachments).forEach((fileName) => {
18574
- const attachment = attachments[fileName];
18575
- if (attachment.filename.endsWith(".chargy"))
18576
- expandedFiles.push({
18577
- name: attachment.filename,
18578
- path: FileInfos[0]?.path,
18579
- type: "application/chargy",
18580
- data: attachment.content,
18581
- info: "A CHARGY file extracted from a PDF/A-3 or newer attachment"
18582
- });
18583
- else if (attachment.filename.endsWith(".xml"))
18584
- expandedFiles.push({
18585
- name: attachment.filename,
18586
- path: FileInfos[0]?.path,
18587
- type: "application/xml",
18588
- data: attachment.content,
18589
- info: "A XML file extracted from a PDF/A-3 or newer attachment"
18590
- });
18591
- else if (attachment.filename.endsWith(".json"))
18592
- expandedFiles.push({
18593
- name: attachment.filename,
18594
- path: FileInfos[0]?.path,
18595
- type: "application/json",
18596
- data: attachment.content,
18597
- info: "A JSON file extracted from a PDF/A-3 or newer attachment"
18598
- });
18599
- else if (attachment.filename.endsWith(".csv"))
18600
- expandedFiles.push({
18601
- name: attachment.filename,
18602
- path: FileInfos[0]?.path,
18603
- type: "text/csv",
18604
- data: attachment.content,
18605
- info: "A CSV file extracted from a PDF/A-3 or newer attachment"
18606
- });
18607
- });
18622
+ const attachmentsUnknown = await pdfDocument.getAttachments();
18623
+ if (isMandatoryJSONObject(attachmentsUnknown))
18624
+ Object.values(attachmentsUnknown).forEach((attachmentUnknown) => {
18625
+ if (!isPdfAttachment(attachmentUnknown))
18626
+ return;
18627
+ const attachment = attachmentUnknown;
18628
+ if (attachment.filename.endsWith(".chargy"))
18629
+ expandedFiles.push({
18630
+ name: attachment.filename,
18631
+ path: FileInfos[0]?.path,
18632
+ type: "application/chargy",
18633
+ data: attachment.content,
18634
+ info: "A CHARGY file extracted from a PDF/A-3 or newer attachment"
18635
+ });
18636
+ else if (attachment.filename.endsWith(".xml"))
18637
+ expandedFiles.push({
18638
+ name: attachment.filename,
18639
+ path: FileInfos[0]?.path,
18640
+ type: "application/xml",
18641
+ data: attachment.content,
18642
+ info: "A XML file extracted from a PDF/A-3 or newer attachment"
18643
+ });
18644
+ else if (attachment.filename.endsWith(".json"))
18645
+ expandedFiles.push({
18646
+ name: attachment.filename,
18647
+ path: FileInfos[0]?.path,
18648
+ type: "application/json",
18649
+ data: attachment.content,
18650
+ info: "A JSON file extracted from a PDF/A-3 or newer attachment"
18651
+ });
18652
+ else if (attachment.filename.endsWith(".csv"))
18653
+ expandedFiles.push({
18654
+ name: attachment.filename,
18655
+ path: FileInfos[0]?.path,
18656
+ type: "text/csv",
18657
+ data: attachment.content,
18658
+ info: "A CSV file extracted from a PDF/A-3 or newer attachment"
18659
+ });
18660
+ });
18608
18661
  } catch (error) {
18609
18662
  console.error(`Error extracting PDF/A-3 attachments: ${String(error)}`);
18610
18663
  }
@@ -18650,7 +18703,7 @@ var Chargy = class {
18650
18703
  break;
18651
18704
  }
18652
18705
  processedFile.result = await new SAFEXML(this).tryToParseSAFEXML(XMLDocument);
18653
- if (processedFile.result.status && processedFile.result.status !== "Unvalidated" /* Unvalidated */ && getElementsByLocalName(XMLDocument, "chargingStation").length === 0) {
18706
+ if (processedFile.result.status != null && processedFile.result.status !== "Unvalidated" /* Unvalidated */ && getElementsByLocalName(XMLDocument, "chargingStation").length === 0) {
18654
18707
  processedFile.result = new XMLContainer(this).tryToParseXMLContainer(XMLDocument);
18655
18708
  }
18656
18709
  break;
@@ -18734,8 +18787,7 @@ var Chargy = class {
18734
18787
  if (isMandatoryJSONObject(JSONContent)) {
18735
18788
  const JSONContext = JSONContent["@context"];
18736
18789
  if (IsAChargeTransparencyLiveLink(JSONContent)) {
18737
- if (JSONContent.timestamp == null)
18738
- JSONContent.timestamp = (/* @__PURE__ */ new Date()).toISOString();
18790
+ JSONContent.timestamp ??= (/* @__PURE__ */ new Date()).toISOString();
18739
18791
  processedFile.result = JSONContent;
18740
18792
  } else if (isMandatoryString(JSONContext)) {
18741
18793
  if (JSONContext.startsWith("https://open.charging.cloud/contexts/CTR+json"))
@@ -18779,25 +18831,18 @@ var Chargy = class {
18779
18831
  processedFiles.push(processedFile);
18780
18832
  }
18781
18833
  if (processedFiles.length == 1) {
18782
- const processedFile = processedFiles[0];
18783
- if (processedFile) {
18784
- if (IsAChargeTransparencyRecord(processedFile.result))
18785
- return this.processChargeTransparencyRecord(processedFile.result);
18786
- if (IsAChargeTransparencyLiveLink(processedFile.result))
18787
- return processedFile.result;
18788
- if (IsAPublicKeyLookup(processedFile.result))
18789
- return {
18790
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
18791
- message: this.GetMultilanguageText("UnknownOrInvalidChargeTransparencyRecord"),
18792
- certainty: 0
18793
- };
18834
+ const processedFile = getFirstArrayElement(processedFiles, "Missing processed file");
18835
+ if (IsAChargeTransparencyRecord(processedFile.result))
18836
+ return this.processChargeTransparencyRecord(processedFile.result);
18837
+ if (IsAChargeTransparencyLiveLink(processedFile.result))
18794
18838
  return processedFile.result;
18795
- }
18796
- return {
18797
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
18798
- message: this.GetMultilanguageText("UnknownOrInvalidChargeTransparencyRecord"),
18799
- certainty: 0
18800
- };
18839
+ if (IsAPublicKeyLookup(processedFile.result))
18840
+ return {
18841
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
18842
+ message: this.GetMultilanguageText("UnknownOrInvalidChargeTransparencyRecord"),
18843
+ certainty: 0
18844
+ };
18845
+ return processedFile.result;
18801
18846
  } else if (processedFiles.length > 1) {
18802
18847
  const mergedCTR = {
18803
18848
  "@id": "",
@@ -18811,14 +18856,12 @@ var Chargy = class {
18811
18856
  mergedCTR["@id"] = processedFileResult["@id"];
18812
18857
  if (mergedCTR["@context"] === "")
18813
18858
  mergedCTR["@context"] = processedFileResult["@context"];
18814
- if (!mergedCTR.begin || mergedCTR.begin && processedFileResult.begin && mergedCTR.begin > processedFileResult.begin)
18859
+ if (processedFileResult.begin != null && processedFileResult.begin.length > 0 && (mergedCTR.begin == null || mergedCTR.begin.length === 0 || mergedCTR.begin > processedFileResult.begin))
18815
18860
  mergedCTR.begin = processedFileResult.begin;
18816
- if (!mergedCTR.end || mergedCTR.end && processedFileResult.end && mergedCTR.end < processedFileResult.end)
18861
+ if (processedFileResult.end != null && processedFileResult.end.length > 0 && (mergedCTR.end == null || mergedCTR.end.length === 0 || mergedCTR.end < processedFileResult.end))
18817
18862
  mergedCTR.end = processedFileResult.end;
18818
- if (!mergedCTR.description)
18819
- mergedCTR.description = processedFileResult.description;
18820
- if (!mergedCTR.contract)
18821
- mergedCTR.contract = processedFileResult.contract;
18863
+ mergedCTR.description ??= processedFileResult.description;
18864
+ mergedCTR.contract ??= processedFileResult.contract;
18822
18865
  if (!mergedCTR.chargingStationOperators)
18823
18866
  mergedCTR.chargingStationOperators = processedFileResult.chargingStationOperators;
18824
18867
  else if (processedFileResult.chargingStationOperators)
@@ -18850,17 +18893,14 @@ var Chargy = class {
18850
18893
  for (const mediationService of processedFileResult.mediationServices)
18851
18894
  mergedCTR.mediationServices.push(mediationService);
18852
18895
  } else if (IsAPublicKeyInfo(processedFileResult)) {
18853
- if (!mergedCTR.publicKeys)
18854
- mergedCTR.publicKeys = new Array();
18896
+ mergedCTR.publicKeys ??= new Array();
18855
18897
  mergedCTR.publicKeys.push(processedFileResult);
18856
18898
  } else if (IsAPublicKeyLookup(processedFileResult)) {
18857
- if (!mergedCTR.publicKeys)
18858
- mergedCTR.publicKeys = new Array();
18899
+ mergedCTR.publicKeys ??= new Array();
18859
18900
  for (const publicKey of processedFileResult.publicKeys)
18860
18901
  mergedCTR.publicKeys.push(publicKey);
18861
18902
  } else {
18862
- if (mergedCTR.invalidDataSets === void 0)
18863
- mergedCTR.invalidDataSets = new Array();
18903
+ mergedCTR.invalidDataSets ??= new Array();
18864
18904
  mergedCTR.invalidDataSets.push(processedFile);
18865
18905
  }
18866
18906
  }
@@ -18888,8 +18928,6 @@ var Chargy = class {
18888
18928
  this.EVSEs = [];
18889
18929
  this.meters = [];
18890
18930
  this.chargingSessions = [];
18891
- this.eMobilityProviders = [];
18892
- this.mediationServices = [];
18893
18931
  try {
18894
18932
  this.internalCTR = CloneCTR(CTR);
18895
18933
  this.currentCTR = CTR;
@@ -19016,9 +19054,9 @@ var Chargy = class {
19016
19054
  if (measurement.name !== "ENERGY_TOTAL" || measurement.values.length < 2) {
19017
19055
  continue;
19018
19056
  }
19019
- const firstValue2 = measurement.values[0];
19020
- const lastValue = measurement.values[measurement.values.length - 1];
19021
- if (firstValue2 == null || lastValue == null) {
19057
+ const firstValue2 = measurement.values.at(0);
19058
+ const lastValue = measurement.values.at(-1);
19059
+ if (firstValue2 === void 0 || lastValue === void 0) {
19022
19060
  continue;
19023
19061
  }
19024
19062
  const firstValueKWh = this.measurementValueInKWh(measurement, firstValue2);
@@ -19167,14 +19205,12 @@ var Chargy = class {
19167
19205
  mergedCTR["@id"] = ctr["@id"];
19168
19206
  if (mergedCTR["@context"] === "")
19169
19207
  mergedCTR["@context"] = ctr["@context"];
19170
- if (!mergedCTR.begin || mergedCTR.begin && ctr.begin && mergedCTR.begin > ctr.begin)
19208
+ if (ctr.begin != null && ctr.begin.length > 0 && (mergedCTR.begin == null || mergedCTR.begin.length === 0 || mergedCTR.begin > ctr.begin))
19171
19209
  mergedCTR.begin = ctr.begin;
19172
- if (!mergedCTR.end || mergedCTR.end && ctr.end && mergedCTR.end < ctr.end)
19210
+ if (ctr.end != null && ctr.end.length > 0 && (mergedCTR.end == null || mergedCTR.end.length === 0 || mergedCTR.end < ctr.end))
19173
19211
  mergedCTR.end = ctr.end;
19174
- if (!mergedCTR.description)
19175
- mergedCTR.description = ctr.description;
19176
- if (!mergedCTR.contract)
19177
- mergedCTR.contract = ctr.contract;
19212
+ mergedCTR.description ??= ctr.description;
19213
+ mergedCTR.contract ??= ctr.contract;
19178
19214
  if (!mergedCTR.chargingStationOperators)
19179
19215
  mergedCTR.chargingStationOperators = ctr.chargingStationOperators;
19180
19216
  else if (ctr.chargingStationOperators)
@@ -19235,6 +19271,6 @@ buffer/index.js:
19235
19271
  *)
19236
19272
  */
19237
19273
 
19238
- 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 };
19274
+ 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 };
19239
19275
  //# sourceMappingURL=index.js.map
19240
19276
  //# sourceMappingURL=index.js.map