node-red-zelecproto 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/645.js +42 -7
  2. package/698.js +44 -0
  3. package/package.json +1 -1
package/645.js CHANGED
@@ -755,6 +755,9 @@ function decode645(_msg) {
755
755
  unit: 'V',
756
756
  description: `${di === '02800008' ? '时钟电池电压' : '停电抄表电池电压'}: ${v.toFixed(2)}V`
757
757
  };
758
+ } else if (di === '0280000A' && arrPush.length >= 8) {
759
+ // 0280000A: 内部电池工作时间,4字节,单位分
760
+ value = bytesToIntBE(arrPush.slice(-4).reverse());
758
761
  } else if (di === '0400040A' && arrPush.length >= 7) {
759
762
  // 无功脉冲常数:DI(4) + N3(3字节BCD,小端)
760
763
  const dataBytes = arrPush.slice(4, 7); // LE:低字节在前
@@ -768,13 +771,7 @@ function decode645(_msg) {
768
771
  } else if (di === '03300D01' && arrPush.length >= 16) {
769
772
  value = parseCoverOpenLast645(arrPush);
770
773
  } else {
771
- // 未匹配的DI,返回去偏移(−0x33)后的原始数据,便于排查/厂商私有解析
772
- value = {
773
- rawMinus33: bytesToHex(arrPush).replace(/\s+/g, ''), // 含DI(4B) + 数据
774
- di,
775
- data: bytesToHex(arrPush.slice(4)).replace(/\s+/g, ''), // 纯数据部分(不含DI)
776
- note: '未识别DI,已返回去0x33的原始数据'
777
- };
774
+ value = parseGeneric645Data(di, arrPush);
778
775
  }
779
776
  } catch (e) {
780
777
  return Object.assign(result, { ok: false, reason: 'decode_exception', exec_addr, di, ctrl, len, raw: put, err: String(e) });
@@ -888,6 +885,44 @@ function bcdDigitsStrLE(bytes) {
888
885
  return s;
889
886
  }
890
887
 
888
+ function parseGeneric645Data(di, arrPush) {
889
+ const dataBytes = Array.from(arrPush.slice(4));
890
+ const dataHex = bytesToHex(dataBytes).replace(/\s+/g, '');
891
+ const result = {
892
+ rawMinus33: bytesToHex(arrPush).replace(/\s+/g, ''),
893
+ di,
894
+ data: dataHex,
895
+ length: dataBytes.length,
896
+ note: '未识别DI,已按通用格式解析候选值'
897
+ };
898
+
899
+ if (dataBytes.length === 0) return result;
900
+
901
+ result.uintLE = bytesToUInt(dataBytes, true);
902
+ result.uintBE = bytesToUInt(dataBytes, false);
903
+
904
+ try {
905
+ result.bcdLE = bcdLEToInt(dataBytes);
906
+ result.bcdText = bcdDigitsStrLE(dataBytes);
907
+ } catch (_) {
908
+ result.bcdLE = null;
909
+ }
910
+
911
+ if (dataBytes.every(b => b >= 0x20 && b <= 0x7E)) {
912
+ result.ascii = Buffer.from(dataBytes).toString('ascii');
913
+ }
914
+
915
+ return result;
916
+ }
917
+
918
+ function bytesToUInt(bytes, littleEndian) {
919
+ if (!bytes || bytes.length === 0) return null;
920
+ const arr = littleEndian ? bytes.slice().reverse() : bytes;
921
+ const hex = Buffer.from(arr).toString('hex') || '0';
922
+ const value = BigInt(`0x${hex}`);
923
+ return value <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(value) : value.toString();
924
+ }
925
+
891
926
 
892
927
  // === 开盖明细专用工具 ===
893
928
 
package/698.js CHANGED
@@ -140,6 +140,7 @@ const OAD_CATEGORIES = {
140
140
  BATTERY_VOLTAGE: {
141
141
  "CLOCK_BATTERY_VOLTAGE": { oad: "20110200", desc: "时钟电池电压", type: "double-long-unsigned", unit: "V", scale: -2 },
142
142
  "POWER_DOWN_READING_BATTERY_VOLTAGE": { oad: "20120200", desc: "停电抄表电池电压", type: "double-long-unsigned", unit: "V", scale: -2 },
143
+ "CLOCK_BATTERY_WORK_TIME": { oad: "20130200", desc: "时钟电池工作时间", type: "double-long-unsigned", unit: "min", scale: 0 },
143
144
  },
144
145
  FREEZE_DATA: {
145
146
  "DAILY_FREEZE": { oad: "50040200", desc: "日冻结", requestType: "record" },
@@ -1781,6 +1782,48 @@ function parseBatteryVoltage(dataBuffer, oad) {
1781
1782
  return result;
1782
1783
  }
1783
1784
 
1785
+ /**
1786
+ * 解析时钟电池工作时间(分钟)
1787
+ * @param {Buffer} dataBuffer - 数据缓冲区
1788
+ * @param {string} oad - OAD标识
1789
+ * @returns {Object} 解析结果
1790
+ */
1791
+ function parseClockBatteryWorkTime(dataBuffer, oad) {
1792
+ const oadInfo = getOADInfo(oad);
1793
+ const result = createStandardResult(oadInfo ? oadInfo.desc : "时钟电池工作时间", oad, dataBuffer);
1794
+
1795
+ try {
1796
+ const { result: genericResult } = enhancedParseData(dataBuffer, oad.slice(0, 4), oad.slice(4, 6));
1797
+
1798
+ if (genericResult.dataType !== '双长无符号整数' || typeof genericResult.parsedValue !== 'number') {
1799
+ throw new Error(`时钟电池工作时间数据格式不正确: ${genericResult.dataType}`);
1800
+ }
1801
+
1802
+ const rawMinutes = genericResult.parsedValue;
1803
+ result.value = rawMinutes;
1804
+
1805
+ setSuccessResult(result, [{
1806
+ type: oadInfo ? oadInfo.desc : "时钟电池工作时间",
1807
+ rawValue: rawMinutes,
1808
+ minutes: rawMinutes,
1809
+ workMinutes: rawMinutes,
1810
+ clock_battery_work_min: rawMinutes,
1811
+ unit: "min",
1812
+ description: `${oadInfo ? oadInfo.desc : "时钟电池工作时间"} ${rawMinutes}分钟`
1813
+ }], {
1814
+ unit: "min",
1815
+ scale: 0,
1816
+ count: 1,
1817
+ generic: genericResult
1818
+ });
1819
+
1820
+ } catch (e) {
1821
+ setErrorResult(result, e.message);
1822
+ }
1823
+
1824
+ return result;
1825
+ }
1826
+
1784
1827
  function parseEnergyData(dataBuffer, oad) {
1785
1828
  const result = createStandardResult("电能数据", oad, dataBuffer);
1786
1829
  try {
@@ -2277,6 +2320,7 @@ function oadParserRouter(payload, oad) {
2277
2320
  if (oad === '40070205') return parseLCDDecimalDigits(payload); //抄读当前组合有功电能数据块
2278
2321
  if (oad === '20110200') return parseBatteryVoltage(payload, oad); // 时钟电池电压
2279
2322
  if (oad === '20120200') return parseBatteryVoltage(payload, oad); // 停电抄表电池电压
2323
+ if (oad === '20130200') return parseClockBatteryWorkTime(payload, oad); // 时钟电池工作时间
2280
2324
  // 通用兜底
2281
2325
  const oadInfo = getOADInfo(oad) || { desc: "通用数据" };
2282
2326
  const genericStdResult = createStandardResult(oadInfo.desc, oad, payload);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-zelecproto",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "node-red zelecproto node",
5
5
  "main": "index.js",
6
6
  "scripts": {