@alexgyver/ble 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/ble2light.js +128 -40
  2. package/package.json +6 -6
package/ble2light.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { sleep, SerialExecutor } from "@alexgyver/utils";
2
+
1
3
  export default class BLEJS {
2
4
  static State = {
3
5
  Closed: 'closed',
@@ -6,16 +8,13 @@ export default class BLEJS {
6
8
  Closing: 'closing',
7
9
  };
8
10
 
9
- //#region handlers
10
- onbin = null;
11
-
11
+ onbin(b) { }
12
12
  onopen() { }
13
13
  onclose() { }
14
14
  onchange(s) { }
15
15
  onselect(name) { }
16
16
  onerror(e) { }
17
17
 
18
- //#region constructor
19
18
  constructor(params = {}) {
20
19
  const def = {
21
20
  serviceUUID: '0000ffe0-0000-1000-8000-00805f9b34fb',
@@ -24,10 +23,10 @@ export default class BLEJS {
24
23
  auto_open: false,
25
24
  reconnect: 1000,
26
25
  };
26
+
27
27
  this.cfg = { ...def, ...params };
28
28
  }
29
29
 
30
- //#region methods
31
30
  config(params = {}) {
32
31
  this.cfg = { ...this.cfg, ...params };
33
32
  }
@@ -51,37 +50,57 @@ export default class BLEJS {
51
50
  async select() {
52
51
  try {
53
52
  await this.close();
54
- if (this._device) this._device.removeEventListener('gattserverdisconnected', this._disconnect_h);
53
+
54
+ if (this._device) {
55
+ this._device.removeEventListener(
56
+ 'gattserverdisconnected',
57
+ this._disconnect_h
58
+ );
59
+ }
60
+
55
61
  this._device = await navigator.bluetooth.requestDevice({
56
62
  filters: [{ services: [this.cfg.serviceUUID] }],
57
- optionalServices: [this.cfg.serviceUUID]
63
+ optionalServices: [this.cfg.serviceUUID],
58
64
  });
59
- this._device.addEventListener("gattserverdisconnected", this._disconnect_h);
65
+
66
+ this._device.addEventListener(
67
+ 'gattserverdisconnected',
68
+ this._disconnect_h
69
+ );
60
70
  } catch (e) {
61
71
  this._error(e);
62
72
  this._device = null;
63
73
  }
64
74
 
65
75
  this.onselect(this.getName());
76
+
66
77
  if (this.cfg.auto_open) this.open();
78
+
67
79
  return this.selected();
68
80
  }
69
81
 
70
82
  async open() {
71
- if (!this._device) {
72
- this._error("No device");
73
- return;
74
- }
75
- if (this.opened()) return;
83
+ return this._lifecycle.runNothrow(async () => {
84
+ if (!this._device) {
85
+ this._error('No device');
86
+ return false;
87
+ }
88
+
89
+ if (this.opened()) return true;
90
+
91
+ if (this.cfg.reconnect) this.retry = true;
92
+
93
+ await this._open();
76
94
 
77
- if (this.cfg.reconnect) this.retry = true;
78
- await this._open();
95
+ return this.opened();
96
+ });
79
97
  }
80
98
 
81
99
  async _open() {
82
- if (this._state != BLEJS.State.Closed) return;
100
+ if (this._state !== BLEJS.State.Closed) return;
83
101
 
84
102
  this._change(BLEJS.State.Opening);
103
+
85
104
  try {
86
105
  const server = await this._device.gatt.connect();
87
106
  const service = await server.getPrimaryService(this.cfg.serviceUUID);
@@ -90,76 +109,145 @@ export default class BLEJS {
90
109
  this._tx = await service.getCharacteristic(this.cfg.txUUID);
91
110
 
92
111
  await this._tx.startNotifications();
93
- this._tx.addEventListener("characteristicvaluechanged", this._data_h);
112
+ this._tx.addEventListener(
113
+ 'characteristicvaluechanged',
114
+ this._data_h
115
+ );
94
116
 
117
+ this._sender.reset();
95
118
  this._change(BLEJS.State.Open);
96
119
  } catch (e) {
97
120
  this._error(e);
121
+ this._sender.reset();
98
122
  this._change(BLEJS.State.Closed);
99
- if (this.retry) sleep(this.cfg.reconnect).then(() => this._open());
123
+
124
+ if (this.retry) {
125
+ sleep(this.cfg.reconnect).then(() => {
126
+ this._lifecycle.runNothrow(() => this._open());
127
+ });
128
+ }
100
129
  }
101
130
  }
102
131
 
103
132
  async close() {
104
- this.retry = false;
105
- if (this._device?.gatt?.connected) await this._close();
133
+ return this._lifecycle.runNothrow(async () => {
134
+ this.retry = false;
135
+ this._sender.reset();
136
+
137
+ if (this._state !== BLEJS.State.Closed) {
138
+ await this._close();
139
+ }
140
+
141
+ return true;
142
+ });
106
143
  }
107
144
 
108
145
  async _close() {
146
+ if (this._state === BLEJS.State.Closed) return;
147
+
109
148
  this._change(BLEJS.State.Closing);
149
+
110
150
  try {
111
- if (this._device?.gatt?.connected) this._device.gatt.disconnect();
112
- else this._disconnect();
151
+ if (this._device?.gatt?.connected) {
152
+ this._device.gatt.disconnect();
153
+ } else {
154
+ await this._disconnect();
155
+ }
113
156
  } catch (e) {
114
157
  this._error(e);
158
+ await this._disconnect();
115
159
  }
116
160
  }
117
161
 
118
162
  async sendBin(data, fast = true) {
119
- try {
120
- if (fast) await this._rx.writeValueWithoutResponse(data);
121
- else await this._rx.writeValueWithResponse(data);
122
- } catch (e) {
123
- this._error(e);
124
- }
163
+ if (!this.opened() || !this._rx) return false;
164
+
165
+ return this._sender.runNothrow(async () => {
166
+ if (!this.opened() || !this._rx) return false;
167
+
168
+ if (fast) {
169
+ await this._rx.writeValueWithoutResponse(data);
170
+ } else {
171
+ await this._rx.writeValueWithResponse(data);
172
+ }
173
+
174
+ return true;
175
+ });
125
176
  }
126
177
 
127
- //#region private
128
178
  _state = BLEJS.State.Closed;
129
179
  _device = null;
130
180
  _rx = null;
131
181
  _tx = null;
132
182
 
183
+ retry = false;
184
+
185
+ _sender = new SerialExecutor();
186
+ _lifecycle = new SerialExecutor();
187
+
133
188
  async _disconnect(e) {
134
- this._change(BLEJS.State.Closed);
135
- if (this._tx) this._tx.removeEventListener('characteristicvaluechanged', this._data_h);
189
+ this._sender.reset();
190
+
191
+ if (this._tx) {
192
+ try {
193
+ this._tx.removeEventListener(
194
+ 'characteristicvaluechanged',
195
+ this._data_h
196
+ );
197
+ } catch (e) { }
198
+ }
136
199
 
137
200
  this._rx = null;
138
201
  this._tx = null;
139
202
 
140
- if (this.retry) sleep(this.cfg.reconnect).then(() => this._open());
203
+ this._change(BLEJS.State.Closed);
204
+
205
+ if (this.retry) {
206
+ sleep(this.cfg.reconnect).then(() => {
207
+ this._lifecycle.runNothrow(() => this._open());
208
+ });
209
+ }
210
+
141
211
  await sleep(50);
142
212
  }
213
+
143
214
  _disconnect_h = this._disconnect.bind(this);
144
215
 
145
216
  _data(e) {
146
- const dv = e.target.value;
147
- const value = new Uint8Array(dv.buffer, dv.byteOffset, dv.byteLength);
148
- if (this.onbin) this.onbin(value);
217
+ try {
218
+ const dv = e.target.value;
219
+ const value = new Uint8Array(
220
+ dv.buffer,
221
+ dv.byteOffset,
222
+ dv.byteLength
223
+ );
224
+
225
+ this.onbin(value);
226
+ } catch (e) {
227
+ this._error(e);
228
+ }
149
229
  }
230
+
150
231
  _data_h = this._data.bind(this);
151
232
 
152
233
  _error(e) {
153
234
  this.onerror('[BLE] ' + e);
154
235
  }
236
+
155
237
  _change(s) {
238
+ if (this._state === s) return;
239
+
156
240
  this._state = s;
157
241
  this.onchange(s);
242
+
158
243
  switch (s) {
159
- case BLEJS.State.Open: this.onopen(); break;
160
- case BLEJS.State.Closed: this.onclose(); break;
244
+ case BLEJS.State.Open:
245
+ this.onopen();
246
+ break;
247
+
248
+ case BLEJS.State.Closed:
249
+ this.onclose();
250
+ break;
161
251
  }
162
252
  }
163
- }
164
-
165
- const sleep = (ms) => new Promise(r => setTimeout(r, ms));
253
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexgyver/ble",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Web BLE Serial",
5
5
  "main": "./ble.js",
6
6
  "module": "./ble.js",
@@ -14,14 +14,14 @@
14
14
  "url": "git+https://github.com/GyverLibs/ble.js.git"
15
15
  },
16
16
  "devDependencies": {
17
- "css-loader": "^7.1.3",
17
+ "css-loader": "^7.1.4",
18
18
  "style-loader": "^4.0.0",
19
- "webpack": "^5.105.1",
20
- "webpack-cli": "^6.0.1",
21
- "webpack-dev-server": "^5.2.3"
19
+ "webpack": "^5.106.2",
20
+ "webpack-cli": "^7.0.2",
21
+ "webpack-dev-server": "^5.2.4"
22
22
  },
23
23
  "dependencies": {
24
- "@alexgyver/utils": "^1.2.4"
24
+ "@alexgyver/utils": "^1.2.6"
25
25
  },
26
26
  "author": "AlexGyver <alex@alexgyver.ru>",
27
27
  "license": "MIT"