tirecheck-device-sdk 0.2.65 → 0.2.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -221,6 +221,14 @@ const bridgeTools = {
221
221
  hexToDecimalArray(hex) {
222
222
  return hex.match(/.{1,2}/g)?.map((byte) => Number.parseInt(byte, 16)) || [];
223
223
  },
224
+ /** Combine little-endian bytes (low byte first) into a single integer. */
225
+ bytesToInt(bytes) {
226
+ return bytes.reduce((acc, byte, index) => acc + ((byte || 0) << 8 * index), 0);
227
+ },
228
+ /** Split an integer into `byteCount` little-endian bytes (low byte first). */
229
+ intToBytes(value, byteCount) {
230
+ return Array.from({ length: byteCount }, (_unused, index) => value >> 8 * index & 255);
231
+ },
224
232
  getFwVersion(payload) {
225
233
  if (payload?.length !== 3) {
226
234
  console.warn("Could not process FwVersion ", payload);
@@ -239,9 +247,7 @@ const bridgeTools = {
239
247
  },
240
248
  convertBarToKpaByte(deviceId, value) {
241
249
  if (!value) return 0;
242
- const deviceData = getBridgeFromStore(deviceId);
243
- if (!deviceData) throw new Error(`Cannot convert bar to kpa byte, no device data found: ${deviceId}`);
244
- const bitValue = deviceData.name.includes("030717") ? 6.7 : 5.0625;
250
+ const bitValue = this.usesKpaPressure(deviceId) ? 1 : 5.0625;
245
251
  return _.round((value + 1) * 100 / bitValue);
246
252
  },
247
253
  convertSensorIdForBridge(sensorId) {
@@ -264,9 +270,7 @@ const bridgeTools = {
264
270
  if (!_.isNumber(value)) {
265
271
  throw new TypeError("Value has to be a number");
266
272
  }
267
- const deviceData = getBridgeFromStore(deviceId);
268
- if (!deviceData) throw new Error(`Cannot convert kpa byte to bar, no device data found: ${deviceId}`);
269
- const bitValue = deviceData.name.includes("030717") ? 6.7 : 5.0625;
273
+ const bitValue = this.usesKpaPressure(deviceId) ? 1 : 5.0625;
270
274
  const rawBar = value * bitValue / 100;
271
275
  return _.round(Math.max(rawBar - decrementValue, 0), 1);
272
276
  },
@@ -280,6 +284,9 @@ const bridgeTools = {
280
284
  }
281
285
  return false;
282
286
  },
287
+ usesKpaPressure(deviceId) {
288
+ return this.isVersionGreaterThan(deviceId, "1.1.F");
289
+ },
283
290
  convertSensorIdFromBridge(sensorId) {
284
291
  if (sensorId.startsWith("B")) {
285
292
  return Number.parseInt(sensorId, 16).toString();
@@ -1259,6 +1266,78 @@ const bridgeCommandStructures = {
1259
1266
  }
1260
1267
  }
1261
1268
  },
1269
+ /**
1270
+ * kPa per-axle pressure layout used from FW 1.2.0 onwards (same sub-command 0x30 as `pressuresPerAxle`).
1271
+ * Each axle packs the same three values (set; min; max) but every value is a 2-byte little-endian raw kPa
1272
+ * uint16 (no 5.0625 bit scaling), so each axle is 6 bytes instead of 3. Selected at runtime via
1273
+ * `bridgeTools.usesKpaPressure(deviceId)`.
1274
+ */
1275
+ pressuresPerAxleKpa: {
1276
+ id: [98, 48],
1277
+ name: "pressuresPerAxleKpa",
1278
+ structure: {
1279
+ axle01: {
1280
+ size: 6,
1281
+ description: "Axle 01 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1282
+ },
1283
+ axle02: {
1284
+ size: 6,
1285
+ description: "Axle 02 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1286
+ },
1287
+ axle03: {
1288
+ size: 6,
1289
+ description: "Axle 03 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1290
+ },
1291
+ axle04: {
1292
+ size: 6,
1293
+ description: "Axle 04 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1294
+ },
1295
+ axle05: {
1296
+ size: 6,
1297
+ description: "Axle 05 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1298
+ },
1299
+ axle06: {
1300
+ size: 6,
1301
+ description: "Axle 06 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1302
+ },
1303
+ axle07: {
1304
+ size: 6,
1305
+ description: "Axle 07 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1306
+ },
1307
+ axle08: {
1308
+ size: 6,
1309
+ description: "Axle 08 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1310
+ },
1311
+ axle09: {
1312
+ size: 6,
1313
+ description: "Axle 09 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1314
+ },
1315
+ axle10: {
1316
+ size: 6,
1317
+ description: "Axle 10 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1318
+ },
1319
+ axle11: {
1320
+ size: 6,
1321
+ description: "Axle 11 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1322
+ },
1323
+ axle12: {
1324
+ size: 6,
1325
+ description: "Axle 12 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1326
+ },
1327
+ axle13: {
1328
+ size: 6,
1329
+ description: "Axle 13 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1330
+ },
1331
+ axle14: {
1332
+ size: 6,
1333
+ description: "Axle 14 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1334
+ },
1335
+ axle15: {
1336
+ size: 6,
1337
+ description: "Axle 15 set pressure; min pressure; max pressure (2-byte little-endian kPa values)"
1338
+ }
1339
+ }
1340
+ },
1262
1341
  autolearnSettings: {
1263
1342
  id: [98, 160],
1264
1343
  name: "autolearnSettings",
@@ -1564,6 +1643,95 @@ const bridgeCommandStructures = {
1564
1643
  version: "1.0.3"
1565
1644
  }
1566
1645
  }
1646
+ },
1647
+ idsPerWheel: {
1648
+ // base sub-command id, the actual axle is addressed via `0x20 + axleIndex` (0x20 - 0x2F)
1649
+ id: [98, 32],
1650
+ name: "idsPerWheel",
1651
+ structure: {
1652
+ wheel01: {
1653
+ size: 4,
1654
+ description: "Wheel 01 sensor ID (4-byte, little-endian)"
1655
+ },
1656
+ wheel02: {
1657
+ size: 4,
1658
+ description: "Wheel 02 sensor ID (4-byte, little-endian)"
1659
+ },
1660
+ wheel03: {
1661
+ size: 4,
1662
+ description: "Wheel 03 sensor ID (4-byte, little-endian)"
1663
+ },
1664
+ wheel04: {
1665
+ size: 4,
1666
+ description: "Wheel 04 sensor ID (4-byte, little-endian)"
1667
+ },
1668
+ wheel05: {
1669
+ size: 4,
1670
+ description: "Wheel 05 sensor ID (4-byte, little-endian)"
1671
+ },
1672
+ wheel06: {
1673
+ size: 4,
1674
+ description: "Wheel 06 sensor ID (4-byte, little-endian), left-outer position"
1675
+ },
1676
+ wheel07: {
1677
+ size: 4,
1678
+ description: "Wheel 07 sensor ID (4-byte, little-endian), left-inner position"
1679
+ },
1680
+ wheel08: {
1681
+ size: 4,
1682
+ description: "Wheel 08 sensor ID (4-byte, little-endian), center / spare position"
1683
+ },
1684
+ wheel09: {
1685
+ size: 4,
1686
+ description: "Wheel 09 sensor ID (4-byte, little-endian), right-inner position"
1687
+ },
1688
+ wheel10: {
1689
+ size: 4,
1690
+ description: "Wheel 10 sensor ID (4-byte, little-endian), right-outer position"
1691
+ },
1692
+ wheel11: {
1693
+ size: 4,
1694
+ description: "Wheel 11 sensor ID (4-byte, little-endian)"
1695
+ },
1696
+ wheel12: {
1697
+ size: 4,
1698
+ description: "Wheel 12 sensor ID (4-byte, little-endian)"
1699
+ },
1700
+ wheel13: {
1701
+ size: 4,
1702
+ description: "Wheel 13 sensor ID (4-byte, little-endian)"
1703
+ },
1704
+ wheel14: {
1705
+ size: 4,
1706
+ description: "Wheel 14 sensor ID (4-byte, little-endian)"
1707
+ },
1708
+ wheel15: {
1709
+ size: 4,
1710
+ description: "Wheel 15 sensor ID (4-byte, little-endian)"
1711
+ }
1712
+ }
1713
+ },
1714
+ firmwareVersion: {
1715
+ id: [98, 144],
1716
+ name: "firmwareVersion",
1717
+ structure: {
1718
+ bluetoothStackVersion: {
1719
+ size: 20,
1720
+ description: "Bluetooth stack version + bootloader (e.g. BT stack 4.0.0.191)"
1721
+ },
1722
+ configurationDataVersion: {
1723
+ size: 4,
1724
+ description: "Configuration data version"
1725
+ },
1726
+ bleChipFwCompilationDate: {
1727
+ size: 7,
1728
+ description: "BLE chip FW compilation date: second, minute, hour, day, month, year (2-byte, big-endian)"
1729
+ },
1730
+ bluetoothChipFwVersion: {
1731
+ size: 4,
1732
+ description: "Bluetooth chip FW version: major.minor.patch + release type (e.g. 1.2.0 Release)"
1733
+ }
1734
+ }
1567
1735
  }
1568
1736
  };
1569
1737
 
@@ -1973,12 +2141,13 @@ const bridgeCommands = {
1973
2141
  );
1974
2142
  return await this.writeCommand(deviceData, commandIds$1.writeData, subCommandIds.autolearnIdStatus, payload);
1975
2143
  },
1976
- async getAutolearnUnknownSensors(device) {
1977
- const result = await this.readCommand(device, subCommandIds.autolearnUnknownSensors);
2144
+ async getAutolearnUnknownSensors(deviceId) {
2145
+ const deviceData = bridgeTools.getBridgeFromStore(deviceId);
2146
+ const result = await this.readCommand(deviceData, subCommandIds.autolearnUnknownSensors);
1978
2147
  const structurized = bridgeTools.convertBytesToStructure(
1979
2148
  bridgeCommandStructures.autolearnUnknownSensors.structure,
1980
2149
  result.data,
1981
- device.advertisingData.fwVersion
2150
+ deviceData.advertisingData.fwVersion
1982
2151
  );
1983
2152
  return { ...structurized, isFactory: result.isFactory };
1984
2153
  },
@@ -2002,8 +2171,9 @@ const bridgeCommands = {
2002
2171
  async getPressuresPerAxle(deviceId) {
2003
2172
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
2004
2173
  const result = await this.readCommand(deviceData, subCommandIds.pressurePerAxle);
2174
+ const structure = bridgeTools.usesKpaPressure(deviceId) ? bridgeCommandStructures.pressuresPerAxleKpa.structure : bridgeCommandStructures.pressuresPerAxle.structure;
2005
2175
  const structurizedData = bridgeTools.convertBytesToStructure(
2006
- bridgeCommandStructures.pressuresPerAxle.structure,
2176
+ structure,
2007
2177
  result.data,
2008
2178
  deviceData.advertisingData.fwVersion
2009
2179
  );
@@ -2011,8 +2181,9 @@ const bridgeCommands = {
2011
2181
  },
2012
2182
  async setPressuresPerAxle(deviceId, structurizedPayload) {
2013
2183
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
2184
+ const structure = bridgeTools.usesKpaPressure(deviceId) ? bridgeCommandStructures.pressuresPerAxleKpa.structure : bridgeCommandStructures.pressuresPerAxle.structure;
2014
2185
  const payload = bridgeTools.convertStructureToBytes(
2015
- bridgeCommandStructures.pressuresPerAxle.structure,
2186
+ structure,
2016
2187
  structurizedPayload,
2017
2188
  deviceData.advertisingData.fwVersion
2018
2189
  );
@@ -2049,6 +2220,18 @@ const bridgeCommands = {
2049
2220
  );
2050
2221
  return structurizedData;
2051
2222
  },
2223
+ async getFirmwareVersion(deviceId) {
2224
+ const deviceData = bridgeTools.getBridgeFromStore(deviceId);
2225
+ const result = await this.readCommand(deviceData, subCommandIds.firmwareVersion, {
2226
+ headerLength: 5,
2227
+ footerLength: 0
2228
+ });
2229
+ return bridgeTools.convertBytesToStructure(
2230
+ bridgeCommandStructures.firmwareVersion.structure,
2231
+ result.data,
2232
+ deviceData.advertisingData.fwVersion
2233
+ );
2234
+ },
2052
2235
  async getSensorMeasurement(deviceId, positionId) {
2053
2236
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
2054
2237
  const isSpare = String(positionId).endsWith("0");
@@ -2062,7 +2245,7 @@ const bridgeCommands = {
2062
2245
  const result = await this.writeCommand(deviceData, commandIds$1.sensorMeasurement, subCommandId, []);
2063
2246
  return result;
2064
2247
  },
2065
- async readCommand(device, subCommandId) {
2248
+ async readCommand(device, subCommandId, { headerLength = 19, footerLength = 8 } = {}) {
2066
2249
  const commandLength = 2;
2067
2250
  const result = await this.promisify(device, [
2068
2251
  ...this.getCommandHeader(device),
@@ -2070,9 +2253,9 @@ const bridgeCommands = {
2070
2253
  commandIds$1.readData,
2071
2254
  subCommandId
2072
2255
  ]);
2073
- const data = result.slice(19, result.length - 8);
2074
- const crc = result.slice(result.length - 8, result.length - 4);
2075
- const isFactory = crc.every((n) => n === 0);
2256
+ const data = result.slice(headerLength, result.length - footerLength);
2257
+ const crc = result.slice(result.length - footerLength, result.length - footerLength + 4);
2258
+ const isFactory = crc.length === 4 && crc.every((n) => n === 0);
2076
2259
  return { data, isFactory };
2077
2260
  },
2078
2261
  async writeCommand(device, commandId, subCommandId, payload) {
@@ -2209,7 +2392,7 @@ async function setVehicleLayout(deviceId, tcVehicle) {
2209
2392
  }
2210
2393
  await bridgeCommands.setVehicleLayout(deviceId, result);
2211
2394
  }
2212
- async function getConfiguration(deviceId) {
2395
+ async function getConfiguration(deviceId, includeVehicleData = false) {
2213
2396
  const customerCANSettings = await bridgeCommands.getCustomerCANSettings(deviceId);
2214
2397
  const workshopCANSettings = await bridgeCommands.getWorkshopCANSettings(deviceId);
2215
2398
  const customerPressureThresholds = await bridgeCommands.getCustomerPressureThresholds(deviceId);
@@ -2220,7 +2403,7 @@ async function getConfiguration(deviceId) {
2220
2403
  if (bridgeTools.isVersionGreaterThan(deviceId, "0.9.7")) {
2221
2404
  autolearnSettings = await bridgeCommands.getAutolearnSettings(deviceId);
2222
2405
  }
2223
- return {
2406
+ const configuration = {
2224
2407
  customerCANSettings,
2225
2408
  workshopCANSettings,
2226
2409
  customerPressureThresholds,
@@ -2229,6 +2412,24 @@ async function getConfiguration(deviceId) {
2229
2412
  pressuresPerAxle,
2230
2413
  autolearnSettings
2231
2414
  };
2415
+ if (includeVehicleData) {
2416
+ configuration.vehicleLayout = await bridgeCommands.getVehicleLayout(deviceId);
2417
+ configuration.axleInfo = [];
2418
+ for (let axleIndex = 0; axleIndex < 15; axleIndex++) {
2419
+ const axleBytes = await bridgeCommands.getAxleInfo(deviceId, axleIndex);
2420
+ configuration.axleInfo.push(
2421
+ bridgeTools.convertBytesToStructure(bridgeCommandStructures.idsPerWheel.structure, axleBytes)
2422
+ );
2423
+ }
2424
+ if (bridgeTools.isVersionGreaterThan(deviceId, "1.1.F")) {
2425
+ configuration.firmwareVersion = await bridgeCommands.getFirmwareVersion(deviceId);
2426
+ }
2427
+ if (bridgeTools.isVersionGreaterThan(deviceId, "0.9.7")) {
2428
+ configuration.autolearnIdStatus = await bridgeCommands.getAutolearnIdStatus(deviceId);
2429
+ configuration.autolearnUnknownSensors = await bridgeCommands.getAutolearnUnknownSensors(deviceId);
2430
+ }
2431
+ }
2432
+ return configuration;
2232
2433
  }
2233
2434
  function bridgeVehiclesDifference(original, change) {
2234
2435
  const differences = [];
@@ -2397,6 +2598,8 @@ async function setAxleInfo(deviceId, tcVehicle) {
2397
2598
  async function setAxlesPressure(deviceId, axles) {
2398
2599
  let data = [];
2399
2600
  let bridgeAxlesPressureData;
2601
+ const width = bridgeTools.usesKpaPressure(deviceId) ? 2 : 1;
2602
+ const maxFallback = width === 2 ? 65535 : 255;
2400
2603
  for (let index = 0; index < 15; index++) {
2401
2604
  let { targetPressure, maxTargetPressure, minTargetPressure, isSpare } = axles[index] || {};
2402
2605
  maxTargetPressure = bridgeTools.convertBarToKpaByte(deviceId, maxTargetPressure);
@@ -2410,14 +2613,19 @@ async function setAxlesPressure(deviceId, axles) {
2410
2613
  if (!bridgeAxlesPressureData) {
2411
2614
  bridgeAxlesPressureData = await bridgeCommands.getAxlesPressure(deviceId);
2412
2615
  }
2413
- maxTargetPressure = bridgeAxlesPressureData.data[index * 3] || 255;
2616
+ const base = index * width * 3;
2617
+ maxTargetPressure = bridgeTools.bytesToInt(bridgeAxlesPressureData.data.slice(base, base + width)) || maxFallback;
2414
2618
  }
2415
2619
  if (targetPressure > maxTargetPressure) {
2416
2620
  targetPressure = maxTargetPressure;
2417
2621
  } else if (targetPressure < minTargetPressure) {
2418
2622
  targetPressure = minTargetPressure;
2419
2623
  }
2420
- data = data.concat([maxTargetPressure, minTargetPressure, targetPressure]);
2624
+ data = data.concat([
2625
+ ...bridgeTools.intToBytes(maxTargetPressure, width),
2626
+ ...bridgeTools.intToBytes(minTargetPressure, width),
2627
+ ...bridgeTools.intToBytes(targetPressure, width)
2628
+ ]);
2421
2629
  }
2422
2630
  await bridgeCommands.setAxlesPressure(deviceId, data);
2423
2631
  }
@@ -2764,21 +2972,20 @@ async function assignTyres(deviceId, tcVehicle) {
2764
2972
  }
2765
2973
  async function assignAxlePressureLimits(deviceId, tcVehicle, tcVehicleAxle, axleIndex, bridgeAxlesPressureData) {
2766
2974
  const axlesPressureData = bridgeAxlesPressureData ?? (await bridgeCommands.getAxlesPressure(deviceId)).data;
2767
- if (axlesPressureData[axleIndex * 3]) {
2768
- tcVehicleAxle.maxTargetPressure = _.floor(
2769
- bridgeTools.convertKpaByteToBar(deviceId, axlesPressureData[axleIndex * 3]),
2770
- 1
2771
- );
2975
+ const width = bridgeTools.usesKpaPressure(deviceId) ? 2 : 1;
2976
+ const base = axleIndex * width * 3;
2977
+ const maxRaw = bridgeTools.bytesToInt(axlesPressureData.slice(base, base + width));
2978
+ const minRaw = bridgeTools.bytesToInt(axlesPressureData.slice(base + width, base + width * 2));
2979
+ const setRaw = bridgeTools.bytesToInt(axlesPressureData.slice(base + width * 2, base + width * 3));
2980
+ if (maxRaw) {
2981
+ tcVehicleAxle.maxTargetPressure = _.floor(bridgeTools.convertKpaByteToBar(deviceId, maxRaw), 1);
2772
2982
  }
2773
- if (axlesPressureData[axleIndex * 3 + 1]) {
2774
- tcVehicleAxle.minTargetPressure = _.ceil(
2775
- bridgeTools.convertKpaByteToBar(deviceId, axlesPressureData[axleIndex * 3 + 1]),
2776
- 1
2777
- );
2983
+ if (minRaw) {
2984
+ tcVehicleAxle.minTargetPressure = _.ceil(bridgeTools.convertKpaByteToBar(deviceId, minRaw), 1);
2778
2985
  }
2779
- if (axlesPressureData[axleIndex * 3 + 2]) {
2986
+ if (setRaw) {
2780
2987
  tcVehicleAxle.targetPressure = _.round(
2781
- bridgeTools.convertKpaByteToBar(deviceId, axlesPressureData[axleIndex * 3 + 2], void 0),
2988
+ bridgeTools.convertKpaByteToBar(deviceId, setRaw, void 0),
2782
2989
  1
2783
2990
  );
2784
2991
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tirecheck-device-sdk",
3
- "version": "0.2.65",
3
+ "version": "0.2.67",
4
4
  "description": "SDK for working with various devices produced by Tirecheck via Bluetooth (CAN Bridge, Routers, Sensors, FlexiGauge, PressureStick, etc)",
5
5
  "author": "Leonid Buneev <leonid.buneev@tirecheck.com>",
6
6
  "license": "ISC",