@tempivo/sensor-beacon 0.3.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -11
- package/android/build.gradle +13 -5
- package/android/src/main/AndroidManifest.xml +2 -1
- package/android/src/main/java/expo/modules/tempivosensorbeacon/SensorBeaconNative.java +6 -16
- package/android/src/main/java/expo/modules/tempivosensorbeacon/TempivoSensorBeaconModule.kt +13 -6
- package/android-aar/library/src/main/java/com/tempivo/sensor/beacon/PartnerBleRules.kt +17 -6
- package/android-aar/library/src/main/java/com/tempivo/sensor/beacon/SensorBleRuntime.kt +34 -124
- package/android-aar/library/src/main/java/com/tempivo/sensor/beacon/SensorSdkScanTelemetry.kt +138 -0
- package/android-aar/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorBeaconDecoder.kt +99 -18
- package/android-aar/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorBeaconScanner.kt +165 -65
- package/android-aar/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorError.kt +0 -17
- package/android-aar/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorProfile.kt +59 -2
- package/android-aar/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorQr.kt +7 -17
- package/android-aar/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorSession.kt +9 -38
- package/dist/decoder.d.ts +0 -2
- package/dist/decoder.js +0 -17
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/native-helpers.d.ts +0 -1
- package/dist/native-helpers.js +3 -18
- package/dist/native-module.js +5 -2
- package/dist/normalize.d.ts +6 -0
- package/dist/normalize.js +29 -0
- package/dist/profile.d.ts +5 -0
- package/dist/profile.js +47 -1
- package/dist/qr.d.ts +4 -7
- package/dist/qr.js +9 -24
- package/dist/react-native.d.ts +24 -1
- package/dist/react-native.js +22 -1
- package/dist/session-types.d.ts +11 -4
- package/dist/tempivo-sensor-beacon.aar +0 -0
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64/TempivoSensorBridge.framework/Headers/TempivoSensorBridge.h +1 -3
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64/TempivoSensorBridge.framework/TempivoSensorBridge +0 -0
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64-simulator/TempivoSensorBridge.framework/Headers/TempivoSensorBridge.h +1 -3
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64-simulator/TempivoSensorBridge.framework/TempivoSensorBridge +0 -0
- package/ios/Sources/TempivoSensorBeacon/TempivoSensorBeaconDecoder.swift +12 -2
- package/ios/Sources/TempivoSensorBeacon/TempivoSensorBeaconScanner.swift +4 -80
- package/ios/Sources/TempivoSensorBeacon/TempivoSensorBeaconTypes.swift +0 -15
- package/ios/Sources/TempivoSensorBeacon/TempivoSensorError.swift +1 -15
- package/ios/Sources/TempivoSensorBeacon/TempivoSensorProfile.swift +57 -3
- package/ios/Sources/TempivoSensorBeacon/TempivoSensorQr.swift +9 -23
- package/ios/Sources/TempivoSensorBeacon/TempivoSensorSession.swift +10 -36
- package/ios/Sources/TempivoSensorBeacon/TempivoSensorSessionTypes.swift +10 -2
- package/ios/TempivoSensorBeaconModule.swift +139 -25
- package/package.json +6 -1
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
package com.tempivo.sensor.beacon
|
|
2
2
|
|
|
3
|
-
import android.app.Application
|
|
4
3
|
import android.content.Context
|
|
5
4
|
import kotlinx.coroutines.Dispatchers
|
|
6
5
|
import kotlinx.coroutines.runBlocking
|
|
@@ -14,17 +13,12 @@ import kotlinx.coroutines.withContext
|
|
|
14
13
|
class TempivoSensorSession(
|
|
15
14
|
context: Context,
|
|
16
15
|
) {
|
|
17
|
-
enum class SessionType {
|
|
18
|
-
MODERN,
|
|
19
|
-
LEGACY,
|
|
20
|
-
}
|
|
21
|
-
|
|
22
16
|
data class TriggerResult(
|
|
23
17
|
val ok: Boolean,
|
|
24
18
|
val supported: Boolean,
|
|
25
19
|
)
|
|
26
20
|
|
|
27
|
-
private val application = context.applicationContext as Application
|
|
21
|
+
private val application = context.applicationContext as android.app.Application
|
|
28
22
|
private val mutex = Mutex()
|
|
29
23
|
private var session: SensorBleRuntime.Session? = null
|
|
30
24
|
|
|
@@ -32,18 +26,10 @@ class TempivoSensorSession(
|
|
|
32
26
|
serial: String,
|
|
33
27
|
bluetoothMac: String,
|
|
34
28
|
pin: String,
|
|
35
|
-
sessionType: SessionType = SessionType.MODERN,
|
|
36
|
-
deviceId: String? = null,
|
|
37
|
-
firmware: String? = null,
|
|
38
29
|
) {
|
|
39
30
|
val pinInt =
|
|
40
31
|
pin.trim().toIntOrNull()
|
|
41
32
|
?: throw TempivoSensorException(TempivoSensorException.Code.INVALID_PIN, "PIN must be numeric.")
|
|
42
|
-
val resolved =
|
|
43
|
-
TempivoSensorQrParser.resolveSessionType(
|
|
44
|
-
if (sessionType == SessionType.LEGACY) "HC5" else "HC7",
|
|
45
|
-
firmware,
|
|
46
|
-
)
|
|
47
33
|
try {
|
|
48
34
|
mutex.withLock {
|
|
49
35
|
SensorBleRuntime.disconnect(session)
|
|
@@ -55,20 +41,13 @@ class TempivoSensorSession(
|
|
|
55
41
|
serial = TempivoSensorQrParser.normalizeSerial(serial),
|
|
56
42
|
bluetoothMac = bluetoothMac,
|
|
57
43
|
pin = pinInt,
|
|
58
|
-
legacy = resolved == SessionType.LEGACY,
|
|
59
|
-
deviceId = deviceId?.ifBlank { null } ?: serial,
|
|
60
|
-
encryptionKey = pin.trim(),
|
|
61
44
|
)
|
|
62
45
|
}
|
|
63
46
|
}
|
|
64
47
|
} catch (e: Throwable) {
|
|
65
48
|
throw SensorBleRuntime.mapError(e).let {
|
|
66
49
|
if (it.code == TempivoSensorException.Code.UNKNOWN) {
|
|
67
|
-
TempivoSensorException(
|
|
68
|
-
TempivoSensorException.Code.CONNECT_FAILED,
|
|
69
|
-
it.message ?: "Could not connect.",
|
|
70
|
-
e,
|
|
71
|
-
)
|
|
50
|
+
TempivoSensorException(TempivoSensorException.Code.CONNECT_FAILED, "Could not connect.", e)
|
|
72
51
|
} else {
|
|
73
52
|
it
|
|
74
53
|
}
|
|
@@ -76,15 +55,8 @@ class TempivoSensorSession(
|
|
|
76
55
|
}
|
|
77
56
|
}
|
|
78
57
|
|
|
79
|
-
suspend fun connect(qr: TempivoSensorQr
|
|
80
|
-
connect(
|
|
81
|
-
serial = qr.serial,
|
|
82
|
-
bluetoothMac = seen?.bluetoothMac ?: qr.bluetoothMac,
|
|
83
|
-
pin = qr.pin,
|
|
84
|
-
sessionType = qr.sessionType,
|
|
85
|
-
deviceId = seen?.deviceId,
|
|
86
|
-
firmware = seen?.firmware,
|
|
87
|
-
)
|
|
58
|
+
suspend fun connect(qr: TempivoSensorQr) {
|
|
59
|
+
connect(qr.serial, qr.bluetoothMac, qr.pin)
|
|
88
60
|
}
|
|
89
61
|
|
|
90
62
|
suspend fun disconnect() {
|
|
@@ -95,15 +67,16 @@ class TempivoSensorSession(
|
|
|
95
67
|
}
|
|
96
68
|
|
|
97
69
|
suspend fun getConfiguration(): TempivoSensorConfiguration {
|
|
98
|
-
return runGatt {
|
|
70
|
+
return runGatt {
|
|
71
|
+
SensorBleRuntime.decompile(SensorBleRuntime.readConfiguration(requireSession()))
|
|
72
|
+
}
|
|
99
73
|
}
|
|
100
74
|
|
|
101
75
|
suspend fun getConfigurationJson(): String = TempivoSensorProfile.toJson(getConfiguration())
|
|
102
76
|
|
|
103
77
|
suspend fun setConfiguration(configuration: TempivoSensorConfiguration) {
|
|
104
|
-
val (rules, calendars) = SensorBleRuntime.compileRules(configuration)
|
|
105
78
|
runGatt {
|
|
106
|
-
SensorBleRuntime.
|
|
79
|
+
SensorBleRuntime.writeConfiguration(requireSession(), configuration)
|
|
107
80
|
}
|
|
108
81
|
}
|
|
109
82
|
|
|
@@ -119,9 +92,7 @@ class TempivoSensorSession(
|
|
|
119
92
|
return runGatt { SensorBleRuntime.readCalibration(requireSession()) }
|
|
120
93
|
}
|
|
121
94
|
|
|
122
|
-
|
|
123
|
-
fun connectBlocking(qr: TempivoSensorQr, seen: TempivoSensorBeaconScanner.SeenDevice? = null) =
|
|
124
|
-
runBlocking { connect(qr, seen) }
|
|
95
|
+
fun connectBlocking(qr: TempivoSensorQr) = runBlocking { connect(qr) }
|
|
125
96
|
|
|
126
97
|
fun disconnectBlocking() = runBlocking { disconnect() }
|
|
127
98
|
|
package/dist/decoder.d.ts
CHANGED
|
@@ -11,5 +11,3 @@ export declare function splitSensorBeaconFrames(payload: Uint8Array): Uint8Array
|
|
|
11
11
|
export declare function buildSensorBeaconReading(adv03: Uint8Array | null | undefined, adv04: Uint8Array | null | undefined, rawHex?: string): SensorBeaconReading | null;
|
|
12
12
|
/** One-shot decode of manufacturer payload (after company id strip). */
|
|
13
13
|
export declare function decodeSensorBeaconPayload(data: Uint8Array): SensorBeaconReading | null;
|
|
14
|
-
/** FW 7+ → modern (`false`); FW 6-/5.x → legacy (`true`). */
|
|
15
|
-
export declare function legacyHintFromFirmware(firmware: string | null | undefined): boolean | null;
|
package/dist/decoder.js
CHANGED
|
@@ -306,20 +306,3 @@ export function decodeSensorBeaconPayload(data) {
|
|
|
306
306
|
const merged03 = adv03 ?? adv02;
|
|
307
307
|
return buildSensorBeaconReading(merged03, adv04, bufferToHex(data));
|
|
308
308
|
}
|
|
309
|
-
/** FW 7+ → modern (`false`); FW 6-/5.x → legacy (`true`). */
|
|
310
|
-
export function legacyHintFromFirmware(firmware) {
|
|
311
|
-
if (!firmware?.trim())
|
|
312
|
-
return null;
|
|
313
|
-
const t = firmware.trim();
|
|
314
|
-
if (/^FW 5/i.test(t))
|
|
315
|
-
return true;
|
|
316
|
-
const m = /^(\d+)\.\d+/.exec(t);
|
|
317
|
-
if (!m)
|
|
318
|
-
return null;
|
|
319
|
-
const major = parseInt(m[1], 10);
|
|
320
|
-
if (major >= 7)
|
|
321
|
-
return false;
|
|
322
|
-
if (major >= 1)
|
|
323
|
-
return true;
|
|
324
|
-
return null;
|
|
325
|
-
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export { ADV_FRAME_03_LEN, TEMPVO_SENSOR_MANUFACTURER_ID, buildSensorBeaconReading, decodeMeasurementSlot, decodeSensorBeaconPayload, lookupDeviceKeys, macKeyFromAddress, serialKeyFromAdv03Frame, splitSensorBeaconFrames, } from './decoder.js';
|
|
2
2
|
export { ingestManufacturerPayload } from './ingest.js';
|
|
3
|
-
export { dataViewToUint8Array, normalizeManufacturerBytes } from './normalize.js';
|
|
3
|
+
export { dataViewToUint8Array, manufacturerPayloadsFromScanRecordBytes, normalizeManufacturerBytes } from './normalize.js';
|
|
4
4
|
export { MEASURE_SPECS, type MeasureSpec } from './measure-specs.js';
|
|
5
5
|
export { createSensorBeaconFrameCache, type SensorBeaconFrameCache, type SensorBeaconMeasurement, type SensorBeaconReading, } from './types.js';
|
|
6
6
|
export { TempivoSensorError, type TempivoSensorErrorCode } from './errors.js';
|
|
7
|
-
export { DEFAULT_SENSOR_MODEL, bluetoothMacFromSerial, normalizeSensorSerial, encodeSensorPinPayload, parseSensorQrJson,
|
|
7
|
+
export { DEFAULT_SENSOR_MODEL, assertSupportedSensorModel, bluetoothMacFromSerial, normalizeSensorSerial, encodeSensorPinPayload, parseSensorQrJson, sessionTypeFromModel, } from './qr.js';
|
|
8
8
|
export { calibrationFromExtendedJson, decodeLaboratoryCalibrationTimestamp, } from './calibration.js';
|
|
9
|
-
export { DEFAULT_ALERT_HYSTERESIS_C, compileSensorProfileToBleJson, configurationFromApiProfile, parseSensorConfiguration, parseSensorConfigurationJson, pickPartnerConfigurationJson, } from './profile.js';
|
|
9
|
+
export { BLE_MAX_MEASUREMENT_INTERVAL_MINUTES, BLE_MAX_TRANSMISSION_INTERVAL_SECONDS, BLE_MIN_MEASUREMENT_INTERVAL_MINUTES, BLE_MIN_TRANSMISSION_INTERVAL_SECONDS, DEFAULT_ALERT_HYSTERESIS_C, compileSensorProfileToBleJson, configurationFromApiProfile, parseSensorConfiguration, parseSensorConfigurationJson, pickPartnerConfigurationJson, } from './profile.js';
|
|
10
10
|
export type { TempivoSchedule, TempivoScheduleAlways, TempivoScheduleWeek, TempivoSensorCalibration, TempivoSensorConfiguration, TempivoSensorQr, TempivoSensorSessionType, TempivoTemperatureAlert, TempivoTemperatureChannel, TempivoTemperatureMaxAlert, TempivoTemperatureMinAlert, TempivoTemperatureRangeAlert, TempivoTriggerTransmissionResult, } from './session-types.js';
|
|
11
11
|
export { addDeviceFoundListener, connect, disconnect, getCalibration, getConfiguration, isNativeSensorBeaconAvailable, isScanning, requestPermissions, setConfigurationJson, startScan, stopScan, triggerTransmission, } from './native-bridge.js';
|
|
12
12
|
export type { TempivoDeviceFoundSubscription, TempivoNativeCalibration, TempivoNativeMeasurement, TempivoNativePermissionResponse, TempivoNativePermissionStatus, TempivoNativeQr, TempivoNativeTelemetry, TempivoSensorBeaconDevice, } from './native-types.js';
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export { ADV_FRAME_03_LEN, TEMPVO_SENSOR_MANUFACTURER_ID, buildSensorBeaconReading, decodeMeasurementSlot, decodeSensorBeaconPayload, lookupDeviceKeys, macKeyFromAddress, serialKeyFromAdv03Frame, splitSensorBeaconFrames, } from './decoder.js';
|
|
2
2
|
export { ingestManufacturerPayload } from './ingest.js';
|
|
3
|
-
export { dataViewToUint8Array, normalizeManufacturerBytes } from './normalize.js';
|
|
3
|
+
export { dataViewToUint8Array, manufacturerPayloadsFromScanRecordBytes, normalizeManufacturerBytes } from './normalize.js';
|
|
4
4
|
export { MEASURE_SPECS } from './measure-specs.js';
|
|
5
5
|
export { createSensorBeaconFrameCache, } from './types.js';
|
|
6
6
|
export { TempivoSensorError } from './errors.js';
|
|
7
|
-
export { DEFAULT_SENSOR_MODEL, bluetoothMacFromSerial, normalizeSensorSerial, encodeSensorPinPayload, parseSensorQrJson,
|
|
7
|
+
export { DEFAULT_SENSOR_MODEL, assertSupportedSensorModel, bluetoothMacFromSerial, normalizeSensorSerial, encodeSensorPinPayload, parseSensorQrJson, sessionTypeFromModel, } from './qr.js';
|
|
8
8
|
export { calibrationFromExtendedJson, decodeLaboratoryCalibrationTimestamp, } from './calibration.js';
|
|
9
|
-
export { DEFAULT_ALERT_HYSTERESIS_C, compileSensorProfileToBleJson, configurationFromApiProfile, parseSensorConfiguration, parseSensorConfigurationJson, pickPartnerConfigurationJson, } from './profile.js';
|
|
9
|
+
export { BLE_MAX_MEASUREMENT_INTERVAL_MINUTES, BLE_MAX_TRANSMISSION_INTERVAL_SECONDS, BLE_MIN_MEASUREMENT_INTERVAL_MINUTES, BLE_MIN_TRANSMISSION_INTERVAL_SECONDS, DEFAULT_ALERT_HYSTERESIS_C, compileSensorProfileToBleJson, configurationFromApiProfile, parseSensorConfiguration, parseSensorConfigurationJson, pickPartnerConfigurationJson, } from './profile.js';
|
|
10
10
|
export { addDeviceFoundListener, connect, disconnect, getCalibration, getConfiguration, isNativeSensorBeaconAvailable, isScanning, requestPermissions, setConfigurationJson, startScan, stopScan, triggerTransmission, } from './native-bridge.js';
|
package/dist/native-helpers.d.ts
CHANGED
|
@@ -2,5 +2,4 @@ import { TempivoSensorError } from './errors.js';
|
|
|
2
2
|
import type { TempivoSensorConfiguration, TempivoSensorQr } from './session-types.js';
|
|
3
3
|
export declare function qrToConnectJson(qr: string | TempivoSensorQr): string;
|
|
4
4
|
export declare function configToJson(config: string | TempivoSensorConfiguration): string;
|
|
5
|
-
export declare function sanitizePartnerErrorText(text: string): string;
|
|
6
5
|
export declare function mapNativeError(error: unknown): TempivoSensorError;
|
package/dist/native-helpers.js
CHANGED
|
@@ -24,25 +24,10 @@ export function configToJson(config) {
|
|
|
24
24
|
function isSensorCode(value) {
|
|
25
25
|
return !!value && SENSOR_CODES.includes(value);
|
|
26
26
|
}
|
|
27
|
-
export function sanitizePartnerErrorText(text) {
|
|
28
|
-
return text
|
|
29
|
-
.replace(/\bpl\.[A-Za-z][A-Za-z0-9_.$]*/gi, '')
|
|
30
|
-
.replace(/\befento[A-Za-z0-9_$]*/gi, '')
|
|
31
|
-
.replace(/\s+/g, ' ')
|
|
32
|
-
.replace(/^[:\s.\-/]+|[:\s.\-/]+$/g, '')
|
|
33
|
-
.trim();
|
|
34
|
-
}
|
|
35
27
|
export function mapNativeError(error) {
|
|
36
|
-
if (error instanceof TempivoSensorError)
|
|
37
|
-
|
|
38
|
-
return new TempivoSensorError(error.code, clean || 'Sensor request failed.');
|
|
39
|
-
}
|
|
28
|
+
if (error instanceof TempivoSensorError)
|
|
29
|
+
return error;
|
|
40
30
|
const raw = error;
|
|
41
31
|
const code = isSensorCode(raw?.code) ? raw.code : 'unknown';
|
|
42
|
-
|
|
43
|
-
const caused = /Caused by:\s*(.+)$/s.exec(message);
|
|
44
|
-
if (caused?.[1])
|
|
45
|
-
message = caused[1].trim();
|
|
46
|
-
message = sanitizePartnerErrorText(message) || 'Sensor request failed.';
|
|
47
|
-
return new TempivoSensorError(code, message);
|
|
32
|
+
return new TempivoSensorError(code, raw?.message || 'Sensor request failed.');
|
|
48
33
|
}
|
package/dist/native-module.js
CHANGED
|
@@ -50,12 +50,15 @@ export function isScanning() {
|
|
|
50
50
|
return getNative().isScanning();
|
|
51
51
|
}
|
|
52
52
|
export function addDeviceFoundListener(listener) {
|
|
53
|
-
|
|
53
|
+
const native = getNative();
|
|
54
|
+
if (typeof native.addListener !== 'function') {
|
|
55
|
+
throw new TempivoSensorError('runtimeUnavailable', 'Native scan events are unavailable in this build.');
|
|
56
|
+
}
|
|
57
|
+
return native.addListener('onDeviceFound', listener);
|
|
54
58
|
}
|
|
55
59
|
export async function connect(qr) {
|
|
56
60
|
await ensureBlePermission();
|
|
57
61
|
try {
|
|
58
|
-
getNative().stopScan();
|
|
59
62
|
return await getNative().connect(qrToConnectJson(qr));
|
|
60
63
|
}
|
|
61
64
|
catch (error) {
|
package/dist/normalize.d.ts
CHANGED
|
@@ -4,3 +4,9 @@ export declare function dataViewToUint8Array(dv: DataView): Uint8Array;
|
|
|
4
4
|
* Web Bluetooth and Android often already return payload **without** the prefix.
|
|
5
5
|
*/
|
|
6
6
|
export declare function normalizeManufacturerBytes(data: Uint8Array | DataView | ArrayBuffer): Uint8Array;
|
|
7
|
+
/**
|
|
8
|
+
* Parse Android-style `ScanRecord.getBytes()` AD structures and return every Tempivo
|
|
9
|
+
* manufacturer payload (company id stripped). Use this when both `0x03` and `0x04` share
|
|
10
|
+
* company `0x026C` — `getManufacturerSpecificData(0x026C)` can keep only one blob.
|
|
11
|
+
*/
|
|
12
|
+
export declare function manufacturerPayloadsFromScanRecordBytes(scanRecordBytes: Uint8Array | null | undefined): Uint8Array[];
|
package/dist/normalize.js
CHANGED
|
@@ -28,3 +28,32 @@ export function normalizeManufacturerBytes(data) {
|
|
|
28
28
|
}
|
|
29
29
|
return bytes;
|
|
30
30
|
}
|
|
31
|
+
const AD_TYPE_MANUFACTURER = 0xff;
|
|
32
|
+
/**
|
|
33
|
+
* Parse Android-style `ScanRecord.getBytes()` AD structures and return every Tempivo
|
|
34
|
+
* manufacturer payload (company id stripped). Use this when both `0x03` and `0x04` share
|
|
35
|
+
* company `0x026C` — `getManufacturerSpecificData(0x026C)` can keep only one blob.
|
|
36
|
+
*/
|
|
37
|
+
export function manufacturerPayloadsFromScanRecordBytes(scanRecordBytes) {
|
|
38
|
+
if (!scanRecordBytes || scanRecordBytes.length === 0)
|
|
39
|
+
return [];
|
|
40
|
+
const out = [];
|
|
41
|
+
let i = 0;
|
|
42
|
+
const n = scanRecordBytes.length;
|
|
43
|
+
while (i < n) {
|
|
44
|
+
const len = scanRecordBytes[i] & 0xff;
|
|
45
|
+
if (len === 0)
|
|
46
|
+
break;
|
|
47
|
+
if (i + 1 + len > n)
|
|
48
|
+
break;
|
|
49
|
+
const type = scanRecordBytes[i + 1] & 0xff;
|
|
50
|
+
if (type === AD_TYPE_MANUFACTURER && len >= 3) {
|
|
51
|
+
const company = (scanRecordBytes[i + 2] & 0xff) | ((scanRecordBytes[i + 3] & 0xff) << 8);
|
|
52
|
+
if (company === TEMPVO_SENSOR_MANUFACTURER_ID && len > 3) {
|
|
53
|
+
out.push(scanRecordBytes.subarray(i + 4, i + 1 + len));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
i += 1 + len;
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
package/dist/profile.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { TempivoSensorConfiguration } from './session-types.js';
|
|
2
2
|
/** Same default as Cellular API config profiles. */
|
|
3
3
|
export declare const DEFAULT_ALERT_HYSTERESIS_C = 1;
|
|
4
|
+
/** Same limits as Cellular API simple profiles. */
|
|
5
|
+
export declare const BLE_MIN_MEASUREMENT_INTERVAL_MINUTES = 60;
|
|
6
|
+
export declare const BLE_MAX_MEASUREMENT_INTERVAL_MINUTES = 600;
|
|
7
|
+
export declare const BLE_MIN_TRANSMISSION_INTERVAL_SECONDS = 3600;
|
|
8
|
+
export declare const BLE_MAX_TRANSMISSION_INTERVAL_SECONDS = 604800;
|
|
4
9
|
/** Validate Cellular API config-profile JSON for BLE setConfiguration. */
|
|
5
10
|
export declare function parseSensorConfiguration(input: unknown): TempivoSensorConfiguration;
|
|
6
11
|
/** Same as {@link parseSensorConfiguration}: GET `{ profile }` or the profile object. */
|
package/dist/profile.js
CHANGED
|
@@ -168,7 +168,9 @@ function parseAlert(item, index) {
|
|
|
168
168
|
function looksLikeSimpleProfile(rec) {
|
|
169
169
|
return (rec.temperatureAlerts !== undefined ||
|
|
170
170
|
rec.schedule !== undefined ||
|
|
171
|
-
typeof rec.slug === 'string'
|
|
171
|
+
typeof rec.slug === 'string' ||
|
|
172
|
+
rec.measurementIntervalMinutes !== undefined ||
|
|
173
|
+
rec.transmissionIntervalSeconds !== undefined);
|
|
172
174
|
}
|
|
173
175
|
/**
|
|
174
176
|
* GET /devices/config-profiles/{slug} returns `{ profile }`. Also accepts the profile object.
|
|
@@ -188,6 +190,48 @@ function rejectWireAlarmRules(rec) {
|
|
|
188
190
|
throw new TempivoSensorError('invalidConfig', 'Use a config profile with temperatureAlerts (GET /devices/config-profiles/{slug}), not alarmRules.');
|
|
189
191
|
}
|
|
190
192
|
}
|
|
193
|
+
/** Same limits as Cellular API simple profiles. */
|
|
194
|
+
export const BLE_MIN_MEASUREMENT_INTERVAL_MINUTES = 60;
|
|
195
|
+
export const BLE_MAX_MEASUREMENT_INTERVAL_MINUTES = 600;
|
|
196
|
+
export const BLE_MIN_TRANSMISSION_INTERVAL_SECONDS = 3600;
|
|
197
|
+
export const BLE_MAX_TRANSMISSION_INTERVAL_SECONDS = 604_800;
|
|
198
|
+
function parseOptionalIntervals(body) {
|
|
199
|
+
const out = {};
|
|
200
|
+
if (body.measurementIntervalMinutes !== undefined) {
|
|
201
|
+
const n = parseFiniteNumber(body.measurementIntervalMinutes);
|
|
202
|
+
if (n === undefined || !Number.isFinite(n) || n <= 0) {
|
|
203
|
+
throw new TempivoSensorError('invalidConfig', 'measurementIntervalMinutes must be a positive number.');
|
|
204
|
+
}
|
|
205
|
+
if (n < BLE_MIN_MEASUREMENT_INTERVAL_MINUTES) {
|
|
206
|
+
throw new TempivoSensorError('invalidConfig', `measurementIntervalMinutes must be at least ${BLE_MIN_MEASUREMENT_INTERVAL_MINUTES} (1 hour).`);
|
|
207
|
+
}
|
|
208
|
+
if (n > BLE_MAX_MEASUREMENT_INTERVAL_MINUTES) {
|
|
209
|
+
throw new TempivoSensorError('invalidConfig', `measurementIntervalMinutes must be at most ${BLE_MAX_MEASUREMENT_INTERVAL_MINUTES}.`);
|
|
210
|
+
}
|
|
211
|
+
out.measurementIntervalMinutes = n;
|
|
212
|
+
}
|
|
213
|
+
if (body.transmissionIntervalSeconds !== undefined) {
|
|
214
|
+
const n = parseFiniteNumber(body.transmissionIntervalSeconds);
|
|
215
|
+
if (n === undefined || !Number.isInteger(n) || n <= 0) {
|
|
216
|
+
throw new TempivoSensorError('invalidConfig', 'transmissionIntervalSeconds must be a positive integer.');
|
|
217
|
+
}
|
|
218
|
+
if (n < BLE_MIN_TRANSMISSION_INTERVAL_SECONDS) {
|
|
219
|
+
throw new TempivoSensorError('invalidConfig', `transmissionIntervalSeconds must be at least ${BLE_MIN_TRANSMISSION_INTERVAL_SECONDS} (1 hour).`);
|
|
220
|
+
}
|
|
221
|
+
if (n > BLE_MAX_TRANSMISSION_INTERVAL_SECONDS) {
|
|
222
|
+
throw new TempivoSensorError('invalidConfig', `transmissionIntervalSeconds must be at most ${BLE_MAX_TRANSMISSION_INTERVAL_SECONDS}.`);
|
|
223
|
+
}
|
|
224
|
+
out.transmissionIntervalSeconds = n;
|
|
225
|
+
}
|
|
226
|
+
if (out.measurementIntervalMinutes != null &&
|
|
227
|
+
out.transmissionIntervalSeconds != null) {
|
|
228
|
+
const maxTx = out.measurementIntervalMinutes * 60 * 60;
|
|
229
|
+
if (out.transmissionIntervalSeconds > maxTx) {
|
|
230
|
+
throw new TempivoSensorError('invalidConfig', 'transmissionIntervalSeconds must be at most 60 times the measurement interval.');
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return out;
|
|
234
|
+
}
|
|
191
235
|
/** Validate Cellular API config-profile JSON for BLE setConfiguration. */
|
|
192
236
|
export function parseSensorConfiguration(input) {
|
|
193
237
|
if (!isRecord(input)) {
|
|
@@ -201,9 +245,11 @@ export function parseSensorConfiguration(input) {
|
|
|
201
245
|
}
|
|
202
246
|
const temperatureAlerts = (alertsRaw ?? []).map((item, i) => parseAlert(item, i));
|
|
203
247
|
assertAlertSlotBudget(temperatureAlerts);
|
|
248
|
+
const intervals = parseOptionalIntervals(body);
|
|
204
249
|
return {
|
|
205
250
|
temperatureAlerts,
|
|
206
251
|
schedule: parseSchedule(body.schedule),
|
|
252
|
+
...intervals,
|
|
207
253
|
};
|
|
208
254
|
}
|
|
209
255
|
/** Same as {@link parseSensorConfiguration}: GET `{ profile }` or the profile object. */
|
package/dist/qr.d.ts
CHANGED
|
@@ -2,19 +2,16 @@ import type { TempivoSensorQr, TempivoSensorSessionType } from './session-types.
|
|
|
2
2
|
export declare function normalizeSensorSerial(value: string): string;
|
|
3
3
|
/** `282C024F0012` → `28:2C:02:4F:00:12`. */
|
|
4
4
|
export declare function bluetoothMacFromSerial(serial: string): string;
|
|
5
|
-
/** BLE default when QR omits `model`.
|
|
5
|
+
/** BLE default when QR omits `model`. */
|
|
6
6
|
export declare const DEFAULT_SENSOR_MODEL = "HC7";
|
|
7
|
-
export declare function
|
|
8
|
-
|
|
9
|
-
* Advertisement firmware wins over sticker model. FW 7+ is modern. FW 6.x / 5.x is legacy (HC5).
|
|
10
|
-
*/
|
|
11
|
-
export declare function resolveConnectSessionType(model: string | undefined | null, firmware?: string | null): TempivoSensorSessionType;
|
|
7
|
+
export declare function assertSupportedSensorModel(model: string): void;
|
|
8
|
+
export declare function sessionTypeFromModel(_model: string | undefined | null): TempivoSensorSessionType;
|
|
12
9
|
/**
|
|
13
10
|
* 3-byte big-endian numeric PIN for GATT command payloads that check a reset code
|
|
14
11
|
* (`setConfiguration`, trigger, and many other privileged writes).
|
|
15
12
|
*/
|
|
16
13
|
export declare function encodeSensorPinPayload(pin: string): Uint8Array;
|
|
17
14
|
/**
|
|
18
|
-
* Parse sensor label QR JSON: `{"sn":"…","pin":"…"
|
|
15
|
+
* Parse sensor label QR JSON: `{"sn":"…","pin":"…"}`.
|
|
19
16
|
*/
|
|
20
17
|
export declare function parseSensorQrJson(text: string): TempivoSensorQr;
|
package/dist/qr.js
CHANGED
|
@@ -13,32 +13,16 @@ export function bluetoothMacFromSerial(serial) {
|
|
|
13
13
|
parts.push(key.slice(i, i + 2));
|
|
14
14
|
return parts.join(':');
|
|
15
15
|
}
|
|
16
|
-
/** BLE default when QR omits `model`.
|
|
16
|
+
/** BLE default when QR omits `model`. */
|
|
17
17
|
export const DEFAULT_SENSOR_MODEL = 'HC7';
|
|
18
|
-
export function
|
|
19
|
-
if (model == null || model.trim() === '')
|
|
20
|
-
return 'modern';
|
|
18
|
+
export function assertSupportedSensorModel(model) {
|
|
21
19
|
const m = model.trim().toUpperCase().replace(/-/g, '');
|
|
22
|
-
if (m === 'HC5'
|
|
23
|
-
|
|
24
|
-
return 'modern';
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Advertisement firmware wins over sticker model. FW 7+ is modern. FW 6.x / 5.x is legacy (HC5).
|
|
28
|
-
*/
|
|
29
|
-
export function resolveConnectSessionType(model, firmware) {
|
|
30
|
-
const t = firmware?.trim() ?? '';
|
|
31
|
-
if (/^FW\s*5/i.test(t))
|
|
32
|
-
return 'legacy';
|
|
33
|
-
const m = /^(\d+)\.\d+/.exec(t);
|
|
34
|
-
if (m) {
|
|
35
|
-
const major = Number.parseInt(m[1], 10);
|
|
36
|
-
if (major >= 7)
|
|
37
|
-
return 'modern';
|
|
38
|
-
if (major >= 1)
|
|
39
|
-
return 'legacy';
|
|
20
|
+
if (m === 'HC5') {
|
|
21
|
+
throw new TempivoSensorError('invalidQr', 'HC5 is not supported by the partner SDK. Use HC7 sensors.');
|
|
40
22
|
}
|
|
41
|
-
|
|
23
|
+
}
|
|
24
|
+
export function sessionTypeFromModel(_model) {
|
|
25
|
+
return 'modern';
|
|
42
26
|
}
|
|
43
27
|
/**
|
|
44
28
|
* 3-byte big-endian numeric PIN for GATT command payloads that check a reset code
|
|
@@ -66,7 +50,7 @@ function pinFromRecord(rec) {
|
|
|
66
50
|
return undefined;
|
|
67
51
|
}
|
|
68
52
|
/**
|
|
69
|
-
* Parse sensor label QR JSON: `{"sn":"…","pin":"…"
|
|
53
|
+
* Parse sensor label QR JSON: `{"sn":"…","pin":"…"}`.
|
|
70
54
|
*/
|
|
71
55
|
export function parseSensorQrJson(text) {
|
|
72
56
|
let rec;
|
|
@@ -97,6 +81,7 @@ export function parseSensorQrJson(text) {
|
|
|
97
81
|
}
|
|
98
82
|
const rawModel = typeof rec.model === 'string' ? rec.model.trim() : '';
|
|
99
83
|
const model = rawModel || DEFAULT_SENSOR_MODEL;
|
|
84
|
+
assertSupportedSensorModel(model);
|
|
100
85
|
return {
|
|
101
86
|
serial,
|
|
102
87
|
pin,
|
package/dist/react-native.d.ts
CHANGED
|
@@ -1 +1,24 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { ADV_FRAME_03_LEN, TEMPVO_SENSOR_MANUFACTURER_ID, buildSensorBeaconReading, decodeMeasurementSlot, decodeSensorBeaconPayload, lookupDeviceKeys, macKeyFromAddress, serialKeyFromAdv03Frame, splitSensorBeaconFrames, } from './decoder.js';
|
|
2
|
+
export { ingestManufacturerPayload } from './ingest.js';
|
|
3
|
+
export { dataViewToUint8Array, manufacturerPayloadsFromScanRecordBytes, normalizeManufacturerBytes } from './normalize.js';
|
|
4
|
+
export { MEASURE_SPECS, type MeasureSpec } from './measure-specs.js';
|
|
5
|
+
export { createSensorBeaconFrameCache, type SensorBeaconFrameCache, type SensorBeaconMeasurement, type SensorBeaconReading, } from './types.js';
|
|
6
|
+
export { TempivoSensorError, type TempivoSensorErrorCode } from './errors.js';
|
|
7
|
+
export { DEFAULT_SENSOR_MODEL, bluetoothMacFromSerial, normalizeSensorSerial, encodeSensorPinPayload, parseSensorQrJson, sessionTypeFromModel, } from './qr.js';
|
|
8
|
+
export { calibrationFromExtendedJson, decodeLaboratoryCalibrationTimestamp, } from './calibration.js';
|
|
9
|
+
export { BLE_MAX_MEASUREMENT_INTERVAL_MINUTES, BLE_MAX_TRANSMISSION_INTERVAL_SECONDS, BLE_MIN_MEASUREMENT_INTERVAL_MINUTES, BLE_MIN_TRANSMISSION_INTERVAL_SECONDS, DEFAULT_ALERT_HYSTERESIS_C, compileSensorProfileToBleJson, configurationFromApiProfile, parseSensorConfiguration, parseSensorConfigurationJson, pickPartnerConfigurationJson, } from './profile.js';
|
|
10
|
+
export type { TempivoSchedule, TempivoScheduleAlways, TempivoScheduleWeek, TempivoSensorCalibration, TempivoSensorConfiguration, TempivoSensorQr, TempivoSensorSessionType, TempivoTemperatureAlert, TempivoTemperatureChannel, TempivoTemperatureMaxAlert, TempivoTemperatureMinAlert, TempivoTemperatureRangeAlert, TempivoTriggerTransmissionResult, } from './session-types.js';
|
|
11
|
+
export type { TempivoDeviceFoundSubscription, TempivoNativeCalibration, TempivoNativeMeasurement, TempivoNativePermissionResponse, TempivoNativePermissionStatus, TempivoNativeQr, TempivoNativeTelemetry, TempivoSensorBeaconDevice, } from './native-types.js';
|
|
12
|
+
import * as native from './native-module.js';
|
|
13
|
+
export declare const isNativeSensorBeaconAvailable: typeof native.isNativeSensorBeaconAvailable;
|
|
14
|
+
export declare const requestPermissions: typeof native.requestPermissions;
|
|
15
|
+
export declare const startScan: typeof native.startScan;
|
|
16
|
+
export declare const stopScan: typeof native.stopScan;
|
|
17
|
+
export declare const isScanning: typeof native.isScanning;
|
|
18
|
+
export declare const addDeviceFoundListener: typeof native.addDeviceFoundListener;
|
|
19
|
+
export declare const connect: typeof native.connect;
|
|
20
|
+
export declare const disconnect: typeof native.disconnect;
|
|
21
|
+
export declare const getConfiguration: typeof native.getConfiguration;
|
|
22
|
+
export declare const setConfigurationJson: typeof native.setConfigurationJson;
|
|
23
|
+
export declare const triggerTransmission: typeof native.triggerTransmission;
|
|
24
|
+
export declare const getCalibration: typeof native.getCalibration;
|
package/dist/react-native.js
CHANGED
|
@@ -1 +1,22 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { ADV_FRAME_03_LEN, TEMPVO_SENSOR_MANUFACTURER_ID, buildSensorBeaconReading, decodeMeasurementSlot, decodeSensorBeaconPayload, lookupDeviceKeys, macKeyFromAddress, serialKeyFromAdv03Frame, splitSensorBeaconFrames, } from './decoder.js';
|
|
2
|
+
export { ingestManufacturerPayload } from './ingest.js';
|
|
3
|
+
export { dataViewToUint8Array, manufacturerPayloadsFromScanRecordBytes, normalizeManufacturerBytes } from './normalize.js';
|
|
4
|
+
export { MEASURE_SPECS } from './measure-specs.js';
|
|
5
|
+
export { createSensorBeaconFrameCache, } from './types.js';
|
|
6
|
+
export { TempivoSensorError } from './errors.js';
|
|
7
|
+
export { DEFAULT_SENSOR_MODEL, bluetoothMacFromSerial, normalizeSensorSerial, encodeSensorPinPayload, parseSensorQrJson, sessionTypeFromModel, } from './qr.js';
|
|
8
|
+
export { calibrationFromExtendedJson, decodeLaboratoryCalibrationTimestamp, } from './calibration.js';
|
|
9
|
+
export { BLE_MAX_MEASUREMENT_INTERVAL_MINUTES, BLE_MAX_TRANSMISSION_INTERVAL_SECONDS, BLE_MIN_MEASUREMENT_INTERVAL_MINUTES, BLE_MIN_TRANSMISSION_INTERVAL_SECONDS, DEFAULT_ALERT_HYSTERESIS_C, compileSensorProfileToBleJson, configurationFromApiProfile, parseSensorConfiguration, parseSensorConfigurationJson, pickPartnerConfigurationJson, } from './profile.js';
|
|
10
|
+
import * as native from './native-module.js';
|
|
11
|
+
export const isNativeSensorBeaconAvailable = native.isNativeSensorBeaconAvailable;
|
|
12
|
+
export const requestPermissions = native.requestPermissions;
|
|
13
|
+
export const startScan = native.startScan;
|
|
14
|
+
export const stopScan = native.stopScan;
|
|
15
|
+
export const isScanning = native.isScanning;
|
|
16
|
+
export const addDeviceFoundListener = native.addDeviceFoundListener;
|
|
17
|
+
export const connect = native.connect;
|
|
18
|
+
export const disconnect = native.disconnect;
|
|
19
|
+
export const getConfiguration = native.getConfiguration;
|
|
20
|
+
export const setConfigurationJson = native.setConfigurationJson;
|
|
21
|
+
export const triggerTransmission = native.triggerTransmission;
|
|
22
|
+
export const getCalibration = native.getCalibration;
|
package/dist/session-types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/** Partner SDK: modern GATT only (HC7 / firmware 7+). */
|
|
2
|
+
export type TempivoSensorSessionType = 'modern';
|
|
2
3
|
export type TempivoTemperatureChannel = 'ambient' | 'probe';
|
|
3
4
|
export type TempivoTemperatureRangeAlert = {
|
|
4
5
|
type: 'range';
|
|
@@ -39,18 +40,24 @@ export type TempivoScheduleWeek = {
|
|
|
39
40
|
};
|
|
40
41
|
export type TempivoSchedule = TempivoScheduleAlways | TempivoScheduleWeek;
|
|
41
42
|
/**
|
|
42
|
-
* Same JSON as Cellular API
|
|
43
|
-
*
|
|
43
|
+
* Same JSON as Cellular API config profiles (`temperatureAlerts` + `schedule`),
|
|
44
|
+
* plus optional `measurementIntervalMinutes` / `transmissionIntervalSeconds` for BLE.
|
|
45
|
+
* Extra profile fields (`slug`, `name`) are ignored over BLE.
|
|
44
46
|
*/
|
|
45
47
|
export type TempivoSensorConfiguration = {
|
|
46
48
|
temperatureAlerts: TempivoTemperatureAlert[];
|
|
47
49
|
schedule: TempivoSchedule;
|
|
50
|
+
/** Sampling interval in minutes (Cellular API). Optional. */
|
|
51
|
+
measurementIntervalMinutes?: number;
|
|
52
|
+
/** Uplink interval in seconds (Cellular API). Optional. */
|
|
53
|
+
transmissionIntervalSeconds?: number;
|
|
48
54
|
};
|
|
49
55
|
export type TempivoSensorQr = {
|
|
50
56
|
serial: string;
|
|
51
57
|
pin: string;
|
|
52
|
-
/**
|
|
58
|
+
/** Optional sticker field. Defaults to HC7. HC5 is rejected. */
|
|
53
59
|
model?: string;
|
|
60
|
+
/** Always `modern` (HC7 GATT). */
|
|
54
61
|
sessionType: TempivoSensorSessionType;
|
|
55
62
|
bluetoothMac: string;
|
|
56
63
|
};
|
|
Binary file
|
|
@@ -145,14 +145,12 @@ __attribute__((swift_name("TempivoSensorBridge")))
|
|
|
145
145
|
@interface TSBTempivoSensorBridge : TSBBase
|
|
146
146
|
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
|
147
147
|
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
|
148
|
-
- (NSString *)connectPayloadJsonSerial:(NSString *)serial bluetoothMac:(NSString *)bluetoothMac pin:(int32_t)pin legacy:(BOOL)legacy
|
|
148
|
+
- (NSString *)connectPayloadJsonSerial:(NSString *)serial bluetoothMac:(NSString *)bluetoothMac pin:(int32_t)pin legacy:(BOOL)legacy __attribute__((swift_name("connectPayloadJson(serial:bluetoothMac:pin:legacy:)")));
|
|
149
149
|
- (void)disconnect __attribute__((swift_name("disconnect()")));
|
|
150
150
|
- (NSString *)getCalibrationPayloadJson __attribute__((swift_name("getCalibrationPayloadJson()")));
|
|
151
151
|
- (NSString *)getConfigurationPayloadJson __attribute__((swift_name("getConfigurationPayloadJson()")));
|
|
152
152
|
- (void)initialize __attribute__((swift_name("initialize()")));
|
|
153
153
|
- (NSString *)setConfigurationPayloadJsonJson:(NSString *)json __attribute__((swift_name("setConfigurationPayloadJson(json:)")));
|
|
154
|
-
- (void)startDeviceScanOnDeviceJson:(void (^)(NSString *))onDeviceJson __attribute__((swift_name("startDeviceScan(onDeviceJson:)")));
|
|
155
|
-
- (void)stopDeviceScan __attribute__((swift_name("stopDeviceScan()")));
|
|
156
154
|
- (NSString *)triggerTransmissionPayloadJson __attribute__((swift_name("triggerTransmissionPayloadJson()")));
|
|
157
155
|
@end
|
|
158
156
|
|
|
Binary file
|
|
@@ -145,14 +145,12 @@ __attribute__((swift_name("TempivoSensorBridge")))
|
|
|
145
145
|
@interface TSBTempivoSensorBridge : TSBBase
|
|
146
146
|
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
|
147
147
|
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
|
148
|
-
- (NSString *)connectPayloadJsonSerial:(NSString *)serial bluetoothMac:(NSString *)bluetoothMac pin:(int32_t)pin legacy:(BOOL)legacy
|
|
148
|
+
- (NSString *)connectPayloadJsonSerial:(NSString *)serial bluetoothMac:(NSString *)bluetoothMac pin:(int32_t)pin legacy:(BOOL)legacy __attribute__((swift_name("connectPayloadJson(serial:bluetoothMac:pin:legacy:)")));
|
|
149
149
|
- (void)disconnect __attribute__((swift_name("disconnect()")));
|
|
150
150
|
- (NSString *)getCalibrationPayloadJson __attribute__((swift_name("getCalibrationPayloadJson()")));
|
|
151
151
|
- (NSString *)getConfigurationPayloadJson __attribute__((swift_name("getConfigurationPayloadJson()")));
|
|
152
152
|
- (void)initialize __attribute__((swift_name("initialize()")));
|
|
153
153
|
- (NSString *)setConfigurationPayloadJsonJson:(NSString *)json __attribute__((swift_name("setConfigurationPayloadJson(json:)")));
|
|
154
|
-
- (void)startDeviceScanOnDeviceJson:(void (^)(NSString *))onDeviceJson __attribute__((swift_name("startDeviceScan(onDeviceJson:)")));
|
|
155
|
-
- (void)stopDeviceScan __attribute__((swift_name("stopDeviceScan()")));
|
|
156
154
|
- (NSString *)triggerTransmissionPayloadJson __attribute__((swift_name("triggerTransmissionPayloadJson()")));
|
|
157
155
|
@end
|
|
158
156
|
|
|
Binary file
|
|
@@ -154,7 +154,12 @@ public enum TempivoSensorBeaconDecoder {
|
|
|
154
154
|
let bytes = [UInt8](manufacturerData)
|
|
155
155
|
guard bytes.count >= 3 else { return false }
|
|
156
156
|
let company = UInt16(bytes[0]) | (UInt16(bytes[1]) << 8)
|
|
157
|
-
guard company == TEMPVO_SENSOR_MANUFACTURER_ID else {
|
|
157
|
+
guard company == TEMPVO_SENSOR_MANUFACTURER_ID else {
|
|
158
|
+
// Already-normalized payload (no company id).
|
|
159
|
+
return ingestNormalizedPayload(bytes, primaryMacKey: primaryMacKey, last03: &last03, last04: &last04)
|
|
160
|
+
}
|
|
161
|
+
// ADV + SCAN_RSP may be concatenated as `6C02`+frame03+`6C02`+frame04.
|
|
162
|
+
// strip once then let splitSensorFrames skip the second company id bytes.
|
|
158
163
|
return ingestNormalizedPayload(Array(bytes.dropFirst(2)), primaryMacKey: primaryMacKey, last03: &last03, last04: &last04)
|
|
159
164
|
}
|
|
160
165
|
|
|
@@ -180,7 +185,12 @@ public enum TempivoSensorBeaconDecoder {
|
|
|
180
185
|
}
|
|
181
186
|
}
|
|
182
187
|
} else if tag == 0x04 {
|
|
183
|
-
let
|
|
188
|
+
let serialFromCached03 =
|
|
189
|
+
lookupKeys(primaryMacKey: primaryMacKey)
|
|
190
|
+
.compactMap { last03[$0] }
|
|
191
|
+
.compactMap { serialKeyFromAdv03([UInt8]($0)) }
|
|
192
|
+
.first
|
|
193
|
+
let keys = lookupKeys(primaryMacKey: primaryMacKey, extraSerialKey: serialFromCached03)
|
|
184
194
|
let data = Data(fr)
|
|
185
195
|
for key in keys {
|
|
186
196
|
if last04[key] != data {
|