tirecheck-device-sdk 0.1.94 → 0.1.96

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
@@ -502,7 +502,7 @@ const deviceMeta = {
502
502
  getDeviceInfoFromAdvertising: bridgeOtaAdvertisingParser.getDeviceInfoFromAdvertising
503
503
  },
504
504
  flexiGaugeTpms: {
505
- nameRegex: /Flexi.*/,
505
+ nameRegex: /^Flexi.*/,
506
506
  communication: {
507
507
  serviceId: "4880c12c-fdcb-4077-8920-a450d7f9b907",
508
508
  characteristicId: "fec26ec4-6d71-4442-9f81-55bc21d658d6"
@@ -520,28 +520,21 @@ const deviceMeta = {
520
520
  },
521
521
  reconnect: true
522
522
  // Do we need it here?
523
+ },
524
+ pressureStick: {
525
+ nameRegex: /Pressure Stick.*/,
526
+ communication: {
527
+ serviceId: "4880c12c-fdcb-4077-8920-a450d7f9b907",
528
+ characteristicId: "fec26ec4-6d71-4442-9f81-55bc21d658d6"
529
+ },
530
+ getDeviceInfoFromAdvertising: (device) => {
531
+ const bleDevice = {
532
+ ...device,
533
+ type: "pressureStick"
534
+ };
535
+ return bleDevice;
536
+ }
523
537
  }
524
- // pressureStick: {
525
- // nameRegex: /Pressure Stick.*/,
526
- // characteristic: {
527
- // serviceId: '4880c12c-fdcb-4077-8920-a450d7f9b907',
528
- // characteristicId: 'fec26ec4-6d71-4442-9f81-55bc21d658d6',
529
- // },
530
- // getDeviceInfoFromAdvertising: () => {},
531
- // capabilities: [
532
- // {
533
- // id: 'pressure',
534
- // // processFn: processPressure,
535
- // regex: /P([0-9.]+)mBar/,
536
- // },
537
- // // only pressure is needed for initial implementation, uncomment tpms functionality when needed
538
- // // {
539
- // // id: 'tpms',
540
- // // processFn: processTpms,
541
- // // regex: /^\*TPMS/,
542
- // // },
543
- // ],
544
- // },
545
538
  };
546
539
 
547
540
  const checkUnreachableDevicesTimeouts = {};
@@ -565,7 +558,7 @@ const bluetooth = {
565
558
  stopScan() {
566
559
  ble.stopScan();
567
560
  },
568
- connect,
561
+ connect: connect$1,
569
562
  disconnect: disconnect$1,
570
563
  write,
571
564
  read
@@ -592,7 +585,7 @@ async function scanDevices(services = [], duration) {
592
585
  (e) => console.error("ble.startScanWithOptions error:", e)
593
586
  );
594
587
  }
595
- async function connect(deviceId, disconnectCallback) {
588
+ async function connect$1(deviceId, disconnectCallback) {
596
589
  if (toolsSvc.canCommunicateWith(deviceId)) return console.warn("Connect Warn: Already connected to device");
597
590
  store.setState(deviceId, "connecting");
598
591
  let connectedDevice;
@@ -713,6 +706,78 @@ function getDeviceNameFromAdvertising(advertising) {
713
706
  return deviceName;
714
707
  }
715
708
 
709
+ const otaServiceUuid = "1d14d6ee-fd63-4fa1-bfa4-8f47b42119f0";
710
+ const otaControlCharacteristicUuid = "f7bf3564-fb6d-4e53-88a4-5e37e0326063";
711
+ const otaDataCharacteristicUuid = "984227f3-34fc-4045-a5d0-2c581f81a153";
712
+ const bridgeOtaCommands = {
713
+ async beginOta(deviceId) {
714
+ await bluetooth.write(deviceId, otaServiceUuid, otaControlCharacteristicUuid, new Uint8Array([0]).buffer, true);
715
+ },
716
+ async uploadOtaChunk(deviceId, data) {
717
+ await bluetooth.write(deviceId, otaServiceUuid, otaDataCharacteristicUuid, data, true);
718
+ },
719
+ async endOta(deviceId) {
720
+ await bluetooth.write(deviceId, otaServiceUuid, otaControlCharacteristicUuid, new Uint8Array([3]).buffer, true);
721
+ }
722
+ };
723
+
724
+ const bridgeOtaService = {
725
+ async updateFirmware(deviceId, bootloader, firmware, progressCallback) {
726
+ await delay(2e3);
727
+ progressCallback("Connecting to the bridge...", 0.1);
728
+ await bridgeOta.connect(deviceId);
729
+ progressCallback("Uploading bootloader...", 0.12);
730
+ await bridgeOtaCommands.beginOta(deviceId);
731
+ await uploadOta(deviceId, bootloader, (str, percents) => progressCallback(str, 0.12 + percents * 0.2));
732
+ await bridgeOtaCommands.endOta(deviceId);
733
+ progressCallback("Uploading application...", 0.32);
734
+ await bridgeOtaCommands.beginOta(deviceId);
735
+ await uploadOta(deviceId, firmware, (str, percents) => progressCallback(str, 0.32 + percents * 0.5));
736
+ await bridgeOtaCommands.endOta(deviceId);
737
+ progressCallback("Upload completed, disconnecting...", 0.81);
738
+ await bridgeOta.disconnect(deviceId);
739
+ progressCallback("Disconnected...", 1);
740
+ }
741
+ };
742
+ async function uploadOta(deviceId, firmwareBinary, reportStatus) {
743
+ let uploadedBytes = 0;
744
+ let chunkIndex = 0;
745
+ const mtu = store.platform === "android" ? 512 : deviceMeta.bridgeOta.mtu;
746
+ while (uploadedBytes < firmwareBinary.byteLength) {
747
+ if (chunkIndex % 100 === 0)
748
+ reportStatus(
749
+ `Uploading new firmware... (${___default.round(uploadedBytes / 1e3)} / ${___default.round(
750
+ firmwareBinary.byteLength / 1e3
751
+ )} KB)`,
752
+ uploadedBytes / firmwareBinary.byteLength
753
+ );
754
+ const chunkSize = Math.min(mtu - 3, firmwareBinary.byteLength - uploadedBytes);
755
+ const chunk = firmwareBinary.slice(uploadedBytes, uploadedBytes + chunkSize);
756
+ await bridgeOtaCommands.uploadOtaChunk(deviceId, chunk);
757
+ uploadedBytes += chunkSize;
758
+ chunkIndex++;
759
+ }
760
+ }
761
+
762
+ const bridgeOta = {
763
+ async connect(deviceId) {
764
+ await bluetooth.connect(deviceId, this.disconnect);
765
+ const _deviceId = store.deviceIdMapingTable[deviceId] ?? deviceId;
766
+ if (store.platform !== "ios") {
767
+ await ble.requestMtu(_deviceId, 512);
768
+ }
769
+ store.setState(deviceId, "paired");
770
+ },
771
+ async disconnect(deviceId, reason) {
772
+ store.setState(deviceId, "disconnecting");
773
+ await bluetooth.disconnect(deviceId);
774
+ store.setState(deviceId, void 0, reason ?? "manualDisconnection");
775
+ },
776
+ async updateFirmware(deviceId, bootloader, firmware, progressCallback) {
777
+ return bridgeOtaService.updateFirmware(deviceId, bootloader, firmware, progressCallback);
778
+ }
779
+ };
780
+
716
781
  const bridgeCommandStructures = {
717
782
  workshopCanSettings: {
718
783
  id: [98, 96],
@@ -1530,25 +1595,26 @@ const bridgeSecurity = {
1530
1595
  };
1531
1596
 
1532
1597
  const bridgeMeta = deviceMeta.bridge;
1533
- let promiseQueue = Promise.resolve();
1534
- let currentResolve = (_v) => {
1535
- };
1536
- let currentReject = (_v) => {
1537
- };
1538
- let responseIdentifier;
1539
- const promiseQueue$1 = {
1540
- clearQueue(message) {
1541
- currentReject(new Error(message ?? "Stopped sending commands"));
1542
- promiseQueue = Promise.resolve();
1543
- responseIdentifier = [];
1598
+ const devicePromiseQueue = {};
1599
+ const deviceCurrentResolve = {};
1600
+ const deviceCurrentReject = {};
1601
+ const deviceResponseIdentifier = {};
1602
+ const promiseQueue = {
1603
+ clearQueue(deviceId, message) {
1604
+ if (deviceCurrentReject[deviceId]) {
1605
+ deviceCurrentReject[deviceId](new Error(message ?? "Stopped sending commands"));
1606
+ }
1607
+ devicePromiseQueue[deviceId] = Promise.resolve();
1608
+ deviceResponseIdentifier[deviceId] = [];
1544
1609
  },
1545
1610
  async enqueue(device, payload) {
1546
- promiseQueue = promiseQueue.then(() => {
1611
+ if (devicePromiseQueue[device.id] === void 0) devicePromiseQueue[device.id] = Promise.resolve();
1612
+ devicePromiseQueue[device.id] = devicePromiseQueue[device.id].then(() => {
1547
1613
  const promise = new Promise((resolve, reject) => {
1548
- currentResolve = resolve;
1549
- currentReject = reject;
1614
+ deviceCurrentResolve[device.id] = resolve;
1615
+ deviceCurrentReject[device.id] = reject;
1550
1616
  const isKeepAlive = payload[3] === commandIds.keepAlive;
1551
- responseIdentifier = [isKeepAlive ? 126 : 0, payload[4]];
1617
+ deviceResponseIdentifier[device.id] = [isKeepAlive ? 126 : 0, payload[4]];
1552
1618
  const signedData = bridgeSecurity.getSignedCommand(device, payload);
1553
1619
  if (!toolsSvc.canCommunicateWith(device.id)) return reject(new Error("Bridge not connected"));
1554
1620
  if (signedData.length > 110) {
@@ -1574,21 +1640,21 @@ const promiseQueue$1 = {
1574
1640
  );
1575
1641
  }
1576
1642
  });
1577
- return withTimeout(promise, 5e3, `Command timed out ${responseIdentifier}`);
1643
+ return withTimeout(promise, 5e3, `Command timed out ${deviceResponseIdentifier[device.id]}, ${device.id}`);
1578
1644
  });
1579
- return promiseQueue;
1645
+ return devicePromiseQueue[device.id];
1580
1646
  },
1581
1647
  async processMessage(deviceId, payload) {
1582
1648
  const numberArray = Array.from(new Uint8Array(payload));
1583
1649
  if (numberArray[3] === 127) {
1584
1650
  console.error(numberArray);
1585
- return currentReject(new Error(`Command not succesful: ${numberArray[4]}`));
1651
+ return deviceCurrentReject[deviceId](new Error(`Command not succesful: ${numberArray[4]}`));
1586
1652
  }
1587
1653
  if ([226, 81].includes(numberArray[3]) && numberArray[4] && toolsSvc.canCommunicateWith(deviceId)) {
1588
1654
  store.bridgeRebootRequired[deviceId] = true;
1589
1655
  }
1590
- if ((!responseIdentifier[0] || numberArray[3] === responseIdentifier[0]) && (!responseIdentifier[1] || numberArray[4] === responseIdentifier[1])) {
1591
- return currentResolve(numberArray);
1656
+ if ((!deviceResponseIdentifier[deviceId][0] || numberArray[3] === deviceResponseIdentifier[deviceId][0]) && (!deviceResponseIdentifier[deviceId][1] || numberArray[4] === deviceResponseIdentifier[deviceId][1])) {
1657
+ return deviceCurrentResolve[deviceId](numberArray);
1592
1658
  }
1593
1659
  console.warn("message from the device not belonging to the pending promise: ", numberArray);
1594
1660
  }
@@ -1975,79 +2041,7 @@ const bridgeCommands = {
1975
2041
  }
1976
2042
  this.sendKeepAliveCommand(device);
1977
2043
  }, 1e4);
1978
- return promiseQueue$1.enqueue(device, writeCommand);
1979
- }
1980
- };
1981
-
1982
- const otaServiceUuid = "1d14d6ee-fd63-4fa1-bfa4-8f47b42119f0";
1983
- const otaControlCharacteristicUuid = "f7bf3564-fb6d-4e53-88a4-5e37e0326063";
1984
- const otaDataCharacteristicUuid = "984227f3-34fc-4045-a5d0-2c581f81a153";
1985
- const bridgeOtaCommands = {
1986
- async beginOta(deviceId) {
1987
- await bluetooth.write(deviceId, otaServiceUuid, otaControlCharacteristicUuid, new Uint8Array([0]).buffer, true);
1988
- },
1989
- async uploadOtaChunk(deviceId, data) {
1990
- await bluetooth.write(deviceId, otaServiceUuid, otaDataCharacteristicUuid, data, true);
1991
- },
1992
- async endOta(deviceId) {
1993
- await bluetooth.write(deviceId, otaServiceUuid, otaControlCharacteristicUuid, new Uint8Array([3]).buffer, true);
1994
- }
1995
- };
1996
-
1997
- const bridgeOtaService = {
1998
- async updateFirmware(deviceId, bootloader, firmware, progressCallback) {
1999
- await delay(2e3);
2000
- progressCallback("Connecting to the bridge...", 0.1);
2001
- await bridgeOta.connect(deviceId);
2002
- progressCallback("Uploading bootloader...", 0.12);
2003
- await bridgeOtaCommands.beginOta(deviceId);
2004
- await uploadOta(deviceId, bootloader, (str, percents) => progressCallback(str, 0.12 + percents * 0.2));
2005
- await bridgeOtaCommands.endOta(deviceId);
2006
- progressCallback("Uploading application...", 0.32);
2007
- await bridgeOtaCommands.beginOta(deviceId);
2008
- await uploadOta(deviceId, firmware, (str, percents) => progressCallback(str, 0.32 + percents * 0.5));
2009
- await bridgeOtaCommands.endOta(deviceId);
2010
- progressCallback("Upload completed, disconnecting...", 0.81);
2011
- await bridgeOta.disconnect(deviceId);
2012
- progressCallback("Disconnected...", 1);
2013
- }
2014
- };
2015
- async function uploadOta(deviceId, firmwareBinary, reportStatus) {
2016
- let uploadedBytes = 0;
2017
- let chunkIndex = 0;
2018
- const mtu = store.platform === "android" ? 512 : deviceMeta.bridgeOta.mtu;
2019
- while (uploadedBytes < firmwareBinary.byteLength) {
2020
- if (chunkIndex % 100 === 0)
2021
- reportStatus(
2022
- `Uploading new firmware... (${___default.round(uploadedBytes / 1e3)} / ${___default.round(
2023
- firmwareBinary.byteLength / 1e3
2024
- )} KB)`,
2025
- uploadedBytes / firmwareBinary.byteLength
2026
- );
2027
- const chunkSize = Math.min(mtu - 3, firmwareBinary.byteLength - uploadedBytes);
2028
- const chunk = firmwareBinary.slice(uploadedBytes, uploadedBytes + chunkSize);
2029
- await bridgeOtaCommands.uploadOtaChunk(deviceId, chunk);
2030
- uploadedBytes += chunkSize;
2031
- chunkIndex++;
2032
- }
2033
- }
2034
-
2035
- const bridgeOta = {
2036
- async connect(deviceId) {
2037
- await bluetooth.connect(deviceId, this.disconnect);
2038
- const _deviceId = store.deviceIdMapingTable[deviceId] ?? deviceId;
2039
- if (store.platform !== "ios") {
2040
- await ble.requestMtu(_deviceId, 512);
2041
- }
2042
- store.setState(deviceId, "paired");
2043
- },
2044
- async disconnect(deviceId, reason) {
2045
- store.setState(deviceId, "disconnecting");
2046
- await bluetooth.disconnect(deviceId);
2047
- store.setState(deviceId, void 0, reason ?? "manualDisconnection");
2048
- },
2049
- async updateFirmware(deviceId, bootloader, firmware, progressCallback) {
2050
- return bridgeOtaService.updateFirmware(deviceId, bootloader, firmware, progressCallback);
2044
+ return promiseQueue.enqueue(device, writeCommand);
2051
2045
  }
2052
2046
  };
2053
2047
 
@@ -2069,8 +2063,13 @@ const bridgeService = {
2069
2063
  getVehicleReadings,
2070
2064
  resetAutolearnStatuses,
2071
2065
  getAutolearnStatuses,
2072
- isRebootRequired
2066
+ isRebootRequired,
2067
+ sendPinCommand
2073
2068
  };
2069
+ async function sendPinCommand(deviceId) {
2070
+ if (!canCommunicateWith(deviceId)) throw new Error("Bridge not connected");
2071
+ await bridgeCommands.sendPinCommand(deviceId);
2072
+ }
2074
2073
  async function updateFirmware(deviceId, bootloader, firmware, reportStatus) {
2075
2074
  reportStatus("Sending OTA Request...", 0.02);
2076
2075
  await bridgeCommands.sendOtaRequest(deviceId);
@@ -2392,7 +2391,7 @@ async function getVehicleReadings(deviceId, tcVehicle) {
2392
2391
  try {
2393
2392
  for (const vehicleTyre of tcVehicle.tcTyres) {
2394
2393
  if (vehicleTyre.tcTpmsSensor && vehicleTyre.mountedOn?.positionId) {
2395
- if (!canCommunicateWith(deviceId)) throw new Error("getVehicleReadings: no connected bridge");
2394
+ if (!canCommunicateWith(deviceId)) break;
2396
2395
  const reading = await getSensorReading(deviceId, vehicleTyre.mountedOn.positionId);
2397
2396
  readings.push(reading);
2398
2397
  }
@@ -2690,12 +2689,28 @@ function isRebootRequired(deviceId) {
2690
2689
 
2691
2690
  const bridge = {
2692
2691
  disconnect,
2693
- async connect(deviceId, accessLevel) {
2694
- if (canCommunicateWith(deviceId)) return;
2695
- await promiseQueue$1.clearQueue("Previous pending commands aborted");
2696
- const bridgeMeta = deviceMeta.bridge;
2697
- await bluetooth.connect(deviceId, disconnect);
2698
- const _deviceId = store.deviceIdMapingTable[deviceId] ?? deviceId;
2692
+ connect,
2693
+ getVehicle: bridgeService.getVehicle,
2694
+ setVehicle: bridgeService.setVehicle,
2695
+ getConfiguration: bridgeService.getConfiguration,
2696
+ setConfiguration: bridgeService.setConfiguration,
2697
+ getSensorReading: bridgeService.getSensorReading,
2698
+ getVehicleReadings: bridgeService.getVehicleReadings,
2699
+ getAutolearnStatuses: bridgeService.getAutolearnStatuses,
2700
+ resetAutolearnStatuses: bridgeService.resetAutolearnStatuses,
2701
+ updateFirmware: bridgeService.updateFirmware,
2702
+ isRebootRequired: bridgeService.isRebootRequired
2703
+ };
2704
+ async function connect(deviceId, accessLevel) {
2705
+ if (canCommunicateWith(deviceId)) return;
2706
+ await promiseQueue.clearQueue(deviceId, "Previous pending commands aborted");
2707
+ const bridgeMeta = deviceMeta.bridge;
2708
+ await bluetooth.connect(deviceId, disconnect);
2709
+ if (store.deviceState[deviceId] === "paired") {
2710
+ return console.warn("Connect Warn: Already connected");
2711
+ }
2712
+ const _deviceId = store.deviceIdMapingTable[deviceId] ?? deviceId;
2713
+ try {
2699
2714
  if (store.platform !== "ios") {
2700
2715
  await ble.requestMtu(_deviceId, deviceMeta.bridge.mtu);
2701
2716
  }
@@ -2703,28 +2718,22 @@ const bridge = {
2703
2718
  _deviceId,
2704
2719
  bridgeMeta.communication.serviceId,
2705
2720
  bridgeMeta.communication.characteristicId,
2706
- (notification) => promiseQueue$1.processMessage(deviceId, notification),
2721
+ (notification) => promiseQueue.processMessage(deviceId, notification),
2707
2722
  (error) => console.error("startNotification Error", error)
2708
2723
  );
2709
2724
  store.deviceAccessLevel[deviceId] = accessLevel ?? "driver";
2710
2725
  store.bridgeRebootRequired[deviceId] = false;
2711
- await bridgeCommands.sendPinCommand(deviceId);
2726
+ await bridgeService.sendPinCommand(deviceId);
2712
2727
  store.setState(deviceId, "paired");
2713
- },
2714
- getVehicle: bridgeService.getVehicle,
2715
- setVehicle: bridgeService.setVehicle,
2716
- getConfiguration: bridgeService.getConfiguration,
2717
- setConfiguration: bridgeService.setConfiguration,
2718
- getSensorReading: bridgeService.getSensorReading,
2719
- getVehicleReadings: bridgeService.getVehicleReadings,
2720
- getAutolearnStatuses: bridgeService.getAutolearnStatuses,
2721
- resetAutolearnStatuses: bridgeService.resetAutolearnStatuses,
2722
- updateFirmware: bridgeService.updateFirmware,
2723
- isRebootRequired: bridgeService.isRebootRequired
2724
- };
2728
+ } catch (e) {
2729
+ disconnect(deviceId);
2730
+ throw new Error(`Pairing unsuccessful ${e}`);
2731
+ }
2732
+ }
2725
2733
  async function disconnect(deviceId, reason) {
2734
+ await waitUntil(() => store.deviceState[deviceId] === "paired" || store.deviceState[deviceId] === void 0);
2726
2735
  store.setState(deviceId, "disconnecting");
2727
- promiseQueue$1.clearQueue("Previous pending commands aborted");
2736
+ promiseQueue.clearQueue(deviceId, "Previous pending commands aborted");
2728
2737
  await bluetooth.disconnect(deviceId);
2729
2738
  delete store.devices[deviceId];
2730
2739
  deviceUnreachableCallback?.(deviceId);
@@ -2736,11 +2745,13 @@ const simulatorSvc = {
2736
2745
  registerEvent(eventName, callback) {
2737
2746
  callbacks[eventName] = callback;
2738
2747
  },
2739
- triggerEvent(eventName, deviceId) {
2740
- const simulatedDevice = store.simulatedDevices[deviceId];
2741
- if (!simulatedDevice) throw new Error(`Device not found`);
2742
- const payload = simulatedDevice.simulatorData?.events?.[eventName];
2743
- if (!payload) throw new Error(`Event not found`);
2748
+ triggerEvent(eventName, deviceId, payload) {
2749
+ if (payload === void 0) {
2750
+ const simulatedDevice = store.simulatedDevices[deviceId];
2751
+ if (!simulatedDevice) throw new Error(`Device not found`);
2752
+ payload = simulatedDevice.simulatorData?.events?.[eventName];
2753
+ if (!payload) throw new Error(`Event not found`);
2754
+ }
2744
2755
  const callback = callbacks[eventName];
2745
2756
  if (!callback) {
2746
2757
  console.warn(`Event ${eventName} not registered`);
@@ -2779,10 +2790,7 @@ async function getBattery(deviceId) {
2779
2790
  }
2780
2791
 
2781
2792
  let sensorReadings = [];
2782
- let treadDepthCallback;
2783
- let buttonCallback;
2784
- let tpmsCallback;
2785
- const capabilities = [
2793
+ const capabilities$1 = [
2786
2794
  {
2787
2795
  id: "td",
2788
2796
  processFn: processTreadDepth,
@@ -2819,7 +2827,7 @@ const flexiGaugeTpmsService = {
2819
2827
  processMessage(deviceId, message) {
2820
2828
  const numberArray = Array.from(new Uint8Array(message));
2821
2829
  const stringFromBytes = String.fromCharCode.apply(null, numberArray).replace("\r\n", "");
2822
- for (const capability of capabilities) {
2830
+ for (const capability of capabilities$1) {
2823
2831
  if (capability.regex.test(stringFromBytes)) {
2824
2832
  return capability.processFn(deviceId, stringFromBytes);
2825
2833
  }
@@ -2829,12 +2837,12 @@ const flexiGaugeTpmsService = {
2829
2837
  function processTreadDepth(deviceId, value) {
2830
2838
  const treadDepth = value.match(/\d+/)?.[0];
2831
2839
  const convertedValue = Number(treadDepth) / 1e3;
2832
- treadDepthCallback(deviceId, convertedValue);
2840
+ simulatorSvc.triggerEvent("fg:treadDepth", deviceId, convertedValue);
2833
2841
  }
2834
2842
  function processButtonPress(deviceId, value) {
2835
2843
  const buttonName = value.match(/\*(.)/);
2836
2844
  if (!buttonName || !buttonName[1]) throw new Error("Unrecognized button");
2837
- buttonCallback(deviceId, buttonName[1]);
2845
+ simulatorSvc.triggerEvent("fg:button", deviceId, buttonName[1]);
2838
2846
  }
2839
2847
  function processTpms(deviceId, value) {
2840
2848
  const groupedValue = value.split(" ");
@@ -2854,12 +2862,13 @@ function processTpms(deviceId, value) {
2854
2862
  }
2855
2863
  if (type === "ENDSCANNING") {
2856
2864
  if (!sensorReadings.length) {
2857
- tpmsCallback(deviceId, void 0);
2865
+ simulatorSvc.triggerEvent("fg:tpms", deviceId, null);
2866
+ return;
2858
2867
  }
2859
2868
  const strongestReading = sensorReadings.reduce((accumulator, currentReading) => {
2860
2869
  return Number(currentReading.Rssi) > Number(accumulator.Rssi) ? currentReading : accumulator;
2861
2870
  }, sensorReadings[0]);
2862
- tpmsCallback(deviceId, strongestReading);
2871
+ simulatorSvc.triggerEvent("fg:tpms", deviceId, strongestReading);
2863
2872
  }
2864
2873
  }
2865
2874
 
@@ -2888,6 +2897,55 @@ const flexiGaugeTpms = {
2888
2897
  startTpmsScan: flexiGaugeTpmsService.startTpmsScan
2889
2898
  };
2890
2899
 
2900
+ const capabilities = [
2901
+ {
2902
+ id: "pressure",
2903
+ processFn: processPressure,
2904
+ regex: /P([0-9.]+)mBar/
2905
+ }
2906
+ ];
2907
+ const pressureStickService = {
2908
+ onPressure(callback) {
2909
+ simulatorSvc.registerEvent("ps:pressure", callback);
2910
+ },
2911
+ processMessage(deviceId, message) {
2912
+ const numberArray = Array.from(new Uint8Array(message));
2913
+ const stringFromBytes = String.fromCharCode.apply(null, numberArray).replace("\r\n", "");
2914
+ for (const capability of capabilities) {
2915
+ if (capability.regex.test(stringFromBytes)) {
2916
+ return capability.processFn(deviceId, stringFromBytes);
2917
+ }
2918
+ }
2919
+ }
2920
+ };
2921
+ function processPressure(deviceId, msg) {
2922
+ const match = /P([0-9.]+)mBar/i.exec(msg);
2923
+ if (!match) throw new Error("Incorrect pressure message");
2924
+ const pressure = Number(match[1]) / 1e3;
2925
+ simulatorSvc.triggerEvent("ps:pressure", deviceId, pressure);
2926
+ }
2927
+
2928
+ const pressureStick = {
2929
+ async connect(deviceId) {
2930
+ const psMeta = deviceMeta.pressureStick;
2931
+ await bluetooth.connect(deviceId, this.disconnect);
2932
+ await ble.startNotification(
2933
+ deviceId,
2934
+ psMeta.communication.serviceId,
2935
+ psMeta.communication.characteristicId,
2936
+ (notification) => pressureStickService.processMessage(deviceId, notification),
2937
+ (error) => console.warn("ble.startNotification error", error)
2938
+ );
2939
+ store.setState(deviceId, "paired");
2940
+ },
2941
+ async disconnect(deviceId, reason) {
2942
+ store.setState(deviceId, "disconnecting");
2943
+ await bluetooth.disconnect(deviceId);
2944
+ store.setState(deviceId, void 0, reason ?? "manualDisconnection");
2945
+ },
2946
+ onPressure: pressureStickService.onPressure
2947
+ };
2948
+
2891
2949
  const bridgeSimulator = {
2892
2950
  isRebootRequired(deviceId) {
2893
2951
  return store.bridgeRebootRequired[deviceId];
@@ -3261,6 +3319,8 @@ function createTirecheckDeviceSdk(platform, bleImplementation) {
3261
3319
  bridgeOta,
3262
3320
  /** Methods for working with Tirecheck TPMS FlexiGauge */
3263
3321
  flexiGaugeTpms,
3322
+ /** Methods for working with Tirecheck Pressure Stick */
3323
+ pressureStick,
3264
3324
  /** Allows simulating devices without actually using bluetooth */
3265
3325
  simulator
3266
3326
  };
package/dist/index.d.cts CHANGED
@@ -83,6 +83,14 @@ declare const _default$1: {
83
83
  getDeviceInfoFromAdvertising: (device: PeripheralData) => BleFlexiGaugeTpms;
84
84
  reconnect: boolean;
85
85
  };
86
+ pressureStick: {
87
+ nameRegex: RegExp;
88
+ communication: {
89
+ serviceId: string;
90
+ characteristicId: string;
91
+ };
92
+ getDeviceInfoFromAdvertising: (device: PeripheralData) => BlePressureStick;
93
+ };
86
94
  };
87
95
 
88
96
  declare const _default: {
@@ -734,7 +742,7 @@ type BridgeCommandStructurized<T extends BridgeCommandStructureProperties> = {
734
742
  };
735
743
  type BleDeviceType = keyof typeof _default$1;
736
744
  /** distinguish by type, e.g. `if (device.type === 'bridge')`, to access furhter fields */
737
- type BleDevice = BleBridge | BleBridgeOta | BleFlexiGaugeTpms;
745
+ type BleDevice = BleBridge | BleBridgeOta | BleFlexiGaugeTpms | BlePressureStick;
738
746
  type BleDeviceSimulated = BleBridgeSimulated | BleFlexiGaugeTpmsSimulated;
739
747
  type BleDeviceStatus = 'connected' | 'connecting' | 'disconnecting' | undefined;
740
748
  interface BleDeviceBase {
@@ -764,6 +772,9 @@ interface BleBridgeOta extends BleDeviceBase {
764
772
  };
765
773
  type: 'bridgeOta';
766
774
  }
775
+ interface BlePressureStick extends BleDeviceBase {
776
+ type: 'pressureStick';
777
+ }
767
778
  interface BleBridgeSimulated extends BleBridge {
768
779
  isDisabled?: boolean;
769
780
  simulatorData: {
@@ -809,11 +820,12 @@ type Wrapper<T extends Record<string, (...args: any) => any>> = {
809
820
  };
810
821
  type ReportStatusFn = (status: string, completionPercentage: number) => void;
811
822
  type DeviceState = 'connected' | 'connecting' | 'disconnecting' | 'paired' | undefined;
812
- type StateReason = 'lostConnection' | 'manualDisconnection' | 'failedConnection' | 'failedDisconnection' | 'firmwareUpdate';
823
+ type StateReason = 'lostConnection' | 'manualDisconnection' | 'failedConnection' | 'failedDisconnection' | 'firmwareUpdate' | string;
813
824
  interface EventHandlers {
814
825
  'fg:treadDepth'?: (deviceId: string, value: number) => void;
815
826
  'fg:button'?: (deviceId: string, value: string) => void;
816
827
  'fg:tpms'?: (deviceId: string, value: FgSensorReading | undefined) => void;
828
+ 'ps:pressure'?: (deviceId: string, value: number) => void;
817
829
  }
818
830
  type EventName = keyof EventHandlers;
819
831
 
@@ -836,7 +848,7 @@ declare function createTirecheckDeviceSdk(platform: DevicePlatform, bleImplement
836
848
  /** Methods for working with Tirecheck CAN Bridge */
837
849
  bridge: {
838
850
  disconnect: (deviceId: string, reason?: StateReason) => Promise<void>;
839
- connect(deviceId: string, accessLevel: BridgeAccessLevel): Promise<void>;
851
+ connect: (deviceId: string, accessLevel: BridgeAccessLevel) => Promise<void>;
840
852
  getVehicle: (deviceId: string) => Promise<BridgeTcVehicle>;
841
853
  setVehicle: (deviceId: string, tcVehicle: BridgeTcVehicle) => Promise<void>;
842
854
  getConfiguration: (deviceId: string) => Promise<BridgeConfiguration>;
@@ -864,14 +876,20 @@ declare function createTirecheckDeviceSdk(platform: DevicePlatform, bleImplement
864
876
  getBattery: (deviceId: string) => Promise<number>;
865
877
  startTpmsScan: (deviceId: string) => void;
866
878
  };
879
+ /** Methods for working with Tirecheck Pressure Stick */
880
+ pressureStick: {
881
+ connect(deviceId: string): Promise<void>;
882
+ disconnect(deviceId: string, reason?: StateReason): Promise<void>;
883
+ onPressure: (callback: (deviceId: string, value: number) => void) => void;
884
+ };
867
885
  /** Allows simulating devices without actually using bluetooth */
868
886
  simulator: {
869
887
  putSimulatedDevices(devices: Record<string, DeepPartial<BleDeviceSimulated>>): Record<string, BleDeviceSimulated>;
870
888
  putSimulatedDevice(device: DeepPartial<BleDeviceSimulated>): BleBridgeSimulated | BleFlexiGaugeTpmsSimulated;
871
889
  deleteSimulatedDevice(deviceId: string): void;
872
890
  getSimulatedDevices(): Record<string, BleDeviceSimulated>;
873
- triggerEvent: (eventName: EventName, deviceId: string) => void;
891
+ triggerEvent: (eventName: EventName, deviceId: string, payload?: any) => void;
874
892
  };
875
893
  };
876
894
 
877
- export { type BleBridge, type BleBridgeAdvertisingData, type BleBridgeOta, type BleBridgeSimulated, type BleDevice, type BleDeviceBase, type BleDeviceSimulated, type BleDeviceStatus, type BleDeviceType, type BleFlexiGaugeTpms, type BleFlexiGaugeTpmsSimulated, type BridgeAccessLevel, type BridgeAutolearnStatus, type BridgeCommandStructure, type BridgeCommandStructureProperties, type BridgeCommandStructurized, type BridgeConfiguration, type BridgeReading, type BridgeTcIssue, type BridgeTcTyre, type BridgeTcVehicle, BridgeTcVehicleAxle, type DeepPartial, type DevicePlatform, type DeviceState, type EventHandlers, type EventName, type FgSensorReading, type PositionInfo, type ReportStatusFn, type Simulator, type StateReason, type Wrapper, createTirecheckDeviceSdk };
895
+ export { type BleBridge, type BleBridgeAdvertisingData, type BleBridgeOta, type BleBridgeSimulated, type BleDevice, type BleDeviceBase, type BleDeviceSimulated, type BleDeviceStatus, type BleDeviceType, type BleFlexiGaugeTpms, type BleFlexiGaugeTpmsSimulated, type BlePressureStick, type BridgeAccessLevel, type BridgeAutolearnStatus, type BridgeCommandStructure, type BridgeCommandStructureProperties, type BridgeCommandStructurized, type BridgeConfiguration, type BridgeReading, type BridgeTcIssue, type BridgeTcTyre, type BridgeTcVehicle, BridgeTcVehicleAxle, type DeepPartial, type DevicePlatform, type DeviceState, type EventHandlers, type EventName, type FgSensorReading, type PositionInfo, type ReportStatusFn, type Simulator, type StateReason, type Wrapper, createTirecheckDeviceSdk };
package/dist/index.d.mts CHANGED
@@ -83,6 +83,14 @@ declare const _default$1: {
83
83
  getDeviceInfoFromAdvertising: (device: PeripheralData) => BleFlexiGaugeTpms;
84
84
  reconnect: boolean;
85
85
  };
86
+ pressureStick: {
87
+ nameRegex: RegExp;
88
+ communication: {
89
+ serviceId: string;
90
+ characteristicId: string;
91
+ };
92
+ getDeviceInfoFromAdvertising: (device: PeripheralData) => BlePressureStick;
93
+ };
86
94
  };
87
95
 
88
96
  declare const _default: {
@@ -734,7 +742,7 @@ type BridgeCommandStructurized<T extends BridgeCommandStructureProperties> = {
734
742
  };
735
743
  type BleDeviceType = keyof typeof _default$1;
736
744
  /** distinguish by type, e.g. `if (device.type === 'bridge')`, to access furhter fields */
737
- type BleDevice = BleBridge | BleBridgeOta | BleFlexiGaugeTpms;
745
+ type BleDevice = BleBridge | BleBridgeOta | BleFlexiGaugeTpms | BlePressureStick;
738
746
  type BleDeviceSimulated = BleBridgeSimulated | BleFlexiGaugeTpmsSimulated;
739
747
  type BleDeviceStatus = 'connected' | 'connecting' | 'disconnecting' | undefined;
740
748
  interface BleDeviceBase {
@@ -764,6 +772,9 @@ interface BleBridgeOta extends BleDeviceBase {
764
772
  };
765
773
  type: 'bridgeOta';
766
774
  }
775
+ interface BlePressureStick extends BleDeviceBase {
776
+ type: 'pressureStick';
777
+ }
767
778
  interface BleBridgeSimulated extends BleBridge {
768
779
  isDisabled?: boolean;
769
780
  simulatorData: {
@@ -809,11 +820,12 @@ type Wrapper<T extends Record<string, (...args: any) => any>> = {
809
820
  };
810
821
  type ReportStatusFn = (status: string, completionPercentage: number) => void;
811
822
  type DeviceState = 'connected' | 'connecting' | 'disconnecting' | 'paired' | undefined;
812
- type StateReason = 'lostConnection' | 'manualDisconnection' | 'failedConnection' | 'failedDisconnection' | 'firmwareUpdate';
823
+ type StateReason = 'lostConnection' | 'manualDisconnection' | 'failedConnection' | 'failedDisconnection' | 'firmwareUpdate' | string;
813
824
  interface EventHandlers {
814
825
  'fg:treadDepth'?: (deviceId: string, value: number) => void;
815
826
  'fg:button'?: (deviceId: string, value: string) => void;
816
827
  'fg:tpms'?: (deviceId: string, value: FgSensorReading | undefined) => void;
828
+ 'ps:pressure'?: (deviceId: string, value: number) => void;
817
829
  }
818
830
  type EventName = keyof EventHandlers;
819
831
 
@@ -836,7 +848,7 @@ declare function createTirecheckDeviceSdk(platform: DevicePlatform, bleImplement
836
848
  /** Methods for working with Tirecheck CAN Bridge */
837
849
  bridge: {
838
850
  disconnect: (deviceId: string, reason?: StateReason) => Promise<void>;
839
- connect(deviceId: string, accessLevel: BridgeAccessLevel): Promise<void>;
851
+ connect: (deviceId: string, accessLevel: BridgeAccessLevel) => Promise<void>;
840
852
  getVehicle: (deviceId: string) => Promise<BridgeTcVehicle>;
841
853
  setVehicle: (deviceId: string, tcVehicle: BridgeTcVehicle) => Promise<void>;
842
854
  getConfiguration: (deviceId: string) => Promise<BridgeConfiguration>;
@@ -864,14 +876,20 @@ declare function createTirecheckDeviceSdk(platform: DevicePlatform, bleImplement
864
876
  getBattery: (deviceId: string) => Promise<number>;
865
877
  startTpmsScan: (deviceId: string) => void;
866
878
  };
879
+ /** Methods for working with Tirecheck Pressure Stick */
880
+ pressureStick: {
881
+ connect(deviceId: string): Promise<void>;
882
+ disconnect(deviceId: string, reason?: StateReason): Promise<void>;
883
+ onPressure: (callback: (deviceId: string, value: number) => void) => void;
884
+ };
867
885
  /** Allows simulating devices without actually using bluetooth */
868
886
  simulator: {
869
887
  putSimulatedDevices(devices: Record<string, DeepPartial<BleDeviceSimulated>>): Record<string, BleDeviceSimulated>;
870
888
  putSimulatedDevice(device: DeepPartial<BleDeviceSimulated>): BleBridgeSimulated | BleFlexiGaugeTpmsSimulated;
871
889
  deleteSimulatedDevice(deviceId: string): void;
872
890
  getSimulatedDevices(): Record<string, BleDeviceSimulated>;
873
- triggerEvent: (eventName: EventName, deviceId: string) => void;
891
+ triggerEvent: (eventName: EventName, deviceId: string, payload?: any) => void;
874
892
  };
875
893
  };
876
894
 
877
- export { type BleBridge, type BleBridgeAdvertisingData, type BleBridgeOta, type BleBridgeSimulated, type BleDevice, type BleDeviceBase, type BleDeviceSimulated, type BleDeviceStatus, type BleDeviceType, type BleFlexiGaugeTpms, type BleFlexiGaugeTpmsSimulated, type BridgeAccessLevel, type BridgeAutolearnStatus, type BridgeCommandStructure, type BridgeCommandStructureProperties, type BridgeCommandStructurized, type BridgeConfiguration, type BridgeReading, type BridgeTcIssue, type BridgeTcTyre, type BridgeTcVehicle, BridgeTcVehicleAxle, type DeepPartial, type DevicePlatform, type DeviceState, type EventHandlers, type EventName, type FgSensorReading, type PositionInfo, type ReportStatusFn, type Simulator, type StateReason, type Wrapper, createTirecheckDeviceSdk };
895
+ export { type BleBridge, type BleBridgeAdvertisingData, type BleBridgeOta, type BleBridgeSimulated, type BleDevice, type BleDeviceBase, type BleDeviceSimulated, type BleDeviceStatus, type BleDeviceType, type BleFlexiGaugeTpms, type BleFlexiGaugeTpmsSimulated, type BlePressureStick, type BridgeAccessLevel, type BridgeAutolearnStatus, type BridgeCommandStructure, type BridgeCommandStructureProperties, type BridgeCommandStructurized, type BridgeConfiguration, type BridgeReading, type BridgeTcIssue, type BridgeTcTyre, type BridgeTcVehicle, BridgeTcVehicleAxle, type DeepPartial, type DevicePlatform, type DeviceState, type EventHandlers, type EventName, type FgSensorReading, type PositionInfo, type ReportStatusFn, type Simulator, type StateReason, type Wrapper, createTirecheckDeviceSdk };
package/dist/index.d.ts CHANGED
@@ -83,6 +83,14 @@ declare const _default$1: {
83
83
  getDeviceInfoFromAdvertising: (device: PeripheralData) => BleFlexiGaugeTpms;
84
84
  reconnect: boolean;
85
85
  };
86
+ pressureStick: {
87
+ nameRegex: RegExp;
88
+ communication: {
89
+ serviceId: string;
90
+ characteristicId: string;
91
+ };
92
+ getDeviceInfoFromAdvertising: (device: PeripheralData) => BlePressureStick;
93
+ };
86
94
  };
87
95
 
88
96
  declare const _default: {
@@ -734,7 +742,7 @@ type BridgeCommandStructurized<T extends BridgeCommandStructureProperties> = {
734
742
  };
735
743
  type BleDeviceType = keyof typeof _default$1;
736
744
  /** distinguish by type, e.g. `if (device.type === 'bridge')`, to access furhter fields */
737
- type BleDevice = BleBridge | BleBridgeOta | BleFlexiGaugeTpms;
745
+ type BleDevice = BleBridge | BleBridgeOta | BleFlexiGaugeTpms | BlePressureStick;
738
746
  type BleDeviceSimulated = BleBridgeSimulated | BleFlexiGaugeTpmsSimulated;
739
747
  type BleDeviceStatus = 'connected' | 'connecting' | 'disconnecting' | undefined;
740
748
  interface BleDeviceBase {
@@ -764,6 +772,9 @@ interface BleBridgeOta extends BleDeviceBase {
764
772
  };
765
773
  type: 'bridgeOta';
766
774
  }
775
+ interface BlePressureStick extends BleDeviceBase {
776
+ type: 'pressureStick';
777
+ }
767
778
  interface BleBridgeSimulated extends BleBridge {
768
779
  isDisabled?: boolean;
769
780
  simulatorData: {
@@ -809,11 +820,12 @@ type Wrapper<T extends Record<string, (...args: any) => any>> = {
809
820
  };
810
821
  type ReportStatusFn = (status: string, completionPercentage: number) => void;
811
822
  type DeviceState = 'connected' | 'connecting' | 'disconnecting' | 'paired' | undefined;
812
- type StateReason = 'lostConnection' | 'manualDisconnection' | 'failedConnection' | 'failedDisconnection' | 'firmwareUpdate';
823
+ type StateReason = 'lostConnection' | 'manualDisconnection' | 'failedConnection' | 'failedDisconnection' | 'firmwareUpdate' | string;
813
824
  interface EventHandlers {
814
825
  'fg:treadDepth'?: (deviceId: string, value: number) => void;
815
826
  'fg:button'?: (deviceId: string, value: string) => void;
816
827
  'fg:tpms'?: (deviceId: string, value: FgSensorReading | undefined) => void;
828
+ 'ps:pressure'?: (deviceId: string, value: number) => void;
817
829
  }
818
830
  type EventName = keyof EventHandlers;
819
831
 
@@ -836,7 +848,7 @@ declare function createTirecheckDeviceSdk(platform: DevicePlatform, bleImplement
836
848
  /** Methods for working with Tirecheck CAN Bridge */
837
849
  bridge: {
838
850
  disconnect: (deviceId: string, reason?: StateReason) => Promise<void>;
839
- connect(deviceId: string, accessLevel: BridgeAccessLevel): Promise<void>;
851
+ connect: (deviceId: string, accessLevel: BridgeAccessLevel) => Promise<void>;
840
852
  getVehicle: (deviceId: string) => Promise<BridgeTcVehicle>;
841
853
  setVehicle: (deviceId: string, tcVehicle: BridgeTcVehicle) => Promise<void>;
842
854
  getConfiguration: (deviceId: string) => Promise<BridgeConfiguration>;
@@ -864,14 +876,20 @@ declare function createTirecheckDeviceSdk(platform: DevicePlatform, bleImplement
864
876
  getBattery: (deviceId: string) => Promise<number>;
865
877
  startTpmsScan: (deviceId: string) => void;
866
878
  };
879
+ /** Methods for working with Tirecheck Pressure Stick */
880
+ pressureStick: {
881
+ connect(deviceId: string): Promise<void>;
882
+ disconnect(deviceId: string, reason?: StateReason): Promise<void>;
883
+ onPressure: (callback: (deviceId: string, value: number) => void) => void;
884
+ };
867
885
  /** Allows simulating devices without actually using bluetooth */
868
886
  simulator: {
869
887
  putSimulatedDevices(devices: Record<string, DeepPartial<BleDeviceSimulated>>): Record<string, BleDeviceSimulated>;
870
888
  putSimulatedDevice(device: DeepPartial<BleDeviceSimulated>): BleBridgeSimulated | BleFlexiGaugeTpmsSimulated;
871
889
  deleteSimulatedDevice(deviceId: string): void;
872
890
  getSimulatedDevices(): Record<string, BleDeviceSimulated>;
873
- triggerEvent: (eventName: EventName, deviceId: string) => void;
891
+ triggerEvent: (eventName: EventName, deviceId: string, payload?: any) => void;
874
892
  };
875
893
  };
876
894
 
877
- export { type BleBridge, type BleBridgeAdvertisingData, type BleBridgeOta, type BleBridgeSimulated, type BleDevice, type BleDeviceBase, type BleDeviceSimulated, type BleDeviceStatus, type BleDeviceType, type BleFlexiGaugeTpms, type BleFlexiGaugeTpmsSimulated, type BridgeAccessLevel, type BridgeAutolearnStatus, type BridgeCommandStructure, type BridgeCommandStructureProperties, type BridgeCommandStructurized, type BridgeConfiguration, type BridgeReading, type BridgeTcIssue, type BridgeTcTyre, type BridgeTcVehicle, BridgeTcVehicleAxle, type DeepPartial, type DevicePlatform, type DeviceState, type EventHandlers, type EventName, type FgSensorReading, type PositionInfo, type ReportStatusFn, type Simulator, type StateReason, type Wrapper, createTirecheckDeviceSdk };
895
+ export { type BleBridge, type BleBridgeAdvertisingData, type BleBridgeOta, type BleBridgeSimulated, type BleDevice, type BleDeviceBase, type BleDeviceSimulated, type BleDeviceStatus, type BleDeviceType, type BleFlexiGaugeTpms, type BleFlexiGaugeTpmsSimulated, type BlePressureStick, type BridgeAccessLevel, type BridgeAutolearnStatus, type BridgeCommandStructure, type BridgeCommandStructureProperties, type BridgeCommandStructurized, type BridgeConfiguration, type BridgeReading, type BridgeTcIssue, type BridgeTcTyre, type BridgeTcVehicle, BridgeTcVehicleAxle, type DeepPartial, type DevicePlatform, type DeviceState, type EventHandlers, type EventName, type FgSensorReading, type PositionInfo, type ReportStatusFn, type Simulator, type StateReason, type Wrapper, createTirecheckDeviceSdk };
package/dist/index.mjs CHANGED
@@ -495,7 +495,7 @@ const deviceMeta = {
495
495
  getDeviceInfoFromAdvertising: bridgeOtaAdvertisingParser.getDeviceInfoFromAdvertising
496
496
  },
497
497
  flexiGaugeTpms: {
498
- nameRegex: /Flexi.*/,
498
+ nameRegex: /^Flexi.*/,
499
499
  communication: {
500
500
  serviceId: "4880c12c-fdcb-4077-8920-a450d7f9b907",
501
501
  characteristicId: "fec26ec4-6d71-4442-9f81-55bc21d658d6"
@@ -513,28 +513,21 @@ const deviceMeta = {
513
513
  },
514
514
  reconnect: true
515
515
  // Do we need it here?
516
+ },
517
+ pressureStick: {
518
+ nameRegex: /Pressure Stick.*/,
519
+ communication: {
520
+ serviceId: "4880c12c-fdcb-4077-8920-a450d7f9b907",
521
+ characteristicId: "fec26ec4-6d71-4442-9f81-55bc21d658d6"
522
+ },
523
+ getDeviceInfoFromAdvertising: (device) => {
524
+ const bleDevice = {
525
+ ...device,
526
+ type: "pressureStick"
527
+ };
528
+ return bleDevice;
529
+ }
516
530
  }
517
- // pressureStick: {
518
- // nameRegex: /Pressure Stick.*/,
519
- // characteristic: {
520
- // serviceId: '4880c12c-fdcb-4077-8920-a450d7f9b907',
521
- // characteristicId: 'fec26ec4-6d71-4442-9f81-55bc21d658d6',
522
- // },
523
- // getDeviceInfoFromAdvertising: () => {},
524
- // capabilities: [
525
- // {
526
- // id: 'pressure',
527
- // // processFn: processPressure,
528
- // regex: /P([0-9.]+)mBar/,
529
- // },
530
- // // only pressure is needed for initial implementation, uncomment tpms functionality when needed
531
- // // {
532
- // // id: 'tpms',
533
- // // processFn: processTpms,
534
- // // regex: /^\*TPMS/,
535
- // // },
536
- // ],
537
- // },
538
531
  };
539
532
 
540
533
  const checkUnreachableDevicesTimeouts = {};
@@ -558,7 +551,7 @@ const bluetooth = {
558
551
  stopScan() {
559
552
  ble.stopScan();
560
553
  },
561
- connect,
554
+ connect: connect$1,
562
555
  disconnect: disconnect$1,
563
556
  write,
564
557
  read
@@ -585,7 +578,7 @@ async function scanDevices(services = [], duration) {
585
578
  (e) => console.error("ble.startScanWithOptions error:", e)
586
579
  );
587
580
  }
588
- async function connect(deviceId, disconnectCallback) {
581
+ async function connect$1(deviceId, disconnectCallback) {
589
582
  if (toolsSvc.canCommunicateWith(deviceId)) return console.warn("Connect Warn: Already connected to device");
590
583
  store.setState(deviceId, "connecting");
591
584
  let connectedDevice;
@@ -706,6 +699,78 @@ function getDeviceNameFromAdvertising(advertising) {
706
699
  return deviceName;
707
700
  }
708
701
 
702
+ const otaServiceUuid = "1d14d6ee-fd63-4fa1-bfa4-8f47b42119f0";
703
+ const otaControlCharacteristicUuid = "f7bf3564-fb6d-4e53-88a4-5e37e0326063";
704
+ const otaDataCharacteristicUuid = "984227f3-34fc-4045-a5d0-2c581f81a153";
705
+ const bridgeOtaCommands = {
706
+ async beginOta(deviceId) {
707
+ await bluetooth.write(deviceId, otaServiceUuid, otaControlCharacteristicUuid, new Uint8Array([0]).buffer, true);
708
+ },
709
+ async uploadOtaChunk(deviceId, data) {
710
+ await bluetooth.write(deviceId, otaServiceUuid, otaDataCharacteristicUuid, data, true);
711
+ },
712
+ async endOta(deviceId) {
713
+ await bluetooth.write(deviceId, otaServiceUuid, otaControlCharacteristicUuid, new Uint8Array([3]).buffer, true);
714
+ }
715
+ };
716
+
717
+ const bridgeOtaService = {
718
+ async updateFirmware(deviceId, bootloader, firmware, progressCallback) {
719
+ await delay(2e3);
720
+ progressCallback("Connecting to the bridge...", 0.1);
721
+ await bridgeOta.connect(deviceId);
722
+ progressCallback("Uploading bootloader...", 0.12);
723
+ await bridgeOtaCommands.beginOta(deviceId);
724
+ await uploadOta(deviceId, bootloader, (str, percents) => progressCallback(str, 0.12 + percents * 0.2));
725
+ await bridgeOtaCommands.endOta(deviceId);
726
+ progressCallback("Uploading application...", 0.32);
727
+ await bridgeOtaCommands.beginOta(deviceId);
728
+ await uploadOta(deviceId, firmware, (str, percents) => progressCallback(str, 0.32 + percents * 0.5));
729
+ await bridgeOtaCommands.endOta(deviceId);
730
+ progressCallback("Upload completed, disconnecting...", 0.81);
731
+ await bridgeOta.disconnect(deviceId);
732
+ progressCallback("Disconnected...", 1);
733
+ }
734
+ };
735
+ async function uploadOta(deviceId, firmwareBinary, reportStatus) {
736
+ let uploadedBytes = 0;
737
+ let chunkIndex = 0;
738
+ const mtu = store.platform === "android" ? 512 : deviceMeta.bridgeOta.mtu;
739
+ while (uploadedBytes < firmwareBinary.byteLength) {
740
+ if (chunkIndex % 100 === 0)
741
+ reportStatus(
742
+ `Uploading new firmware... (${_.round(uploadedBytes / 1e3)} / ${_.round(
743
+ firmwareBinary.byteLength / 1e3
744
+ )} KB)`,
745
+ uploadedBytes / firmwareBinary.byteLength
746
+ );
747
+ const chunkSize = Math.min(mtu - 3, firmwareBinary.byteLength - uploadedBytes);
748
+ const chunk = firmwareBinary.slice(uploadedBytes, uploadedBytes + chunkSize);
749
+ await bridgeOtaCommands.uploadOtaChunk(deviceId, chunk);
750
+ uploadedBytes += chunkSize;
751
+ chunkIndex++;
752
+ }
753
+ }
754
+
755
+ const bridgeOta = {
756
+ async connect(deviceId) {
757
+ await bluetooth.connect(deviceId, this.disconnect);
758
+ const _deviceId = store.deviceIdMapingTable[deviceId] ?? deviceId;
759
+ if (store.platform !== "ios") {
760
+ await ble.requestMtu(_deviceId, 512);
761
+ }
762
+ store.setState(deviceId, "paired");
763
+ },
764
+ async disconnect(deviceId, reason) {
765
+ store.setState(deviceId, "disconnecting");
766
+ await bluetooth.disconnect(deviceId);
767
+ store.setState(deviceId, void 0, reason ?? "manualDisconnection");
768
+ },
769
+ async updateFirmware(deviceId, bootloader, firmware, progressCallback) {
770
+ return bridgeOtaService.updateFirmware(deviceId, bootloader, firmware, progressCallback);
771
+ }
772
+ };
773
+
709
774
  const bridgeCommandStructures = {
710
775
  workshopCanSettings: {
711
776
  id: [98, 96],
@@ -1523,25 +1588,26 @@ const bridgeSecurity = {
1523
1588
  };
1524
1589
 
1525
1590
  const bridgeMeta = deviceMeta.bridge;
1526
- let promiseQueue = Promise.resolve();
1527
- let currentResolve = (_v) => {
1528
- };
1529
- let currentReject = (_v) => {
1530
- };
1531
- let responseIdentifier;
1532
- const promiseQueue$1 = {
1533
- clearQueue(message) {
1534
- currentReject(new Error(message ?? "Stopped sending commands"));
1535
- promiseQueue = Promise.resolve();
1536
- responseIdentifier = [];
1591
+ const devicePromiseQueue = {};
1592
+ const deviceCurrentResolve = {};
1593
+ const deviceCurrentReject = {};
1594
+ const deviceResponseIdentifier = {};
1595
+ const promiseQueue = {
1596
+ clearQueue(deviceId, message) {
1597
+ if (deviceCurrentReject[deviceId]) {
1598
+ deviceCurrentReject[deviceId](new Error(message ?? "Stopped sending commands"));
1599
+ }
1600
+ devicePromiseQueue[deviceId] = Promise.resolve();
1601
+ deviceResponseIdentifier[deviceId] = [];
1537
1602
  },
1538
1603
  async enqueue(device, payload) {
1539
- promiseQueue = promiseQueue.then(() => {
1604
+ if (devicePromiseQueue[device.id] === void 0) devicePromiseQueue[device.id] = Promise.resolve();
1605
+ devicePromiseQueue[device.id] = devicePromiseQueue[device.id].then(() => {
1540
1606
  const promise = new Promise((resolve, reject) => {
1541
- currentResolve = resolve;
1542
- currentReject = reject;
1607
+ deviceCurrentResolve[device.id] = resolve;
1608
+ deviceCurrentReject[device.id] = reject;
1543
1609
  const isKeepAlive = payload[3] === commandIds.keepAlive;
1544
- responseIdentifier = [isKeepAlive ? 126 : 0, payload[4]];
1610
+ deviceResponseIdentifier[device.id] = [isKeepAlive ? 126 : 0, payload[4]];
1545
1611
  const signedData = bridgeSecurity.getSignedCommand(device, payload);
1546
1612
  if (!toolsSvc.canCommunicateWith(device.id)) return reject(new Error("Bridge not connected"));
1547
1613
  if (signedData.length > 110) {
@@ -1567,21 +1633,21 @@ const promiseQueue$1 = {
1567
1633
  );
1568
1634
  }
1569
1635
  });
1570
- return withTimeout(promise, 5e3, `Command timed out ${responseIdentifier}`);
1636
+ return withTimeout(promise, 5e3, `Command timed out ${deviceResponseIdentifier[device.id]}, ${device.id}`);
1571
1637
  });
1572
- return promiseQueue;
1638
+ return devicePromiseQueue[device.id];
1573
1639
  },
1574
1640
  async processMessage(deviceId, payload) {
1575
1641
  const numberArray = Array.from(new Uint8Array(payload));
1576
1642
  if (numberArray[3] === 127) {
1577
1643
  console.error(numberArray);
1578
- return currentReject(new Error(`Command not succesful: ${numberArray[4]}`));
1644
+ return deviceCurrentReject[deviceId](new Error(`Command not succesful: ${numberArray[4]}`));
1579
1645
  }
1580
1646
  if ([226, 81].includes(numberArray[3]) && numberArray[4] && toolsSvc.canCommunicateWith(deviceId)) {
1581
1647
  store.bridgeRebootRequired[deviceId] = true;
1582
1648
  }
1583
- if ((!responseIdentifier[0] || numberArray[3] === responseIdentifier[0]) && (!responseIdentifier[1] || numberArray[4] === responseIdentifier[1])) {
1584
- return currentResolve(numberArray);
1649
+ if ((!deviceResponseIdentifier[deviceId][0] || numberArray[3] === deviceResponseIdentifier[deviceId][0]) && (!deviceResponseIdentifier[deviceId][1] || numberArray[4] === deviceResponseIdentifier[deviceId][1])) {
1650
+ return deviceCurrentResolve[deviceId](numberArray);
1585
1651
  }
1586
1652
  console.warn("message from the device not belonging to the pending promise: ", numberArray);
1587
1653
  }
@@ -1968,79 +2034,7 @@ const bridgeCommands = {
1968
2034
  }
1969
2035
  this.sendKeepAliveCommand(device);
1970
2036
  }, 1e4);
1971
- return promiseQueue$1.enqueue(device, writeCommand);
1972
- }
1973
- };
1974
-
1975
- const otaServiceUuid = "1d14d6ee-fd63-4fa1-bfa4-8f47b42119f0";
1976
- const otaControlCharacteristicUuid = "f7bf3564-fb6d-4e53-88a4-5e37e0326063";
1977
- const otaDataCharacteristicUuid = "984227f3-34fc-4045-a5d0-2c581f81a153";
1978
- const bridgeOtaCommands = {
1979
- async beginOta(deviceId) {
1980
- await bluetooth.write(deviceId, otaServiceUuid, otaControlCharacteristicUuid, new Uint8Array([0]).buffer, true);
1981
- },
1982
- async uploadOtaChunk(deviceId, data) {
1983
- await bluetooth.write(deviceId, otaServiceUuid, otaDataCharacteristicUuid, data, true);
1984
- },
1985
- async endOta(deviceId) {
1986
- await bluetooth.write(deviceId, otaServiceUuid, otaControlCharacteristicUuid, new Uint8Array([3]).buffer, true);
1987
- }
1988
- };
1989
-
1990
- const bridgeOtaService = {
1991
- async updateFirmware(deviceId, bootloader, firmware, progressCallback) {
1992
- await delay(2e3);
1993
- progressCallback("Connecting to the bridge...", 0.1);
1994
- await bridgeOta.connect(deviceId);
1995
- progressCallback("Uploading bootloader...", 0.12);
1996
- await bridgeOtaCommands.beginOta(deviceId);
1997
- await uploadOta(deviceId, bootloader, (str, percents) => progressCallback(str, 0.12 + percents * 0.2));
1998
- await bridgeOtaCommands.endOta(deviceId);
1999
- progressCallback("Uploading application...", 0.32);
2000
- await bridgeOtaCommands.beginOta(deviceId);
2001
- await uploadOta(deviceId, firmware, (str, percents) => progressCallback(str, 0.32 + percents * 0.5));
2002
- await bridgeOtaCommands.endOta(deviceId);
2003
- progressCallback("Upload completed, disconnecting...", 0.81);
2004
- await bridgeOta.disconnect(deviceId);
2005
- progressCallback("Disconnected...", 1);
2006
- }
2007
- };
2008
- async function uploadOta(deviceId, firmwareBinary, reportStatus) {
2009
- let uploadedBytes = 0;
2010
- let chunkIndex = 0;
2011
- const mtu = store.platform === "android" ? 512 : deviceMeta.bridgeOta.mtu;
2012
- while (uploadedBytes < firmwareBinary.byteLength) {
2013
- if (chunkIndex % 100 === 0)
2014
- reportStatus(
2015
- `Uploading new firmware... (${_.round(uploadedBytes / 1e3)} / ${_.round(
2016
- firmwareBinary.byteLength / 1e3
2017
- )} KB)`,
2018
- uploadedBytes / firmwareBinary.byteLength
2019
- );
2020
- const chunkSize = Math.min(mtu - 3, firmwareBinary.byteLength - uploadedBytes);
2021
- const chunk = firmwareBinary.slice(uploadedBytes, uploadedBytes + chunkSize);
2022
- await bridgeOtaCommands.uploadOtaChunk(deviceId, chunk);
2023
- uploadedBytes += chunkSize;
2024
- chunkIndex++;
2025
- }
2026
- }
2027
-
2028
- const bridgeOta = {
2029
- async connect(deviceId) {
2030
- await bluetooth.connect(deviceId, this.disconnect);
2031
- const _deviceId = store.deviceIdMapingTable[deviceId] ?? deviceId;
2032
- if (store.platform !== "ios") {
2033
- await ble.requestMtu(_deviceId, 512);
2034
- }
2035
- store.setState(deviceId, "paired");
2036
- },
2037
- async disconnect(deviceId, reason) {
2038
- store.setState(deviceId, "disconnecting");
2039
- await bluetooth.disconnect(deviceId);
2040
- store.setState(deviceId, void 0, reason ?? "manualDisconnection");
2041
- },
2042
- async updateFirmware(deviceId, bootloader, firmware, progressCallback) {
2043
- return bridgeOtaService.updateFirmware(deviceId, bootloader, firmware, progressCallback);
2037
+ return promiseQueue.enqueue(device, writeCommand);
2044
2038
  }
2045
2039
  };
2046
2040
 
@@ -2062,8 +2056,13 @@ const bridgeService = {
2062
2056
  getVehicleReadings,
2063
2057
  resetAutolearnStatuses,
2064
2058
  getAutolearnStatuses,
2065
- isRebootRequired
2059
+ isRebootRequired,
2060
+ sendPinCommand
2066
2061
  };
2062
+ async function sendPinCommand(deviceId) {
2063
+ if (!canCommunicateWith(deviceId)) throw new Error("Bridge not connected");
2064
+ await bridgeCommands.sendPinCommand(deviceId);
2065
+ }
2067
2066
  async function updateFirmware(deviceId, bootloader, firmware, reportStatus) {
2068
2067
  reportStatus("Sending OTA Request...", 0.02);
2069
2068
  await bridgeCommands.sendOtaRequest(deviceId);
@@ -2385,7 +2384,7 @@ async function getVehicleReadings(deviceId, tcVehicle) {
2385
2384
  try {
2386
2385
  for (const vehicleTyre of tcVehicle.tcTyres) {
2387
2386
  if (vehicleTyre.tcTpmsSensor && vehicleTyre.mountedOn?.positionId) {
2388
- if (!canCommunicateWith(deviceId)) throw new Error("getVehicleReadings: no connected bridge");
2387
+ if (!canCommunicateWith(deviceId)) break;
2389
2388
  const reading = await getSensorReading(deviceId, vehicleTyre.mountedOn.positionId);
2390
2389
  readings.push(reading);
2391
2390
  }
@@ -2683,12 +2682,28 @@ function isRebootRequired(deviceId) {
2683
2682
 
2684
2683
  const bridge = {
2685
2684
  disconnect,
2686
- async connect(deviceId, accessLevel) {
2687
- if (canCommunicateWith(deviceId)) return;
2688
- await promiseQueue$1.clearQueue("Previous pending commands aborted");
2689
- const bridgeMeta = deviceMeta.bridge;
2690
- await bluetooth.connect(deviceId, disconnect);
2691
- const _deviceId = store.deviceIdMapingTable[deviceId] ?? deviceId;
2685
+ connect,
2686
+ getVehicle: bridgeService.getVehicle,
2687
+ setVehicle: bridgeService.setVehicle,
2688
+ getConfiguration: bridgeService.getConfiguration,
2689
+ setConfiguration: bridgeService.setConfiguration,
2690
+ getSensorReading: bridgeService.getSensorReading,
2691
+ getVehicleReadings: bridgeService.getVehicleReadings,
2692
+ getAutolearnStatuses: bridgeService.getAutolearnStatuses,
2693
+ resetAutolearnStatuses: bridgeService.resetAutolearnStatuses,
2694
+ updateFirmware: bridgeService.updateFirmware,
2695
+ isRebootRequired: bridgeService.isRebootRequired
2696
+ };
2697
+ async function connect(deviceId, accessLevel) {
2698
+ if (canCommunicateWith(deviceId)) return;
2699
+ await promiseQueue.clearQueue(deviceId, "Previous pending commands aborted");
2700
+ const bridgeMeta = deviceMeta.bridge;
2701
+ await bluetooth.connect(deviceId, disconnect);
2702
+ if (store.deviceState[deviceId] === "paired") {
2703
+ return console.warn("Connect Warn: Already connected");
2704
+ }
2705
+ const _deviceId = store.deviceIdMapingTable[deviceId] ?? deviceId;
2706
+ try {
2692
2707
  if (store.platform !== "ios") {
2693
2708
  await ble.requestMtu(_deviceId, deviceMeta.bridge.mtu);
2694
2709
  }
@@ -2696,28 +2711,22 @@ const bridge = {
2696
2711
  _deviceId,
2697
2712
  bridgeMeta.communication.serviceId,
2698
2713
  bridgeMeta.communication.characteristicId,
2699
- (notification) => promiseQueue$1.processMessage(deviceId, notification),
2714
+ (notification) => promiseQueue.processMessage(deviceId, notification),
2700
2715
  (error) => console.error("startNotification Error", error)
2701
2716
  );
2702
2717
  store.deviceAccessLevel[deviceId] = accessLevel ?? "driver";
2703
2718
  store.bridgeRebootRequired[deviceId] = false;
2704
- await bridgeCommands.sendPinCommand(deviceId);
2719
+ await bridgeService.sendPinCommand(deviceId);
2705
2720
  store.setState(deviceId, "paired");
2706
- },
2707
- getVehicle: bridgeService.getVehicle,
2708
- setVehicle: bridgeService.setVehicle,
2709
- getConfiguration: bridgeService.getConfiguration,
2710
- setConfiguration: bridgeService.setConfiguration,
2711
- getSensorReading: bridgeService.getSensorReading,
2712
- getVehicleReadings: bridgeService.getVehicleReadings,
2713
- getAutolearnStatuses: bridgeService.getAutolearnStatuses,
2714
- resetAutolearnStatuses: bridgeService.resetAutolearnStatuses,
2715
- updateFirmware: bridgeService.updateFirmware,
2716
- isRebootRequired: bridgeService.isRebootRequired
2717
- };
2721
+ } catch (e) {
2722
+ disconnect(deviceId);
2723
+ throw new Error(`Pairing unsuccessful ${e}`);
2724
+ }
2725
+ }
2718
2726
  async function disconnect(deviceId, reason) {
2727
+ await waitUntil(() => store.deviceState[deviceId] === "paired" || store.deviceState[deviceId] === void 0);
2719
2728
  store.setState(deviceId, "disconnecting");
2720
- promiseQueue$1.clearQueue("Previous pending commands aborted");
2729
+ promiseQueue.clearQueue(deviceId, "Previous pending commands aborted");
2721
2730
  await bluetooth.disconnect(deviceId);
2722
2731
  delete store.devices[deviceId];
2723
2732
  deviceUnreachableCallback?.(deviceId);
@@ -2729,11 +2738,13 @@ const simulatorSvc = {
2729
2738
  registerEvent(eventName, callback) {
2730
2739
  callbacks[eventName] = callback;
2731
2740
  },
2732
- triggerEvent(eventName, deviceId) {
2733
- const simulatedDevice = store.simulatedDevices[deviceId];
2734
- if (!simulatedDevice) throw new Error(`Device not found`);
2735
- const payload = simulatedDevice.simulatorData?.events?.[eventName];
2736
- if (!payload) throw new Error(`Event not found`);
2741
+ triggerEvent(eventName, deviceId, payload) {
2742
+ if (payload === void 0) {
2743
+ const simulatedDevice = store.simulatedDevices[deviceId];
2744
+ if (!simulatedDevice) throw new Error(`Device not found`);
2745
+ payload = simulatedDevice.simulatorData?.events?.[eventName];
2746
+ if (!payload) throw new Error(`Event not found`);
2747
+ }
2737
2748
  const callback = callbacks[eventName];
2738
2749
  if (!callback) {
2739
2750
  console.warn(`Event ${eventName} not registered`);
@@ -2772,10 +2783,7 @@ async function getBattery(deviceId) {
2772
2783
  }
2773
2784
 
2774
2785
  let sensorReadings = [];
2775
- let treadDepthCallback;
2776
- let buttonCallback;
2777
- let tpmsCallback;
2778
- const capabilities = [
2786
+ const capabilities$1 = [
2779
2787
  {
2780
2788
  id: "td",
2781
2789
  processFn: processTreadDepth,
@@ -2812,7 +2820,7 @@ const flexiGaugeTpmsService = {
2812
2820
  processMessage(deviceId, message) {
2813
2821
  const numberArray = Array.from(new Uint8Array(message));
2814
2822
  const stringFromBytes = String.fromCharCode.apply(null, numberArray).replace("\r\n", "");
2815
- for (const capability of capabilities) {
2823
+ for (const capability of capabilities$1) {
2816
2824
  if (capability.regex.test(stringFromBytes)) {
2817
2825
  return capability.processFn(deviceId, stringFromBytes);
2818
2826
  }
@@ -2822,12 +2830,12 @@ const flexiGaugeTpmsService = {
2822
2830
  function processTreadDepth(deviceId, value) {
2823
2831
  const treadDepth = value.match(/\d+/)?.[0];
2824
2832
  const convertedValue = Number(treadDepth) / 1e3;
2825
- treadDepthCallback(deviceId, convertedValue);
2833
+ simulatorSvc.triggerEvent("fg:treadDepth", deviceId, convertedValue);
2826
2834
  }
2827
2835
  function processButtonPress(deviceId, value) {
2828
2836
  const buttonName = value.match(/\*(.)/);
2829
2837
  if (!buttonName || !buttonName[1]) throw new Error("Unrecognized button");
2830
- buttonCallback(deviceId, buttonName[1]);
2838
+ simulatorSvc.triggerEvent("fg:button", deviceId, buttonName[1]);
2831
2839
  }
2832
2840
  function processTpms(deviceId, value) {
2833
2841
  const groupedValue = value.split(" ");
@@ -2847,12 +2855,13 @@ function processTpms(deviceId, value) {
2847
2855
  }
2848
2856
  if (type === "ENDSCANNING") {
2849
2857
  if (!sensorReadings.length) {
2850
- tpmsCallback(deviceId, void 0);
2858
+ simulatorSvc.triggerEvent("fg:tpms", deviceId, null);
2859
+ return;
2851
2860
  }
2852
2861
  const strongestReading = sensorReadings.reduce((accumulator, currentReading) => {
2853
2862
  return Number(currentReading.Rssi) > Number(accumulator.Rssi) ? currentReading : accumulator;
2854
2863
  }, sensorReadings[0]);
2855
- tpmsCallback(deviceId, strongestReading);
2864
+ simulatorSvc.triggerEvent("fg:tpms", deviceId, strongestReading);
2856
2865
  }
2857
2866
  }
2858
2867
 
@@ -2881,6 +2890,55 @@ const flexiGaugeTpms = {
2881
2890
  startTpmsScan: flexiGaugeTpmsService.startTpmsScan
2882
2891
  };
2883
2892
 
2893
+ const capabilities = [
2894
+ {
2895
+ id: "pressure",
2896
+ processFn: processPressure,
2897
+ regex: /P([0-9.]+)mBar/
2898
+ }
2899
+ ];
2900
+ const pressureStickService = {
2901
+ onPressure(callback) {
2902
+ simulatorSvc.registerEvent("ps:pressure", callback);
2903
+ },
2904
+ processMessage(deviceId, message) {
2905
+ const numberArray = Array.from(new Uint8Array(message));
2906
+ const stringFromBytes = String.fromCharCode.apply(null, numberArray).replace("\r\n", "");
2907
+ for (const capability of capabilities) {
2908
+ if (capability.regex.test(stringFromBytes)) {
2909
+ return capability.processFn(deviceId, stringFromBytes);
2910
+ }
2911
+ }
2912
+ }
2913
+ };
2914
+ function processPressure(deviceId, msg) {
2915
+ const match = /P([0-9.]+)mBar/i.exec(msg);
2916
+ if (!match) throw new Error("Incorrect pressure message");
2917
+ const pressure = Number(match[1]) / 1e3;
2918
+ simulatorSvc.triggerEvent("ps:pressure", deviceId, pressure);
2919
+ }
2920
+
2921
+ const pressureStick = {
2922
+ async connect(deviceId) {
2923
+ const psMeta = deviceMeta.pressureStick;
2924
+ await bluetooth.connect(deviceId, this.disconnect);
2925
+ await ble.startNotification(
2926
+ deviceId,
2927
+ psMeta.communication.serviceId,
2928
+ psMeta.communication.characteristicId,
2929
+ (notification) => pressureStickService.processMessage(deviceId, notification),
2930
+ (error) => console.warn("ble.startNotification error", error)
2931
+ );
2932
+ store.setState(deviceId, "paired");
2933
+ },
2934
+ async disconnect(deviceId, reason) {
2935
+ store.setState(deviceId, "disconnecting");
2936
+ await bluetooth.disconnect(deviceId);
2937
+ store.setState(deviceId, void 0, reason ?? "manualDisconnection");
2938
+ },
2939
+ onPressure: pressureStickService.onPressure
2940
+ };
2941
+
2884
2942
  const bridgeSimulator = {
2885
2943
  isRebootRequired(deviceId) {
2886
2944
  return store.bridgeRebootRequired[deviceId];
@@ -3254,6 +3312,8 @@ function createTirecheckDeviceSdk(platform, bleImplementation) {
3254
3312
  bridgeOta,
3255
3313
  /** Methods for working with Tirecheck TPMS FlexiGauge */
3256
3314
  flexiGaugeTpms,
3315
+ /** Methods for working with Tirecheck Pressure Stick */
3316
+ pressureStick,
3257
3317
  /** Allows simulating devices without actually using bluetooth */
3258
3318
  simulator
3259
3319
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tirecheck-device-sdk",
3
- "version": "0.1.94",
3
+ "version": "0.1.96",
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",