ota-hub-reactjs 0.0.13 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base/device-whisperer.d.ts +0 -1
- package/dist/transport_layers/esp32-device-whisperer.js +5 -1
- package/dist/transport_layers/mqtt-device-whisperer.d.ts +3 -2
- package/dist/transport_layers/mqtt-device-whisperer.js +6 -4
- package/dist/transport_layers/serial-device-whisperer.d.ts +2 -1
- package/dist/transport_layers/serial-device-whisperer.js +53 -24
- package/package.json +1 -1
|
@@ -27,7 +27,6 @@ export type DeviceConnectionState = {
|
|
|
27
27
|
export declare function createDefaultInitialDeviceState<T extends DeviceConnectionState>(uuid: string, props?: any): T;
|
|
28
28
|
export type DeviceWhispererProps<T extends DeviceConnectionState> = {
|
|
29
29
|
createInitialConnectionState?: (uuid: string) => Partial<T>;
|
|
30
|
-
connectOn?: boolean;
|
|
31
30
|
};
|
|
32
31
|
export declare function MultiDeviceWhisperer<T extends DeviceConnectionState>({ createInitialConnectionState, }?: DeviceWhispererProps<T>): {
|
|
33
32
|
connections: T[];
|
|
@@ -256,7 +256,7 @@ export function ESP32MultiDeviceWhisperer({ ...props } = {}) {
|
|
|
256
256
|
const port = await navigator.serial.requestPort({
|
|
257
257
|
filters: [{ usbVendorId: 0x303a }]
|
|
258
258
|
});
|
|
259
|
-
|
|
259
|
+
const return_uuid = await base.addConnection({
|
|
260
260
|
uuid,
|
|
261
261
|
propCreator: (id) => {
|
|
262
262
|
const props = propCreator?.(id);
|
|
@@ -271,6 +271,10 @@ export function ESP32MultiDeviceWhisperer({ ...props } = {}) {
|
|
|
271
271
|
};
|
|
272
272
|
}
|
|
273
273
|
});
|
|
274
|
+
const conn = base.getConnection(return_uuid);
|
|
275
|
+
if (conn?.autoConnect)
|
|
276
|
+
await connect(return_uuid);
|
|
277
|
+
return return_uuid;
|
|
274
278
|
};
|
|
275
279
|
const removeConnection = async (uuid) => {
|
|
276
280
|
try {
|
|
@@ -3,7 +3,7 @@ export type MQTTConnectionState = DeviceConnectionState & {
|
|
|
3
3
|
pingFunction?: (props?: any) => void;
|
|
4
4
|
touchHeartbeat?: () => void;
|
|
5
5
|
};
|
|
6
|
-
export declare function MQTTMultiDeviceWhisperer<AppOrMessageLayer extends MQTTConnectionState>({ serverUrl, uuidFromMessage, subTopicFromUuid, pubTopicFromUuid, serverPort, clientId, username, password,
|
|
6
|
+
export declare function MQTTMultiDeviceWhisperer<AppOrMessageLayer extends MQTTConnectionState>({ serverUrl, uuidFromMessage, subTopicFromUuid, pubTopicFromUuid, serverPort, clientId, username, password, serverAutoConnect, serverConnectOn, ...props }: {
|
|
7
7
|
serverUrl: string;
|
|
8
8
|
uuidFromMessage: (topic: string, payload: Buffer<ArrayBufferLike>) => string;
|
|
9
9
|
subTopicFromUuid?: (uuid: string) => string;
|
|
@@ -12,7 +12,8 @@ export declare function MQTTMultiDeviceWhisperer<AppOrMessageLayer extends MQTTC
|
|
|
12
12
|
clientId?: string;
|
|
13
13
|
username?: string;
|
|
14
14
|
password?: string;
|
|
15
|
-
|
|
15
|
+
serverAutoConnect?: boolean;
|
|
16
|
+
serverConnectOn?: boolean;
|
|
16
17
|
} & DeviceWhispererProps<AppOrMessageLayer>): {
|
|
17
18
|
addConnection: ({ uuid, propCreator }: AddConnectionProps<AppOrMessageLayer>) => Promise<string | undefined>;
|
|
18
19
|
removeConnection: (uuid: string) => Promise<void>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEffect, useRef } from "react";
|
|
2
2
|
import { MultiDeviceWhisperer } from "../base/device-whisperer.js";
|
|
3
3
|
import mqtt from "mqtt";
|
|
4
|
-
export function MQTTMultiDeviceWhisperer({ serverUrl, uuidFromMessage, subTopicFromUuid = undefined, pubTopicFromUuid = undefined, serverPort = 8883, clientId = undefined, username = undefined, password = undefined,
|
|
4
|
+
export function MQTTMultiDeviceWhisperer({ serverUrl, uuidFromMessage, subTopicFromUuid = undefined, pubTopicFromUuid = undefined, serverPort = 8883, clientId = undefined, username = undefined, password = undefined, serverAutoConnect = true, serverConnectOn = false, ...props }) {
|
|
5
5
|
const base = MultiDeviceWhisperer(props);
|
|
6
6
|
const clientRef = useRef(null);
|
|
7
7
|
const isUnmountedRef = useRef(false);
|
|
@@ -211,7 +211,9 @@ export function MQTTMultiDeviceWhisperer({ serverUrl, uuidFromMessage, subTopicF
|
|
|
211
211
|
// Delete this adding connections item
|
|
212
212
|
addingConnections.current.delete(uuid);
|
|
213
213
|
// Connect immediately
|
|
214
|
-
|
|
214
|
+
const conn = base.getConnection(uuid);
|
|
215
|
+
if (conn?.autoConnect)
|
|
216
|
+
await connect(uuid);
|
|
215
217
|
return uuid;
|
|
216
218
|
};
|
|
217
219
|
const removeConnection = async (uuid) => {
|
|
@@ -228,11 +230,11 @@ export function MQTTMultiDeviceWhisperer({ serverUrl, uuidFromMessage, subTopicF
|
|
|
228
230
|
}
|
|
229
231
|
};
|
|
230
232
|
useEffect(() => {
|
|
231
|
-
if (!(
|
|
233
|
+
if (!(serverAutoConnect || serverConnectOn))
|
|
232
234
|
return;
|
|
233
235
|
const cleanup = connectToMQTTServer();
|
|
234
236
|
return cleanup;
|
|
235
|
-
}, [serverUrl,
|
|
237
|
+
}, [serverUrl, serverConnectOn]);
|
|
236
238
|
return {
|
|
237
239
|
...base,
|
|
238
240
|
addConnection,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { DeviceConnectionState, AddConnectionProps } from "../base/device-whisperer.js";
|
|
2
2
|
export declare class UsbTransport {
|
|
3
3
|
device: USBDevice;
|
|
4
|
-
|
|
4
|
+
controlInterface: number;
|
|
5
|
+
dataInterface: number;
|
|
5
6
|
endpointIn: number;
|
|
6
7
|
endpointOut: number;
|
|
7
8
|
private static readonly SET_LINE_CODING;
|
|
@@ -14,7 +14,8 @@ import { useEffect } from "react";
|
|
|
14
14
|
// usb-transport.ts
|
|
15
15
|
export class UsbTransport {
|
|
16
16
|
constructor(device) {
|
|
17
|
-
this.
|
|
17
|
+
this.controlInterface = 0;
|
|
18
|
+
this.dataInterface = 1;
|
|
18
19
|
this.endpointIn = 0;
|
|
19
20
|
this.endpointOut = 0;
|
|
20
21
|
this.device = device;
|
|
@@ -27,25 +28,40 @@ export class UsbTransport {
|
|
|
27
28
|
if (this.device.configuration === null) {
|
|
28
29
|
await this.device.selectConfiguration(1);
|
|
29
30
|
}
|
|
30
|
-
// Find the CDC Data interface (usually class 10) or just the first one with Bulk endpoints
|
|
31
31
|
const interfaces = this.device.configuration?.interfaces || [];
|
|
32
|
-
let
|
|
33
|
-
|
|
32
|
+
let ctrlIface;
|
|
33
|
+
let dataIface;
|
|
34
|
+
dataIface = interfaces.find(iface => {
|
|
34
35
|
const endpoints = iface.alternate.endpoints;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
return endpoints.some(e => e.direction === 'in' && e.type === 'bulk') &&
|
|
37
|
+
endpoints.some(e => e.direction === 'out' && e.type === 'bulk');
|
|
38
|
+
});
|
|
39
|
+
if (dataIface) {
|
|
40
|
+
this.dataInterface = dataIface.interfaceNumber;
|
|
41
|
+
ctrlIface = interfaces.find(i => i.interfaceNumber === this.dataInterface - 1)
|
|
42
|
+
|| interfaces.find(i => i.alternate.interfaceClass === 2);
|
|
43
|
+
this.controlInterface = ctrlIface ? ctrlIface.interfaceNumber : this.dataInterface;
|
|
44
|
+
}
|
|
45
|
+
if (!dataIface) {
|
|
46
|
+
throw new Error("No serial-compatible Bulk interface found.");
|
|
47
|
+
}
|
|
48
|
+
// Note: On Android, if the OS has claimed Interface 0, this first call will fail.
|
|
49
|
+
try {
|
|
50
|
+
if (this.controlInterface !== this.dataInterface) {
|
|
51
|
+
await this.device.claimInterface(this.controlInterface);
|
|
40
52
|
}
|
|
41
53
|
}
|
|
42
|
-
|
|
43
|
-
|
|
54
|
+
catch (e) {
|
|
55
|
+
console.warn("Could not claim Control Interface (OS locked?). Proceeding to Data...", e);
|
|
56
|
+
// We continue, but setSignals might fail later.
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
await this.device.claimInterface(this.dataInterface);
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
throw new Error(`Failed to claim Data Interface. Android OS has locked the device driver. Try using a 'Vendor Specific' USB Class device or a native Serial App workaround.`);
|
|
44
63
|
}
|
|
45
|
-
|
|
46
|
-
await this.device.claimInterface(this.interfaceNumber);
|
|
47
|
-
// Map endpoints
|
|
48
|
-
const endpoints = targetInterface.alternate.endpoints;
|
|
64
|
+
const endpoints = dataIface.alternate.endpoints;
|
|
49
65
|
this.endpointIn = endpoints.find(e => e.direction === 'in' && e.type === 'bulk').endpointNumber;
|
|
50
66
|
this.endpointOut = endpoints.find(e => e.direction === 'out' && e.type === 'bulk').endpointNumber;
|
|
51
67
|
await this.setBaudRate(baudRate);
|
|
@@ -57,7 +73,6 @@ export class UsbTransport {
|
|
|
57
73
|
async write(data) {
|
|
58
74
|
if (!this.device.opened)
|
|
59
75
|
return;
|
|
60
|
-
// Cast to 'unknown' then 'BufferSource' to satisfy the strict type definition
|
|
61
76
|
await this.device.transferOut(this.endpointOut, data);
|
|
62
77
|
}
|
|
63
78
|
/**
|
|
@@ -85,14 +100,13 @@ export class UsbTransport {
|
|
|
85
100
|
async setSignals({ dtr, rts }) {
|
|
86
101
|
if (!this.device.opened)
|
|
87
102
|
return;
|
|
88
|
-
// CDC-ACM: DTR is bit 0, RTS is bit 1
|
|
89
103
|
const value = (Number(dtr) | (Number(rts) << 1));
|
|
90
104
|
await this.device.controlTransferOut({
|
|
91
105
|
requestType: 'class',
|
|
92
106
|
recipient: 'interface',
|
|
93
107
|
request: UsbTransport.SET_CONTROL_LINE_STATE,
|
|
94
108
|
value: value,
|
|
95
|
-
index: this.
|
|
109
|
+
index: this.controlInterface
|
|
96
110
|
});
|
|
97
111
|
}
|
|
98
112
|
async setBaudRate(baud) {
|
|
@@ -102,20 +116,31 @@ export class UsbTransport {
|
|
|
102
116
|
// 4 bytes: baud (LE), 1 byte: stop bits, 1 byte: parity, 1 byte: data bits
|
|
103
117
|
const buffer = new ArrayBuffer(7);
|
|
104
118
|
const view = new DataView(buffer);
|
|
105
|
-
view.setUint32(0, baud, true);
|
|
106
|
-
view.setUint8(4, 0);
|
|
107
|
-
view.setUint8(5, 0);
|
|
108
|
-
view.setUint8(6, 8);
|
|
119
|
+
view.setUint32(0, baud, true);
|
|
120
|
+
view.setUint8(4, 0);
|
|
121
|
+
view.setUint8(5, 0);
|
|
122
|
+
view.setUint8(6, 8);
|
|
109
123
|
await this.device.controlTransferOut({
|
|
110
124
|
requestType: 'class',
|
|
111
125
|
recipient: 'interface',
|
|
112
126
|
request: UsbTransport.SET_LINE_CODING,
|
|
113
127
|
value: 0,
|
|
114
|
-
index: this.
|
|
128
|
+
index: this.controlInterface
|
|
115
129
|
}, buffer);
|
|
116
130
|
}
|
|
117
131
|
async disconnect() {
|
|
118
132
|
if (this.device.opened) {
|
|
133
|
+
// Release both
|
|
134
|
+
try {
|
|
135
|
+
await this.device.releaseInterface(this.dataInterface);
|
|
136
|
+
}
|
|
137
|
+
catch (e) { }
|
|
138
|
+
if (this.controlInterface !== this.dataInterface) {
|
|
139
|
+
try {
|
|
140
|
+
await this.device.releaseInterface(this.controlInterface);
|
|
141
|
+
}
|
|
142
|
+
catch (e) { }
|
|
143
|
+
}
|
|
119
144
|
await this.device.close();
|
|
120
145
|
}
|
|
121
146
|
}
|
|
@@ -292,7 +317,7 @@ export function SerialMultiDeviceWhisperer({ ...props } = {}) {
|
|
|
292
317
|
const device = await navigator.usb.requestDevice({
|
|
293
318
|
filters: []
|
|
294
319
|
});
|
|
295
|
-
|
|
320
|
+
const return_uuid = await base.addConnection({
|
|
296
321
|
uuid,
|
|
297
322
|
propCreator: (id) => {
|
|
298
323
|
const props = propCreator?.(id);
|
|
@@ -308,6 +333,10 @@ export function SerialMultiDeviceWhisperer({ ...props } = {}) {
|
|
|
308
333
|
};
|
|
309
334
|
}
|
|
310
335
|
});
|
|
336
|
+
const conn = base.getConnection(return_uuid);
|
|
337
|
+
if (conn?.autoConnect)
|
|
338
|
+
await connect(return_uuid);
|
|
339
|
+
return return_uuid;
|
|
311
340
|
}
|
|
312
341
|
catch (e) {
|
|
313
342
|
console.log("User cancelled or no device selected");
|
package/package.json
CHANGED