@tempivo/sensor-beacon 1.1.5 → 1.1.7
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/CHANGELOG.md +16 -0
- package/README.md +16 -8
- package/android/src/main/java/expo/modules/tempivosensorbeacon/SensorBeaconNative.java +11 -0
- package/android/src/main/java/expo/modules/tempivosensorbeacon/TempivoSensorBeaconModule.kt +8 -0
- package/android-aar/library/src/main/java/com/tempivo/sensor/beacon/SensorBleRuntime.kt +9 -0
- package/android-aar/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorQr.kt +7 -1
- package/android-aar/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorSession.kt +12 -0
- package/dist/connect-helpers.d.ts +1 -1
- package/dist/connect-helpers.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/native-bridge.d.ts +4 -0
- package/dist/native-bridge.js +6 -0
- package/dist/native-helpers.js +21 -2
- package/dist/native-module.d.ts +10 -0
- package/dist/native-module.js +33 -0
- package/dist/production-defaults.d.ts +18 -0
- package/dist/production-defaults.js +139 -0
- package/dist/qr.d.ts +2 -0
- package/dist/qr.js +16 -3
- package/dist/react-native.d.ts +3 -13
- package/dist/react-native.js +2 -13
- package/dist/tempivo-sensor-beacon.aar +0 -0
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64/TempivoSensorBridge.framework/Headers/TempivoSensorBridge.h +1 -0
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64/TempivoSensorBridge.framework/TempivoSensorBridge +2 -2
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64-simulator/TempivoSensorBridge.framework/Headers/TempivoSensorBridge.h +1 -0
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64-simulator/TempivoSensorBridge.framework/TempivoSensorBridge +2 -2
- package/ios/Sources/TempivoSensorBeacon/TempivoSensorQr.swift +8 -2
- package/ios/Sources/TempivoSensorBeacon/TempivoSensorSession.swift +11 -0
- package/ios/TempivoSensorBeaconModule.swift +9 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,22 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.1.7] - 2026-09-30
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `clearMeasurementQueue()`: clear on-device measurement / uplink queue (memory reset). Manual recovery only; not used by `setConfigurationJson`.
|
|
14
|
+
|
|
15
|
+
## [1.1.6] - 2026-09-25
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Parsed sticker model **TS10** stays `TS10` on `TempivoSensorQr` (connect / native still maps to HC7).
|
|
20
|
+
- Production defaults check is looser: PLMN `1000000` and legacy `0xFFFFFFFF` as automatic, DEL-only APN user/password as unused, DNS `255.255.255.255` as automatic, any regional NB-IoT band mask, any non-empty firmware string.
|
|
21
|
+
- React Native entry re-exports native BLE helpers live from the native module (avoids a stale snapshot when Metro loads).
|
|
22
|
+
- Docs: prefer Cellular API for laboratory calibration date; BLE `getCalibration` is optional. Examples no longer call `getCalibration()`.
|
|
23
|
+
- Docs: cloud `laboratoryCalibrationDate` is live (certificate and/or device extended-config uplink); remove “not released yet” wording.
|
|
24
|
+
|
|
9
25
|
## [1.1.5] - 2026-09-08
|
|
10
26
|
|
|
11
27
|
### Fixed
|
package/README.md
CHANGED
|
@@ -50,7 +50,6 @@ import {
|
|
|
50
50
|
setConfigurationJson,
|
|
51
51
|
getConfiguration,
|
|
52
52
|
triggerTransmission,
|
|
53
|
-
getCalibration,
|
|
54
53
|
disconnect,
|
|
55
54
|
} from '@tempivo/sensor-beacon';
|
|
56
55
|
|
|
@@ -82,7 +81,6 @@ try {
|
|
|
82
81
|
// other queued Cellular fields can still downlink. To cancel the whole queue:
|
|
83
82
|
// DELETE /api/v1/devices/{serial}/config (see docs/cellular-api.md).
|
|
84
83
|
const applied = await getConfiguration();
|
|
85
|
-
const cal = await getCalibration();
|
|
86
84
|
} finally {
|
|
87
85
|
await disconnect(); // required so advertising / startScan can see the sensor again
|
|
88
86
|
}
|
|
@@ -109,7 +107,8 @@ The Expo config plugin sets **minSdk 26**, Android BLE permissions, and **`NSBlu
|
|
|
109
107
|
| `connect` / `disconnect` | GATT session with parsed QR (`TempivoSensorQr`). |
|
|
110
108
|
| `getConfiguration` / `setConfigurationJson` | Read / write alert rules, schedule, optional intervals. |
|
|
111
109
|
| `triggerTransmission` | Ask firmware to uplink now; returns `{ ok }`. Cloud pending syncs after that uplink (or schedule/button), not from the BLE write alone. |
|
|
112
|
-
| `
|
|
110
|
+
| `clearMeasurementQueue` | Clear on-device measurement / uplink queue (memory reset). Manual recovery only; not used by `setConfigurationJson`. |
|
|
111
|
+
| `getCalibration` | Optional BLE read of laboratory calibration date. Prefer the Cellular API (see below). |
|
|
113
112
|
|
|
114
113
|
**Cloud queue:** BLE updates the sensor only. After uplink, Tempivo drops from Cellular `pendingConfig` only fields the device already matches; other queued fields can still downlink. Cancel the whole queue with `DELETE /api/v1/devices/{serial}/config` (see Tempivo Cellular API docs).
|
|
115
114
|
|
|
@@ -305,14 +304,14 @@ Use `parseSensorConfigurationJson` to validate before write. Use `parseSensorCon
|
|
|
305
304
|
Sticker QR is JSON. Parse with `parseSensorQrJson`.
|
|
306
305
|
|
|
307
306
|
```json
|
|
308
|
-
{ "sn": "282C024F0012", "pin": "111111" }
|
|
307
|
+
{ "sn": "282C024F0012", "pin": "111111", "model": "TS10" }
|
|
309
308
|
```
|
|
310
309
|
|
|
311
310
|
| Field | Type | Meaning |
|
|
312
311
|
|------|------|---------|
|
|
313
312
|
| `serial` | string | Device serial, 12 hex chars, no colons. From QR `sn`. |
|
|
314
313
|
| `pin` | string | Sticker PIN. Required on `connect`. Also accepted as QR `resetCode`. |
|
|
315
|
-
| `model` | string | Optional. Defaults to **HC7**. **HC5** is rejected. |
|
|
314
|
+
| `model` | string | Optional. Defaults to **HC7**. **TS10** is Tempivo’s HC7 alias (normalized to HC7). **HC5** is rejected. |
|
|
316
315
|
| `sessionType` | `modern` | Always modern GATT (HC7 / firmware 7+). |
|
|
317
316
|
| `bluetoothMac` | string | BLE MAC with colons, derived from `serial` or scan row. |
|
|
318
317
|
| `deviceId` | string | Optional. Platform BLE id from scan. Pass when connecting to a selected scan row. |
|
|
@@ -358,7 +357,16 @@ Filter manufacturer data on company id **0x026C**. Active scanning is on so scan
|
|
|
358
357
|
|
|
359
358
|
`triggerTransmission()` returns `{ ok }`. `ok: false` means the firmware rejected the command; it is not thrown as an error.
|
|
360
359
|
|
|
361
|
-
|
|
360
|
+
### Laboratory calibration date
|
|
361
|
+
|
|
362
|
+
Prefer **cloud to cloud**, not BLE:
|
|
363
|
+
|
|
364
|
+
- After the sensor is registered, use **`GET /api/v1/assets/{assetId}`** (`laboratoryCalibrationDate`, and `calibrationCertificate` when a PDF is linked).
|
|
365
|
+
- Download PDF: **`GET /api/v1/assets/{assetId}/calibration-certificate`**.
|
|
366
|
+
|
|
367
|
+
`laboratoryCalibrationDate` is live. Sources (first wins): uploaded certificate date, then device extended-config `LABORATORY_CALIBRATION_DATE` after cellular uplink. `null` only when neither exists yet (see Cellular API sample serial `STOREVIEW001` for a fixed demo date).
|
|
368
|
+
|
|
369
|
+
BLE `getCalibration()` can still read the on-device date when present; it is not shown in the examples above.
|
|
362
370
|
|
|
363
371
|
## Node / TypeScript helpers
|
|
364
372
|
|
|
@@ -402,8 +410,9 @@ session.connect(qr)
|
|
|
402
410
|
try {
|
|
403
411
|
session.setConfigurationJson(profileJson)
|
|
404
412
|
val trigger = session.triggerTransmission()
|
|
413
|
+
// Manual recovery only (not part of setConfiguration):
|
|
414
|
+
// session.clearMeasurementQueue()
|
|
405
415
|
val applied = session.getConfiguration()
|
|
406
|
-
val cal = session.getCalibration()
|
|
407
416
|
} finally {
|
|
408
417
|
// Without disconnect, the sensor will not advertise for startScan.
|
|
409
418
|
session.disconnect()
|
|
@@ -429,7 +438,6 @@ defer { session.disconnect() } // advertising resumes after disconnect
|
|
|
429
438
|
try session.setConfigurationJson(profileJson)
|
|
430
439
|
_ = try session.triggerTransmission()
|
|
431
440
|
let applied = try session.getConfiguration()
|
|
432
|
-
let cal = try session.getCalibration()
|
|
433
441
|
```
|
|
434
442
|
|
|
435
443
|
```swift
|
|
@@ -122,6 +122,17 @@ final class SensorBeaconNative {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
Map<String, Object> clearMeasurementQueue() {
|
|
126
|
+
try {
|
|
127
|
+
requireSessionConnected().clearMeasurementQueueBlocking();
|
|
128
|
+
Map<String, Object> payload = new HashMap<>();
|
|
129
|
+
payload.put("ok", true);
|
|
130
|
+
return payload;
|
|
131
|
+
} catch (Throwable error) {
|
|
132
|
+
throw wrap(error);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
125
136
|
Map<String, Object> getCalibration() {
|
|
126
137
|
try {
|
|
127
138
|
return calibrationMap(requireSessionConnected().getCalibrationBlocking());
|
|
@@ -92,6 +92,14 @@ class TempivoSensorBeaconModule : Module() {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
AsyncFunction("clearMeasurementQueue") {
|
|
96
|
+
try {
|
|
97
|
+
native.clearMeasurementQueue()
|
|
98
|
+
} catch (error: Throwable) {
|
|
99
|
+
throw error.toSensorException()
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
95
103
|
AsyncFunction("getCalibration") {
|
|
96
104
|
try {
|
|
97
105
|
native.calibration
|
|
@@ -119,6 +119,15 @@ internal object SensorBleRuntime {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Clear on-device measurement / uplink queue (memory reset).
|
|
124
|
+
* Manual recovery only: not used by [writeConfiguration] / partner setConfiguration.
|
|
125
|
+
*/
|
|
126
|
+
suspend fun clearMeasurementQueue(session: Session) {
|
|
127
|
+
val base = modernGetConfiguration(session.connection)
|
|
128
|
+
session.connection.commands.setConfiguration(base.copy(resetMemoryRequest = true)) { }
|
|
129
|
+
}
|
|
130
|
+
|
|
122
131
|
suspend fun readCalibration(session: Session): TempivoSensorCalibration {
|
|
123
132
|
val ext = session.connection.commands.getExtendedConfiguration { }
|
|
124
133
|
return TempivoSensorCalibrationDecoder.decode(ext.laboratoryCalibrationTimestamp)
|
|
@@ -40,6 +40,12 @@ object TempivoSensorQrParser {
|
|
|
40
40
|
return bluetoothMacFromSerial(trimmed)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
fun normalizeModel(model: String): String {
|
|
44
|
+
val m = model.trim().uppercase(Locale.US).replace("-", "")
|
|
45
|
+
if (m.isEmpty() || m == "HC7" || m == "TS10") return DEFAULT_MODEL
|
|
46
|
+
return model.trim()
|
|
47
|
+
}
|
|
48
|
+
|
|
43
49
|
fun assertSupportedModel(model: String) {
|
|
44
50
|
val m = model.trim().uppercase(Locale.US).replace("-", "")
|
|
45
51
|
if (m == "HC5") {
|
|
@@ -70,7 +76,7 @@ object TempivoSensorQrParser {
|
|
|
70
76
|
if (pin.isEmpty()) {
|
|
71
77
|
throw TempivoSensorException(TempivoSensorException.Code.INVALID_QR, "QR is missing PIN.")
|
|
72
78
|
}
|
|
73
|
-
val model = rec.optString("model")
|
|
79
|
+
val model = normalizeModel(rec.optString("model"))
|
|
74
80
|
assertSupportedModel(model)
|
|
75
81
|
val hex = if (serial.length == 12) serial else serial.takeLast(12)
|
|
76
82
|
val macOverride =
|
|
@@ -170,6 +170,16 @@ class TempivoSensorSession(
|
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
/**
|
|
174
|
+
* Clear on-device measurement / uplink queue (memory reset). Manual recovery only.
|
|
175
|
+
*/
|
|
176
|
+
suspend fun clearMeasurementQueue() {
|
|
177
|
+
runGatt {
|
|
178
|
+
ensureSdkConnected()
|
|
179
|
+
SensorBleRuntime.clearMeasurementQueue(requireSession())
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
173
183
|
suspend fun getCalibration(): TempivoSensorCalibration {
|
|
174
184
|
return runGatt {
|
|
175
185
|
ensureSdkConnected()
|
|
@@ -192,6 +202,8 @@ class TempivoSensorSession(
|
|
|
192
202
|
|
|
193
203
|
fun triggerTransmissionBlocking(): TriggerResult = runBlocking { triggerTransmission() }
|
|
194
204
|
|
|
205
|
+
fun clearMeasurementQueueBlocking() = runBlocking { clearMeasurementQueue() }
|
|
206
|
+
|
|
195
207
|
fun getCalibrationBlocking(): TempivoSensorCalibration = runBlocking { getCalibration() }
|
|
196
208
|
|
|
197
209
|
private fun requireSession(): SensorBleRuntime.Session =
|
|
@@ -26,7 +26,7 @@ export declare function serialHexFromSensorQrScan(data: string | {
|
|
|
26
26
|
* False when both are 12-hex and differ (wrong sticker for selected device).
|
|
27
27
|
*/
|
|
28
28
|
export declare function sensorQrSerialMatchesSelected(qrSerialHex: string | null | undefined, selectedSerial: string | null | undefined): boolean;
|
|
29
|
-
/** Normalize sticker `model` to HC5/HC7, or null if missing/unknown. */
|
|
29
|
+
/** Normalize sticker `model` to HC5/HC7, or null if missing/unknown. TS10 is Tempivo’s HC7 alias. */
|
|
30
30
|
export declare function normalizeSensorStickerModel(model: string | undefined | null): SensorStickerModel | null;
|
|
31
31
|
/**
|
|
32
32
|
* Map label PIN to native connect credentials (resetCode + encryptionKey for 5–6 digit codes).
|
package/dist/connect-helpers.js
CHANGED
|
@@ -64,14 +64,14 @@ export function sensorQrSerialMatchesSelected(qrSerialHex, selectedSerial) {
|
|
|
64
64
|
return true;
|
|
65
65
|
return qr === sel;
|
|
66
66
|
}
|
|
67
|
-
/** Normalize sticker `model` to HC5/HC7, or null if missing/unknown. */
|
|
67
|
+
/** Normalize sticker `model` to HC5/HC7, or null if missing/unknown. TS10 is Tempivo’s HC7 alias. */
|
|
68
68
|
export function normalizeSensorStickerModel(model) {
|
|
69
69
|
if (model == null || model.trim() === '')
|
|
70
70
|
return null;
|
|
71
71
|
const m = model.trim().toUpperCase().replace(/-/g, '');
|
|
72
72
|
if (m === 'HC5')
|
|
73
73
|
return 'HC5';
|
|
74
|
-
if (m === 'HC7')
|
|
74
|
+
if (m === 'HC7' || m === 'TS10')
|
|
75
75
|
return 'HC7';
|
|
76
76
|
return null;
|
|
77
77
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,5 +12,5 @@ export type { ParsedSensorQrLoose, SensorBleConnectCredentials, } from './connec
|
|
|
12
12
|
export { calibrationFromExtendedJson, decodeLaboratoryCalibrationTimestamp, } from './calibration.js';
|
|
13
13
|
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, parseSensorConfigurationFromDevice, parseSensorConfigurationFromDeviceJson, parseSensorConfigurationJson, pickPartnerConfigurationJson, } from './profile.js';
|
|
14
14
|
export type { TempivoSchedule, TempivoScheduleAlways, TempivoScheduleWeek, TempivoSensorCalibration, TempivoSensorConfiguration, TempivoSensorQr, TempivoSensorSessionType, TempivoTemperatureAlert, TempivoTemperatureChannel, TempivoTemperatureMaxAlert, TempivoTemperatureMinAlert, TempivoTemperatureRangeAlert, TempivoTriggerTransmissionResult, } from './session-types.js';
|
|
15
|
-
export { addDeviceFoundListener, connect, disconnect, getCalibration, getConfiguration, isNativeSensorBeaconAvailable, isScanning, requestPermissions, setConfigurationJson, startScan, stopScan, triggerTransmission, } from './native-bridge.js';
|
|
15
|
+
export { addDeviceFoundListener, connect, clearMeasurementQueue, disconnect, getCalibration, getConfiguration, getProtoConfiguration, isNativeSensorBeaconAvailable, isScanning, requestPermissions, setConfigurationJson, startScan, stopScan, triggerTransmission, } from './native-bridge.js';
|
|
16
16
|
export type { TempivoDeviceFoundSubscription, TempivoNativeCalibration, TempivoNativeMeasurement, TempivoNativePermissionResponse, TempivoNativePermissionStatus, TempivoNativeQr, TempivoNativeTelemetry, TempivoSensorBeaconDevice, } from './native-types.js';
|
package/dist/index.js
CHANGED
|
@@ -9,4 +9,4 @@ export { isMissingAdvertisementFirmware, sensorModelFromFirmware, } from './mode
|
|
|
9
9
|
export { buildSensorQrConnectJson, draftSensorQrConnectJsonFromScanDevice, formatSensorReadingLine, mergeScanTargetIntoSensorQr, normalizeSensorStickerModel, parseSensorQrForConnect, pinFromSensorQrRecord, resolveSensorBleConnectCredentialsFromPin, sensorQrConnectJsonFromLoose, sensorQrSerialMatchesSelected, serialHexFromSensorQrScan, tryParseSensorQrJson, } from './connect-helpers.js';
|
|
10
10
|
export { calibrationFromExtendedJson, decodeLaboratoryCalibrationTimestamp, } from './calibration.js';
|
|
11
11
|
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, parseSensorConfigurationFromDevice, parseSensorConfigurationFromDeviceJson, parseSensorConfigurationJson, pickPartnerConfigurationJson, } from './profile.js';
|
|
12
|
-
export { addDeviceFoundListener, connect, disconnect, getCalibration, getConfiguration, isNativeSensorBeaconAvailable, isScanning, requestPermissions, setConfigurationJson, startScan, stopScan, triggerTransmission, } from './native-bridge.js';
|
|
12
|
+
export { addDeviceFoundListener, connect, clearMeasurementQueue, disconnect, getCalibration, getConfiguration, getProtoConfiguration, isNativeSensorBeaconAvailable, isScanning, requestPermissions, setConfigurationJson, startScan, stopScan, triggerTransmission, } from './native-bridge.js';
|
package/dist/native-bridge.d.ts
CHANGED
|
@@ -11,4 +11,8 @@ export declare function disconnect(): Promise<void>;
|
|
|
11
11
|
export declare function getConfiguration(): Promise<TempivoSensorConfiguration>;
|
|
12
12
|
export declare function setConfigurationJson(config: string | TempivoSensorConfiguration): Promise<void>;
|
|
13
13
|
export declare function triggerTransmission(): Promise<TempivoTriggerTransmissionResult>;
|
|
14
|
+
export declare function clearMeasurementQueue(): Promise<{
|
|
15
|
+
ok: boolean;
|
|
16
|
+
}>;
|
|
14
17
|
export declare function getCalibration(): Promise<TempivoNativeCalibration>;
|
|
18
|
+
export declare function getProtoConfiguration(): Promise<Record<string, unknown>>;
|
package/dist/native-bridge.js
CHANGED
|
@@ -46,6 +46,12 @@ export async function setConfigurationJson(config) {
|
|
|
46
46
|
export async function triggerTransmission() {
|
|
47
47
|
return (await loadNative()).triggerTransmission();
|
|
48
48
|
}
|
|
49
|
+
export async function clearMeasurementQueue() {
|
|
50
|
+
return (await loadNative()).clearMeasurementQueue();
|
|
51
|
+
}
|
|
49
52
|
export async function getCalibration() {
|
|
50
53
|
return (await loadNative()).getCalibration();
|
|
51
54
|
}
|
|
55
|
+
export async function getProtoConfiguration() {
|
|
56
|
+
return (await loadNative()).getProtoConfiguration();
|
|
57
|
+
}
|
package/dist/native-helpers.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TempivoSensorError } from './errors.js';
|
|
2
2
|
import { pickPartnerConfigurationJson } from './profile.js';
|
|
3
|
+
import { normalizeQrModelField } from './qr.js';
|
|
3
4
|
const SENSOR_CODES = [
|
|
4
5
|
'invalidPin',
|
|
5
6
|
'invalidQr',
|
|
@@ -10,13 +11,31 @@ const SENSOR_CODES = [
|
|
|
10
11
|
'connectFailed',
|
|
11
12
|
'unknown',
|
|
12
13
|
];
|
|
14
|
+
function rewriteStickerModel(json) {
|
|
15
|
+
try {
|
|
16
|
+
const parsed = JSON.parse(json);
|
|
17
|
+
if (parsed == null || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
18
|
+
return json;
|
|
19
|
+
const rec = parsed;
|
|
20
|
+
if (typeof rec.model !== 'string')
|
|
21
|
+
return json;
|
|
22
|
+
const next = normalizeQrModelField(rec.model);
|
|
23
|
+
if (next === rec.model)
|
|
24
|
+
return json;
|
|
25
|
+
rec.model = next;
|
|
26
|
+
return JSON.stringify(rec);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return json;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
13
32
|
export function qrToConnectJson(qr) {
|
|
14
33
|
if (typeof qr === 'string')
|
|
15
|
-
return qr;
|
|
34
|
+
return rewriteStickerModel(qr);
|
|
16
35
|
const body = {
|
|
17
36
|
sn: qr.serial,
|
|
18
37
|
pin: qr.pin,
|
|
19
|
-
model: qr.model ?? 'HC7',
|
|
38
|
+
model: normalizeQrModelField(qr.model ?? 'HC7'),
|
|
20
39
|
};
|
|
21
40
|
if (qr.deviceId)
|
|
22
41
|
body.deviceId = qr.deviceId;
|
package/dist/native-module.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TempivoDeviceFoundSubscription, TempivoNativeCalibration, TempivoNativePermissionResponse, TempivoNativeQr, TempivoSensorBeaconDevice } from './native-types.js';
|
|
2
|
+
import { type ProtoConfigObject } from './proto/decode-proto-config.js';
|
|
2
3
|
import type { TempivoSensorConfiguration, TempivoSensorQr, TempivoTriggerTransmissionResult } from './session-types.js';
|
|
3
4
|
export declare function isNativeSensorBeaconAvailable(): boolean;
|
|
4
5
|
export declare function requestPermissions(): Promise<TempivoNativePermissionResponse>;
|
|
@@ -21,4 +22,13 @@ export declare function getConfiguration(): Promise<TempivoSensorConfiguration>;
|
|
|
21
22
|
*/
|
|
22
23
|
export declare function setConfigurationJson(config: string | TempivoSensorConfiguration): Promise<void>;
|
|
23
24
|
export declare function triggerTransmission(): Promise<TempivoTriggerTransmissionResult>;
|
|
25
|
+
/**
|
|
26
|
+
* Clear on-device measurement / uplink queue (memory reset).
|
|
27
|
+
* Manual recovery only: not used by setConfigurationJson.
|
|
28
|
+
*/
|
|
29
|
+
export declare function clearMeasurementQueue(): Promise<{
|
|
30
|
+
ok: boolean;
|
|
31
|
+
}>;
|
|
32
|
+
/** Decoded device ProtoConfig (server, APN, intervals). Requires an open BLE session. */
|
|
33
|
+
export declare function getProtoConfiguration(): Promise<ProtoConfigObject>;
|
|
24
34
|
export declare function getCalibration(): Promise<TempivoNativeCalibration>;
|
package/dist/native-module.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { requireOptionalNativeModule } from 'expo-modules-core';
|
|
2
2
|
import { TempivoSensorError } from './errors.js';
|
|
3
3
|
import { configToJson, mapNativeError, qrToConnectJson } from './native-helpers.js';
|
|
4
|
+
import { decodeProtoConfigBase64 } from './proto/decode-proto-config.js';
|
|
4
5
|
import { partnerConfigFromProtoBase64 } from './proto/partner-from-proto.js';
|
|
5
6
|
import { partnerConfigToProtoBase64 } from './proto/partner-to-proto.js';
|
|
6
7
|
import { parseSensorConfigurationFromDevice } from './profile.js';
|
|
@@ -141,6 +142,38 @@ export async function triggerTransmission() {
|
|
|
141
142
|
throw mapNativeError(error);
|
|
142
143
|
}
|
|
143
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Clear on-device measurement / uplink queue (memory reset).
|
|
147
|
+
* Manual recovery only: not used by setConfigurationJson.
|
|
148
|
+
*/
|
|
149
|
+
export async function clearMeasurementQueue() {
|
|
150
|
+
try {
|
|
151
|
+
const native = getNative();
|
|
152
|
+
if (typeof native.clearMeasurementQueue !== 'function') {
|
|
153
|
+
throw new TempivoSensorError('runtimeUnavailable', 'Native clearMeasurementQueue is unavailable in this build.');
|
|
154
|
+
}
|
|
155
|
+
return await native.clearMeasurementQueue();
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
throw mapNativeError(error);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** Decoded device ProtoConfig (server, APN, intervals). Requires an open BLE session. */
|
|
162
|
+
export async function getProtoConfiguration() {
|
|
163
|
+
try {
|
|
164
|
+
const json = await getNative().getConfigurationJson();
|
|
165
|
+
const parsed = JSON.parse(json);
|
|
166
|
+
const protoB64 = typeof parsed.protoBase64 === 'string' ? parsed.protoBase64 : null;
|
|
167
|
+
if (!protoB64) {
|
|
168
|
+
throw new TempivoSensorError('unknown', 'Device config did not include a proto frame.');
|
|
169
|
+
}
|
|
170
|
+
lastProtoBase64 = protoB64;
|
|
171
|
+
return decodeProtoConfigBase64(protoB64);
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
throw mapNativeError(error);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
144
177
|
export async function getCalibration() {
|
|
145
178
|
try {
|
|
146
179
|
return await getNative().getCalibration();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory software defaults from the NB-IoT default-settings sheet (sw 7.02.xx).
|
|
3
|
+
* Compared against a decoded ProtoConfig. Hardware packaging is not on the radio.
|
|
4
|
+
*/
|
|
5
|
+
export type ProductionCheckLine = {
|
|
6
|
+
ok: boolean;
|
|
7
|
+
name: string;
|
|
8
|
+
expected: string;
|
|
9
|
+
actual: string;
|
|
10
|
+
};
|
|
11
|
+
export type ProductionCheckResult = {
|
|
12
|
+
pass: boolean;
|
|
13
|
+
lines: ProductionCheckLine[];
|
|
14
|
+
};
|
|
15
|
+
export declare function checkProductionDefaults(proto: Record<string, unknown>, extra?: {
|
|
16
|
+
firmware?: string | null;
|
|
17
|
+
hasLiveReading?: boolean | null;
|
|
18
|
+
}): ProductionCheckResult;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory software defaults from the NB-IoT default-settings sheet (sw 7.02.xx).
|
|
3
|
+
* Compared against a decoded ProtoConfig. Hardware packaging is not on the radio.
|
|
4
|
+
*/
|
|
5
|
+
const U32_MAX = 0xffffffff;
|
|
6
|
+
/** Current automatic PLMN. 0xFFFFFFFF is the legacy automatic value. */
|
|
7
|
+
const PLMN_AUTOMATIC = 1_000_000;
|
|
8
|
+
/** Single DEL byte: username/password not used. */
|
|
9
|
+
const DEL = '\u007f';
|
|
10
|
+
function u32(value) {
|
|
11
|
+
if (typeof value === 'bigint') {
|
|
12
|
+
const n = Number(value);
|
|
13
|
+
return Number.isFinite(n) ? n >>> 0 : null;
|
|
14
|
+
}
|
|
15
|
+
if (typeof value !== 'number' || !Number.isFinite(value))
|
|
16
|
+
return null;
|
|
17
|
+
return value < 0 ? value >>> 0 : value;
|
|
18
|
+
}
|
|
19
|
+
function line(name, expected, actual, ok) {
|
|
20
|
+
return { ok, name, expected, actual };
|
|
21
|
+
}
|
|
22
|
+
function showCredential(value) {
|
|
23
|
+
if (typeof value === 'string' && isDelOnly(value))
|
|
24
|
+
return 'not used';
|
|
25
|
+
return show(value);
|
|
26
|
+
}
|
|
27
|
+
function show(value) {
|
|
28
|
+
if (value == null)
|
|
29
|
+
return 'missing';
|
|
30
|
+
if (typeof value === 'string')
|
|
31
|
+
return value === '' ? 'empty' : value;
|
|
32
|
+
if (typeof value === 'number')
|
|
33
|
+
return String(value);
|
|
34
|
+
if (Array.isArray(value))
|
|
35
|
+
return value.length === 0 ? 'empty' : JSON.stringify(value);
|
|
36
|
+
return JSON.stringify(value);
|
|
37
|
+
}
|
|
38
|
+
function eqU32(actual, expected) {
|
|
39
|
+
const n = u32(actual);
|
|
40
|
+
return n != null && n === (expected >>> 0);
|
|
41
|
+
}
|
|
42
|
+
function eqStr(actual, expected) {
|
|
43
|
+
return typeof actual === 'string' && actual.trim().toLowerCase() === expected.toLowerCase();
|
|
44
|
+
}
|
|
45
|
+
function isBlankOrNa(value) {
|
|
46
|
+
if (value == null)
|
|
47
|
+
return true;
|
|
48
|
+
if (typeof value !== 'string')
|
|
49
|
+
return false;
|
|
50
|
+
const s = value.trim();
|
|
51
|
+
return s === '' || s.toUpperCase() === 'N/A' || /^0+$/.test(s) || isDelOnly(s);
|
|
52
|
+
}
|
|
53
|
+
function isDelOnly(value) {
|
|
54
|
+
return value.length > 0 && [...value].every((ch) => ch === DEL);
|
|
55
|
+
}
|
|
56
|
+
function plmnAutomatic(value) {
|
|
57
|
+
const n = u32(value);
|
|
58
|
+
return n === U32_MAX || n === PLMN_AUTOMATIC;
|
|
59
|
+
}
|
|
60
|
+
function dnsAutomatic(value) {
|
|
61
|
+
if (value == null)
|
|
62
|
+
return true;
|
|
63
|
+
if (Array.isArray(value)) {
|
|
64
|
+
if (value.length === 0)
|
|
65
|
+
return true;
|
|
66
|
+
if (value.every((n) => u32(n) === 0))
|
|
67
|
+
return true;
|
|
68
|
+
return value.length === 4 && value.every((n) => u32(n) === 255);
|
|
69
|
+
}
|
|
70
|
+
return u32(value) === 0 || u32(value) === 0xffffffff;
|
|
71
|
+
}
|
|
72
|
+
function rulesOff(rules) {
|
|
73
|
+
if (rules == null)
|
|
74
|
+
return true;
|
|
75
|
+
if (!Array.isArray(rules))
|
|
76
|
+
return false;
|
|
77
|
+
return rules.every((rule) => {
|
|
78
|
+
if (rule == null || typeof rule !== 'object')
|
|
79
|
+
return false;
|
|
80
|
+
const condition = rule.condition;
|
|
81
|
+
if (condition == null || condition === 0 || condition === 1)
|
|
82
|
+
return true;
|
|
83
|
+
const name = String(condition).toUpperCase();
|
|
84
|
+
return name === 'CONDITION_DISABLED' || name === 'CONDITION_UNSPECIFIED' || name === 'DISABLED';
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function firmwareOk(firmware) {
|
|
88
|
+
return firmware.trim().length > 0;
|
|
89
|
+
}
|
|
90
|
+
export function checkProductionDefaults(proto, extra) {
|
|
91
|
+
const lines = [];
|
|
92
|
+
const pushNum = (name, key, expected, label = String(expected)) => {
|
|
93
|
+
const actual = proto[key];
|
|
94
|
+
lines.push(line(name, label, show(u32(actual) ?? actual), eqU32(actual, expected)));
|
|
95
|
+
};
|
|
96
|
+
const pushStr = (name, key, expected) => {
|
|
97
|
+
const actual = proto[key];
|
|
98
|
+
lines.push(line(name, expected, show(actual), eqStr(actual, expected)));
|
|
99
|
+
};
|
|
100
|
+
pushNum('Measurement period base', 'measurementPeriodBase', 300);
|
|
101
|
+
pushNum('Measurement period factor', 'measurementPeriodFactor', 1);
|
|
102
|
+
pushNum('BLE turn off', 'bleTurnoffTime', U32_MAX, 'never');
|
|
103
|
+
pushNum('BLE on network issues', 'networkTroubleshooting', 1, 'DISABLE');
|
|
104
|
+
pushStr('APN', 'apn', 'iot.1nce.net');
|
|
105
|
+
lines.push(line('APN user', 'N/A', showCredential(proto.apnUsername), isBlankOrNa(proto.apnUsername)));
|
|
106
|
+
lines.push(line('APN password', 'N/A', showCredential(proto.apnPassword), isBlankOrNa(proto.apnPassword)));
|
|
107
|
+
lines.push(line('PLMN', 'Automatic', show(u32(proto.plmnSelection) ?? proto.plmnSelection), plmnAutomatic(proto.plmnSelection)));
|
|
108
|
+
{
|
|
109
|
+
const mask = u32(proto.modemBandsMask);
|
|
110
|
+
lines.push(line('NB-IoT bands', 'regional', mask == null ? 'missing' : `0x${mask.toString(16)}`, mask != null));
|
|
111
|
+
}
|
|
112
|
+
pushNum('Supervision period', 'supervisionPeriod', 86400);
|
|
113
|
+
pushNum('Transmission interval', 'transmissionInterval', 10800);
|
|
114
|
+
pushNum('Transfer limit', 'transferLimit', 65535, 'Disabled');
|
|
115
|
+
pushNum('Transfer limit period', 'transferLimitTimer', 65535, 'Disabled');
|
|
116
|
+
pushNum('ACK interval', 'ackInterval', U32_MAX, 'ALWAYS');
|
|
117
|
+
pushNum('Cloud token mode', 'cloudTokenConfig', 2, 'IMEI');
|
|
118
|
+
lines.push(line('Cloud token value', 'zeros', show(proto.cloudToken), isBlankOrNa(proto.cloudToken)));
|
|
119
|
+
pushStr('Server', 'dataServerIp', 'assets.tempivo.com');
|
|
120
|
+
pushNum('Server port', 'dataServerPort', 5683);
|
|
121
|
+
pushStr('Measurements endpoint', 'dataEndpoint', '/m');
|
|
122
|
+
pushStr('Configuration endpoint', 'configurationEndpoint', '/c');
|
|
123
|
+
pushStr('Device info endpoint', 'deviceInfoEndpoint', '/i');
|
|
124
|
+
pushStr('Time endpoint', 'timeEndpoint', '/t');
|
|
125
|
+
pushStr('Extended configuration endpoint', 'extendedConfigurationEndpoint', '/e');
|
|
126
|
+
lines.push(line('DNS server', 'Automatic', show(proto.dnsServerIp), dnsAutomatic(proto.dnsServerIp)));
|
|
127
|
+
pushNum('DNS TTL', 'dnsTtlConfig', 864002, 'refresh if communication fails');
|
|
128
|
+
pushStr('Update server', 'updateServerIp', 'nbiot.efento.io');
|
|
129
|
+
pushNum('Update UDP port', 'updateServerPortUdp', 50000);
|
|
130
|
+
pushNum('Update CoAP port', 'updateServerPortCoap', 5680);
|
|
131
|
+
lines.push(line('Alarm rules', 'OFF', Array.isArray(proto.rules) ? `${proto.rules.length} rules` : 'none', rulesOff(proto.rules)));
|
|
132
|
+
if (extra?.firmware != null && extra.firmware.trim() !== '') {
|
|
133
|
+
lines.push(line('Firmware', 'any', extra.firmware.trim(), firmwareOk(extra.firmware)));
|
|
134
|
+
}
|
|
135
|
+
if (extra?.hasLiveReading != null) {
|
|
136
|
+
lines.push(line('Live measurement', 'temperature or humidity', extra.hasLiveReading ? 'seen' : 'none', extra.hasLiveReading));
|
|
137
|
+
}
|
|
138
|
+
return { pass: lines.every((row) => row.ok), lines };
|
|
139
|
+
}
|
package/dist/qr.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ export declare function bluetoothMacFromSerial(serial: string): string;
|
|
|
5
5
|
/** BLE default when QR omits `model`. */
|
|
6
6
|
export declare const DEFAULT_SENSOR_MODEL = "HC7";
|
|
7
7
|
export declare function assertSupportedSensorModel(model: string): void;
|
|
8
|
+
/** Sticker `model` → HC7 (incl. Tempivo alias TS10). Unknown strings pass through trimmed. */
|
|
9
|
+
export declare function normalizeQrModelField(model: string | undefined | null): string;
|
|
8
10
|
export declare function sessionTypeFromModel(_model: string | undefined | null): TempivoSensorSessionType;
|
|
9
11
|
/**
|
|
10
12
|
* 3-byte big-endian numeric PIN for GATT command payloads that check a reset code
|
package/dist/qr.js
CHANGED
|
@@ -18,9 +18,20 @@ export const DEFAULT_SENSOR_MODEL = 'HC7';
|
|
|
18
18
|
export function assertSupportedSensorModel(model) {
|
|
19
19
|
const m = model.trim().toUpperCase().replace(/-/g, '');
|
|
20
20
|
if (m === 'HC5') {
|
|
21
|
-
throw new TempivoSensorError('invalidQr', 'HC5 is not supported by the partner SDK. Use HC7 sensors.');
|
|
21
|
+
throw new TempivoSensorError('invalidQr', 'HC5 is not supported by the partner SDK. Use HC7 / TS10 sensors.');
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
/** Sticker `model` → HC7 (incl. Tempivo alias TS10). Unknown strings pass through trimmed. */
|
|
25
|
+
export function normalizeQrModelField(model) {
|
|
26
|
+
if (model == null || model.trim() === '')
|
|
27
|
+
return DEFAULT_SENSOR_MODEL;
|
|
28
|
+
const m = model.trim().toUpperCase().replace(/-/g, '');
|
|
29
|
+
if (m === 'TS10' || m === 'HC7')
|
|
30
|
+
return 'HC7';
|
|
31
|
+
if (m === 'HC5')
|
|
32
|
+
return 'HC5';
|
|
33
|
+
return model.trim();
|
|
34
|
+
}
|
|
24
35
|
export function sessionTypeFromModel(_model) {
|
|
25
36
|
return 'modern';
|
|
26
37
|
}
|
|
@@ -80,8 +91,10 @@ export function parseSensorQrJson(text) {
|
|
|
80
91
|
throw new TempivoSensorError('invalidQr', 'QR is missing PIN.');
|
|
81
92
|
}
|
|
82
93
|
const rawModel = typeof rec.model === 'string' ? rec.model.trim() : '';
|
|
83
|
-
const
|
|
84
|
-
assertSupportedSensorModel(
|
|
94
|
+
const normalized = normalizeQrModelField(rawModel || DEFAULT_SENSOR_MODEL);
|
|
95
|
+
assertSupportedSensorModel(normalized);
|
|
96
|
+
const sticker = rawModel.toUpperCase().replace(/-/g, '');
|
|
97
|
+
const model = sticker === 'TS10' ? 'TS10' : normalized;
|
|
85
98
|
return {
|
|
86
99
|
serial,
|
|
87
100
|
pin,
|
package/dist/react-native.d.ts
CHANGED
|
@@ -13,16 +13,6 @@ export { calibrationFromExtendedJson, decodeLaboratoryCalibrationTimestamp, } fr
|
|
|
13
13
|
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, parseSensorConfigurationFromDevice, parseSensorConfigurationFromDeviceJson, parseSensorConfigurationJson, pickPartnerConfigurationJson, } from './profile.js';
|
|
14
14
|
export type { TempivoSchedule, TempivoScheduleAlways, TempivoScheduleWeek, TempivoSensorCalibration, TempivoSensorConfiguration, TempivoSensorQr, TempivoSensorSessionType, TempivoTemperatureAlert, TempivoTemperatureChannel, TempivoTemperatureMaxAlert, TempivoTemperatureMinAlert, TempivoTemperatureRangeAlert, TempivoTriggerTransmissionResult, } from './session-types.js';
|
|
15
15
|
export type { TempivoDeviceFoundSubscription, TempivoNativeCalibration, TempivoNativeMeasurement, TempivoNativePermissionResponse, TempivoNativePermissionStatus, TempivoNativeQr, TempivoNativeTelemetry, TempivoSensorBeaconDevice, } from './native-types.js';
|
|
16
|
-
|
|
17
|
-
export
|
|
18
|
-
export
|
|
19
|
-
export declare const startScan: typeof native.startScan;
|
|
20
|
-
export declare const stopScan: typeof native.stopScan;
|
|
21
|
-
export declare const isScanning: typeof native.isScanning;
|
|
22
|
-
export declare const addDeviceFoundListener: typeof native.addDeviceFoundListener;
|
|
23
|
-
export declare const connect: typeof native.connect;
|
|
24
|
-
export declare const disconnect: typeof native.disconnect;
|
|
25
|
-
export declare const getConfiguration: typeof native.getConfiguration;
|
|
26
|
-
export declare const setConfigurationJson: typeof native.setConfigurationJson;
|
|
27
|
-
export declare const triggerTransmission: typeof native.triggerTransmission;
|
|
28
|
-
export declare const getCalibration: typeof native.getCalibration;
|
|
16
|
+
export { isNativeSensorBeaconAvailable, requestPermissions, startScan, stopScan, isScanning, addDeviceFoundListener, connect, disconnect, getConfiguration, setConfigurationJson, triggerTransmission, clearMeasurementQueue, getCalibration, getProtoConfiguration, } from './native-module.js';
|
|
17
|
+
export { checkProductionDefaults } from './production-defaults.js';
|
|
18
|
+
export type { ProductionCheckLine, ProductionCheckResult } from './production-defaults.js';
|
package/dist/react-native.js
CHANGED
|
@@ -9,16 +9,5 @@ export { isMissingAdvertisementFirmware, sensorModelFromFirmware } from './model
|
|
|
9
9
|
export { buildSensorQrConnectJson, draftSensorQrConnectJsonFromScanDevice, formatSensorReadingLine, mergeScanTargetIntoSensorQr, normalizeSensorStickerModel, parseSensorQrForConnect, pinFromSensorQrRecord, resolveSensorBleConnectCredentialsFromPin, sensorQrConnectJsonFromLoose, sensorQrSerialMatchesSelected, serialHexFromSensorQrScan, tryParseSensorQrJson, } from './connect-helpers.js';
|
|
10
10
|
export { calibrationFromExtendedJson, decodeLaboratoryCalibrationTimestamp, } from './calibration.js';
|
|
11
11
|
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, parseSensorConfigurationFromDevice, parseSensorConfigurationFromDeviceJson, parseSensorConfigurationJson, pickPartnerConfigurationJson, } from './profile.js';
|
|
12
|
-
|
|
13
|
-
export
|
|
14
|
-
export const requestPermissions = native.requestPermissions;
|
|
15
|
-
export const startScan = native.startScan;
|
|
16
|
-
export const stopScan = native.stopScan;
|
|
17
|
-
export const isScanning = native.isScanning;
|
|
18
|
-
export const addDeviceFoundListener = native.addDeviceFoundListener;
|
|
19
|
-
export const connect = native.connect;
|
|
20
|
-
export const disconnect = native.disconnect;
|
|
21
|
-
export const getConfiguration = native.getConfiguration;
|
|
22
|
-
export const setConfigurationJson = native.setConfigurationJson;
|
|
23
|
-
export const triggerTransmission = native.triggerTransmission;
|
|
24
|
-
export const getCalibration = native.getCalibration;
|
|
12
|
+
export { isNativeSensorBeaconAvailable, requestPermissions, startScan, stopScan, isScanning, addDeviceFoundListener, connect, disconnect, getConfiguration, setConfigurationJson, triggerTransmission, clearMeasurementQueue, getCalibration, getProtoConfiguration, } from './native-module.js';
|
|
13
|
+
export { checkProductionDefaults } from './production-defaults.js';
|
|
Binary file
|
|
@@ -169,6 +169,7 @@ __attribute__((swift_name("TempivoSensorBridge")))
|
|
|
169
169
|
@interface TSBTempivoSensorBridge : TSBBase
|
|
170
170
|
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
|
171
171
|
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
|
172
|
+
- (NSString *)clearMeasurementQueuePayloadJson __attribute__((swift_name("clearMeasurementQueuePayloadJson()")));
|
|
172
173
|
- (NSString *)connectPayloadJsonDeviceId:(NSString *)deviceId bluetoothMac:(NSString *)bluetoothMac pin:(NSString *)pin legacy:(BOOL)legacy __attribute__((swift_name("connectPayloadJson(deviceId:bluetoothMac:pin:legacy:)")));
|
|
173
174
|
- (void)disconnect __attribute__((swift_name("disconnect()")));
|
|
174
175
|
- (NSString *)getCalibrationPayloadJson __attribute__((swift_name("getCalibrationPayloadJson()")));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64/TempivoSensorBridge.framework/TempivoSensorBridge
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 78427712 bytes
|
|
4
|
+
sha256: 3d8331bcccc757e88f3cc11ebd41a81837c0712942178f3bfdd869094b90cd45
|
|
@@ -169,6 +169,7 @@ __attribute__((swift_name("TempivoSensorBridge")))
|
|
|
169
169
|
@interface TSBTempivoSensorBridge : TSBBase
|
|
170
170
|
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
|
|
171
171
|
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
|
|
172
|
+
- (NSString *)clearMeasurementQueuePayloadJson __attribute__((swift_name("clearMeasurementQueuePayloadJson()")));
|
|
172
173
|
- (NSString *)connectPayloadJsonDeviceId:(NSString *)deviceId bluetoothMac:(NSString *)bluetoothMac pin:(NSString *)pin legacy:(BOOL)legacy __attribute__((swift_name("connectPayloadJson(deviceId:bluetoothMac:pin:legacy:)")));
|
|
173
174
|
- (void)disconnect __attribute__((swift_name("disconnect()")));
|
|
174
175
|
- (NSString *)getCalibrationPayloadJson __attribute__((swift_name("getCalibrationPayloadJson()")));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64-simulator/TempivoSensorBridge.framework/TempivoSensorBridge
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 35253832 bytes
|
|
4
|
+
sha256: e861ca361a1210560b37ef321f2a2590a8f634f493a424a50cfd2c4c90b4e401
|
|
@@ -54,6 +54,12 @@ public enum TempivoSensorQrParser {
|
|
|
54
54
|
|
|
55
55
|
public static let defaultModel = "HC7"
|
|
56
56
|
|
|
57
|
+
public static func normalizeModel(_ model: String) -> String {
|
|
58
|
+
let m = model.trimmingCharacters(in: .whitespacesAndNewlines).uppercased().replacingOccurrences(of: "-", with: "")
|
|
59
|
+
if m.isEmpty || m == "HC7" || m == "TS10" { return defaultModel }
|
|
60
|
+
return model.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
61
|
+
}
|
|
62
|
+
|
|
57
63
|
public static func assertSupportedModel(_ model: String) throws {
|
|
58
64
|
let m = model.trimmingCharacters(in: .whitespacesAndNewlines).uppercased().replacingOccurrences(of: "-", with: "")
|
|
59
65
|
if m == "HC5" {
|
|
@@ -84,8 +90,8 @@ public enum TempivoSensorQrParser {
|
|
|
84
90
|
guard !pin.isEmpty else {
|
|
85
91
|
throw TempivoSensorError(.invalidQr, "QR is missing PIN.")
|
|
86
92
|
}
|
|
87
|
-
let rawModel = (obj["model"] as? String)
|
|
88
|
-
let model = rawModel
|
|
93
|
+
let rawModel = (obj["model"] as? String) ?? ""
|
|
94
|
+
let model = normalizeModel(rawModel)
|
|
89
95
|
try assertSupportedModel(model)
|
|
90
96
|
let hex = serial.count == 12 ? serial : String(serial.suffix(12))
|
|
91
97
|
let macOverride =
|
|
@@ -146,6 +146,17 @@ public final class TempivoSensorSession: @unchecked Sendable {
|
|
|
146
146
|
#endif
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
/// Clear on-device measurement / uplink queue (memory reset). Manual recovery only.
|
|
150
|
+
public func clearMeasurementQueue() throws {
|
|
151
|
+
#if canImport(TempivoSensorBridge)
|
|
152
|
+
try ensureSdkConnected()
|
|
153
|
+
let result = parseBridgeJson(bridge.clearMeasurementQueuePayloadJson())
|
|
154
|
+
try throwIfBridgeError(result)
|
|
155
|
+
#else
|
|
156
|
+
throw TempivoSensorError(.runtimeUnavailable, "Sensor GATT requires a physical device with the native runtime.")
|
|
157
|
+
#endif
|
|
158
|
+
}
|
|
159
|
+
|
|
149
160
|
public func getCalibration() throws -> TempivoSensorCalibration {
|
|
150
161
|
#if canImport(TempivoSensorBridge)
|
|
151
162
|
try ensureSdkConnected()
|
|
@@ -120,6 +120,15 @@ public class TempivoSensorBeaconModule: Module {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
AsyncFunction("clearMeasurementQueue") { () -> [String: Any] in
|
|
124
|
+
do {
|
|
125
|
+
try self.session.clearMeasurementQueue()
|
|
126
|
+
return ["ok": true]
|
|
127
|
+
} catch {
|
|
128
|
+
throw self.mapError(error)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
123
132
|
AsyncFunction("getCalibration") { () -> [String: Any] in
|
|
124
133
|
do {
|
|
125
134
|
let cal = try self.session.getCalibration()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tempivo/sensor-beacon",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
4
4
|
"description": "Tempivo sensor BLE SDK. Native scan and GATT for Expo, React Native, Android, and iOS. Node helpers decode advertisements and parse QR or config (no radio).",
|
|
5
5
|
"homepage": "https://app.tempivo.com/integrations",
|
|
6
6
|
"repository": {
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"build:ios-bridge": "bash scripts/build-ios-bridge.sh && node scripts/copy-ios-bridge.mjs",
|
|
57
57
|
"copy:ios-bridge": "node scripts/copy-ios-bridge.mjs",
|
|
58
58
|
"build:all": "npm run build:ts && npm run build:android",
|
|
59
|
-
"prepare": "
|
|
59
|
+
"prepare": "node scripts/prepare-build.mjs",
|
|
60
60
|
"test": "npm run test:all",
|
|
61
61
|
"test:unit": "node --experimental-vm-modules node_modules/jest/bin/jest.js --config jest.config.mjs --testPathIgnorePatterns=ble.integration",
|
|
62
62
|
"test:ble": "TEMPIVO_BLE_INTEGRATION=1 node --experimental-vm-modules node_modules/jest/bin/jest.js --config jest.config.mjs --testPathPattern=ble.integration",
|