tirecheck-device-sdk 0.2.21 → 0.2.23

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
@@ -40,6 +40,8 @@ const store = {
40
40
  // undefined => connecting => connected => paired => disconnecting => undefined
41
41
  /** some bridge commands require bridge reboot to be completed */
42
42
  bridgeRebootRequired: {},
43
+ /** Torque wrench properties, about device settings, mainly used for unit conversion */
44
+ torqueWrenchProperties: {},
43
45
  //** Ios uses generated device Id, bridges send mac address in advertising so internaly we always use mac address but when real device id is needed we check mapping table for it */
44
46
  deviceIdMapingTable: {},
45
47
  /** Used to change device state in store, also notifies app via calback. Every undefined state should have its reason so that app can handle it accordingly */
@@ -97,6 +99,10 @@ function stringToArrayBuffer(string) {
97
99
  }
98
100
  return array.buffer;
99
101
  }
102
+ function decimalToHex(decimal, padStart = 2) {
103
+ const hex = decimal.toString(16);
104
+ return hex.padStart(padStart, "0");
105
+ }
100
106
  const toolsSvc = {
101
107
  delay,
102
108
  setIntervalImmediate,
@@ -511,8 +517,26 @@ const deviceMeta = {
511
517
  },
512
518
  getDeviceInfoFromAdvertising: bridgeOtaAdvertisingParser.getDeviceInfoFromAdvertising
513
519
  },
520
+ // flexiGauge: {
521
+ // nameRegex: /^Flexi.*v.*/,
522
+ // communication: {
523
+ // serviceId: '4880c12c-fdcb-4077-8920-a450d7f9b907',
524
+ // characteristicId: 'fec26ec4-6d71-4442-9f81-55bc21d658d6',
525
+ // },
526
+ // battery: {
527
+ // serviceId: '180f',
528
+ // characteristicId: '2a19',
529
+ // },
530
+ // getDeviceInfoFromAdvertising: (device: PeripheralData) => {
531
+ // const bleDevice: BleDevice = {
532
+ // ...device,
533
+ // type: 'flexiGauge',
534
+ // }
535
+ // return bleDevice
536
+ // },
537
+ // },
514
538
  flexiGaugeTpms: {
515
- nameRegex: /^Flexi.*/,
539
+ nameRegex: /^Flexi.*TPMS.*/,
516
540
  communication: {
517
541
  serviceId: "4880c12c-fdcb-4077-8920-a450d7f9b907",
518
542
  characteristicId: "fec26ec4-6d71-4442-9f81-55bc21d658d6"
@@ -527,9 +551,7 @@ const deviceMeta = {
527
551
  type: "flexiGaugeTpms"
528
552
  };
529
553
  return bleDevice;
530
- },
531
- reconnect: true
532
- // Do we need it here?
554
+ }
533
555
  },
534
556
  pressureStick: {
535
557
  nameRegex: /Pressure Stick.*/,
@@ -544,6 +566,42 @@ const deviceMeta = {
544
566
  };
545
567
  return bleDevice;
546
568
  }
569
+ },
570
+ // ateq: {
571
+ // nameRegex: /ATEQ.*/,
572
+ // communication: {
573
+ // serviceId: 'a002',
574
+ // characteristicId: 'c305',
575
+ // },
576
+ // indicate: {
577
+ // serviceId: 'a002',
578
+ // characteristicId: 'c306',
579
+ // },
580
+ // getDeviceInfoFromAdvertising: (device: PeripheralData) => {
581
+ // const bleDevice: BleDevice = {
582
+ // ...device,
583
+ // type: 'ateq',
584
+ // }
585
+ // return bleDevice
586
+ // },
587
+ // },
588
+ torqueWrench: {
589
+ nameRegex: /^\d+(lbft|NM)-\d+$/i,
590
+ communication: {
591
+ serviceId: "49535343-fe7d-4ae5-8fa9-9fafd205e455",
592
+ characteristicId: "49535343-1e4d-4bd9-ba61-23c647249616"
593
+ },
594
+ battery: {
595
+ serviceId: "180f",
596
+ characteristicId: "2a19"
597
+ },
598
+ getDeviceInfoFromAdvertising: (device) => {
599
+ const bleDevice = {
600
+ ...device,
601
+ type: "torqueWrench"
602
+ };
603
+ return bleDevice;
604
+ }
547
605
  }
548
606
  };
549
607
 
@@ -1517,26 +1575,26 @@ const bridgeSecurity = {
1517
1575
  };
1518
1576
 
1519
1577
  const bridgeMeta = deviceMeta.bridge;
1520
- const devicePromiseQueue = {};
1521
- const deviceCurrentResolve = {};
1522
- const deviceCurrentReject = {};
1523
- const deviceResponseIdentifier = {};
1578
+ const devicePromiseQueue$1 = {};
1579
+ const deviceCurrentResolve$1 = {};
1580
+ const deviceCurrentReject$1 = {};
1581
+ const deviceResponseIdentifier$1 = {};
1524
1582
  const promiseQueue = {
1525
1583
  clearQueue(deviceId, message) {
1526
- if (deviceCurrentReject[deviceId]) {
1527
- deviceCurrentReject[deviceId](new Error(message ?? "Stopped sending commands"));
1584
+ if (deviceCurrentReject$1[deviceId]) {
1585
+ deviceCurrentReject$1[deviceId](new Error(message ?? "Stopped sending commands"));
1528
1586
  }
1529
- devicePromiseQueue[deviceId] = Promise.resolve();
1530
- deviceResponseIdentifier[deviceId] = [];
1587
+ devicePromiseQueue$1[deviceId] = Promise.resolve();
1588
+ deviceResponseIdentifier$1[deviceId] = [];
1531
1589
  },
1532
1590
  async enqueue(device, payload) {
1533
- if (devicePromiseQueue[device.id] === void 0) devicePromiseQueue[device.id] = Promise.resolve();
1534
- devicePromiseQueue[device.id] = devicePromiseQueue[device.id].then(() => {
1591
+ if (devicePromiseQueue$1[device.id] === void 0) devicePromiseQueue$1[device.id] = Promise.resolve();
1592
+ devicePromiseQueue$1[device.id] = devicePromiseQueue$1[device.id].then(() => {
1535
1593
  const promise = new Promise((resolve, reject) => {
1536
- deviceCurrentResolve[device.id] = resolve;
1537
- deviceCurrentReject[device.id] = reject;
1538
- const isKeepAlive = payload[3] === commandIds.keepAlive;
1539
- deviceResponseIdentifier[device.id] = [isKeepAlive ? 126 : 0, payload[4]];
1594
+ deviceCurrentResolve$1[device.id] = resolve;
1595
+ deviceCurrentReject$1[device.id] = reject;
1596
+ const isKeepAlive = payload[3] === commandIds$1.keepAlive;
1597
+ deviceResponseIdentifier$1[device.id] = [isKeepAlive ? 126 : 0, payload[4]];
1540
1598
  const signedData = bridgeSecurity.getSignedCommand(device, payload);
1541
1599
  if (!toolsSvc.canCommunicateWith(device.id)) return reject(new Error("Bridge not connected"));
1542
1600
  if (signedData.length > 110) {
@@ -1562,21 +1620,21 @@ const promiseQueue = {
1562
1620
  );
1563
1621
  }
1564
1622
  });
1565
- return withTimeout(promise, 5e3, `Command timed out ${deviceResponseIdentifier[device.id]}, ${device.id}`);
1623
+ return withTimeout(promise, 5e3, `Command timed out ${deviceResponseIdentifier$1[device.id]}, ${device.id}`);
1566
1624
  });
1567
- return devicePromiseQueue[device.id];
1625
+ return devicePromiseQueue$1[device.id];
1568
1626
  },
1569
1627
  async processMessage(deviceId, payload) {
1570
1628
  const numberArray = Array.from(new Uint8Array(payload));
1571
1629
  if (numberArray[3] === 127) {
1572
1630
  console.error(numberArray);
1573
- return deviceCurrentReject[deviceId](new Error(`Command not succesful: ${numberArray[4]}`));
1631
+ return deviceCurrentReject$1[deviceId](new Error(`Command not succesful: ${numberArray[4]}`));
1574
1632
  }
1575
1633
  if ([226, 81].includes(numberArray[3]) && numberArray[4] && toolsSvc.canCommunicateWith(deviceId)) {
1576
1634
  store.bridgeRebootRequired[deviceId] = true;
1577
1635
  }
1578
- if ((!deviceResponseIdentifier[deviceId][0] || numberArray[3] === deviceResponseIdentifier[deviceId][0]) && (!deviceResponseIdentifier[deviceId][1] || numberArray[4] === deviceResponseIdentifier[deviceId][1])) {
1579
- return deviceCurrentResolve[deviceId](numberArray);
1636
+ if ((!deviceResponseIdentifier$1[deviceId][0] || numberArray[3] === deviceResponseIdentifier$1[deviceId][0]) && (!deviceResponseIdentifier$1[deviceId][1] || numberArray[4] === deviceResponseIdentifier$1[deviceId][1])) {
1637
+ return deviceCurrentResolve$1[deviceId](numberArray);
1580
1638
  }
1581
1639
  console.warn("message from the device not belonging to the pending promise: ", numberArray);
1582
1640
  }
@@ -1593,7 +1651,7 @@ const messageTypeIds = {
1593
1651
  command: 0,
1594
1652
  response: 1
1595
1653
  };
1596
- const commandIds = {
1654
+ const commandIds$1 = {
1597
1655
  readData: 34,
1598
1656
  writeData: 46,
1599
1657
  keepAlive: 62,
@@ -1642,7 +1700,7 @@ const subCommandIds = {
1642
1700
  autolearnIdStatus: 176,
1643
1701
  autolearnUnknownSensors: 192
1644
1702
  };
1645
- _.invert(commandIds);
1703
+ _.invert(commandIds$1);
1646
1704
  _.invert(subCommandIds);
1647
1705
  const keepAliveTimer = {};
1648
1706
  const bridgeCommands = {
@@ -1653,7 +1711,7 @@ const bridgeCommands = {
1653
1711
  },
1654
1712
  async setAxlesPressure(deviceId, data) {
1655
1713
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1656
- await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.pressurePerAxle, data);
1714
+ await this.writeCommand(deviceData, commandIds$1.writeData, subCommandIds.pressurePerAxle, data);
1657
1715
  },
1658
1716
  async setVehicleLayout(deviceId, structurizedPayload) {
1659
1717
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
@@ -1662,7 +1720,7 @@ const bridgeCommands = {
1662
1720
  structurizedPayload,
1663
1721
  deviceData.advertisingData.fwVersion
1664
1722
  );
1665
- await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.vehicleLayout, payload);
1723
+ await this.writeCommand(deviceData, commandIds$1.writeData, subCommandIds.vehicleLayout, payload);
1666
1724
  },
1667
1725
  async getCustomerCANSettings(deviceId) {
1668
1726
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
@@ -1715,18 +1773,18 @@ const bridgeCommands = {
1715
1773
  return { ...structurized, isFactory: result.isFactory };
1716
1774
  },
1717
1775
  async sendKeepAliveCommand(device) {
1718
- return this.promisify(device, [...this.getCommandHeader(device), 2, commandIds.keepAlive, 0]);
1776
+ return this.promisify(device, [...this.getCommandHeader(device), 2, commandIds$1.keepAlive, 0]);
1719
1777
  },
1720
1778
  async sendOtaRequest(deviceId) {
1721
1779
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1722
- const command = [commandIds.otaRequest, 0];
1780
+ const command = [commandIds$1.otaRequest, 0];
1723
1781
  const result = await this.promisify(deviceData, [...this.getCommandHeader(deviceData), command.length, ...command]);
1724
1782
  return result;
1725
1783
  },
1726
1784
  async sendPinCommand(deviceId) {
1727
1785
  const deviceData = await bridgeTools.getBridgeFromStore(deviceId);
1728
1786
  const pin = await bridgeSecurity.getPin(deviceId);
1729
- return this.promisify(deviceData, [...this.getCommandHeader(deviceData), 18, commandIds.pin, 0, ...pin]);
1787
+ return this.promisify(deviceData, [...this.getCommandHeader(deviceData), 18, commandIds$1.pin, 0, ...pin]);
1730
1788
  },
1731
1789
  async setBridgeToRestart(deviceId) {
1732
1790
  if (store.bridgeRebootRequired[deviceId]) return;
@@ -1735,7 +1793,7 @@ const bridgeCommands = {
1735
1793
  await this.promisify(deviceData, [
1736
1794
  ...this.getCommandHeader(deviceData),
1737
1795
  2,
1738
- useNewCommand ? commandIds.ecuReset : commandIds.reboot,
1796
+ useNewCommand ? commandIds$1.ecuReset : commandIds$1.reboot,
1739
1797
  useNewCommand ? subCommandIds.ecuResetSubCommand : subCommandIds.rebootSubCommand
1740
1798
  ]);
1741
1799
  },
@@ -1746,7 +1804,7 @@ const bridgeCommands = {
1746
1804
  structurizedPayload,
1747
1805
  deviceData.advertisingData.fwVersion
1748
1806
  );
1749
- return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.customerCanSettings, payload);
1807
+ return await this.writeCommand(deviceData, commandIds$1.writeData, subCommandIds.customerCanSettings, payload);
1750
1808
  },
1751
1809
  async setWorkshopCANSettings(deviceId, structurizedPayload) {
1752
1810
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
@@ -1755,7 +1813,7 @@ const bridgeCommands = {
1755
1813
  structurizedPayload,
1756
1814
  deviceData.advertisingData.fwVersion
1757
1815
  );
1758
- return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.workshopCanSettings, payload);
1816
+ return await this.writeCommand(deviceData, commandIds$1.writeData, subCommandIds.workshopCanSettings, payload);
1759
1817
  },
1760
1818
  async setCustomerPressureThresholds(deviceId, structurizedPayload) {
1761
1819
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
@@ -1764,7 +1822,7 @@ const bridgeCommands = {
1764
1822
  structurizedPayload,
1765
1823
  deviceData.advertisingData.fwVersion
1766
1824
  );
1767
- return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.customerPressureThresholds, payload);
1825
+ return await this.writeCommand(deviceData, commandIds$1.writeData, subCommandIds.customerPressureThresholds, payload);
1768
1826
  },
1769
1827
  async setCustomerTemperatureThresholds(deviceId, structurizedPayload) {
1770
1828
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
@@ -1775,7 +1833,7 @@ const bridgeCommands = {
1775
1833
  );
1776
1834
  return await this.writeCommand(
1777
1835
  deviceData,
1778
- commandIds.writeData,
1836
+ commandIds$1.writeData,
1779
1837
  subCommandIds.customerTemperatureThresholds,
1780
1838
  payload
1781
1839
  );
@@ -1787,7 +1845,7 @@ const bridgeCommands = {
1787
1845
  structurizedPayload,
1788
1846
  deviceData.advertisingData.fwVersion
1789
1847
  );
1790
- return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.customerImbalanceThresholds, payload);
1848
+ return await this.writeCommand(deviceData, commandIds$1.writeData, subCommandIds.customerImbalanceThresholds, payload);
1791
1849
  },
1792
1850
  async getAutolearnSettings(deviceId) {
1793
1851
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
@@ -1816,7 +1874,7 @@ const bridgeCommands = {
1816
1874
  structurizedPayload,
1817
1875
  deviceData.advertisingData.fwVersion
1818
1876
  );
1819
- return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.autolearnSettings, payload);
1877
+ return await this.writeCommand(deviceData, commandIds$1.writeData, subCommandIds.autolearnSettings, payload);
1820
1878
  },
1821
1879
  async setAutolearnIdStatus(deviceId, structurizedPayload) {
1822
1880
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
@@ -1825,7 +1883,7 @@ const bridgeCommands = {
1825
1883
  structurizedPayload,
1826
1884
  deviceData.advertisingData.fwVersion
1827
1885
  );
1828
- return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.autolearnIdStatus, payload);
1886
+ return await this.writeCommand(deviceData, commandIds$1.writeData, subCommandIds.autolearnIdStatus, payload);
1829
1887
  },
1830
1888
  async getAutolearnUnknownSensors(device) {
1831
1889
  const result = await this.readCommand(device, subCommandIds.autolearnUnknownSensors);
@@ -1846,7 +1904,7 @@ const bridgeCommands = {
1846
1904
  // move logic to bridge svc
1847
1905
  async setAxleInfo(deviceId, axleIndex, data) {
1848
1906
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1849
- await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.idsPerWheel(axleIndex), data);
1907
+ await this.writeCommand(deviceData, commandIds$1.writeData, subCommandIds.idsPerWheel(axleIndex), data);
1850
1908
  },
1851
1909
  async getAxlesPressure(deviceId) {
1852
1910
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
@@ -1870,7 +1928,7 @@ const bridgeCommands = {
1870
1928
  structurizedPayload,
1871
1929
  deviceData.advertisingData.fwVersion
1872
1930
  );
1873
- return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.pressurePerAxle, payload);
1931
+ return await this.writeCommand(deviceData, commandIds$1.writeData, subCommandIds.pressurePerAxle, payload);
1874
1932
  },
1875
1933
  // // async setPressureThresholds(device: BleBridge, rules: any) {
1876
1934
  // // // https://tirecheck.atlassian.net/wiki/spaces/HWPRG/pages/6547767302/Technical+Design+Document+BLE+CAN+Bridge+Krone#Example.1
@@ -1913,7 +1971,7 @@ const bridgeCommands = {
1913
1971
  }
1914
1972
  const result = await this.writeCommand(
1915
1973
  deviceData,
1916
- commandIds.sensorMeasurement,
1974
+ commandIds$1.sensorMeasurement,
1917
1975
  subCommandIds.sensorMeasurementPerWheel(axlePosition, tyrePosition, isTwinTyre, isSpare),
1918
1976
  []
1919
1977
  );
@@ -1924,7 +1982,7 @@ const bridgeCommands = {
1924
1982
  const result = await this.promisify(device, [
1925
1983
  ...this.getCommandHeader(device),
1926
1984
  commandLength,
1927
- commandIds.readData,
1985
+ commandIds$1.readData,
1928
1986
  subCommandId
1929
1987
  ]);
1930
1988
  const data = result.slice(19, result.length - 8);
@@ -2889,6 +2947,342 @@ const pressureStick = {
2889
2947
  onPressure: pressureStickService.onPressure
2890
2948
  };
2891
2949
 
2950
+ const devicePromiseQueue = {};
2951
+ const deviceCurrentResolve = {};
2952
+ const deviceCurrentReject = {};
2953
+ const deviceResponseIdentifier = {};
2954
+ const deviceCurrentPartialMessage = {};
2955
+ const torqueWrenchPromiseQueue = {
2956
+ clearQueue(deviceId, message) {
2957
+ if (deviceCurrentReject[deviceId]) {
2958
+ deviceCurrentReject[deviceId](new Error(message ?? "Stopped sending commands"));
2959
+ }
2960
+ devicePromiseQueue[deviceId] = Promise.resolve();
2961
+ deviceResponseIdentifier[deviceId] = void 0;
2962
+ },
2963
+ async enqueue(deviceId, communication, payload, responseIdentifier, mtu = 20) {
2964
+ if (devicePromiseQueue[deviceId] === void 0) devicePromiseQueue[deviceId] = Promise.resolve();
2965
+ devicePromiseQueue[deviceId] = devicePromiseQueue[deviceId].then(() => {
2966
+ const promise = new Promise((resolve, reject) => {
2967
+ deviceCurrentResolve[deviceId] = resolve;
2968
+ deviceCurrentReject[deviceId] = reject;
2969
+ deviceResponseIdentifier[deviceId] = responseIdentifier;
2970
+ deviceCurrentPartialMessage[deviceId] = [];
2971
+ if (!toolsSvc.canCommunicateWith(deviceId)) return reject(new Error("Torque wrench not connected"));
2972
+ const chunks = [];
2973
+ for (let i = 0; i < payload.length; i += mtu) {
2974
+ chunks.push(payload.slice(i, i + mtu));
2975
+ }
2976
+ for (const chunk of chunks) {
2977
+ const convertedChunk = new Uint8Array(chunk).buffer;
2978
+ bluetooth.write(deviceId, communication.serviceId, communication.characteristicId, convertedChunk);
2979
+ }
2980
+ });
2981
+ return withTimeout(promise, 5e3, `Command timed out ${deviceResponseIdentifier[deviceId]}, ${deviceId}`);
2982
+ });
2983
+ return devicePromiseQueue[deviceId];
2984
+ },
2985
+ async processMessage(deviceId, payload, getIdentifier, isComplete, isError) {
2986
+ const numberArray = Array.from(new Uint8Array(payload));
2987
+ if (!deviceCurrentPartialMessage[deviceId]) deviceCurrentPartialMessage[deviceId] = [];
2988
+ deviceCurrentPartialMessage[deviceId] = _.concat(deviceCurrentPartialMessage[deviceId], numberArray);
2989
+ if (!isComplete(deviceCurrentPartialMessage[deviceId])) {
2990
+ return;
2991
+ }
2992
+ if (isError(deviceCurrentPartialMessage[deviceId])) {
2993
+ return deviceCurrentReject[deviceId](
2994
+ new Error("Error response", { cause: deviceCurrentPartialMessage[deviceId] })
2995
+ );
2996
+ }
2997
+ const identifier = getIdentifier(deviceCurrentPartialMessage[deviceId]);
2998
+ if (deviceResponseIdentifier[deviceId] === identifier) {
2999
+ deviceCurrentResolve[deviceId](deviceCurrentPartialMessage[deviceId]);
3000
+ }
3001
+ }
3002
+ };
3003
+
3004
+ const commandStart = "$9";
3005
+ const commandEnd = "*";
3006
+ const commandIds = {
3007
+ error: "004",
3008
+ acknowledge: "005",
3009
+ commTest: "100",
3010
+ getProperties: "120",
3011
+ startJob: "204",
3012
+ stopJob: "206",
3013
+ getNumberOfReadings: "224",
3014
+ getReading: "200",
3015
+ // Can only be called once for each reading.
3016
+ getReadingAgain: "202",
3017
+ getBattery: "150",
3018
+ getTime: "209",
3019
+ setTime: "208"
3020
+ };
3021
+ const errors = {
3022
+ "01": "Bad string",
3023
+ "02": "Bad checksum",
3024
+ "03": "Unknown command",
3025
+ "04": "No device present for command to act on",
3026
+ "05": "Invalid sample speed",
3027
+ "06": "Torque module offset difference bigger than 25%",
3028
+ "07": "Torque module gain outside 0.9 to 1.1",
3029
+ "08": "No RF properties",
3030
+ "09": "No reply from RF",
3031
+ "0A": "RF device already paired on this device",
3032
+ "0C": "Invalid frequency",
3033
+ "0D": "Invalid LED selection",
3034
+ "0F": "Transducer preloaded",
3035
+ "10": "No more readings",
3036
+ "11": "Job already loaded",
3037
+ "12": "No trace stored",
3038
+ "13": "Wrong transducers selected for Multi Start Mode",
3039
+ "14": "No short trace stored",
3040
+ "15": "Job finished",
3041
+ "16": "Missing time and date",
3042
+ "17": "Bad units for wrench type",
3043
+ "18": "Battery low"
3044
+ };
3045
+ const twMeta = deviceMeta.torqueWrench;
3046
+ const torqueWrenchCommands = {
3047
+ async sendCommand(deviceId, command, params) {
3048
+ const commandId = commandIds[command];
3049
+ let message = `${commandStart}${commandId}`;
3050
+ if (params?.length) {
3051
+ message += `,${params.join(",")}`;
3052
+ }
3053
+ message += commandEnd;
3054
+ const crc = getChecksum(message);
3055
+ message += `${crc}\r`;
3056
+ const array = new Uint8Array(message.length);
3057
+ for (let i = 0, l = message.length; i < l; i++) {
3058
+ array[i] = message.charCodeAt(i);
3059
+ }
3060
+ const decimalArray = Array.from(array);
3061
+ let result;
3062
+ try {
3063
+ result = await torqueWrenchPromiseQueue.enqueue(deviceId, twMeta.communication, decimalArray, commandIds[command]);
3064
+ } catch (error) {
3065
+ const formattedError = formatError(error);
3066
+ throw new Error(formattedError);
3067
+ }
3068
+ return result.map((num) => String.fromCharCode(num)).join("");
3069
+ },
3070
+ processMessage(deviceId, payload) {
3071
+ torqueWrenchPromiseQueue.processMessage(deviceId, payload, getIdentifier, isComplete, isError);
3072
+ }
3073
+ };
3074
+ function isComplete(message) {
3075
+ const completeReading = message[0] === 123 && message.at(-1) === 13;
3076
+ const completeCommand = message[0] === 36 && message.at(-1) === 13;
3077
+ return completeReading || completeCommand;
3078
+ }
3079
+ function isError(message) {
3080
+ return message[4] === 52;
3081
+ }
3082
+ function getIdentifier(message) {
3083
+ if (message[0] === 123) return "200";
3084
+ return message.slice(6, 9).map((num) => String.fromCharCode(num)).join("");
3085
+ }
3086
+ function getChecksum(message) {
3087
+ let checksum = 0;
3088
+ for (const ch of message) {
3089
+ checksum ^= ch.charCodeAt(0);
3090
+ }
3091
+ return decimalToHex(checksum).toUpperCase();
3092
+ }
3093
+ function formatError(error) {
3094
+ if (!error.cause) throw new Error(error);
3095
+ const message = error.cause.slice(6, 8);
3096
+ const errorId = message.map((num) => String.fromCharCode(num)).join("");
3097
+ return errors[errorId] || "Unknown error";
3098
+ }
3099
+
3100
+ let jobInterval = null;
3101
+ const torqueWrenchService = {
3102
+ onReading(callback) {
3103
+ simulatorSvc.registerEvent("tw:reading", callback);
3104
+ },
3105
+ async getProperties(deviceId) {
3106
+ const result = {
3107
+ serialNumber: "",
3108
+ span: 0,
3109
+ calibrationDate: "",
3110
+ ppr: 0,
3111
+ units: "Nm",
3112
+ threshold: 10
3113
+ };
3114
+ const message = await torqueWrenchCommands.sendCommand(deviceId, "getProperties");
3115
+ const params = getMessageParams(message);
3116
+ if (params[4] === "3") result.units = "Nm";
3117
+ else if (params[4] === "7") result.units = "lb-ft";
3118
+ result.serialNumber = params[0];
3119
+ result.span = Number.parseInt(params[1]);
3120
+ if (result.units === "lb-ft") result.span = Math.floor(result.span * 0.738);
3121
+ result.calibrationDate = params[2];
3122
+ result.ppr = Number.parseInt(params[3]);
3123
+ return result;
3124
+ },
3125
+ async startJob(deviceId, params) {
3126
+ await this.stopJob(deviceId);
3127
+ const { units, span, ppr, threshold } = store.torqueWrenchProperties[deviceId];
3128
+ const { torqueMin, torqueMax, angleMin, angleMax, direction, jobTimeout } = params;
3129
+ const msgParams = {
3130
+ id: "01",
3131
+ nuts: decimalToHex(params.nuts),
3132
+ mode: units === "lb-ft" ? "20" : "1",
3133
+ // Peak measurement mode
3134
+ cycle: "7",
3135
+ // 10 seconds cycle (probably for measurements - not sure what it does exactly, not specified in docs)
3136
+ control: torqueMin != null || torqueMax != null ? "0" : "1",
3137
+ direction: direction === "counter-clockwise" ? "1" : "0",
3138
+ minTorqueThreshold: torqueToAdcParam(threshold, span, units),
3139
+ torqueMin: torqueToAdcParam(torqueMin ?? 0, span, units),
3140
+ torqueMax: torqueToAdcParam(torqueMax ?? -1, span, units),
3141
+ clickThreshold: torqueToAdcParam(threshold, span, units),
3142
+ // Probably not used in our case (for this specified mode).
3143
+ angleMin: angleToPulsesParam(angleMin ?? 0, ppr),
3144
+ angleMax: angleToPulsesParam(angleMax ?? -1, ppr),
3145
+ frequency: "0542"
3146
+ // No idea
3147
+ };
3148
+ const paramsString = Object.values(msgParams);
3149
+ await torqueWrenchCommands.sendCommand(deviceId, "startJob", paramsString);
3150
+ jobInterval = setInterval(async () => {
3151
+ const numberOfReading = await this.getNumberOfReadings(deviceId);
3152
+ if (numberOfReading.count > 0) this.getReading(deviceId);
3153
+ }, 2e3);
3154
+ if (jobTimeout) {
3155
+ await new Promise(
3156
+ (resolve) => setTimeout(() => {
3157
+ this.stopJob(deviceId);
3158
+ resolve("");
3159
+ }, jobTimeout * 1e3)
3160
+ );
3161
+ }
3162
+ },
3163
+ async stopJob(deviceId) {
3164
+ clearInterval(jobInterval);
3165
+ return torqueWrenchCommands.sendCommand(deviceId, "stopJob");
3166
+ },
3167
+ async getNumberOfReadings(deviceId) {
3168
+ const message = await torqueWrenchCommands.sendCommand(deviceId, "getNumberOfReadings");
3169
+ const params = getMessageParams(message);
3170
+ return { count: Number(params[0]), jobId: params[1] };
3171
+ },
3172
+ async getReading(deviceId) {
3173
+ const reading = await torqueWrenchCommands.sendCommand(deviceId, "getReading");
3174
+ const properties = {
3175
+ jobId: reading.slice(2, 4),
3176
+ nut: reading.slice(4, 6),
3177
+ torqueAdc: reading.slice(6, 10),
3178
+ anglePulses: reading.slice(10, 14),
3179
+ duration: reading.slice(14, 18)
3180
+ };
3181
+ const torque = adcToTorque(
3182
+ properties.torqueAdc,
3183
+ store.torqueWrenchProperties[deviceId].span,
3184
+ store.torqueWrenchProperties[deviceId].units
3185
+ );
3186
+ const angle = pulsesToAngle(properties.anglePulses, store.torqueWrenchProperties[deviceId].ppr);
3187
+ const formattedReading = {
3188
+ jobId: Number.parseInt(properties.jobId, 16),
3189
+ nut: Number.parseInt(properties.nut, 16),
3190
+ torque,
3191
+ angle,
3192
+ duration: Number.parseInt(properties.duration, 16) / 1e3
3193
+ };
3194
+ simulatorSvc.triggerEvent("tw:reading", deviceId, formattedReading);
3195
+ },
3196
+ // getReadingAgain(deviceId: string) {
3197
+ // return torqueWrenchCommands.sendCommand(deviceId, 'getNumberOfReadings')
3198
+ // },
3199
+ async getBattery(deviceId) {
3200
+ const message = await torqueWrenchCommands.sendCommand(deviceId, "getBattery");
3201
+ const params = getMessageParams(message);
3202
+ return Number(params[0]);
3203
+ },
3204
+ async getTime(deviceId) {
3205
+ const message = await torqueWrenchCommands.sendCommand(deviceId, "getTime");
3206
+ const match = message.match(/209,([^*]*)\*/);
3207
+ console.log("\u{1F680} ~ getTime ~ match:", match);
3208
+ if (!match[1]) throw new Error("Invalid time response");
3209
+ const hh = match[1].substring(0, 2);
3210
+ const mm = match[1].substring(2, 4);
3211
+ const ss = match[1].substring(4, 6);
3212
+ const dd = match[1].substring(6, 8);
3213
+ const MM = match[1].substring(8, 10);
3214
+ const yy = match[1].substring(10, 12);
3215
+ const fullYear = `20${yy}`;
3216
+ return /* @__PURE__ */ new Date(`${fullYear}-${MM}-${dd}T${hh}:${mm}:${ss}Z`);
3217
+ },
3218
+ setTime(deviceId, date) {
3219
+ const hours = String(date.getHours()).padStart(2, "0");
3220
+ const minutes = String(date.getMinutes()).padStart(2, "0");
3221
+ const seconds = String(date.getSeconds()).padStart(2, "0");
3222
+ const day = String(date.getDate()).padStart(2, "0");
3223
+ const month = String(date.getMonth() + 1).padStart(2, "0");
3224
+ const year = String(date.getFullYear()).slice(-2);
3225
+ const params = [hours, minutes, seconds, day, month, year];
3226
+ return torqueWrenchCommands.sendCommand(deviceId, "setTime", params);
3227
+ }
3228
+ };
3229
+ function torqueToAdcParam(value, span, deviceUnits) {
3230
+ if (value < 0) return "FFFF";
3231
+ if (deviceUnits !== "Nm") value = value * 0.738;
3232
+ const adc = Math.round(value / span * 16384);
3233
+ return decimalToHex(adc, 4).toUpperCase();
3234
+ }
3235
+ function angleToPulsesParam(value, ppr) {
3236
+ if (value < 0) return "FFFF";
3237
+ const pulses = Math.round(value * ppr / 90);
3238
+ return decimalToHex(pulses, 4).toUpperCase();
3239
+ }
3240
+ function getMessageParams(message) {
3241
+ return message.match(/^\$[^,]+,[^,]+,(.*)\*/)?.[1].split(",") || [];
3242
+ }
3243
+ function adcToTorque(value, span, units) {
3244
+ const torque = Number.parseInt(value, 16) * span / 16384;
3245
+ if (units !== "Nm") return torque / 0.738;
3246
+ return torque;
3247
+ }
3248
+ function pulsesToAngle(value, ppr) {
3249
+ return Number.parseInt(value, 16) * 90 / ppr;
3250
+ }
3251
+
3252
+ const torqueWrench = {
3253
+ async connect(deviceId) {
3254
+ const twMeta = deviceMeta.torqueWrench;
3255
+ await bluetooth.connect(deviceId, this.disconnect);
3256
+ await ble.startNotification(
3257
+ deviceId,
3258
+ twMeta.communication.serviceId,
3259
+ twMeta.communication.characteristicId,
3260
+ (notification) => {
3261
+ torqueWrenchCommands.processMessage(deviceId, notification);
3262
+ },
3263
+ (error) => console.warn("ble.startNotification error", error)
3264
+ );
3265
+ const properties = await torqueWrenchService.getProperties(deviceId);
3266
+ store.torqueWrenchProperties[deviceId] = properties;
3267
+ store.setState(deviceId, "paired");
3268
+ },
3269
+ async disconnect(deviceId, reason) {
3270
+ store.setState(deviceId, "disconnecting");
3271
+ await torqueWrenchService.stopJob(deviceId);
3272
+ await bluetooth.disconnect(deviceId);
3273
+ store.setState(deviceId, void 0, reason ?? "manualDisconnection");
3274
+ },
3275
+ getProperties: torqueWrenchService.getProperties,
3276
+ setTime: torqueWrenchService.setTime,
3277
+ startJob: torqueWrenchService.startJob,
3278
+ stopJob: torqueWrenchService.stopJob,
3279
+ getNumberOfReadings: torqueWrenchService.getNumberOfReadings,
3280
+ getReading: torqueWrenchService.getReading,
3281
+ getBattery: torqueWrenchService.getBattery,
3282
+ getTime: torqueWrenchService.getTime,
3283
+ onReading: torqueWrenchService.onReading
3284
+ };
3285
+
2892
3286
  const bridgeSimulator = {
2893
3287
  isRebootRequired(deviceId) {
2894
3288
  return store.bridgeRebootRequired[deviceId];
@@ -3489,10 +3883,14 @@ function createTirecheckDeviceSdk(platform, bleImplementation, securityKeys) {
3489
3883
  bridgeOta,
3490
3884
  /** Methods for working with Tirecheck TPMS FlexiGauge */
3491
3885
  flexiGaugeTpms,
3886
+ // flexiGauge,
3492
3887
  /** Methods for working with Tirecheck Pressure Stick */
3493
3888
  pressureStick,
3889
+ // ateq,
3494
3890
  /** Allows simulating devices without actually using bluetooth */
3495
- simulator
3891
+ simulator,
3892
+ /** Methods for working with Tirecheck Torque Wrench */
3893
+ torqueWrench
3496
3894
  };
3497
3895
  }
3498
3896