tirecheck-device-sdk 0.1.97 → 0.1.99

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.cjs CHANGED
@@ -123,15 +123,23 @@ const bridgeTools = {
123
123
  if (deviceData.type !== "bridge") throw new Error("Device is not bridge");
124
124
  return deviceData;
125
125
  },
126
- convertBytesToStructure(objStructure, payload) {
127
- const numArray = ___default.clone(payload);
128
- const keys = Object.keys(objStructure);
126
+ convertBytesToStructure(objStructure, payload, fwVersion) {
127
+ let numArray = ___default.clone(payload);
128
+ const keys = Object.keys(objStructure).filter(
129
+ (key) => !objStructure[key].version || !fwVersion || fwVersion >= objStructure[key].version
130
+ );
129
131
  let sumWithInitial = 0;
130
132
  for (const key of keys) {
131
133
  sumWithInitial += objStructure[key].size;
132
134
  }
135
+ if (numArray.length < sumWithInitial) {
136
+ console.warn("missing bytes filled with empty values");
137
+ numArray = numArray.concat(Array.from({ length: sumWithInitial - numArray.length }, () => 0));
138
+ }
133
139
  if (numArray.length !== sumWithInitial) {
134
- throw new Error("Cannot convert bytes to object");
140
+ throw new Error(
141
+ `Cannot convert bytes to object: bytes received ${numArray.length}, expected ${sumWithInitial}, fw version ${fwVersion}`
142
+ );
135
143
  }
136
144
  const result = {};
137
145
  for (const key of keys) {
@@ -140,10 +148,13 @@ const bridgeTools = {
140
148
  }
141
149
  return result;
142
150
  },
143
- convertStructureToBytes(objStructure, structurizedObj) {
144
- const keys = Object.keys(objStructure);
151
+ convertStructureToBytes(objStructure, structurizedObj, fwVersion) {
152
+ const keys = Object.keys(objStructure).filter(
153
+ (key) => !objStructure[key].version || !fwVersion || fwVersion >= objStructure[key].version
154
+ );
145
155
  const result = [];
146
156
  for (const key of keys) {
157
+ if (!structurizedObj[key]) throw new Error(`Missing key ${key} in the structure`);
147
158
  const encoded = this.encodeData(structurizedObj[key], objStructure[key].display);
148
159
  if (encoded.length < objStructure[key].size) {
149
160
  const _padArray = Array.from({ length: objStructure[key].size - encoded.length }, () => 0);
@@ -180,7 +191,7 @@ const bridgeTools = {
180
191
  encodeData(data, displayUnits) {
181
192
  const _data = ___default.clone(data);
182
193
  if (displayUnits === "ascii") {
183
- return _data.split("").map((v, i) => _data.charCodeAt(i));
194
+ return this.asciiToDecimalArray(_data);
184
195
  }
185
196
  if (displayUnits === "decimal") {
186
197
  return this.hexToDecimalArray(this.decimalToHex(_data)).reverse();
@@ -192,16 +203,6 @@ const bridgeTools = {
192
203
  }
193
204
  return this.hexToDecimalArray(_data).reverse();
194
205
  },
195
- // getBridgeId(device: BluetoothDeviceBridge) {
196
- // // [244,177, 0, 34,123, 155] => F4B100227B9B
197
- // return (
198
- // device.advertisingData.macAddress
199
- // ?.map(n => this.decimalToHex(n))
200
- // .reverse()
201
- // .join('')
202
- // .toUpperCase() || ''
203
- // )
204
- // },
205
206
  pkcs(array, length) {
206
207
  const pkcsValue = length - array.length;
207
208
  if (pkcsValue > 0) {
@@ -213,6 +214,9 @@ const bridgeTools = {
213
214
  const hex = decimal.toString(16);
214
215
  return hex.padStart(2, "0");
215
216
  },
217
+ asciiToDecimalArray(ascii) {
218
+ return ascii.split("").map((x) => x.charCodeAt(0));
219
+ },
216
220
  hexToDecimalArray(hex) {
217
221
  return hex.match(/.{1,2}/g)?.map((byte) => Number.parseInt(byte, 16)) || [];
218
222
  },
@@ -402,7 +406,8 @@ function processAndroidAdvertising(adv, isKrone) {
402
406
  }
403
407
  if (messageType === 3 && identificator === 255) {
404
408
  advertisingData.macAddress = packet.slice(5, 11);
405
- advertisingData.vinNum = packet.slice(-17);
409
+ advertisingData.vinNum = packet.slice(11, 28);
410
+ advertisingData.vinExtension = packet[28];
406
411
  }
407
412
  if (messageType === 1 && identificator === 255) {
408
413
  advertisingData.randomAdvNumber = packet.slice(-8);
@@ -439,6 +444,15 @@ function processIosAdvertising(adv, isKrone) {
439
444
  advertisingData.macAddress = adv.slice(17, 23);
440
445
  advertisingData.vinNum = adv.slice(23, 40);
441
446
  }
447
+ if (adv.length === 43) {
448
+ advertisingData.randomAdvNumber = adv.slice(3, 11);
449
+ advertisingData.fwVersion = bridgeTools.getFwVersion(adv.slice(11, 14));
450
+ advertisingData.configVersion = adv[14];
451
+ advertisingData.timeFromStart = adv[15];
452
+ advertisingData.macAddress = adv.slice(17, 23);
453
+ advertisingData.vinNum = adv.slice(23, 40);
454
+ advertisingData.vinExtension = adv[40];
455
+ }
442
456
  return advertisingData;
443
457
  }
444
458
 
@@ -538,7 +552,22 @@ const deviceMeta = {
538
552
  }
539
553
  };
540
554
 
541
- const checkUnreachableDevicesTimeouts = {};
555
+ const timeouts = {};
556
+ const unreachableSvc = {
557
+ clear,
558
+ refresh
559
+ };
560
+ function clear(deviceId) {
561
+ if (timeouts[deviceId]) clearTimeout(timeouts[deviceId]);
562
+ }
563
+ function refresh(deviceId, deviceUnreachableCallback) {
564
+ clear(deviceId);
565
+ timeouts[deviceId] = setTimeout(() => {
566
+ delete store.devices[deviceId];
567
+ deviceUnreachableCallback?.(deviceId);
568
+ }, 6e4);
569
+ }
570
+
542
571
  let deviceAdvertisingCallback;
543
572
  let deviceUnreachableCallback;
544
573
  let deviceStateChangeCallback;
@@ -608,7 +637,7 @@ async function connect$1(deviceId, disconnectCallback) {
608
637
  }
609
638
  }
610
639
  }
611
- clearTimeout(checkUnreachableDevicesTimeouts[deviceId]);
640
+ unreachableSvc.clear(deviceId);
612
641
  store.setState(deviceId, "connected");
613
642
  return connectedDevice;
614
643
  }
@@ -670,7 +699,7 @@ function processDevice(device) {
670
699
  console.warn("Error processing advertising", e);
671
700
  return;
672
701
  }
673
- refreshUnreachableTimeouts(processedDevice.id);
702
+ unreachableSvc.refresh(processedDevice.id, deviceUnreachableCallback);
674
703
  return processedDevice;
675
704
  }
676
705
  function getDeviceTypeFromName(name) {
@@ -683,15 +712,6 @@ function getDeviceTypeFromName(name) {
683
712
  }
684
713
  return deviceType;
685
714
  }
686
- function refreshUnreachableTimeouts(deviceId) {
687
- if (checkUnreachableDevicesTimeouts[deviceId]) {
688
- clearTimeout(checkUnreachableDevicesTimeouts[deviceId]);
689
- }
690
- checkUnreachableDevicesTimeouts[deviceId] = setTimeout(() => {
691
- delete store.devices[deviceId];
692
- deviceUnreachableCallback?.(deviceId);
693
- }, 6e4);
694
- }
695
715
  function getDeviceName(device) {
696
716
  const isBridge = deviceMeta.bridge.nameRegex.test(device.name) || deviceMeta.bridgeOta.nameRegex.test(device.name);
697
717
  if (isBridge && !device.advertising.kCBAdvDataLocalName) {
@@ -1379,12 +1399,7 @@ const bridgeCommandStructures = {
1379
1399
  size: 1,
1380
1400
  description: "VIN extension",
1381
1401
  display: "ascii",
1382
- optional: true
1383
- },
1384
- test: {
1385
- size: 3,
1386
- description: "Test",
1387
- optional: true
1402
+ version: "1.0.3"
1388
1403
  }
1389
1404
  }
1390
1405
  }
@@ -1738,16 +1753,22 @@ const bridgeCommands = {
1738
1753
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1739
1754
  await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.pressurePerAxle, data);
1740
1755
  },
1741
- async setVehicleLayout(deviceId, data) {
1756
+ async setVehicleLayout(deviceId, structurizedPayload) {
1742
1757
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1743
- await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.vehicleLayout, data);
1758
+ const payload = bridgeTools.convertStructureToBytes(
1759
+ bridgeCommandStructures.vehicleLayout.structure,
1760
+ structurizedPayload,
1761
+ deviceData.advertisingData.fwVersion
1762
+ );
1763
+ await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.vehicleLayout, payload);
1744
1764
  },
1745
1765
  async getCustomerCANSettings(deviceId) {
1746
1766
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1747
1767
  const result = await this.readCommand(deviceData, subCommandIds.customerCanSettings);
1748
1768
  const structurized = bridgeTools.convertBytesToStructure(
1749
1769
  bridgeCommandStructures.customerCanSettings.structure,
1750
- result.data
1770
+ result.data,
1771
+ deviceData.advertisingData.fwVersion
1751
1772
  );
1752
1773
  return { ...structurized, isFactory: result.isFactory };
1753
1774
  },
@@ -1756,7 +1777,8 @@ const bridgeCommands = {
1756
1777
  const result = await this.readCommand(deviceData, subCommandIds.workshopCanSettings);
1757
1778
  const structurized = bridgeTools.convertBytesToStructure(
1758
1779
  bridgeCommandStructures.workshopCanSettings.structure,
1759
- result.data
1780
+ result.data,
1781
+ deviceData.advertisingData.fwVersion
1760
1782
  );
1761
1783
  return { ...structurized, isFactory: result.isFactory };
1762
1784
  },
@@ -1765,7 +1787,8 @@ const bridgeCommands = {
1765
1787
  const result = await this.readCommand(deviceData, subCommandIds.customerPressureThresholds);
1766
1788
  const structurized = bridgeTools.convertBytesToStructure(
1767
1789
  bridgeCommandStructures.axlePressureThresholds.structure,
1768
- result.data
1790
+ result.data,
1791
+ deviceData.advertisingData.fwVersion
1769
1792
  );
1770
1793
  return { ...structurized, isFactory: result.isFactory };
1771
1794
  },
@@ -1774,7 +1797,8 @@ const bridgeCommands = {
1774
1797
  const result = await this.readCommand(deviceData, subCommandIds.customerTemperatureThresholds);
1775
1798
  const structurized = bridgeTools.convertBytesToStructure(
1776
1799
  bridgeCommandStructures.axleTemperatureThresholds.structure,
1777
- result.data
1800
+ result.data,
1801
+ deviceData.advertisingData.fwVersion
1778
1802
  );
1779
1803
  return { ...structurized, isFactory: result.isFactory };
1780
1804
  },
@@ -1783,7 +1807,8 @@ const bridgeCommands = {
1783
1807
  const result = await this.readCommand(deviceData, subCommandIds.customerImbalanceThresholds);
1784
1808
  const structurized = bridgeTools.convertBytesToStructure(
1785
1809
  bridgeCommandStructures.axleImbalanceThresholds.structure,
1786
- result.data
1810
+ result.data,
1811
+ deviceData.advertisingData.fwVersion
1787
1812
  );
1788
1813
  return { ...structurized, isFactory: result.isFactory };
1789
1814
  },
@@ -1815,7 +1840,8 @@ const bridgeCommands = {
1815
1840
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1816
1841
  const payload = bridgeTools.convertStructureToBytes(
1817
1842
  bridgeCommandStructures.customerCanSettings.structure,
1818
- structurizedPayload
1843
+ structurizedPayload,
1844
+ deviceData.advertisingData.fwVersion
1819
1845
  );
1820
1846
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.customerCanSettings, payload);
1821
1847
  },
@@ -1841,7 +1867,8 @@ const bridgeCommands = {
1841
1867
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1842
1868
  const payload = bridgeTools.convertStructureToBytes(
1843
1869
  bridgeCommandStructures.workshopCanSettings.structure,
1844
- structurizedPayload
1870
+ structurizedPayload,
1871
+ deviceData.advertisingData.fwVersion
1845
1872
  );
1846
1873
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.workshopCanSettings, payload);
1847
1874
  },
@@ -1849,7 +1876,8 @@ const bridgeCommands = {
1849
1876
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1850
1877
  const payload = bridgeTools.convertStructureToBytes(
1851
1878
  bridgeCommandStructures.axlePressureThresholds.structure,
1852
- structurizedPayload
1879
+ structurizedPayload,
1880
+ deviceData.advertisingData.fwVersion
1853
1881
  );
1854
1882
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.customerPressureThresholds, payload);
1855
1883
  },
@@ -1857,7 +1885,8 @@ const bridgeCommands = {
1857
1885
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1858
1886
  const payload = bridgeTools.convertStructureToBytes(
1859
1887
  bridgeCommandStructures.axleTemperatureThresholds.structure,
1860
- structurizedPayload
1888
+ structurizedPayload,
1889
+ deviceData.advertisingData.fwVersion
1861
1890
  );
1862
1891
  return await this.writeCommand(
1863
1892
  deviceData,
@@ -1870,7 +1899,8 @@ const bridgeCommands = {
1870
1899
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1871
1900
  const payload = bridgeTools.convertStructureToBytes(
1872
1901
  bridgeCommandStructures.axleImbalanceThresholds.structure,
1873
- structurizedPayload
1902
+ structurizedPayload,
1903
+ deviceData.advertisingData.fwVersion
1874
1904
  );
1875
1905
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.customerImbalanceThresholds, payload);
1876
1906
  },
@@ -1879,7 +1909,8 @@ const bridgeCommands = {
1879
1909
  const result = await this.readCommand(deviceData, subCommandIds.autolearnSettings);
1880
1910
  const structurized = bridgeTools.convertBytesToStructure(
1881
1911
  bridgeCommandStructures.autolearnSettings.structure,
1882
- result.data
1912
+ result.data,
1913
+ deviceData.advertisingData.fwVersion
1883
1914
  );
1884
1915
  return { ...structurized, isFactory: result.isFactory };
1885
1916
  },
@@ -1888,7 +1919,8 @@ const bridgeCommands = {
1888
1919
  const result = await this.readCommand(deviceData, subCommandIds.autolearnIdStatus);
1889
1920
  const structurized = bridgeTools.convertBytesToStructure(
1890
1921
  bridgeCommandStructures.autolearnIdStatus.structure,
1891
- result.data
1922
+ result.data,
1923
+ deviceData.advertisingData.fwVersion
1892
1924
  );
1893
1925
  return { ...structurized, isFactory: result.isFactory };
1894
1926
  },
@@ -1896,7 +1928,8 @@ const bridgeCommands = {
1896
1928
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1897
1929
  const payload = bridgeTools.convertStructureToBytes(
1898
1930
  bridgeCommandStructures.autolearnSettings.structure,
1899
- structurizedPayload
1931
+ structurizedPayload,
1932
+ deviceData.advertisingData.fwVersion
1900
1933
  );
1901
1934
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.autolearnSettings, payload);
1902
1935
  },
@@ -1904,7 +1937,8 @@ const bridgeCommands = {
1904
1937
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1905
1938
  const payload = bridgeTools.convertStructureToBytes(
1906
1939
  bridgeCommandStructures.autolearnIdStatus.structure,
1907
- structurizedPayload
1940
+ structurizedPayload,
1941
+ deviceData.advertisingData.fwVersion
1908
1942
  );
1909
1943
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.autolearnIdStatus, payload);
1910
1944
  },
@@ -1912,7 +1946,8 @@ const bridgeCommands = {
1912
1946
  const result = await this.readCommand(device, subCommandIds.autolearnUnknownSensors);
1913
1947
  const structurized = bridgeTools.convertBytesToStructure(
1914
1948
  bridgeCommandStructures.autolearnUnknownSensors.structure,
1915
- result.data
1949
+ result.data,
1950
+ device.advertisingData.fwVersion
1916
1951
  );
1917
1952
  return { ...structurized, isFactory: result.isFactory };
1918
1953
  },
@@ -1938,7 +1973,8 @@ const bridgeCommands = {
1938
1973
  const result = await this.readCommand(deviceData, subCommandIds.pressurePerAxle);
1939
1974
  const structurizedData = bridgeTools.convertBytesToStructure(
1940
1975
  bridgeCommandStructures.pressuresPerAxle.structure,
1941
- result.data
1976
+ result.data,
1977
+ deviceData.advertisingData.fwVersion
1942
1978
  );
1943
1979
  return structurizedData;
1944
1980
  },
@@ -1946,7 +1982,8 @@ const bridgeCommands = {
1946
1982
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1947
1983
  const payload = bridgeTools.convertStructureToBytes(
1948
1984
  bridgeCommandStructures.pressuresPerAxle.structure,
1949
- structurizedPayload
1985
+ structurizedPayload,
1986
+ deviceData.advertisingData.fwVersion
1950
1987
  );
1951
1988
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.pressurePerAxle, payload);
1952
1989
  },
@@ -1974,7 +2011,12 @@ const bridgeCommands = {
1974
2011
  async getVehicleLayout(deviceId) {
1975
2012
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1976
2013
  const result = await this.readCommand(deviceData, subCommandIds.vehicleLayout);
1977
- return result.data;
2014
+ const structurizedData = bridgeTools.convertBytesToStructure(
2015
+ bridgeCommandStructures.vehicleLayout.structure,
2016
+ result.data,
2017
+ deviceData.advertisingData.fwVersion
2018
+ );
2019
+ return structurizedData;
1978
2020
  },
1979
2021
  async getSensorMeasurement(deviceId, positionId) {
1980
2022
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
@@ -2051,12 +2093,12 @@ const bridgeCommands = {
2051
2093
  };
2052
2094
 
2053
2095
  const vehicleLayoutAxleTypes = {
2054
- noAxle: [0, 0],
2055
- twoTyresAxle: [128, 2],
2056
- twoTyresAxleSpare: [128, 3],
2057
- fourTyresAxle: [192, 6],
2058
- fourTyresAxleSpare: [192, 7],
2059
- spareTyreAxle: [1, 0]
2096
+ noAxle: "0000",
2097
+ twoTyresAxle: "0280",
2098
+ twoTyresAxleSpare: "0380",
2099
+ fourTyresAxle: "06C0",
2100
+ fourTyresAxleSpare: "07C0",
2101
+ spareTyreAxle: "0001"
2060
2102
  };
2061
2103
  const bridgeService = {
2062
2104
  updateFirmware,
@@ -2091,37 +2133,49 @@ async function updateFirmware(deviceId, bootloader, firmware, reportStatus) {
2091
2133
  async function setVehicleLayout(deviceId, tcVehicle) {
2092
2134
  const spareTyres = tcVehicle.tcTyres?.filter((tyre) => String(tyre.mountedOn?.positionId).endsWith("0"));
2093
2135
  let spareTyresCount = Math.min(spareTyres.length || 0, 2);
2094
- let layout = [];
2136
+ const result = {
2137
+ axle01: "0000",
2138
+ axle02: "0000",
2139
+ axle03: "0000",
2140
+ axle04: "0000",
2141
+ axle05: "0000",
2142
+ axle06: "0000",
2143
+ axle07: "0000",
2144
+ axle08: "0000",
2145
+ axle09: "0000",
2146
+ axle10: "0000",
2147
+ axle11: "0000",
2148
+ axle12: "0000",
2149
+ axle13: "0000",
2150
+ axle14: "0000",
2151
+ axle15: "0000",
2152
+ vin: tcVehicle.vin ?? "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
2153
+ vinExtension: tcVehicle.vinExtension ?? "\0"
2154
+ };
2095
2155
  for (let index = 0; index < 15; index++) {
2096
- const tyresCount = tcVehicle.axles && tcVehicle.axles[index]?.tyresCount;
2097
- if (tyresCount === 2) {
2098
- let value = vehicleLayoutAxleTypes.twoTyresAxle;
2156
+ const resultKey = Object.keys(result)[index];
2157
+ const tyreCount = tcVehicle.axles[index]?.tyresCount;
2158
+ if (tyreCount === 2) {
2099
2159
  if (spareTyresCount) {
2100
- value = vehicleLayoutAxleTypes.twoTyresAxleSpare;
2160
+ result[resultKey] = vehicleLayoutAxleTypes.twoTyresAxleSpare;
2101
2161
  spareTyresCount -= 1;
2162
+ } else {
2163
+ result[resultKey] = vehicleLayoutAxleTypes.twoTyresAxle;
2102
2164
  }
2103
- layout = [...layout, ...value];
2104
2165
  continue;
2105
2166
  }
2106
- if (tyresCount === 4) {
2107
- let value = vehicleLayoutAxleTypes.fourTyresAxle;
2167
+ if (tyreCount === 4) {
2108
2168
  if (spareTyresCount) {
2109
- value = vehicleLayoutAxleTypes.fourTyresAxleSpare;
2169
+ result[resultKey] = vehicleLayoutAxleTypes.fourTyresAxleSpare;
2110
2170
  spareTyresCount -= 1;
2171
+ } else {
2172
+ result[resultKey] = vehicleLayoutAxleTypes.fourTyresAxle;
2111
2173
  }
2112
- layout = [...layout, ...value];
2113
2174
  continue;
2114
2175
  }
2115
- layout = [...layout, ...vehicleLayoutAxleTypes.noAxle];
2116
- }
2117
- let vin = tcVehicle.vin ? tcVehicle.vin.split("").map((x) => x.charCodeAt(0)) : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
2118
- if (vin.length !== 17) {
2119
- throw new Error(`Incorrect VIN length: ${vin}`);
2176
+ result[resultKey] = vehicleLayoutAxleTypes.noAxle;
2120
2177
  }
2121
- if (bridgeTools.isVersionGreaterThan(deviceId, "1.0.2")) {
2122
- vin = [...vin, 0];
2123
- }
2124
- await bridgeCommands.setVehicleLayout(deviceId, [...layout, ...vin]);
2178
+ await bridgeCommands.setVehicleLayout(deviceId, result);
2125
2179
  }
2126
2180
  async function getConfiguration(deviceId) {
2127
2181
  const customerCANSettings = await bridgeCommands.getCustomerCANSettings(deviceId);
@@ -2146,7 +2200,7 @@ async function getConfiguration(deviceId) {
2146
2200
  }
2147
2201
  function bridgeVehiclesDifference(original, change) {
2148
2202
  const differences = [];
2149
- if (original.vin !== change.vin) differences.push("vin");
2203
+ if (original.vin !== change.vin || original.vinExtension !== change.vinExtension) differences.push("vin");
2150
2204
  const originalTyres = original.tcTyres.map((t) => {
2151
2205
  return { positionId: t.mountedOn?.positionId, sensorId: t.tcTpmsSensor?.id || null };
2152
2206
  });
@@ -2593,9 +2647,8 @@ async function getVehicle(deviceId) {
2593
2647
  }
2594
2648
  async function assignAxles(deviceId, tcVehicle) {
2595
2649
  const result = await bridgeCommands.getVehicleLayout(deviceId);
2596
- const data = result.map((x) => bridgeTools.decimalToHex(x));
2597
- const joinedData = Array.from({ length: data.length / 2 }, (_2, index) => data[2 * index + 1] + data[2 * index]);
2598
- const activeAxles = joinedData.slice(0, 15).filter((x) => Number(`0x${x}`));
2650
+ tcVehicle.vinExtension = result.vinExtension;
2651
+ const activeAxles = Object.values(result).slice(0, 15).filter((a) => Number.parseInt(a, 16));
2599
2652
  const axlesPressureData = (await bridgeCommands.getAxlesPressure(deviceId)).data;
2600
2653
  let axleTypesBytes;
2601
2654
  if (bridgeTools.isVersionGreaterThan(deviceId, "0.9.7")) {
@@ -3000,6 +3053,7 @@ const bridgeSimulator = {
3000
3053
  bridge.advertisingData.fwVersion = "1.9.9";
3001
3054
  },
3002
3055
  async connect(deviceId) {
3056
+ if (store.simulatedDevices[deviceId].isDisabled) throw new Error(`Simulated bridge is disabled: ${deviceId}`);
3003
3057
  store.setState(deviceId, "connecting");
3004
3058
  await toolsSvc.delay(100);
3005
3059
  store.setState(deviceId, "connected");
@@ -3267,12 +3321,19 @@ function ensureSimulatorMethodsAreInjected() {
3267
3321
  clearInterval(advertisingInterval);
3268
3322
  advertisingInterval = void 0;
3269
3323
  }
3324
+ let previousDevices = store.simulatedDevices;
3270
3325
  advertisingInterval = toolsSvc.setIntervalImmediate(() => {
3271
3326
  for (const key in store.simulatedDevices) {
3272
3327
  const d = store.simulatedDevices[key];
3273
3328
  if (d.isDisabled) continue;
3329
+ unreachableSvc.refresh(d.id, deviceUnreachableCallback);
3274
3330
  deviceAdvertisingCallback?.(store.simulatedDevices[key]);
3275
3331
  }
3332
+ const missingDevices = ___default.omit(previousDevices, Object.keys(store.simulatedDevices));
3333
+ for (const key in missingDevices) {
3334
+ deviceUnreachableCallback?.(key);
3335
+ }
3336
+ previousDevices = ___default.cloneDeep(store.simulatedDevices);
3276
3337
  }, 2e3);
3277
3338
  };
3278
3339
  for (const [svc, sim] of deviceServicesAndSimulators) {
package/dist/index.d.cts CHANGED
@@ -609,12 +609,7 @@ declare const _default: {
609
609
  size: number;
610
610
  description: string;
611
611
  display: "ascii";
612
- optional: true;
613
- };
614
- test: {
615
- size: number;
616
- description: string;
617
- optional: true;
612
+ version: string;
618
613
  };
619
614
  };
620
615
  };
@@ -626,6 +621,7 @@ type DeepPartial<T> = T extends object ? {
626
621
  interface BridgeTcVehicle {
627
622
  registrationNumber?: string;
628
623
  vin?: string;
624
+ vinExtension?: string;
629
625
  axles: BridgeTcVehicleAxle[];
630
626
  tcTyres: BridgeTcTyre[];
631
627
  /** Ignored in set, returned in get */
@@ -734,7 +730,8 @@ interface BridgeCommandStructureProperties {
734
730
  size: number;
735
731
  display?: 'decimal' | 'ascii' | 'reverseHex';
736
732
  description: string;
737
- optional?: boolean;
733
+ /** From which bridge version is this property available */
734
+ version?: string;
738
735
  };
739
736
  }
740
737
  type BridgeCommandStructurized<T extends BridgeCommandStructureProperties> = {
@@ -803,6 +800,7 @@ type Simulator<Service extends Record<string, any>, SimulatedDeviceType extends
803
800
  interface BleBridgeAdvertisingData {
804
801
  randomAdvNumber: number[];
805
802
  vinNum: number[];
803
+ vinExtension?: number;
806
804
  macAddress: number[];
807
805
  fwVersion?: string;
808
806
  /**
package/dist/index.d.mts CHANGED
@@ -609,12 +609,7 @@ declare const _default: {
609
609
  size: number;
610
610
  description: string;
611
611
  display: "ascii";
612
- optional: true;
613
- };
614
- test: {
615
- size: number;
616
- description: string;
617
- optional: true;
612
+ version: string;
618
613
  };
619
614
  };
620
615
  };
@@ -626,6 +621,7 @@ type DeepPartial<T> = T extends object ? {
626
621
  interface BridgeTcVehicle {
627
622
  registrationNumber?: string;
628
623
  vin?: string;
624
+ vinExtension?: string;
629
625
  axles: BridgeTcVehicleAxle[];
630
626
  tcTyres: BridgeTcTyre[];
631
627
  /** Ignored in set, returned in get */
@@ -734,7 +730,8 @@ interface BridgeCommandStructureProperties {
734
730
  size: number;
735
731
  display?: 'decimal' | 'ascii' | 'reverseHex';
736
732
  description: string;
737
- optional?: boolean;
733
+ /** From which bridge version is this property available */
734
+ version?: string;
738
735
  };
739
736
  }
740
737
  type BridgeCommandStructurized<T extends BridgeCommandStructureProperties> = {
@@ -803,6 +800,7 @@ type Simulator<Service extends Record<string, any>, SimulatedDeviceType extends
803
800
  interface BleBridgeAdvertisingData {
804
801
  randomAdvNumber: number[];
805
802
  vinNum: number[];
803
+ vinExtension?: number;
806
804
  macAddress: number[];
807
805
  fwVersion?: string;
808
806
  /**
package/dist/index.d.ts CHANGED
@@ -609,12 +609,7 @@ declare const _default: {
609
609
  size: number;
610
610
  description: string;
611
611
  display: "ascii";
612
- optional: true;
613
- };
614
- test: {
615
- size: number;
616
- description: string;
617
- optional: true;
612
+ version: string;
618
613
  };
619
614
  };
620
615
  };
@@ -626,6 +621,7 @@ type DeepPartial<T> = T extends object ? {
626
621
  interface BridgeTcVehicle {
627
622
  registrationNumber?: string;
628
623
  vin?: string;
624
+ vinExtension?: string;
629
625
  axles: BridgeTcVehicleAxle[];
630
626
  tcTyres: BridgeTcTyre[];
631
627
  /** Ignored in set, returned in get */
@@ -734,7 +730,8 @@ interface BridgeCommandStructureProperties {
734
730
  size: number;
735
731
  display?: 'decimal' | 'ascii' | 'reverseHex';
736
732
  description: string;
737
- optional?: boolean;
733
+ /** From which bridge version is this property available */
734
+ version?: string;
738
735
  };
739
736
  }
740
737
  type BridgeCommandStructurized<T extends BridgeCommandStructureProperties> = {
@@ -803,6 +800,7 @@ type Simulator<Service extends Record<string, any>, SimulatedDeviceType extends
803
800
  interface BleBridgeAdvertisingData {
804
801
  randomAdvNumber: number[];
805
802
  vinNum: number[];
803
+ vinExtension?: number;
806
804
  macAddress: number[];
807
805
  fwVersion?: string;
808
806
  /**
package/dist/index.mjs CHANGED
@@ -116,15 +116,23 @@ const bridgeTools = {
116
116
  if (deviceData.type !== "bridge") throw new Error("Device is not bridge");
117
117
  return deviceData;
118
118
  },
119
- convertBytesToStructure(objStructure, payload) {
120
- const numArray = _.clone(payload);
121
- const keys = Object.keys(objStructure);
119
+ convertBytesToStructure(objStructure, payload, fwVersion) {
120
+ let numArray = _.clone(payload);
121
+ const keys = Object.keys(objStructure).filter(
122
+ (key) => !objStructure[key].version || !fwVersion || fwVersion >= objStructure[key].version
123
+ );
122
124
  let sumWithInitial = 0;
123
125
  for (const key of keys) {
124
126
  sumWithInitial += objStructure[key].size;
125
127
  }
128
+ if (numArray.length < sumWithInitial) {
129
+ console.warn("missing bytes filled with empty values");
130
+ numArray = numArray.concat(Array.from({ length: sumWithInitial - numArray.length }, () => 0));
131
+ }
126
132
  if (numArray.length !== sumWithInitial) {
127
- throw new Error("Cannot convert bytes to object");
133
+ throw new Error(
134
+ `Cannot convert bytes to object: bytes received ${numArray.length}, expected ${sumWithInitial}, fw version ${fwVersion}`
135
+ );
128
136
  }
129
137
  const result = {};
130
138
  for (const key of keys) {
@@ -133,10 +141,13 @@ const bridgeTools = {
133
141
  }
134
142
  return result;
135
143
  },
136
- convertStructureToBytes(objStructure, structurizedObj) {
137
- const keys = Object.keys(objStructure);
144
+ convertStructureToBytes(objStructure, structurizedObj, fwVersion) {
145
+ const keys = Object.keys(objStructure).filter(
146
+ (key) => !objStructure[key].version || !fwVersion || fwVersion >= objStructure[key].version
147
+ );
138
148
  const result = [];
139
149
  for (const key of keys) {
150
+ if (!structurizedObj[key]) throw new Error(`Missing key ${key} in the structure`);
140
151
  const encoded = this.encodeData(structurizedObj[key], objStructure[key].display);
141
152
  if (encoded.length < objStructure[key].size) {
142
153
  const _padArray = Array.from({ length: objStructure[key].size - encoded.length }, () => 0);
@@ -173,7 +184,7 @@ const bridgeTools = {
173
184
  encodeData(data, displayUnits) {
174
185
  const _data = _.clone(data);
175
186
  if (displayUnits === "ascii") {
176
- return _data.split("").map((v, i) => _data.charCodeAt(i));
187
+ return this.asciiToDecimalArray(_data);
177
188
  }
178
189
  if (displayUnits === "decimal") {
179
190
  return this.hexToDecimalArray(this.decimalToHex(_data)).reverse();
@@ -185,16 +196,6 @@ const bridgeTools = {
185
196
  }
186
197
  return this.hexToDecimalArray(_data).reverse();
187
198
  },
188
- // getBridgeId(device: BluetoothDeviceBridge) {
189
- // // [244,177, 0, 34,123, 155] => F4B100227B9B
190
- // return (
191
- // device.advertisingData.macAddress
192
- // ?.map(n => this.decimalToHex(n))
193
- // .reverse()
194
- // .join('')
195
- // .toUpperCase() || ''
196
- // )
197
- // },
198
199
  pkcs(array, length) {
199
200
  const pkcsValue = length - array.length;
200
201
  if (pkcsValue > 0) {
@@ -206,6 +207,9 @@ const bridgeTools = {
206
207
  const hex = decimal.toString(16);
207
208
  return hex.padStart(2, "0");
208
209
  },
210
+ asciiToDecimalArray(ascii) {
211
+ return ascii.split("").map((x) => x.charCodeAt(0));
212
+ },
209
213
  hexToDecimalArray(hex) {
210
214
  return hex.match(/.{1,2}/g)?.map((byte) => Number.parseInt(byte, 16)) || [];
211
215
  },
@@ -395,7 +399,8 @@ function processAndroidAdvertising(adv, isKrone) {
395
399
  }
396
400
  if (messageType === 3 && identificator === 255) {
397
401
  advertisingData.macAddress = packet.slice(5, 11);
398
- advertisingData.vinNum = packet.slice(-17);
402
+ advertisingData.vinNum = packet.slice(11, 28);
403
+ advertisingData.vinExtension = packet[28];
399
404
  }
400
405
  if (messageType === 1 && identificator === 255) {
401
406
  advertisingData.randomAdvNumber = packet.slice(-8);
@@ -432,6 +437,15 @@ function processIosAdvertising(adv, isKrone) {
432
437
  advertisingData.macAddress = adv.slice(17, 23);
433
438
  advertisingData.vinNum = adv.slice(23, 40);
434
439
  }
440
+ if (adv.length === 43) {
441
+ advertisingData.randomAdvNumber = adv.slice(3, 11);
442
+ advertisingData.fwVersion = bridgeTools.getFwVersion(adv.slice(11, 14));
443
+ advertisingData.configVersion = adv[14];
444
+ advertisingData.timeFromStart = adv[15];
445
+ advertisingData.macAddress = adv.slice(17, 23);
446
+ advertisingData.vinNum = adv.slice(23, 40);
447
+ advertisingData.vinExtension = adv[40];
448
+ }
435
449
  return advertisingData;
436
450
  }
437
451
 
@@ -531,7 +545,22 @@ const deviceMeta = {
531
545
  }
532
546
  };
533
547
 
534
- const checkUnreachableDevicesTimeouts = {};
548
+ const timeouts = {};
549
+ const unreachableSvc = {
550
+ clear,
551
+ refresh
552
+ };
553
+ function clear(deviceId) {
554
+ if (timeouts[deviceId]) clearTimeout(timeouts[deviceId]);
555
+ }
556
+ function refresh(deviceId, deviceUnreachableCallback) {
557
+ clear(deviceId);
558
+ timeouts[deviceId] = setTimeout(() => {
559
+ delete store.devices[deviceId];
560
+ deviceUnreachableCallback?.(deviceId);
561
+ }, 6e4);
562
+ }
563
+
535
564
  let deviceAdvertisingCallback;
536
565
  let deviceUnreachableCallback;
537
566
  let deviceStateChangeCallback;
@@ -601,7 +630,7 @@ async function connect$1(deviceId, disconnectCallback) {
601
630
  }
602
631
  }
603
632
  }
604
- clearTimeout(checkUnreachableDevicesTimeouts[deviceId]);
633
+ unreachableSvc.clear(deviceId);
605
634
  store.setState(deviceId, "connected");
606
635
  return connectedDevice;
607
636
  }
@@ -663,7 +692,7 @@ function processDevice(device) {
663
692
  console.warn("Error processing advertising", e);
664
693
  return;
665
694
  }
666
- refreshUnreachableTimeouts(processedDevice.id);
695
+ unreachableSvc.refresh(processedDevice.id, deviceUnreachableCallback);
667
696
  return processedDevice;
668
697
  }
669
698
  function getDeviceTypeFromName(name) {
@@ -676,15 +705,6 @@ function getDeviceTypeFromName(name) {
676
705
  }
677
706
  return deviceType;
678
707
  }
679
- function refreshUnreachableTimeouts(deviceId) {
680
- if (checkUnreachableDevicesTimeouts[deviceId]) {
681
- clearTimeout(checkUnreachableDevicesTimeouts[deviceId]);
682
- }
683
- checkUnreachableDevicesTimeouts[deviceId] = setTimeout(() => {
684
- delete store.devices[deviceId];
685
- deviceUnreachableCallback?.(deviceId);
686
- }, 6e4);
687
- }
688
708
  function getDeviceName(device) {
689
709
  const isBridge = deviceMeta.bridge.nameRegex.test(device.name) || deviceMeta.bridgeOta.nameRegex.test(device.name);
690
710
  if (isBridge && !device.advertising.kCBAdvDataLocalName) {
@@ -1372,12 +1392,7 @@ const bridgeCommandStructures = {
1372
1392
  size: 1,
1373
1393
  description: "VIN extension",
1374
1394
  display: "ascii",
1375
- optional: true
1376
- },
1377
- test: {
1378
- size: 3,
1379
- description: "Test",
1380
- optional: true
1395
+ version: "1.0.3"
1381
1396
  }
1382
1397
  }
1383
1398
  }
@@ -1731,16 +1746,22 @@ const bridgeCommands = {
1731
1746
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1732
1747
  await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.pressurePerAxle, data);
1733
1748
  },
1734
- async setVehicleLayout(deviceId, data) {
1749
+ async setVehicleLayout(deviceId, structurizedPayload) {
1735
1750
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1736
- await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.vehicleLayout, data);
1751
+ const payload = bridgeTools.convertStructureToBytes(
1752
+ bridgeCommandStructures.vehicleLayout.structure,
1753
+ structurizedPayload,
1754
+ deviceData.advertisingData.fwVersion
1755
+ );
1756
+ await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.vehicleLayout, payload);
1737
1757
  },
1738
1758
  async getCustomerCANSettings(deviceId) {
1739
1759
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1740
1760
  const result = await this.readCommand(deviceData, subCommandIds.customerCanSettings);
1741
1761
  const structurized = bridgeTools.convertBytesToStructure(
1742
1762
  bridgeCommandStructures.customerCanSettings.structure,
1743
- result.data
1763
+ result.data,
1764
+ deviceData.advertisingData.fwVersion
1744
1765
  );
1745
1766
  return { ...structurized, isFactory: result.isFactory };
1746
1767
  },
@@ -1749,7 +1770,8 @@ const bridgeCommands = {
1749
1770
  const result = await this.readCommand(deviceData, subCommandIds.workshopCanSettings);
1750
1771
  const structurized = bridgeTools.convertBytesToStructure(
1751
1772
  bridgeCommandStructures.workshopCanSettings.structure,
1752
- result.data
1773
+ result.data,
1774
+ deviceData.advertisingData.fwVersion
1753
1775
  );
1754
1776
  return { ...structurized, isFactory: result.isFactory };
1755
1777
  },
@@ -1758,7 +1780,8 @@ const bridgeCommands = {
1758
1780
  const result = await this.readCommand(deviceData, subCommandIds.customerPressureThresholds);
1759
1781
  const structurized = bridgeTools.convertBytesToStructure(
1760
1782
  bridgeCommandStructures.axlePressureThresholds.structure,
1761
- result.data
1783
+ result.data,
1784
+ deviceData.advertisingData.fwVersion
1762
1785
  );
1763
1786
  return { ...structurized, isFactory: result.isFactory };
1764
1787
  },
@@ -1767,7 +1790,8 @@ const bridgeCommands = {
1767
1790
  const result = await this.readCommand(deviceData, subCommandIds.customerTemperatureThresholds);
1768
1791
  const structurized = bridgeTools.convertBytesToStructure(
1769
1792
  bridgeCommandStructures.axleTemperatureThresholds.structure,
1770
- result.data
1793
+ result.data,
1794
+ deviceData.advertisingData.fwVersion
1771
1795
  );
1772
1796
  return { ...structurized, isFactory: result.isFactory };
1773
1797
  },
@@ -1776,7 +1800,8 @@ const bridgeCommands = {
1776
1800
  const result = await this.readCommand(deviceData, subCommandIds.customerImbalanceThresholds);
1777
1801
  const structurized = bridgeTools.convertBytesToStructure(
1778
1802
  bridgeCommandStructures.axleImbalanceThresholds.structure,
1779
- result.data
1803
+ result.data,
1804
+ deviceData.advertisingData.fwVersion
1780
1805
  );
1781
1806
  return { ...structurized, isFactory: result.isFactory };
1782
1807
  },
@@ -1808,7 +1833,8 @@ const bridgeCommands = {
1808
1833
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1809
1834
  const payload = bridgeTools.convertStructureToBytes(
1810
1835
  bridgeCommandStructures.customerCanSettings.structure,
1811
- structurizedPayload
1836
+ structurizedPayload,
1837
+ deviceData.advertisingData.fwVersion
1812
1838
  );
1813
1839
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.customerCanSettings, payload);
1814
1840
  },
@@ -1834,7 +1860,8 @@ const bridgeCommands = {
1834
1860
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1835
1861
  const payload = bridgeTools.convertStructureToBytes(
1836
1862
  bridgeCommandStructures.workshopCanSettings.structure,
1837
- structurizedPayload
1863
+ structurizedPayload,
1864
+ deviceData.advertisingData.fwVersion
1838
1865
  );
1839
1866
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.workshopCanSettings, payload);
1840
1867
  },
@@ -1842,7 +1869,8 @@ const bridgeCommands = {
1842
1869
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1843
1870
  const payload = bridgeTools.convertStructureToBytes(
1844
1871
  bridgeCommandStructures.axlePressureThresholds.structure,
1845
- structurizedPayload
1872
+ structurizedPayload,
1873
+ deviceData.advertisingData.fwVersion
1846
1874
  );
1847
1875
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.customerPressureThresholds, payload);
1848
1876
  },
@@ -1850,7 +1878,8 @@ const bridgeCommands = {
1850
1878
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1851
1879
  const payload = bridgeTools.convertStructureToBytes(
1852
1880
  bridgeCommandStructures.axleTemperatureThresholds.structure,
1853
- structurizedPayload
1881
+ structurizedPayload,
1882
+ deviceData.advertisingData.fwVersion
1854
1883
  );
1855
1884
  return await this.writeCommand(
1856
1885
  deviceData,
@@ -1863,7 +1892,8 @@ const bridgeCommands = {
1863
1892
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1864
1893
  const payload = bridgeTools.convertStructureToBytes(
1865
1894
  bridgeCommandStructures.axleImbalanceThresholds.structure,
1866
- structurizedPayload
1895
+ structurizedPayload,
1896
+ deviceData.advertisingData.fwVersion
1867
1897
  );
1868
1898
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.customerImbalanceThresholds, payload);
1869
1899
  },
@@ -1872,7 +1902,8 @@ const bridgeCommands = {
1872
1902
  const result = await this.readCommand(deviceData, subCommandIds.autolearnSettings);
1873
1903
  const structurized = bridgeTools.convertBytesToStructure(
1874
1904
  bridgeCommandStructures.autolearnSettings.structure,
1875
- result.data
1905
+ result.data,
1906
+ deviceData.advertisingData.fwVersion
1876
1907
  );
1877
1908
  return { ...structurized, isFactory: result.isFactory };
1878
1909
  },
@@ -1881,7 +1912,8 @@ const bridgeCommands = {
1881
1912
  const result = await this.readCommand(deviceData, subCommandIds.autolearnIdStatus);
1882
1913
  const structurized = bridgeTools.convertBytesToStructure(
1883
1914
  bridgeCommandStructures.autolearnIdStatus.structure,
1884
- result.data
1915
+ result.data,
1916
+ deviceData.advertisingData.fwVersion
1885
1917
  );
1886
1918
  return { ...structurized, isFactory: result.isFactory };
1887
1919
  },
@@ -1889,7 +1921,8 @@ const bridgeCommands = {
1889
1921
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1890
1922
  const payload = bridgeTools.convertStructureToBytes(
1891
1923
  bridgeCommandStructures.autolearnSettings.structure,
1892
- structurizedPayload
1924
+ structurizedPayload,
1925
+ deviceData.advertisingData.fwVersion
1893
1926
  );
1894
1927
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.autolearnSettings, payload);
1895
1928
  },
@@ -1897,7 +1930,8 @@ const bridgeCommands = {
1897
1930
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1898
1931
  const payload = bridgeTools.convertStructureToBytes(
1899
1932
  bridgeCommandStructures.autolearnIdStatus.structure,
1900
- structurizedPayload
1933
+ structurizedPayload,
1934
+ deviceData.advertisingData.fwVersion
1901
1935
  );
1902
1936
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.autolearnIdStatus, payload);
1903
1937
  },
@@ -1905,7 +1939,8 @@ const bridgeCommands = {
1905
1939
  const result = await this.readCommand(device, subCommandIds.autolearnUnknownSensors);
1906
1940
  const structurized = bridgeTools.convertBytesToStructure(
1907
1941
  bridgeCommandStructures.autolearnUnknownSensors.structure,
1908
- result.data
1942
+ result.data,
1943
+ device.advertisingData.fwVersion
1909
1944
  );
1910
1945
  return { ...structurized, isFactory: result.isFactory };
1911
1946
  },
@@ -1931,7 +1966,8 @@ const bridgeCommands = {
1931
1966
  const result = await this.readCommand(deviceData, subCommandIds.pressurePerAxle);
1932
1967
  const structurizedData = bridgeTools.convertBytesToStructure(
1933
1968
  bridgeCommandStructures.pressuresPerAxle.structure,
1934
- result.data
1969
+ result.data,
1970
+ deviceData.advertisingData.fwVersion
1935
1971
  );
1936
1972
  return structurizedData;
1937
1973
  },
@@ -1939,7 +1975,8 @@ const bridgeCommands = {
1939
1975
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1940
1976
  const payload = bridgeTools.convertStructureToBytes(
1941
1977
  bridgeCommandStructures.pressuresPerAxle.structure,
1942
- structurizedPayload
1978
+ structurizedPayload,
1979
+ deviceData.advertisingData.fwVersion
1943
1980
  );
1944
1981
  return await this.writeCommand(deviceData, commandIds.writeData, subCommandIds.pressurePerAxle, payload);
1945
1982
  },
@@ -1967,7 +2004,12 @@ const bridgeCommands = {
1967
2004
  async getVehicleLayout(deviceId) {
1968
2005
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
1969
2006
  const result = await this.readCommand(deviceData, subCommandIds.vehicleLayout);
1970
- return result.data;
2007
+ const structurizedData = bridgeTools.convertBytesToStructure(
2008
+ bridgeCommandStructures.vehicleLayout.structure,
2009
+ result.data,
2010
+ deviceData.advertisingData.fwVersion
2011
+ );
2012
+ return structurizedData;
1971
2013
  },
1972
2014
  async getSensorMeasurement(deviceId, positionId) {
1973
2015
  const deviceData = bridgeTools.getBridgeFromStore(deviceId);
@@ -2044,12 +2086,12 @@ const bridgeCommands = {
2044
2086
  };
2045
2087
 
2046
2088
  const vehicleLayoutAxleTypes = {
2047
- noAxle: [0, 0],
2048
- twoTyresAxle: [128, 2],
2049
- twoTyresAxleSpare: [128, 3],
2050
- fourTyresAxle: [192, 6],
2051
- fourTyresAxleSpare: [192, 7],
2052
- spareTyreAxle: [1, 0]
2089
+ noAxle: "0000",
2090
+ twoTyresAxle: "0280",
2091
+ twoTyresAxleSpare: "0380",
2092
+ fourTyresAxle: "06C0",
2093
+ fourTyresAxleSpare: "07C0",
2094
+ spareTyreAxle: "0001"
2053
2095
  };
2054
2096
  const bridgeService = {
2055
2097
  updateFirmware,
@@ -2084,37 +2126,49 @@ async function updateFirmware(deviceId, bootloader, firmware, reportStatus) {
2084
2126
  async function setVehicleLayout(deviceId, tcVehicle) {
2085
2127
  const spareTyres = tcVehicle.tcTyres?.filter((tyre) => String(tyre.mountedOn?.positionId).endsWith("0"));
2086
2128
  let spareTyresCount = Math.min(spareTyres.length || 0, 2);
2087
- let layout = [];
2129
+ const result = {
2130
+ axle01: "0000",
2131
+ axle02: "0000",
2132
+ axle03: "0000",
2133
+ axle04: "0000",
2134
+ axle05: "0000",
2135
+ axle06: "0000",
2136
+ axle07: "0000",
2137
+ axle08: "0000",
2138
+ axle09: "0000",
2139
+ axle10: "0000",
2140
+ axle11: "0000",
2141
+ axle12: "0000",
2142
+ axle13: "0000",
2143
+ axle14: "0000",
2144
+ axle15: "0000",
2145
+ vin: tcVehicle.vin ?? "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
2146
+ vinExtension: tcVehicle.vinExtension ?? "\0"
2147
+ };
2088
2148
  for (let index = 0; index < 15; index++) {
2089
- const tyresCount = tcVehicle.axles && tcVehicle.axles[index]?.tyresCount;
2090
- if (tyresCount === 2) {
2091
- let value = vehicleLayoutAxleTypes.twoTyresAxle;
2149
+ const resultKey = Object.keys(result)[index];
2150
+ const tyreCount = tcVehicle.axles[index]?.tyresCount;
2151
+ if (tyreCount === 2) {
2092
2152
  if (spareTyresCount) {
2093
- value = vehicleLayoutAxleTypes.twoTyresAxleSpare;
2153
+ result[resultKey] = vehicleLayoutAxleTypes.twoTyresAxleSpare;
2094
2154
  spareTyresCount -= 1;
2155
+ } else {
2156
+ result[resultKey] = vehicleLayoutAxleTypes.twoTyresAxle;
2095
2157
  }
2096
- layout = [...layout, ...value];
2097
2158
  continue;
2098
2159
  }
2099
- if (tyresCount === 4) {
2100
- let value = vehicleLayoutAxleTypes.fourTyresAxle;
2160
+ if (tyreCount === 4) {
2101
2161
  if (spareTyresCount) {
2102
- value = vehicleLayoutAxleTypes.fourTyresAxleSpare;
2162
+ result[resultKey] = vehicleLayoutAxleTypes.fourTyresAxleSpare;
2103
2163
  spareTyresCount -= 1;
2164
+ } else {
2165
+ result[resultKey] = vehicleLayoutAxleTypes.fourTyresAxle;
2104
2166
  }
2105
- layout = [...layout, ...value];
2106
2167
  continue;
2107
2168
  }
2108
- layout = [...layout, ...vehicleLayoutAxleTypes.noAxle];
2109
- }
2110
- let vin = tcVehicle.vin ? tcVehicle.vin.split("").map((x) => x.charCodeAt(0)) : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
2111
- if (vin.length !== 17) {
2112
- throw new Error(`Incorrect VIN length: ${vin}`);
2169
+ result[resultKey] = vehicleLayoutAxleTypes.noAxle;
2113
2170
  }
2114
- if (bridgeTools.isVersionGreaterThan(deviceId, "1.0.2")) {
2115
- vin = [...vin, 0];
2116
- }
2117
- await bridgeCommands.setVehicleLayout(deviceId, [...layout, ...vin]);
2171
+ await bridgeCommands.setVehicleLayout(deviceId, result);
2118
2172
  }
2119
2173
  async function getConfiguration(deviceId) {
2120
2174
  const customerCANSettings = await bridgeCommands.getCustomerCANSettings(deviceId);
@@ -2139,7 +2193,7 @@ async function getConfiguration(deviceId) {
2139
2193
  }
2140
2194
  function bridgeVehiclesDifference(original, change) {
2141
2195
  const differences = [];
2142
- if (original.vin !== change.vin) differences.push("vin");
2196
+ if (original.vin !== change.vin || original.vinExtension !== change.vinExtension) differences.push("vin");
2143
2197
  const originalTyres = original.tcTyres.map((t) => {
2144
2198
  return { positionId: t.mountedOn?.positionId, sensorId: t.tcTpmsSensor?.id || null };
2145
2199
  });
@@ -2586,9 +2640,8 @@ async function getVehicle(deviceId) {
2586
2640
  }
2587
2641
  async function assignAxles(deviceId, tcVehicle) {
2588
2642
  const result = await bridgeCommands.getVehicleLayout(deviceId);
2589
- const data = result.map((x) => bridgeTools.decimalToHex(x));
2590
- const joinedData = Array.from({ length: data.length / 2 }, (_2, index) => data[2 * index + 1] + data[2 * index]);
2591
- const activeAxles = joinedData.slice(0, 15).filter((x) => Number(`0x${x}`));
2643
+ tcVehicle.vinExtension = result.vinExtension;
2644
+ const activeAxles = Object.values(result).slice(0, 15).filter((a) => Number.parseInt(a, 16));
2592
2645
  const axlesPressureData = (await bridgeCommands.getAxlesPressure(deviceId)).data;
2593
2646
  let axleTypesBytes;
2594
2647
  if (bridgeTools.isVersionGreaterThan(deviceId, "0.9.7")) {
@@ -2993,6 +3046,7 @@ const bridgeSimulator = {
2993
3046
  bridge.advertisingData.fwVersion = "1.9.9";
2994
3047
  },
2995
3048
  async connect(deviceId) {
3049
+ if (store.simulatedDevices[deviceId].isDisabled) throw new Error(`Simulated bridge is disabled: ${deviceId}`);
2996
3050
  store.setState(deviceId, "connecting");
2997
3051
  await toolsSvc.delay(100);
2998
3052
  store.setState(deviceId, "connected");
@@ -3260,12 +3314,19 @@ function ensureSimulatorMethodsAreInjected() {
3260
3314
  clearInterval(advertisingInterval);
3261
3315
  advertisingInterval = void 0;
3262
3316
  }
3317
+ let previousDevices = store.simulatedDevices;
3263
3318
  advertisingInterval = toolsSvc.setIntervalImmediate(() => {
3264
3319
  for (const key in store.simulatedDevices) {
3265
3320
  const d = store.simulatedDevices[key];
3266
3321
  if (d.isDisabled) continue;
3322
+ unreachableSvc.refresh(d.id, deviceUnreachableCallback);
3267
3323
  deviceAdvertisingCallback?.(store.simulatedDevices[key]);
3268
3324
  }
3325
+ const missingDevices = _.omit(previousDevices, Object.keys(store.simulatedDevices));
3326
+ for (const key in missingDevices) {
3327
+ deviceUnreachableCallback?.(key);
3328
+ }
3329
+ previousDevices = _.cloneDeep(store.simulatedDevices);
3269
3330
  }, 2e3);
3270
3331
  };
3271
3332
  for (const [svc, sim] of deviceServicesAndSimulators) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tirecheck-device-sdk",
3
- "version": "0.1.97",
3
+ "version": "0.1.99",
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",