@voltras/node-sdk 0.1.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/LICENSE +21 -0
- package/README.md +272 -0
- package/dist/cjs/bluetooth/adapters/base.js +116 -0
- package/dist/cjs/bluetooth/adapters/base.js.map +1 -0
- package/dist/cjs/bluetooth/adapters/index.js +58 -0
- package/dist/cjs/bluetooth/adapters/index.js.map +1 -0
- package/dist/cjs/bluetooth/adapters/native.js +473 -0
- package/dist/cjs/bluetooth/adapters/native.js.map +1 -0
- package/dist/cjs/bluetooth/adapters/node.js +228 -0
- package/dist/cjs/bluetooth/adapters/node.js.map +1 -0
- package/dist/cjs/bluetooth/adapters/types.js +11 -0
- package/dist/cjs/bluetooth/adapters/types.js.map +1 -0
- package/dist/cjs/bluetooth/adapters/web-bluetooth-base.js +187 -0
- package/dist/cjs/bluetooth/adapters/web-bluetooth-base.js.map +1 -0
- package/dist/cjs/bluetooth/adapters/web.js +112 -0
- package/dist/cjs/bluetooth/adapters/web.js.map +1 -0
- package/dist/cjs/bluetooth/controllers/scanner-controller.js +145 -0
- package/dist/cjs/bluetooth/controllers/scanner-controller.js.map +1 -0
- package/dist/cjs/bluetooth/index.js +27 -0
- package/dist/cjs/bluetooth/index.js.map +1 -0
- package/dist/cjs/bluetooth/models/connection.js +68 -0
- package/dist/cjs/bluetooth/models/connection.js.map +1 -0
- package/dist/cjs/bluetooth/models/device.js +26 -0
- package/dist/cjs/bluetooth/models/device.js.map +1 -0
- package/dist/cjs/bluetooth/models/environment.js +106 -0
- package/dist/cjs/bluetooth/models/environment.js.map +1 -0
- package/dist/cjs/errors.js +167 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.js +116 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/react/hooks.js +262 -0
- package/dist/cjs/react/hooks.js.map +1 -0
- package/dist/cjs/react/index.js +18 -0
- package/dist/cjs/react/index.js.map +1 -0
- package/dist/cjs/sdk/index.js +14 -0
- package/dist/cjs/sdk/index.js.map +1 -0
- package/dist/cjs/sdk/types.js +8 -0
- package/dist/cjs/sdk/types.js.map +1 -0
- package/dist/cjs/sdk/voltra-client.js +632 -0
- package/dist/cjs/sdk/voltra-client.js.map +1 -0
- package/dist/cjs/sdk/voltra-manager.js +419 -0
- package/dist/cjs/sdk/voltra-manager.js.map +1 -0
- package/dist/cjs/shared/index.js +12 -0
- package/dist/cjs/shared/index.js.map +1 -0
- package/dist/cjs/shared/utils.js +51 -0
- package/dist/cjs/shared/utils.js.map +1 -0
- package/dist/cjs/voltra/index.js +56 -0
- package/dist/cjs/voltra/index.js.map +1 -0
- package/dist/cjs/voltra/models/connection.js +68 -0
- package/dist/cjs/voltra/models/connection.js.map +1 -0
- package/dist/cjs/voltra/models/device-filter.js +28 -0
- package/dist/cjs/voltra/models/device-filter.js.map +1 -0
- package/dist/cjs/voltra/models/device.js +152 -0
- package/dist/cjs/voltra/models/device.js.map +1 -0
- package/dist/cjs/voltra/models/telemetry/frame.js +46 -0
- package/dist/cjs/voltra/models/telemetry/frame.js.map +1 -0
- package/dist/cjs/voltra/models/telemetry/index.js +14 -0
- package/dist/cjs/voltra/models/telemetry/index.js.map +1 -0
- package/dist/cjs/voltra/protocol/commands.js +230 -0
- package/dist/cjs/voltra/protocol/commands.js.map +1 -0
- package/dist/cjs/voltra/protocol/constants.js +136 -0
- package/dist/cjs/voltra/protocol/constants.js.map +1 -0
- package/dist/cjs/voltra/protocol/data/chains.json +830 -0
- package/dist/cjs/voltra/protocol/data/eccentric.json +1598 -0
- package/dist/cjs/voltra/protocol/data/protocol.json +54 -0
- package/dist/cjs/voltra/protocol/data/weights.json +62 -0
- package/dist/cjs/voltra/protocol/index.js +25 -0
- package/dist/cjs/voltra/protocol/index.js.map +1 -0
- package/dist/cjs/voltra/protocol/telemetry-decoder.js +146 -0
- package/dist/cjs/voltra/protocol/telemetry-decoder.js.map +1 -0
- package/dist/esm/bluetooth/adapters/base.js +112 -0
- package/dist/esm/bluetooth/adapters/base.js.map +1 -0
- package/dist/esm/bluetooth/adapters/index.js +51 -0
- package/dist/esm/bluetooth/adapters/index.js.map +1 -0
- package/dist/esm/bluetooth/adapters/native.js +469 -0
- package/dist/esm/bluetooth/adapters/native.js.map +1 -0
- package/dist/esm/bluetooth/adapters/node.js +191 -0
- package/dist/esm/bluetooth/adapters/node.js.map +1 -0
- package/dist/esm/bluetooth/adapters/types.js +10 -0
- package/dist/esm/bluetooth/adapters/types.js.map +1 -0
- package/dist/esm/bluetooth/adapters/web-bluetooth-base.js +183 -0
- package/dist/esm/bluetooth/adapters/web-bluetooth-base.js.map +1 -0
- package/dist/esm/bluetooth/adapters/web.js +108 -0
- package/dist/esm/bluetooth/adapters/web.js.map +1 -0
- package/dist/esm/bluetooth/controllers/scanner-controller.js +141 -0
- package/dist/esm/bluetooth/controllers/scanner-controller.js.map +1 -0
- package/dist/esm/bluetooth/index.js +17 -0
- package/dist/esm/bluetooth/index.js.map +1 -0
- package/dist/esm/bluetooth/models/connection.js +63 -0
- package/dist/esm/bluetooth/models/connection.js.map +1 -0
- package/dist/esm/bluetooth/models/device.js +22 -0
- package/dist/esm/bluetooth/models/device.js.map +1 -0
- package/dist/esm/bluetooth/models/environment.js +101 -0
- package/dist/esm/bluetooth/models/environment.js.map +1 -0
- package/dist/esm/errors.js +155 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.js +72 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/react/hooks.js +257 -0
- package/dist/esm/react/hooks.js.map +1 -0
- package/dist/esm/react/index.js +12 -0
- package/dist/esm/react/index.js.map +1 -0
- package/dist/esm/sdk/index.js +9 -0
- package/dist/esm/sdk/index.js.map +1 -0
- package/dist/esm/sdk/types.js +7 -0
- package/dist/esm/sdk/types.js.map +1 -0
- package/dist/esm/sdk/voltra-client.js +628 -0
- package/dist/esm/sdk/voltra-client.js.map +1 -0
- package/dist/esm/sdk/voltra-manager.js +415 -0
- package/dist/esm/sdk/voltra-manager.js.map +1 -0
- package/dist/esm/shared/index.js +5 -0
- package/dist/esm/shared/index.js.map +1 -0
- package/dist/esm/shared/utils.js +45 -0
- package/dist/esm/shared/utils.js.map +1 -0
- package/dist/esm/voltra/index.js +26 -0
- package/dist/esm/voltra/index.js.map +1 -0
- package/dist/esm/voltra/models/connection.js +63 -0
- package/dist/esm/voltra/models/connection.js.map +1 -0
- package/dist/esm/voltra/models/device-filter.js +23 -0
- package/dist/esm/voltra/models/device-filter.js.map +1 -0
- package/dist/esm/voltra/models/device.js +148 -0
- package/dist/esm/voltra/models/device.js.map +1 -0
- package/dist/esm/voltra/models/telemetry/frame.js +40 -0
- package/dist/esm/voltra/models/telemetry/frame.js.map +1 -0
- package/dist/esm/voltra/models/telemetry/index.js +7 -0
- package/dist/esm/voltra/models/telemetry/index.js.map +1 -0
- package/dist/esm/voltra/protocol/commands.js +224 -0
- package/dist/esm/voltra/protocol/commands.js.map +1 -0
- package/dist/esm/voltra/protocol/constants.js +130 -0
- package/dist/esm/voltra/protocol/constants.js.map +1 -0
- package/dist/esm/voltra/protocol/data/chains.json +830 -0
- package/dist/esm/voltra/protocol/data/eccentric.json +1598 -0
- package/dist/esm/voltra/protocol/data/protocol.json +54 -0
- package/dist/esm/voltra/protocol/data/weights.json +62 -0
- package/dist/esm/voltra/protocol/index.js +9 -0
- package/dist/esm/voltra/protocol/index.js.map +1 -0
- package/dist/esm/voltra/protocol/telemetry-decoder.js +140 -0
- package/dist/esm/voltra/protocol/telemetry-decoder.js.map +1 -0
- package/dist/types/bluetooth/adapters/base.d.ts +85 -0
- package/dist/types/bluetooth/adapters/base.d.ts.map +1 -0
- package/dist/types/bluetooth/adapters/index.d.ts +35 -0
- package/dist/types/bluetooth/adapters/index.d.ts.map +1 -0
- package/dist/types/bluetooth/adapters/native.d.ts +109 -0
- package/dist/types/bluetooth/adapters/native.d.ts.map +1 -0
- package/dist/types/bluetooth/adapters/node.d.ts +91 -0
- package/dist/types/bluetooth/adapters/node.d.ts.map +1 -0
- package/dist/types/bluetooth/adapters/types.d.ts +102 -0
- package/dist/types/bluetooth/adapters/types.d.ts.map +1 -0
- package/dist/types/bluetooth/adapters/web-bluetooth-base.d.ts +90 -0
- package/dist/types/bluetooth/adapters/web-bluetooth-base.d.ts.map +1 -0
- package/dist/types/bluetooth/adapters/web.d.ts +57 -0
- package/dist/types/bluetooth/adapters/web.d.ts.map +1 -0
- package/dist/types/bluetooth/controllers/scanner-controller.d.ts +93 -0
- package/dist/types/bluetooth/controllers/scanner-controller.d.ts.map +1 -0
- package/dist/types/bluetooth/index.d.ts +14 -0
- package/dist/types/bluetooth/index.d.ts.map +1 -0
- package/dist/types/bluetooth/models/connection.d.ts +37 -0
- package/dist/types/bluetooth/models/connection.d.ts.map +1 -0
- package/dist/types/bluetooth/models/device.d.ts +25 -0
- package/dist/types/bluetooth/models/device.d.ts.map +1 -0
- package/dist/types/bluetooth/models/environment.d.ts +45 -0
- package/dist/types/bluetooth/models/environment.d.ts.map +1 -0
- package/dist/types/errors.d.ts +113 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/index.d.ts +55 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/react/hooks.d.ts +130 -0
- package/dist/types/react/hooks.d.ts.map +1 -0
- package/dist/types/react/index.d.ts +12 -0
- package/dist/types/react/index.d.ts.map +1 -0
- package/dist/types/sdk/index.d.ts +11 -0
- package/dist/types/sdk/index.d.ts.map +1 -0
- package/dist/types/sdk/types.d.ts +104 -0
- package/dist/types/sdk/types.d.ts.map +1 -0
- package/dist/types/sdk/voltra-client.d.ts +221 -0
- package/dist/types/sdk/voltra-client.d.ts.map +1 -0
- package/dist/types/sdk/voltra-manager.d.ts +226 -0
- package/dist/types/sdk/voltra-manager.d.ts.map +1 -0
- package/dist/types/shared/index.d.ts +5 -0
- package/dist/types/shared/index.d.ts.map +1 -0
- package/dist/types/shared/utils.d.ts +25 -0
- package/dist/types/shared/utils.d.ts.map +1 -0
- package/dist/types/voltra/index.d.ts +13 -0
- package/dist/types/voltra/index.d.ts.map +1 -0
- package/dist/types/voltra/models/connection.d.ts +37 -0
- package/dist/types/voltra/models/connection.d.ts.map +1 -0
- package/dist/types/voltra/models/device-filter.d.ts +19 -0
- package/dist/types/voltra/models/device-filter.d.ts.map +1 -0
- package/dist/types/voltra/models/device.d.ts +105 -0
- package/dist/types/voltra/models/device.d.ts.map +1 -0
- package/dist/types/voltra/models/telemetry/frame.d.ts +41 -0
- package/dist/types/voltra/models/telemetry/frame.d.ts.map +1 -0
- package/dist/types/voltra/models/telemetry/index.d.ts +8 -0
- package/dist/types/voltra/models/telemetry/index.d.ts.map +1 -0
- package/dist/types/voltra/protocol/commands.d.ts +99 -0
- package/dist/types/voltra/protocol/commands.d.ts.map +1 -0
- package/dist/types/voltra/protocol/constants.d.ts +103 -0
- package/dist/types/voltra/protocol/constants.d.ts.map +1 -0
- package/dist/types/voltra/protocol/index.d.ts +9 -0
- package/dist/types/voltra/protocol/index.d.ts.map +1 -0
- package/dist/types/voltra/protocol/telemetry-decoder.d.ts +45 -0
- package/dist/types/voltra/protocol/telemetry-decoder.d.ts.map +1 -0
- package/package.json +111 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Voltra
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# @voltras/node-sdk
|
|
2
|
+
|
|
3
|
+
SDK for connecting to and controlling Voltra fitness devices.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@voltras/node-sdk)
|
|
6
|
+
[](https://github.com/voltra/node-sdk/actions/workflows/ci.yml)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Simple API**: `VoltraManager` handles discovery, returns `VoltraClient` for device control
|
|
12
|
+
- **Cross-platform**: Web browsers, Node.js, and React Native
|
|
13
|
+
- **Multi-device**: Connect to multiple devices simultaneously
|
|
14
|
+
- **React hooks**: Clean `useVoltraScanner` and `useVoltraDevice` hooks
|
|
15
|
+
- **TypeScript**: Full type definitions included
|
|
16
|
+
- **Real-time telemetry**: Stream position, velocity, and force data
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @voltras/node-sdk
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Platform dependencies
|
|
25
|
+
|
|
26
|
+
| Platform | Additional Install |
|
|
27
|
+
|----------|-------------------|
|
|
28
|
+
| React Native | `npm install react-native-ble-plx` |
|
|
29
|
+
| Node.js | `npm install webbluetooth` |
|
|
30
|
+
| Web browsers | None (uses Web Bluetooth API) |
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
### Web / Node.js
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { VoltraManager } from '@voltras/node-sdk';
|
|
38
|
+
|
|
39
|
+
// Create manager (auto-detects platform)
|
|
40
|
+
const manager = new VoltraManager();
|
|
41
|
+
|
|
42
|
+
// Scan and connect to first device
|
|
43
|
+
const client = await manager.connectFirst();
|
|
44
|
+
|
|
45
|
+
// Or connect by name
|
|
46
|
+
const client = await manager.connectByName('VTR-123456');
|
|
47
|
+
|
|
48
|
+
// Control the device
|
|
49
|
+
await client.setWeight(50);
|
|
50
|
+
|
|
51
|
+
client.onFrame((frame) => {
|
|
52
|
+
console.log('Position:', frame.position, 'Velocity:', frame.velocity);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await client.startRecording();
|
|
56
|
+
// ... workout ...
|
|
57
|
+
await client.stopRecording();
|
|
58
|
+
|
|
59
|
+
// Cleanup
|
|
60
|
+
manager.dispose();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### React Native
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { VoltraManager } from '@voltras/node-sdk';
|
|
67
|
+
|
|
68
|
+
// Specify native platform
|
|
69
|
+
const manager = VoltraManager.forNative();
|
|
70
|
+
// or: new VoltraManager({ platform: 'native' })
|
|
71
|
+
|
|
72
|
+
// Rest of the API is identical
|
|
73
|
+
const client = await manager.connectFirst();
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### React Hooks
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
import { VoltraManager } from '@voltras/node-sdk';
|
|
80
|
+
import { useVoltraScanner, useVoltraDevice } from '@voltras/node-sdk/react';
|
|
81
|
+
|
|
82
|
+
function WorkoutScreen() {
|
|
83
|
+
const manager = useMemo(() => VoltraManager.forNative(), []);
|
|
84
|
+
const [client, setClient] = useState<VoltraClient | null>(null);
|
|
85
|
+
|
|
86
|
+
// Scanner state
|
|
87
|
+
const { devices, isScanning, scan } = useVoltraScanner(manager);
|
|
88
|
+
|
|
89
|
+
// Device state
|
|
90
|
+
const { connectionState, currentFrame, isRecording } = useVoltraDevice(client);
|
|
91
|
+
|
|
92
|
+
const handleConnect = async (device: DiscoveredDevice) => {
|
|
93
|
+
const connected = await manager.connect(device);
|
|
94
|
+
setClient(connected);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<View>
|
|
99
|
+
<Button onPress={() => scan()}>
|
|
100
|
+
{isScanning ? 'Scanning...' : 'Scan'}
|
|
101
|
+
</Button>
|
|
102
|
+
|
|
103
|
+
{devices.map((device) => (
|
|
104
|
+
<Button key={device.id} onPress={() => handleConnect(device)}>
|
|
105
|
+
{device.name}
|
|
106
|
+
</Button>
|
|
107
|
+
))}
|
|
108
|
+
|
|
109
|
+
{connectionState === 'connected' && (
|
|
110
|
+
<Text>Position: {currentFrame?.position}</Text>
|
|
111
|
+
)}
|
|
112
|
+
</View>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Multi-Device
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const manager = new VoltraManager();
|
|
121
|
+
|
|
122
|
+
// Listen for device events
|
|
123
|
+
manager.onDeviceConnected((client, deviceId, deviceName) => {
|
|
124
|
+
console.log('Connected:', deviceName);
|
|
125
|
+
client.onFrame((frame) => console.log(`[${deviceName}]`, frame.position));
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Connect to multiple devices
|
|
129
|
+
const devices = await manager.scan();
|
|
130
|
+
await manager.connect(devices[0]);
|
|
131
|
+
await manager.connect(devices[1]);
|
|
132
|
+
|
|
133
|
+
// Access individual clients
|
|
134
|
+
const client = manager.getClient(devices[0].id);
|
|
135
|
+
await client?.setWeight(50);
|
|
136
|
+
|
|
137
|
+
// Or get all clients
|
|
138
|
+
for (const client of manager.getAllClients()) {
|
|
139
|
+
await client.startRecording();
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## API Reference
|
|
144
|
+
|
|
145
|
+
### VoltraManager
|
|
146
|
+
|
|
147
|
+
Main entry point for the SDK.
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const manager = new VoltraManager(options?);
|
|
151
|
+
// or
|
|
152
|
+
const manager = VoltraManager.forWeb();
|
|
153
|
+
const manager = VoltraManager.forNode();
|
|
154
|
+
const manager = VoltraManager.forNative();
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Methods:**
|
|
158
|
+
- `scan(options?)` - Scan for Voltra devices
|
|
159
|
+
- `connect(device)` - Connect and return a VoltraClient
|
|
160
|
+
- `connectFirst(options?)` - Connect to first available device
|
|
161
|
+
- `connectByName(name, options?)` - Scan + connect by device name
|
|
162
|
+
- `getClient(deviceId)` - Get connected client by ID
|
|
163
|
+
- `getAllClients()` - Get all connected clients
|
|
164
|
+
- `disconnect(deviceId)` - Disconnect specific device
|
|
165
|
+
- `disconnectAll()` - Disconnect all devices
|
|
166
|
+
- `dispose()` - Clean up resources
|
|
167
|
+
|
|
168
|
+
### VoltraClient
|
|
169
|
+
|
|
170
|
+
Controls a single connected device.
|
|
171
|
+
|
|
172
|
+
**Methods:**
|
|
173
|
+
- `setWeight(lbs)` - Set weight (5-200 in increments of 5)
|
|
174
|
+
- `setChains(lbs)` - Set chains (0-100)
|
|
175
|
+
- `setEccentric(percent)` - Set eccentric adjustment (-195 to +195)
|
|
176
|
+
- `startRecording()` - Start recording
|
|
177
|
+
- `stopRecording()` - Stop recording
|
|
178
|
+
- `onFrame(callback)` - Subscribe to telemetry frames
|
|
179
|
+
- `disconnect()` - Disconnect from device
|
|
180
|
+
|
|
181
|
+
**Properties:**
|
|
182
|
+
- `connectionState` - 'disconnected' | 'connecting' | 'authenticating' | 'connected'
|
|
183
|
+
- `isConnected` - Whether connected
|
|
184
|
+
- `settings` - Current device settings
|
|
185
|
+
- `recordingState` - 'idle' | 'preparing' | 'ready' | 'active' | 'stopping'
|
|
186
|
+
- `isRecording` - Whether recording
|
|
187
|
+
|
|
188
|
+
### TelemetryFrame
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
interface TelemetryFrame {
|
|
192
|
+
sequence: number; // Packet sequence number
|
|
193
|
+
timestamp: number; // Unix ms when received
|
|
194
|
+
phase: number; // Movement phase (see MovementPhase)
|
|
195
|
+
position: number; // Position (0-600 raw)
|
|
196
|
+
velocity: number; // Velocity (raw value)
|
|
197
|
+
force: number; // Force (signed value)
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### React Hooks
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
import { useVoltraScanner, useVoltraDevice } from '@voltras/node-sdk/react';
|
|
205
|
+
|
|
206
|
+
// Scanner state
|
|
207
|
+
const { devices, isScanning, scan, error, clear } = useVoltraScanner(manager);
|
|
208
|
+
|
|
209
|
+
// Device state
|
|
210
|
+
const {
|
|
211
|
+
connectionState,
|
|
212
|
+
isConnected,
|
|
213
|
+
recordingState,
|
|
214
|
+
isRecording,
|
|
215
|
+
currentFrame,
|
|
216
|
+
settings,
|
|
217
|
+
error,
|
|
218
|
+
} = useVoltraDevice(client);
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Error Handling
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
import {
|
|
225
|
+
VoltraSDKError,
|
|
226
|
+
ConnectionError,
|
|
227
|
+
AuthenticationError,
|
|
228
|
+
NotConnectedError,
|
|
229
|
+
} from '@voltras/node-sdk';
|
|
230
|
+
|
|
231
|
+
try {
|
|
232
|
+
await manager.connectByName('VTR-123');
|
|
233
|
+
} catch (error) {
|
|
234
|
+
if (error instanceof ConnectionError) {
|
|
235
|
+
console.log('Connection failed:', error.code);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Examples
|
|
241
|
+
|
|
242
|
+
See the [examples](./examples) directory:
|
|
243
|
+
|
|
244
|
+
- [Node.js](./examples/node) - CLI examples
|
|
245
|
+
- [Web Browser](./examples/web) - Interactive demo
|
|
246
|
+
- [React Native](./examples/react-native) - Expo app
|
|
247
|
+
|
|
248
|
+
## Documentation
|
|
249
|
+
|
|
250
|
+
### Getting Started
|
|
251
|
+
|
|
252
|
+
Step-by-step setup guides for each platform:
|
|
253
|
+
|
|
254
|
+
- [Node.js](./docs/getting-started/node.md) - Prerequisites, setup, running examples
|
|
255
|
+
- [Web Browser](./docs/getting-started/web.md) - Browser requirements, HTTPS, Vite setup
|
|
256
|
+
- [React Native](./docs/getting-started/react-native.md) - Expo, permissions, development builds
|
|
257
|
+
|
|
258
|
+
### Concepts
|
|
259
|
+
|
|
260
|
+
Technical deep-dives:
|
|
261
|
+
|
|
262
|
+
- [Bluetooth Protocol](./docs/concepts/bluetooth-protocol.md) - Voltra BLE protocol, commands, telemetry format
|
|
263
|
+
- [Platform Adapters](./docs/concepts/platform-adapters.md) - Native vs Web vs Node.js differences
|
|
264
|
+
|
|
265
|
+
### Other
|
|
266
|
+
|
|
267
|
+
- [Troubleshooting](./docs/troubleshooting.md) - Common issues and solutions
|
|
268
|
+
- [Roadmap](./docs/roadmap/) - Planned features (ReplayBLEAdapter, etc.)
|
|
269
|
+
|
|
270
|
+
## License
|
|
271
|
+
|
|
272
|
+
MIT - see [LICENSE](./LICENSE)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BaseBLEAdapter
|
|
4
|
+
*
|
|
5
|
+
* Abstract base class for all BLE adapters. Provides shared implementation
|
|
6
|
+
* for connection state management and callback registration/notification.
|
|
7
|
+
*
|
|
8
|
+
* Subclasses implement the platform-specific BLE operations:
|
|
9
|
+
* - NativeBLEAdapter: react-native-ble-plx for iOS/Android
|
|
10
|
+
* - WebBLEAdapter: Web Bluetooth API for browsers
|
|
11
|
+
* - NodeBLEAdapter: webbluetooth npm for Node.js
|
|
12
|
+
* - ReplayBLEAdapter: Playback for testing/demos
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.BaseBLEAdapter = void 0;
|
|
16
|
+
/**
|
|
17
|
+
* Abstract base class implementing shared BLE adapter functionality.
|
|
18
|
+
*
|
|
19
|
+
* Provides:
|
|
20
|
+
* - Connection state management with change notifications
|
|
21
|
+
* - Notification callback registration (supports multiple listeners)
|
|
22
|
+
* - State callback registration (supports multiple listeners)
|
|
23
|
+
* - Protected utilities for subclasses to emit events
|
|
24
|
+
*/
|
|
25
|
+
class BaseBLEAdapter {
|
|
26
|
+
constructor() {
|
|
27
|
+
/** Current connection state */
|
|
28
|
+
this.connectionState = 'disconnected';
|
|
29
|
+
/** Registered notification callbacks */
|
|
30
|
+
this.notificationCallbacks = [];
|
|
31
|
+
/** Registered connection state callbacks */
|
|
32
|
+
this.stateCallbacks = [];
|
|
33
|
+
}
|
|
34
|
+
// ===========================================================================
|
|
35
|
+
// BLEAdapter interface - implemented
|
|
36
|
+
// ===========================================================================
|
|
37
|
+
/**
|
|
38
|
+
* Get the current connection state.
|
|
39
|
+
*/
|
|
40
|
+
getConnectionState() {
|
|
41
|
+
return this.connectionState;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Check if currently connected to a device.
|
|
45
|
+
*/
|
|
46
|
+
isConnected() {
|
|
47
|
+
return this.connectionState === 'connected';
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Register a callback for notifications from the device.
|
|
51
|
+
* @param callback Function called with notification data
|
|
52
|
+
* @returns Unsubscribe function
|
|
53
|
+
*/
|
|
54
|
+
onNotification(callback) {
|
|
55
|
+
this.notificationCallbacks.push(callback);
|
|
56
|
+
return () => {
|
|
57
|
+
const index = this.notificationCallbacks.indexOf(callback);
|
|
58
|
+
if (index >= 0) {
|
|
59
|
+
this.notificationCallbacks.splice(index, 1);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Register a callback for connection state changes.
|
|
65
|
+
* @param callback Function called when state changes
|
|
66
|
+
* @returns Unsubscribe function
|
|
67
|
+
*/
|
|
68
|
+
onConnectionStateChange(callback) {
|
|
69
|
+
this.stateCallbacks.push(callback);
|
|
70
|
+
return () => {
|
|
71
|
+
const index = this.stateCallbacks.indexOf(callback);
|
|
72
|
+
if (index >= 0) {
|
|
73
|
+
this.stateCallbacks.splice(index, 1);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
// ===========================================================================
|
|
78
|
+
// Protected utilities for subclasses
|
|
79
|
+
// ===========================================================================
|
|
80
|
+
/**
|
|
81
|
+
* Set connection state and notify all registered callbacks.
|
|
82
|
+
* Only notifies if state actually changed.
|
|
83
|
+
*
|
|
84
|
+
* @param state New connection state
|
|
85
|
+
*/
|
|
86
|
+
setConnectionState(state) {
|
|
87
|
+
if (this.connectionState !== state) {
|
|
88
|
+
this.connectionState = state;
|
|
89
|
+
for (const callback of this.stateCallbacks) {
|
|
90
|
+
try {
|
|
91
|
+
callback(state);
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
console.error('[BaseBLEAdapter] State callback error:', e);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Emit notification data to all registered callbacks.
|
|
101
|
+
*
|
|
102
|
+
* @param data Notification data to emit
|
|
103
|
+
*/
|
|
104
|
+
emitNotification(data) {
|
|
105
|
+
for (const callback of this.notificationCallbacks) {
|
|
106
|
+
try {
|
|
107
|
+
callback(data);
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
console.error('[BaseBLEAdapter] Notification callback error:', e);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.BaseBLEAdapter = BaseBLEAdapter;
|
|
116
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../src/bluetooth/adapters/base.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAWH;;;;;;;;GAQG;AACH,MAAsB,cAAc;IAApC;QACE,+BAA+B;QACrB,oBAAe,GAAoB,cAAc,CAAC;QAE5D,wCAAwC;QAC9B,0BAAqB,GAA2B,EAAE,CAAC;QAE7D,4CAA4C;QAClC,mBAAc,GAA8B,EAAE,CAAC;IAoH3D,CAAC;IAlHC,8EAA8E;IAC9E,qCAAqC;IACrC,8EAA8E;IAE9E;;OAEG;IACH,kBAAkB;QAChB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,eAAe,KAAK,WAAW,CAAC;IAC9C,CAAC;IAED;;;;OAIG;IACH,cAAc,CAAC,QAA8B;QAC3C,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,OAAO,GAAG,EAAE;YACV,MAAM,KAAK,GAAG,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC3D,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;gBACf,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,uBAAuB,CAAC,QAAiC;QACvD,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,OAAO,GAAG,EAAE;YACV,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACpD,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;gBACf,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YACvC,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;IA+BD,8EAA8E;IAC9E,qCAAqC;IACrC,8EAA8E;IAE9E;;;;;OAKG;IACO,kBAAkB,CAAC,KAAsB;QACjD,IAAI,IAAI,CAAC,eAAe,KAAK,KAAK,EAAE,CAAC;YACnC,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;YAC7B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC3C,IAAI,CAAC;oBACH,QAAQ,CAAC,KAAK,CAAC,CAAC;gBAClB,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,CAAC,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACO,gBAAgB,CAAC,IAAgB;QACzC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAClD,IAAI,CAAC;gBACH,QAAQ,CAAC,IAAI,CAAC,CAAC;YACjB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CAAC,+CAA+C,EAAE,CAAC,CAAC,CAAC;YACpE,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA5HD,wCA4HC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BLE Abstraction Layer
|
|
4
|
+
*
|
|
5
|
+
* Provides a unified interface for BLE communication across platforms:
|
|
6
|
+
* - Native (iOS/Android): react-native-ble-plx
|
|
7
|
+
* - Browser: Web Bluetooth API
|
|
8
|
+
* - Node.js: webbluetooth npm package
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.NativeBLEAdapter = exports.NodeBLEAdapter = exports.WebBLEAdapter = void 0;
|
|
12
|
+
exports.createBLEAdapter = createBLEAdapter;
|
|
13
|
+
// Platform adapters
|
|
14
|
+
var web_1 = require("./web");
|
|
15
|
+
Object.defineProperty(exports, "WebBLEAdapter", { enumerable: true, get: function () { return web_1.WebBLEAdapter; } });
|
|
16
|
+
var node_1 = require("./node");
|
|
17
|
+
Object.defineProperty(exports, "NodeBLEAdapter", { enumerable: true, get: function () { return node_1.NodeBLEAdapter; } });
|
|
18
|
+
var native_1 = require("./native");
|
|
19
|
+
Object.defineProperty(exports, "NativeBLEAdapter", { enumerable: true, get: function () { return native_1.NativeBLEAdapter; } });
|
|
20
|
+
const web_2 = require("./web");
|
|
21
|
+
const node_2 = require("./node");
|
|
22
|
+
/**
|
|
23
|
+
* Detect if running in Node.js environment.
|
|
24
|
+
*/
|
|
25
|
+
function isNodeEnvironment() {
|
|
26
|
+
return (typeof process !== 'undefined' && process.versions != null && process.versions.node != null);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Detect if running in browser environment.
|
|
30
|
+
*/
|
|
31
|
+
function isBrowserEnvironment() {
|
|
32
|
+
return (typeof window !== 'undefined' &&
|
|
33
|
+
typeof document !== 'undefined' &&
|
|
34
|
+
typeof navigator !== 'undefined');
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create a BLE adapter based on the current environment.
|
|
38
|
+
*
|
|
39
|
+
* Environment detection:
|
|
40
|
+
* - Web browser: WebBLEAdapter (Web Bluetooth API)
|
|
41
|
+
* - Node.js: NodeBLEAdapter (webbluetooth package)
|
|
42
|
+
*
|
|
43
|
+
* NOTE: For React Native, import and instantiate NativeBLEAdapter directly.
|
|
44
|
+
* This factory is for web/Node.js environments only.
|
|
45
|
+
*
|
|
46
|
+
* @param config Adapter configuration including BLE service UUIDs
|
|
47
|
+
* @returns BLEAdapter instance appropriate for the current environment
|
|
48
|
+
*/
|
|
49
|
+
function createBLEAdapter(config) {
|
|
50
|
+
if (isNodeEnvironment() && !isBrowserEnvironment()) {
|
|
51
|
+
return new node_2.NodeBLEAdapter({ ble: config.ble });
|
|
52
|
+
}
|
|
53
|
+
if (isBrowserEnvironment()) {
|
|
54
|
+
return new web_2.WebBLEAdapter({ ble: config.ble });
|
|
55
|
+
}
|
|
56
|
+
throw new Error('Unknown environment. For React Native, import NativeBLEAdapter directly from @voltras/node-sdk/react-native');
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/bluetooth/adapters/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAkEH,4CAYC;AAjED,oBAAoB;AACpB,6BAAsC;AAA7B,oGAAA,aAAa,OAAA;AACtB,+BAAgF;AAAvE,sGAAA,cAAc,OAAA;AACvB,mCAAsE;AAA7D,0GAAA,gBAAgB,OAAA;AAMzB,+BAAsC;AACtC,iCAAwC;AAUxC;;GAEG;AACH,SAAS,iBAAiB;IACxB,OAAO,CACL,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,QAAQ,IAAI,IAAI,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,CAC5F,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB;IAC3B,OAAO,CACL,OAAO,MAAM,KAAK,WAAW;QAC7B,OAAO,QAAQ,KAAK,WAAW;QAC/B,OAAO,SAAS,KAAK,WAAW,CACjC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,gBAAgB,CAAC,MAA8B;IAC7D,IAAI,iBAAiB,EAAE,IAAI,CAAC,oBAAoB,EAAE,EAAE,CAAC;QACnD,OAAO,IAAI,qBAAc,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,IAAI,oBAAoB,EAAE,EAAE,CAAC;QAC3B,OAAO,IAAI,mBAAa,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,IAAI,KAAK,CACb,6GAA6G,CAC9G,CAAC;AACJ,CAAC"}
|