@tempivo/sensor-beacon 0.2.0 → 0.3.0
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 +142 -114
- package/android/build.gradle +38 -2
- package/android/src/main/AndroidManifest.xml +10 -0
- package/android/src/main/java/expo/modules/tempivosensorbeacon/SensorBeaconNative.java +233 -0
- package/android/src/main/java/expo/modules/tempivosensorbeacon/TempivoSensorBeaconModule.kt +122 -0
- package/android-aar/build.gradle +4 -0
- package/{android → android-aar}/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorSession.kt +13 -0
- package/app.plugin.cjs +142 -0
- package/dist/expo-modules-core.web-stub.d.ts +5 -0
- package/dist/expo-modules-core.web-stub.js +9 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/native-bridge.d.ts +14 -0
- package/dist/native-bridge.js +51 -0
- package/dist/native-helpers.d.ts +5 -0
- package/dist/native-helpers.js +33 -0
- package/dist/native-module.d.ts +14 -0
- package/dist/native-module.js +104 -0
- package/dist/native-types.d.ts +41 -0
- package/dist/native-types.js +1 -0
- package/dist/react-native.d.ts +1 -0
- package/dist/react-native.js +1 -0
- package/dist/tempivo-sensor-beacon.aar +0 -0
- package/expo-module.config.json +12 -0
- package/ios/Frameworks/TempivoSensorBridge.xcframework/Info.plist +43 -0
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64/TempivoSensorBridge.framework/Headers/TempivoSensorBridge.h +159 -0
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64/TempivoSensorBridge.framework/Info.plist +35 -0
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64/TempivoSensorBridge.framework/Modules/module.modulemap +8 -0
- 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 +159 -0
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64-simulator/TempivoSensorBridge.framework/Info.plist +31 -0
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64-simulator/TempivoSensorBridge.framework/Modules/module.modulemap +8 -0
- package/ios/Frameworks/TempivoSensorBridge.xcframework/ios-arm64-simulator/TempivoSensorBridge.framework/TempivoSensorBridge +0 -0
- package/ios/TempivoSensorBeacon.podspec +35 -0
- package/ios/TempivoSensorBeaconModule.swift +208 -0
- package/package.json +48 -7
- /package/{android → android-aar}/gradle/wrapper/gradle-wrapper.jar +0 -0
- /package/{android → android-aar}/gradle/wrapper/gradle-wrapper.properties +0 -0
- /package/{android → android-aar}/gradle.properties +0 -0
- /package/{android → android-aar}/gradlew +0 -0
- /package/{android → android-aar}/library/build.gradle +0 -0
- /package/{android → android-aar}/library/consumer-rules.pro +0 -0
- /package/{android → android-aar}/library/src/main/AndroidManifest.xml +0 -0
- /package/{android → android-aar}/library/src/main/java/com/tempivo/sensor/beacon/PartnerBleRules.kt +0 -0
- /package/{android → android-aar}/library/src/main/java/com/tempivo/sensor/beacon/SensorBleRuntime.kt +0 -0
- /package/{android → android-aar}/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorBeaconDecoder.kt +0 -0
- /package/{android → android-aar}/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorBeaconScanner.kt +0 -0
- /package/{android → android-aar}/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorBeaconTypes.kt +0 -0
- /package/{android → android-aar}/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorCalibration.kt +0 -0
- /package/{android → android-aar}/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorError.kt +0 -0
- /package/{android → android-aar}/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorProfile.kt +0 -0
- /package/{android → android-aar}/library/src/main/java/com/tempivo/sensor/beacon/TempivoSensorQr.kt +0 -0
- /package/{android → android-aar}/settings.gradle +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
package expo.modules.tempivosensorbeacon
|
|
2
|
+
|
|
3
|
+
import android.Manifest
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.os.Build
|
|
6
|
+
import expo.modules.interfaces.permissions.Permissions
|
|
7
|
+
import expo.modules.kotlin.Promise
|
|
8
|
+
import expo.modules.kotlin.exception.CodedException
|
|
9
|
+
import expo.modules.kotlin.modules.Module
|
|
10
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
11
|
+
|
|
12
|
+
class TempivoSensorBeaconModule : Module() {
|
|
13
|
+
private val native = SensorBeaconNative()
|
|
14
|
+
|
|
15
|
+
override fun definition() = ModuleDefinition {
|
|
16
|
+
Name("TempivoSensorBeacon")
|
|
17
|
+
Events("onDeviceFound")
|
|
18
|
+
|
|
19
|
+
AsyncFunction("requestPermissions") { promise: Promise ->
|
|
20
|
+
val manager = appContext.permissions
|
|
21
|
+
?: throw CodedException("runtimeUnavailable", "Permissions manager is not available.", null)
|
|
22
|
+
Permissions.askForPermissionsWithPermissionsManager(manager, promise, *blePermissions())
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
AsyncFunction("startScan") {
|
|
26
|
+
try {
|
|
27
|
+
native.startScan(requireContext()) { payload ->
|
|
28
|
+
sendEvent("onDeviceFound", payload)
|
|
29
|
+
}
|
|
30
|
+
} catch (error: Throwable) {
|
|
31
|
+
throw error.toSensorException()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
Function("stopScan") {
|
|
36
|
+
native.stopScan()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Function("isScanning") {
|
|
40
|
+
native.isScanning
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
AsyncFunction("connect") { qrJson: String ->
|
|
44
|
+
try {
|
|
45
|
+
native.connect(requireContext(), qrJson)
|
|
46
|
+
} catch (error: Throwable) {
|
|
47
|
+
throw error.toSensorException()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
AsyncFunction("disconnect") {
|
|
52
|
+
try {
|
|
53
|
+
native.disconnect()
|
|
54
|
+
} catch (error: Throwable) {
|
|
55
|
+
throw error.toSensorException()
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
AsyncFunction("getConfigurationJson") {
|
|
60
|
+
try {
|
|
61
|
+
native.configurationJson
|
|
62
|
+
} catch (error: Throwable) {
|
|
63
|
+
throw error.toSensorException()
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
AsyncFunction("setConfigurationJson") { json: String ->
|
|
68
|
+
try {
|
|
69
|
+
native.setConfigurationJson(json)
|
|
70
|
+
} catch (error: Throwable) {
|
|
71
|
+
throw error.toSensorException()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
AsyncFunction("triggerTransmission") {
|
|
76
|
+
try {
|
|
77
|
+
native.triggerTransmission()
|
|
78
|
+
} catch (error: Throwable) {
|
|
79
|
+
throw error.toSensorException()
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
AsyncFunction("getCalibration") {
|
|
84
|
+
try {
|
|
85
|
+
native.calibration
|
|
86
|
+
} catch (error: Throwable) {
|
|
87
|
+
throw error.toSensorException()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
OnDestroy {
|
|
92
|
+
native.stopScan()
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private fun requireContext(): Context {
|
|
97
|
+
return appContext.reactContext
|
|
98
|
+
?: appContext.currentActivity
|
|
99
|
+
?: throw CodedException("runtimeUnavailable", "Android context is not available.", null)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private fun blePermissions(): Array<String> {
|
|
103
|
+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
104
|
+
arrayOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT)
|
|
105
|
+
} else {
|
|
106
|
+
arrayOf(
|
|
107
|
+
Manifest.permission.ACCESS_FINE_LOCATION,
|
|
108
|
+
Manifest.permission.BLUETOOTH,
|
|
109
|
+
Manifest.permission.BLUETOOTH_ADMIN,
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private fun Throwable.toSensorException(): CodedException {
|
|
116
|
+
if (this is CodedException) return this
|
|
117
|
+
val native = this as? SensorBeaconNative.NativeError ?: cause as? SensorBeaconNative.NativeError
|
|
118
|
+
if (native != null) {
|
|
119
|
+
return CodedException(native.code, native.message, this)
|
|
120
|
+
}
|
|
121
|
+
return CodedException("unknown", message ?: "Sensor request failed.", this)
|
|
122
|
+
}
|
|
@@ -3,6 +3,7 @@ package com.tempivo.sensor.beacon
|
|
|
3
3
|
import android.app.Application
|
|
4
4
|
import android.content.Context
|
|
5
5
|
import kotlinx.coroutines.Dispatchers
|
|
6
|
+
import kotlinx.coroutines.runBlocking
|
|
6
7
|
import kotlinx.coroutines.sync.Mutex
|
|
7
8
|
import kotlinx.coroutines.sync.withLock
|
|
8
9
|
import kotlinx.coroutines.withContext
|
|
@@ -100,6 +101,18 @@ class TempivoSensorSession(
|
|
|
100
101
|
return runGatt { SensorBleRuntime.readCalibration(requireSession()) }
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
fun connectBlocking(qr: TempivoSensorQr) = runBlocking { connect(qr) }
|
|
105
|
+
|
|
106
|
+
fun disconnectBlocking() = runBlocking { disconnect() }
|
|
107
|
+
|
|
108
|
+
fun getConfigurationJsonBlocking(): String = runBlocking { getConfigurationJson() }
|
|
109
|
+
|
|
110
|
+
fun setConfigurationJsonBlocking(json: String) = runBlocking { setConfigurationJson(json) }
|
|
111
|
+
|
|
112
|
+
fun triggerTransmissionBlocking(): TriggerResult = runBlocking { triggerTransmission() }
|
|
113
|
+
|
|
114
|
+
fun getCalibrationBlocking(): TempivoSensorCalibration = runBlocking { getCalibration() }
|
|
115
|
+
|
|
103
116
|
private fun requireSession(): SensorBleRuntime.Session =
|
|
104
117
|
session
|
|
105
118
|
?: throw TempivoSensorException(TempivoSensorException.Code.NOT_CONNECTED, "Not connected.")
|
package/app.plugin.cjs
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
const Module = require('module');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
function loadConfigPlugins() {
|
|
5
|
+
const candidates = [process.cwd(), path.dirname(process.cwd())];
|
|
6
|
+
for (const base of candidates) {
|
|
7
|
+
try {
|
|
8
|
+
const id = require.resolve('expo/config-plugins', { paths: [base] });
|
|
9
|
+
return require(id);
|
|
10
|
+
} catch {
|
|
11
|
+
// try next
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const fromExpo = require.resolve('expo/package.json', { paths: [process.cwd()] });
|
|
16
|
+
return Module.createRequire(fromExpo)('expo/config-plugins');
|
|
17
|
+
} catch {
|
|
18
|
+
return require('expo/config-plugins');
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
AndroidConfig,
|
|
24
|
+
withInfoPlist,
|
|
25
|
+
withProjectBuildGradle,
|
|
26
|
+
withSettingsGradle,
|
|
27
|
+
withGradleProperties,
|
|
28
|
+
} = loadConfigPlugins();
|
|
29
|
+
|
|
30
|
+
const MAVEN_URL = 'https://maven.efento.io/releases';
|
|
31
|
+
const DEFAULT_BLE_MESSAGE = 'Tempivo uses Bluetooth to find and configure sensors.';
|
|
32
|
+
const MIN_SDK = 26;
|
|
33
|
+
|
|
34
|
+
function insertKotlinStdlibForce(contents, isKts) {
|
|
35
|
+
if (contents.includes('TEMPIVO_KOTLIN_STDLIB_FORCE')) return contents;
|
|
36
|
+
const extra = isKts
|
|
37
|
+
? `
|
|
38
|
+
// TEMPIVO_KOTLIN_STDLIB_FORCE
|
|
39
|
+
subprojects {
|
|
40
|
+
configurations.configureEach {
|
|
41
|
+
resolutionStrategy {
|
|
42
|
+
force("org.jetbrains.kotlin:kotlin-stdlib:2.1.20")
|
|
43
|
+
force("org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.20")
|
|
44
|
+
force("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20")
|
|
45
|
+
force("org.jetbrains.kotlin:kotlin-reflect:2.1.20")
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
`
|
|
50
|
+
: `
|
|
51
|
+
// TEMPIVO_KOTLIN_STDLIB_FORCE
|
|
52
|
+
subprojects { sub ->
|
|
53
|
+
sub.configurations.configureEach {
|
|
54
|
+
resolutionStrategy {
|
|
55
|
+
force 'org.jetbrains.kotlin:kotlin-stdlib:2.1.20'
|
|
56
|
+
force 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.20'
|
|
57
|
+
force 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20'
|
|
58
|
+
force 'org.jetbrains.kotlin:kotlin-reflect:2.1.20'
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
`;
|
|
63
|
+
return `${contents.trimEnd()}\n${extra}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function insertMavenRepo(contents, isKts) {
|
|
67
|
+
if (contents.includes('maven.efento.io')) return contents;
|
|
68
|
+
const line = isKts
|
|
69
|
+
? `\n maven { url = uri("${MAVEN_URL}") }`
|
|
70
|
+
: `\n maven { url '${MAVEN_URL}' }`;
|
|
71
|
+
const token = 'mavenCentral()';
|
|
72
|
+
const idx = contents.lastIndexOf(token);
|
|
73
|
+
if (idx === -1) return contents;
|
|
74
|
+
const at = idx + token.length;
|
|
75
|
+
return contents.slice(0, at) + line + contents.slice(at);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function ensureGradleProperty(items, key, value, shouldReplace) {
|
|
79
|
+
const existing = items.find((item) => item.type === 'property' && item.key === key);
|
|
80
|
+
if (existing && existing.type === 'property') {
|
|
81
|
+
if (shouldReplace(existing.value)) existing.value = value;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
items.push({ type: 'property', key, value });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function withTempivoSensorBeacon(config, props = {}) {
|
|
88
|
+
const bleMessage =
|
|
89
|
+
(props && props.bluetoothPermission) ||
|
|
90
|
+
config.ios?.infoPlist?.NSBluetoothAlwaysUsageDescription ||
|
|
91
|
+
DEFAULT_BLE_MESSAGE;
|
|
92
|
+
|
|
93
|
+
config.android = config.android || {};
|
|
94
|
+
if (!config.android.minSdkVersion || Number(config.android.minSdkVersion) < MIN_SDK) {
|
|
95
|
+
config.android.minSdkVersion = MIN_SDK;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
config = withGradleProperties(config, (mod) => {
|
|
99
|
+
ensureGradleProperty(
|
|
100
|
+
mod.modResults,
|
|
101
|
+
'android.minSdkVersion',
|
|
102
|
+
String(MIN_SDK),
|
|
103
|
+
(current) => !current || Number(current) < MIN_SDK,
|
|
104
|
+
);
|
|
105
|
+
return mod;
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
config = withInfoPlist(config, (mod) => {
|
|
109
|
+
if (!mod.modResults.NSBluetoothAlwaysUsageDescription) {
|
|
110
|
+
mod.modResults.NSBluetoothAlwaysUsageDescription = bleMessage;
|
|
111
|
+
}
|
|
112
|
+
if (!mod.modResults.NSBluetoothPeripheralUsageDescription) {
|
|
113
|
+
mod.modResults.NSBluetoothPeripheralUsageDescription = bleMessage;
|
|
114
|
+
}
|
|
115
|
+
return mod;
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
config = AndroidConfig.Permissions.withPermissions(config, [
|
|
119
|
+
'android.permission.BLUETOOTH',
|
|
120
|
+
'android.permission.BLUETOOTH_ADMIN',
|
|
121
|
+
'android.permission.BLUETOOTH_SCAN',
|
|
122
|
+
'android.permission.BLUETOOTH_CONNECT',
|
|
123
|
+
'android.permission.ACCESS_FINE_LOCATION',
|
|
124
|
+
]);
|
|
125
|
+
|
|
126
|
+
config = withSettingsGradle(config, (mod) => {
|
|
127
|
+
const isKts = mod.modResults.language === 'kt' || (mod.modResults.path || '').endsWith('.kts');
|
|
128
|
+
mod.modResults.contents = insertMavenRepo(mod.modResults.contents, isKts);
|
|
129
|
+
return mod;
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
config = withProjectBuildGradle(config, (mod) => {
|
|
133
|
+
const isKts = mod.modResults.language === 'kt' || (mod.modResults.path || '').endsWith('.kts');
|
|
134
|
+
mod.modResults.contents = insertMavenRepo(mod.modResults.contents, isKts);
|
|
135
|
+
mod.modResults.contents = insertKotlinStdlibForce(mod.modResults.contents, isKts);
|
|
136
|
+
return mod;
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return config;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
module.exports = withTempivoSensorBeacon;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web/Next stub for optional Expo peer. Native BLE uses the real module in Expo/RN builds.
|
|
3
|
+
*/
|
|
4
|
+
export function requireNativeModule(_name) {
|
|
5
|
+
throw new Error('expo-modules-core is not available in the web runtime');
|
|
6
|
+
}
|
|
7
|
+
export function requireOptionalNativeModule(_name) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,3 +8,5 @@ export { DEFAULT_SENSOR_MODEL, bluetoothMacFromSerial, normalizeSensorSerial, en
|
|
|
8
8
|
export { calibrationFromExtendedJson, decodeLaboratoryCalibrationTimestamp, } from './calibration.js';
|
|
9
9
|
export { 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
|
+
export { addDeviceFoundListener, connect, disconnect, getCalibration, getConfiguration, isNativeSensorBeaconAvailable, isScanning, requestPermissions, setConfigurationJson, startScan, stopScan, triggerTransmission, } from './native-bridge.js';
|
|
12
|
+
export type { TempivoDeviceFoundSubscription, TempivoNativeCalibration, TempivoNativeMeasurement, TempivoNativePermissionResponse, TempivoNativePermissionStatus, TempivoNativeQr, TempivoNativeTelemetry, TempivoSensorBeaconDevice, } from './native-types.js';
|
package/dist/index.js
CHANGED
|
@@ -7,3 +7,4 @@ export { TempivoSensorError } from './errors.js';
|
|
|
7
7
|
export { DEFAULT_SENSOR_MODEL, bluetoothMacFromSerial, normalizeSensorSerial, encodeSensorPinPayload, parseSensorQrJson, sessionTypeFromModel, } from './qr.js';
|
|
8
8
|
export { calibrationFromExtendedJson, decodeLaboratoryCalibrationTimestamp, } from './calibration.js';
|
|
9
9
|
export { DEFAULT_ALERT_HYSTERESIS_C, compileSensorProfileToBleJson, configurationFromApiProfile, parseSensorConfiguration, parseSensorConfigurationJson, pickPartnerConfigurationJson, } from './profile.js';
|
|
10
|
+
export { addDeviceFoundListener, connect, disconnect, getCalibration, getConfiguration, isNativeSensorBeaconAvailable, isScanning, requestPermissions, setConfigurationJson, startScan, stopScan, triggerTransmission, } from './native-bridge.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TempivoDeviceFoundSubscription, TempivoNativeCalibration, TempivoNativePermissionResponse, TempivoNativeQr, TempivoSensorBeaconDevice } from './native-types.js';
|
|
2
|
+
import type { TempivoSensorConfiguration, TempivoSensorQr, TempivoTriggerTransmissionResult } from './session-types.js';
|
|
3
|
+
export declare function isNativeSensorBeaconAvailable(): Promise<boolean>;
|
|
4
|
+
export declare function requestPermissions(): Promise<TempivoNativePermissionResponse>;
|
|
5
|
+
export declare function startScan(): Promise<void>;
|
|
6
|
+
export declare function stopScan(): Promise<void>;
|
|
7
|
+
export declare function isScanning(): Promise<boolean>;
|
|
8
|
+
export declare function addDeviceFoundListener(listener: (device: TempivoSensorBeaconDevice) => void): Promise<TempivoDeviceFoundSubscription>;
|
|
9
|
+
export declare function connect(qr: string | TempivoSensorQr): Promise<TempivoNativeQr>;
|
|
10
|
+
export declare function disconnect(): Promise<void>;
|
|
11
|
+
export declare function getConfiguration(): Promise<TempivoSensorConfiguration>;
|
|
12
|
+
export declare function setConfigurationJson(config: string | TempivoSensorConfiguration): Promise<void>;
|
|
13
|
+
export declare function triggerTransmission(): Promise<TempivoTriggerTransmissionResult>;
|
|
14
|
+
export declare function getCalibration(): Promise<TempivoNativeCalibration>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { TempivoSensorError } from './errors.js';
|
|
2
|
+
async function loadNative() {
|
|
3
|
+
try {
|
|
4
|
+
return await import('./native-module.js');
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
throw new TempivoSensorError('runtimeUnavailable', 'Native BLE needs an Expo development build or React Native with Expo modules. Expo Go is not supported.');
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export async function isNativeSensorBeaconAvailable() {
|
|
11
|
+
try {
|
|
12
|
+
const native = await import('./native-module.js');
|
|
13
|
+
return native.isNativeSensorBeaconAvailable();
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export async function requestPermissions() {
|
|
20
|
+
return (await loadNative()).requestPermissions();
|
|
21
|
+
}
|
|
22
|
+
export async function startScan() {
|
|
23
|
+
return (await loadNative()).startScan();
|
|
24
|
+
}
|
|
25
|
+
export async function stopScan() {
|
|
26
|
+
(await loadNative()).stopScan();
|
|
27
|
+
}
|
|
28
|
+
export async function isScanning() {
|
|
29
|
+
return (await loadNative()).isScanning();
|
|
30
|
+
}
|
|
31
|
+
export async function addDeviceFoundListener(listener) {
|
|
32
|
+
return (await loadNative()).addDeviceFoundListener(listener);
|
|
33
|
+
}
|
|
34
|
+
export async function connect(qr) {
|
|
35
|
+
return (await loadNative()).connect(qr);
|
|
36
|
+
}
|
|
37
|
+
export async function disconnect() {
|
|
38
|
+
return (await loadNative()).disconnect();
|
|
39
|
+
}
|
|
40
|
+
export async function getConfiguration() {
|
|
41
|
+
return (await loadNative()).getConfiguration();
|
|
42
|
+
}
|
|
43
|
+
export async function setConfigurationJson(config) {
|
|
44
|
+
return (await loadNative()).setConfigurationJson(config);
|
|
45
|
+
}
|
|
46
|
+
export async function triggerTransmission() {
|
|
47
|
+
return (await loadNative()).triggerTransmission();
|
|
48
|
+
}
|
|
49
|
+
export async function getCalibration() {
|
|
50
|
+
return (await loadNative()).getCalibration();
|
|
51
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { TempivoSensorError } from './errors.js';
|
|
2
|
+
import type { TempivoSensorConfiguration, TempivoSensorQr } from './session-types.js';
|
|
3
|
+
export declare function qrToConnectJson(qr: string | TempivoSensorQr): string;
|
|
4
|
+
export declare function configToJson(config: string | TempivoSensorConfiguration): string;
|
|
5
|
+
export declare function mapNativeError(error: unknown): TempivoSensorError;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { TempivoSensorError } from './errors.js';
|
|
2
|
+
const SENSOR_CODES = [
|
|
3
|
+
'invalidPin',
|
|
4
|
+
'invalidQr',
|
|
5
|
+
'invalidConfig',
|
|
6
|
+
'notConnected',
|
|
7
|
+
'unsupportedCommand',
|
|
8
|
+
'runtimeUnavailable',
|
|
9
|
+
'connectFailed',
|
|
10
|
+
'unknown',
|
|
11
|
+
];
|
|
12
|
+
export function qrToConnectJson(qr) {
|
|
13
|
+
if (typeof qr === 'string')
|
|
14
|
+
return qr;
|
|
15
|
+
return JSON.stringify({
|
|
16
|
+
sn: qr.serial,
|
|
17
|
+
pin: qr.pin,
|
|
18
|
+
model: qr.model ?? 'HC7',
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export function configToJson(config) {
|
|
22
|
+
return typeof config === 'string' ? config : JSON.stringify(config);
|
|
23
|
+
}
|
|
24
|
+
function isSensorCode(value) {
|
|
25
|
+
return !!value && SENSOR_CODES.includes(value);
|
|
26
|
+
}
|
|
27
|
+
export function mapNativeError(error) {
|
|
28
|
+
if (error instanceof TempivoSensorError)
|
|
29
|
+
return error;
|
|
30
|
+
const raw = error;
|
|
31
|
+
const code = isSensorCode(raw?.code) ? raw.code : 'unknown';
|
|
32
|
+
return new TempivoSensorError(code, raw?.message || 'Sensor request failed.');
|
|
33
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TempivoDeviceFoundSubscription, TempivoNativeCalibration, TempivoNativePermissionResponse, TempivoNativeQr, TempivoSensorBeaconDevice } from './native-types.js';
|
|
2
|
+
import type { TempivoSensorConfiguration, TempivoSensorQr, TempivoTriggerTransmissionResult } from './session-types.js';
|
|
3
|
+
export declare function isNativeSensorBeaconAvailable(): boolean;
|
|
4
|
+
export declare function requestPermissions(): Promise<TempivoNativePermissionResponse>;
|
|
5
|
+
export declare function startScan(): Promise<void>;
|
|
6
|
+
export declare function stopScan(): void;
|
|
7
|
+
export declare function isScanning(): boolean;
|
|
8
|
+
export declare function addDeviceFoundListener(listener: (device: TempivoSensorBeaconDevice) => void): TempivoDeviceFoundSubscription;
|
|
9
|
+
export declare function connect(qr: string | TempivoSensorQr): Promise<TempivoNativeQr>;
|
|
10
|
+
export declare function disconnect(): Promise<void>;
|
|
11
|
+
export declare function getConfiguration(): Promise<TempivoSensorConfiguration>;
|
|
12
|
+
export declare function setConfigurationJson(config: string | TempivoSensorConfiguration): Promise<void>;
|
|
13
|
+
export declare function triggerTransmission(): Promise<TempivoTriggerTransmissionResult>;
|
|
14
|
+
export declare function getCalibration(): Promise<TempivoNativeCalibration>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { requireOptionalNativeModule } from 'expo-modules-core';
|
|
2
|
+
import { TempivoSensorError } from './errors.js';
|
|
3
|
+
import { configToJson, mapNativeError, qrToConnectJson } from './native-helpers.js';
|
|
4
|
+
import { parseSensorConfigurationJson } from './profile.js';
|
|
5
|
+
function getNative() {
|
|
6
|
+
const native = requireOptionalNativeModule('TempivoSensorBeacon');
|
|
7
|
+
if (!native) {
|
|
8
|
+
throw new TempivoSensorError('runtimeUnavailable', 'Native BLE needs an Expo development build or React Native with Expo modules. Expo Go is not supported.');
|
|
9
|
+
}
|
|
10
|
+
return native;
|
|
11
|
+
}
|
|
12
|
+
export function isNativeSensorBeaconAvailable() {
|
|
13
|
+
return requireOptionalNativeModule('TempivoSensorBeacon') != null;
|
|
14
|
+
}
|
|
15
|
+
export async function requestPermissions() {
|
|
16
|
+
try {
|
|
17
|
+
const result = await getNative().requestPermissions();
|
|
18
|
+
if (result && typeof result.granted === 'boolean')
|
|
19
|
+
return result;
|
|
20
|
+
return {
|
|
21
|
+
granted: true,
|
|
22
|
+
status: 'granted',
|
|
23
|
+
canAskAgain: true,
|
|
24
|
+
expires: 'never',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
throw mapNativeError(error);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function ensureBlePermission() {
|
|
32
|
+
const perms = await requestPermissions();
|
|
33
|
+
if (perms.granted || perms.status === 'undetermined')
|
|
34
|
+
return;
|
|
35
|
+
throw new TempivoSensorError('runtimeUnavailable', 'Bluetooth permission is required.');
|
|
36
|
+
}
|
|
37
|
+
export async function startScan() {
|
|
38
|
+
await ensureBlePermission();
|
|
39
|
+
try {
|
|
40
|
+
await getNative().startScan();
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
throw mapNativeError(error);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function stopScan() {
|
|
47
|
+
getNative().stopScan();
|
|
48
|
+
}
|
|
49
|
+
export function isScanning() {
|
|
50
|
+
return getNative().isScanning();
|
|
51
|
+
}
|
|
52
|
+
export function addDeviceFoundListener(listener) {
|
|
53
|
+
return getNative().addListener('onDeviceFound', listener);
|
|
54
|
+
}
|
|
55
|
+
export async function connect(qr) {
|
|
56
|
+
await ensureBlePermission();
|
|
57
|
+
try {
|
|
58
|
+
return await getNative().connect(qrToConnectJson(qr));
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw mapNativeError(error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export async function disconnect() {
|
|
65
|
+
try {
|
|
66
|
+
await getNative().disconnect();
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
throw mapNativeError(error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export async function getConfiguration() {
|
|
73
|
+
try {
|
|
74
|
+
const json = await getNative().getConfigurationJson();
|
|
75
|
+
return parseSensorConfigurationJson(json);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
throw mapNativeError(error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export async function setConfigurationJson(config) {
|
|
82
|
+
try {
|
|
83
|
+
await getNative().setConfigurationJson(configToJson(config));
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
throw mapNativeError(error);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export async function triggerTransmission() {
|
|
90
|
+
try {
|
|
91
|
+
return await getNative().triggerTransmission();
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
throw mapNativeError(error);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export async function getCalibration() {
|
|
98
|
+
try {
|
|
99
|
+
return await getNative().getCalibration();
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
throw mapNativeError(error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { TempivoSensorCalibration, TempivoSensorQr, TempivoSensorSessionType } from './session-types.js';
|
|
2
|
+
export type TempivoNativePermissionStatus = 'granted' | 'denied' | 'undetermined';
|
|
3
|
+
export type TempivoNativePermissionResponse = {
|
|
4
|
+
granted: boolean;
|
|
5
|
+
status: TempivoNativePermissionStatus;
|
|
6
|
+
canAskAgain?: boolean;
|
|
7
|
+
expires?: string;
|
|
8
|
+
};
|
|
9
|
+
export type TempivoNativeMeasurement = {
|
|
10
|
+
typeHex: string;
|
|
11
|
+
raw24: number;
|
|
12
|
+
text: string;
|
|
13
|
+
};
|
|
14
|
+
export type TempivoNativeTelemetry = {
|
|
15
|
+
firmware?: string | null;
|
|
16
|
+
batteryOk?: boolean | null;
|
|
17
|
+
encryptionEnabled?: boolean | null;
|
|
18
|
+
cellularStatus?: string | null;
|
|
19
|
+
measurementCounter?: number | null;
|
|
20
|
+
readingTimestampUnix?: number | null;
|
|
21
|
+
readingTimestampIso?: string | null;
|
|
22
|
+
measurementIntervalSeconds?: number | null;
|
|
23
|
+
readingsCount?: number;
|
|
24
|
+
summary?: string | null;
|
|
25
|
+
readings?: TempivoNativeMeasurement[];
|
|
26
|
+
};
|
|
27
|
+
export type TempivoSensorBeaconDevice = {
|
|
28
|
+
deviceId: string;
|
|
29
|
+
rssi: number;
|
|
30
|
+
bluetoothMacAddress?: string | null;
|
|
31
|
+
serialNumber?: string | null;
|
|
32
|
+
summary?: string | null;
|
|
33
|
+
telemetry?: TempivoNativeTelemetry | null;
|
|
34
|
+
};
|
|
35
|
+
export type TempivoNativeQr = TempivoSensorQr & {
|
|
36
|
+
sessionType: TempivoSensorSessionType;
|
|
37
|
+
};
|
|
38
|
+
export type TempivoNativeCalibration = TempivoSensorCalibration;
|
|
39
|
+
export type TempivoDeviceFoundSubscription = {
|
|
40
|
+
remove: () => void;
|
|
41
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './index.js';
|
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"platforms": ["apple", "android"],
|
|
3
|
+
"apple": {
|
|
4
|
+
"modules": ["TempivoSensorBeaconModule"]
|
|
5
|
+
},
|
|
6
|
+
"ios": {
|
|
7
|
+
"modules": ["TempivoSensorBeaconModule"]
|
|
8
|
+
},
|
|
9
|
+
"android": {
|
|
10
|
+
"modules": ["expo.modules.tempivosensorbeacon.TempivoSensorBeaconModule"]
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>AvailableLibraries</key>
|
|
6
|
+
<array>
|
|
7
|
+
<dict>
|
|
8
|
+
<key>BinaryPath</key>
|
|
9
|
+
<string>TempivoSensorBridge.framework/TempivoSensorBridge</string>
|
|
10
|
+
<key>LibraryIdentifier</key>
|
|
11
|
+
<string>ios-arm64</string>
|
|
12
|
+
<key>LibraryPath</key>
|
|
13
|
+
<string>TempivoSensorBridge.framework</string>
|
|
14
|
+
<key>SupportedArchitectures</key>
|
|
15
|
+
<array>
|
|
16
|
+
<string>arm64</string>
|
|
17
|
+
</array>
|
|
18
|
+
<key>SupportedPlatform</key>
|
|
19
|
+
<string>ios</string>
|
|
20
|
+
</dict>
|
|
21
|
+
<dict>
|
|
22
|
+
<key>BinaryPath</key>
|
|
23
|
+
<string>TempivoSensorBridge.framework/TempivoSensorBridge</string>
|
|
24
|
+
<key>LibraryIdentifier</key>
|
|
25
|
+
<string>ios-arm64-simulator</string>
|
|
26
|
+
<key>LibraryPath</key>
|
|
27
|
+
<string>TempivoSensorBridge.framework</string>
|
|
28
|
+
<key>SupportedArchitectures</key>
|
|
29
|
+
<array>
|
|
30
|
+
<string>arm64</string>
|
|
31
|
+
</array>
|
|
32
|
+
<key>SupportedPlatform</key>
|
|
33
|
+
<string>ios</string>
|
|
34
|
+
<key>SupportedPlatformVariant</key>
|
|
35
|
+
<string>simulator</string>
|
|
36
|
+
</dict>
|
|
37
|
+
</array>
|
|
38
|
+
<key>CFBundlePackageType</key>
|
|
39
|
+
<string>XFWK</string>
|
|
40
|
+
<key>XCFrameworkFormatVersion</key>
|
|
41
|
+
<string>1.0</string>
|
|
42
|
+
</dict>
|
|
43
|
+
</plist>
|