incyclist-devices 2.2.9 → 2.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.
Files changed (142) hide show
  1. package/lib/antv2/base/interface.js +2 -2
  2. package/lib/antv2/factories/index.d.ts +1 -0
  3. package/lib/antv2/factories/index.js +17 -0
  4. package/lib/antv2/fe/adapter.js +5 -4
  5. package/lib/antv2/index.d.ts +1 -0
  6. package/lib/antv2/index.js +12 -8
  7. package/lib/base/adpater.js +1 -1
  8. package/lib/ble/adapter-factory.d.ts +20 -24
  9. package/lib/ble/adapter-factory.js +13 -36
  10. package/lib/ble/base/adapter.d.ts +16 -5
  11. package/lib/ble/base/adapter.js +169 -52
  12. package/lib/ble/base/comms.d.ts +2 -74
  13. package/lib/ble/base/comms.js +3 -596
  14. package/lib/ble/base/interface.d.ts +96 -0
  15. package/lib/ble/base/interface.js +544 -0
  16. package/lib/ble/base/peripheral.d.ts +34 -0
  17. package/lib/ble/base/peripheral.js +286 -0
  18. package/lib/ble/base/sensor.d.ts +31 -0
  19. package/lib/ble/base/sensor.js +130 -0
  20. package/lib/ble/base/types.d.ts +7 -0
  21. package/lib/ble/base/types.js +7 -0
  22. package/lib/ble/bindings/mock.js +6 -0
  23. package/lib/ble/bindings/types.d.ts +3 -4
  24. package/lib/ble/ble-interface.d.ts +7 -4
  25. package/lib/ble/ble-interface.js +16 -2
  26. package/lib/ble/ble-peripheral.d.ts +1 -0
  27. package/lib/ble/ble-peripheral.js +7 -11
  28. package/lib/ble/consts.d.ts +0 -6
  29. package/lib/ble/consts.js +1 -7
  30. package/lib/ble/cp/adapter.d.ts +3 -3
  31. package/lib/ble/cp/adapter.js +12 -13
  32. package/lib/ble/cp/comm.d.ts +1 -1
  33. package/lib/ble/cp/comm.js +2 -2
  34. package/lib/ble/cp/index.d.ts +1 -1
  35. package/lib/ble/cp/index.js +2 -2
  36. package/lib/ble/cp/sensor.d.ts +27 -0
  37. package/lib/ble/cp/sensor.js +107 -0
  38. package/lib/ble/elite/comms.d.ts +1 -1
  39. package/lib/ble/elite/comms.js +2 -2
  40. package/lib/ble/factories/adapter-factory.d.ts +32 -0
  41. package/lib/ble/factories/adapter-factory.js +104 -0
  42. package/lib/ble/factories/index.d.ts +2 -0
  43. package/lib/ble/factories/index.js +18 -0
  44. package/lib/ble/factories/interface-factory.d.ts +7 -0
  45. package/lib/ble/factories/interface-factory.js +18 -0
  46. package/lib/ble/fm/adapter.d.ts +9 -4
  47. package/lib/ble/fm/adapter.js +104 -108
  48. package/lib/ble/fm/comms.d.ts +1 -1
  49. package/lib/ble/fm/comms.js +3 -3
  50. package/lib/ble/fm/consts.d.ts +93 -0
  51. package/lib/ble/fm/consts.js +55 -1
  52. package/lib/ble/fm/index.d.ts +1 -1
  53. package/lib/ble/fm/index.js +2 -2
  54. package/lib/ble/fm/sensor.d.ts +44 -0
  55. package/lib/ble/fm/sensor.js +384 -0
  56. package/lib/ble/hr/adapter.d.ts +3 -3
  57. package/lib/ble/hr/adapter.js +5 -8
  58. package/lib/ble/hr/comm.d.ts +1 -1
  59. package/lib/ble/hr/comm.js +2 -2
  60. package/lib/ble/hr/index.d.ts +1 -1
  61. package/lib/ble/hr/index.js +2 -2
  62. package/lib/ble/hr/sensor.d.ts +17 -0
  63. package/lib/ble/hr/sensor.js +52 -0
  64. package/lib/ble/index.d.ts +4 -3
  65. package/lib/ble/index.js +29 -13
  66. package/lib/ble/tacx/adapter.d.ts +4 -2
  67. package/lib/ble/tacx/adapter.js +26 -66
  68. package/lib/ble/tacx/comms.d.ts +1 -1
  69. package/lib/ble/tacx/comms.js +2 -2
  70. package/lib/ble/tacx/consts.d.ts +23 -0
  71. package/lib/ble/tacx/consts.js +27 -0
  72. package/lib/ble/tacx/index.d.ts +1 -1
  73. package/lib/ble/tacx/index.js +2 -2
  74. package/lib/ble/tacx/sensor.d.ts +63 -0
  75. package/lib/ble/tacx/sensor.js +596 -0
  76. package/lib/ble/types.d.ts +81 -52
  77. package/lib/ble/utils.d.ts +7 -2
  78. package/lib/ble/utils.js +84 -9
  79. package/lib/ble/wahoo/adapter.d.ts +2 -2
  80. package/lib/ble/wahoo/adapter.js +4 -72
  81. package/lib/ble/wahoo/comms.d.ts +1 -1
  82. package/lib/ble/wahoo/comms.js +2 -2
  83. package/lib/ble/wahoo/consts.d.ts +16 -0
  84. package/lib/ble/wahoo/consts.js +7 -0
  85. package/lib/ble/wahoo/index.d.ts +1 -1
  86. package/lib/ble/wahoo/index.js +2 -2
  87. package/lib/ble/wahoo/sensor.d.ts +48 -0
  88. package/lib/ble/wahoo/sensor.js +356 -0
  89. package/lib/direct-connect/base/comms.d.ts +3 -0
  90. package/lib/direct-connect/base/comms.js +7 -0
  91. package/lib/direct-connect/base/interface.d.ts +75 -0
  92. package/lib/direct-connect/base/interface.js +306 -0
  93. package/lib/direct-connect/base/peripheral.d.ts +50 -0
  94. package/lib/direct-connect/base/peripheral.js +413 -0
  95. package/lib/direct-connect/base/sensor.d.ts +3 -0
  96. package/lib/direct-connect/base/sensor.js +7 -0
  97. package/lib/direct-connect/bindings/index.d.ts +1 -0
  98. package/lib/direct-connect/bindings/index.js +17 -0
  99. package/lib/direct-connect/bindings/types.d.ts +36 -0
  100. package/lib/direct-connect/bindings/types.js +2 -0
  101. package/lib/direct-connect/consts.d.ts +17 -0
  102. package/lib/direct-connect/consts.js +20 -0
  103. package/lib/direct-connect/index.d.ts +3 -0
  104. package/lib/direct-connect/index.js +22 -0
  105. package/lib/direct-connect/messages/CharacteristicNotification.d.ts +12 -0
  106. package/lib/direct-connect/messages/CharacteristicNotification.js +23 -0
  107. package/lib/direct-connect/messages/DiscoverCharacteristics.d.ts +22 -0
  108. package/lib/direct-connect/messages/DiscoverCharacteristics.js +43 -0
  109. package/lib/direct-connect/messages/DiscoverServices.d.ts +15 -0
  110. package/lib/direct-connect/messages/DiscoverServices.js +33 -0
  111. package/lib/direct-connect/messages/EnableCharacteristicNotifications.d.ts +18 -0
  112. package/lib/direct-connect/messages/EnableCharacteristicNotifications.js +35 -0
  113. package/lib/direct-connect/messages/ReadCharacteristic.d.ts +18 -0
  114. package/lib/direct-connect/messages/ReadCharacteristic.js +34 -0
  115. package/lib/direct-connect/messages/WriteCharacteristic.d.ts +18 -0
  116. package/lib/direct-connect/messages/WriteCharacteristic.js +36 -0
  117. package/lib/direct-connect/messages/error.d.ts +5 -0
  118. package/lib/direct-connect/messages/error.js +18 -0
  119. package/lib/direct-connect/messages/factory.d.ts +6 -0
  120. package/lib/direct-connect/messages/factory.js +44 -0
  121. package/lib/direct-connect/messages/index.d.ts +9 -0
  122. package/lib/direct-connect/messages/index.js +25 -0
  123. package/lib/direct-connect/messages/message.d.ts +20 -0
  124. package/lib/direct-connect/messages/message.js +90 -0
  125. package/lib/direct-connect/types.d.ts +24 -0
  126. package/lib/direct-connect/types.js +9 -0
  127. package/lib/direct-connect/utils.d.ts +5 -0
  128. package/lib/direct-connect/utils.js +73 -0
  129. package/lib/factories/adapters.js +16 -4
  130. package/lib/factories/interfaces.d.ts +2 -1
  131. package/lib/factories/interfaces.js +10 -7
  132. package/lib/index.d.ts +5 -4
  133. package/lib/index.js +6 -2
  134. package/lib/serial/bindings/tcp.d.ts +5 -4
  135. package/lib/serial/bindings/tcp.js +16 -23
  136. package/lib/types/device.d.ts +2 -1
  137. package/lib/types/device.js +1 -0
  138. package/lib/utils/operation.d.ts +17 -0
  139. package/lib/utils/operation.js +20 -0
  140. package/lib/utils/task.d.ts +44 -0
  141. package/lib/utils/task.js +127 -0
  142. package/package.json +3 -1
@@ -0,0 +1,96 @@
1
+ import EventEmitter from "events";
2
+ import { DeviceSettings, InterfaceProps } from "../../types";
3
+ import { EventLogger } from "gd-eventlog";
4
+ import { BleBinding, BleInterfaceState, BlePeripheralAnnouncement, BlePeripheralInfo, BleRawPeripheral, BleScanProps, IBlePeripheral } from "../types";
5
+ import { IBleInterface } from '../../ble/types';
6
+ import { InteruptableTask, TaskState } from "../../utils/task";
7
+ import { InterfaceFactory } from "./types";
8
+ interface Announcement {
9
+ service: BlePeripheralAnnouncement;
10
+ ts: number;
11
+ }
12
+ export declare class BleInterface extends EventEmitter implements IBleInterface<BlePeripheralAnnouncement> {
13
+ protected static _instance: BleInterface;
14
+ static readonly INTERFACE_NAME: string;
15
+ protected logger: EventLogger;
16
+ protected props: InterfaceProps;
17
+ protected logEnabled: boolean;
18
+ protected binding: BleBinding;
19
+ protected debug: boolean;
20
+ protected logDisabled: boolean;
21
+ protected internalEvents: EventEmitter;
22
+ protected services: Announcement[];
23
+ protected incompleteServices: BlePeripheralAnnouncement[];
24
+ protected unsupported: BlePeripheralAnnouncement[];
25
+ protected expectedServices: string[];
26
+ protected matching: string[];
27
+ protected connectTask: InteruptableTask<TaskState, boolean>;
28
+ protected scanTask: InteruptableTask<TaskState, void>;
29
+ protected discoverTask: InteruptableTask<TaskState, void>;
30
+ protected onDiscovered: (peripheral: BlePeripheralInfo) => void;
31
+ protected instanceId: number;
32
+ protected connectedPeripherals: IBlePeripheral[];
33
+ static getInstance(props?: InterfaceProps): BleInterface;
34
+ protected constructor(props: InterfaceProps);
35
+ getLogger(): EventLogger;
36
+ setLogger(logger: EventLogger): void;
37
+ getName(): string;
38
+ setBinding(binding: BleBinding): void;
39
+ getBinding(): BleBinding;
40
+ protected autoConnect(): void;
41
+ connect(reconnect?: boolean): Promise<boolean>;
42
+ disconnect(): Promise<boolean>;
43
+ isConnected(): boolean;
44
+ registerConnected(peripheral: IBlePeripheral): void;
45
+ protected isConnecting(): boolean;
46
+ scan(props: BleScanProps): Promise<DeviceSettings[]>;
47
+ stopScan(): Promise<boolean>;
48
+ onScanDone(): DeviceSettings[];
49
+ pauseLogging(): void;
50
+ resumeLogging(): void;
51
+ isLoggingPaused(): boolean;
52
+ createPeripheral(announcement: BlePeripheralAnnouncement): IBlePeripheral;
53
+ createPeripheralFromSettings(settings: DeviceSettings): IBlePeripheral;
54
+ waitForPeripheral(settings: DeviceSettings): Promise<IBlePeripheral>;
55
+ createDeviceSetting(service: BlePeripheralAnnouncement): DeviceSettings;
56
+ protected reconnect(): Promise<void>;
57
+ protected startPeripheralScan(retry?: boolean): Promise<void>;
58
+ protected stopPeripheralScan(): Promise<void>;
59
+ protected isDiscovering(): boolean;
60
+ protected discoverPeripherals(): Promise<void>;
61
+ pauseDiscovery(): Promise<void>;
62
+ resumeDiscovery(): Promise<void>;
63
+ protected onPeripheralFound(peripheral: BleRawPeripheral): void;
64
+ protected buildAnnouncement(peripheral: BleRawPeripheral): BlePeripheralAnnouncement;
65
+ protected updateWithServices(announcement: BlePeripheralAnnouncement): Promise<BlePeripheralAnnouncement>;
66
+ protected discoverServices(announcement: BlePeripheralAnnouncement): Promise<string[]>;
67
+ protected isScanning(): boolean;
68
+ protected startScan(): Promise<unknown>;
69
+ private emitCachedDevices;
70
+ protected emitDevice(service: BlePeripheralAnnouncement): void;
71
+ protected buildDeviceSettings(matching?: string[]): {
72
+ interface: string;
73
+ name: string;
74
+ }[];
75
+ protected addCompleting(service: BlePeripheralAnnouncement): void;
76
+ protected addUnsupported(service: BlePeripheralAnnouncement): void;
77
+ protected isKnownUnsupported(service: BlePeripheralAnnouncement): boolean;
78
+ protected removeCompleting(service: BlePeripheralAnnouncement): void;
79
+ protected isCompleting(service: BlePeripheralAnnouncement): boolean;
80
+ protected addService(service: BlePeripheralAnnouncement): void;
81
+ protected isSupportedPeripheral(service: BlePeripheralAnnouncement): boolean;
82
+ protected find(service: BlePeripheralAnnouncement): Announcement;
83
+ protected getAll(): Announcement[];
84
+ setDebug(enabled: boolean): void;
85
+ protected connectBle(): Promise<boolean>;
86
+ protected waitForBleConnected(): Promise<boolean>;
87
+ protected onBleStateChange(state: BleInterfaceState): void;
88
+ logEvent(event: any): void;
89
+ logError(err: Error, fn: string, args?: any): void;
90
+ }
91
+ export declare class BleInterfaceFactory extends InterfaceFactory {
92
+ protected iface: BleInterface;
93
+ constructor();
94
+ getInterface(): BleInterface;
95
+ }
96
+ export {};
@@ -0,0 +1,544 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.BleInterfaceFactory = exports.BleInterface = void 0;
16
+ const events_1 = __importDefault(require("events"));
17
+ const gd_eventlog_1 = require("gd-eventlog");
18
+ const task_1 = require("../../utils/task");
19
+ const peripheral_1 = require("./peripheral");
20
+ const utils_1 = require("../utils");
21
+ const types_1 = require("./types");
22
+ const factories_1 = require("../factories");
23
+ const BLE_DEFAULT_SCAN_TIMEOUT = 30 * 1000;
24
+ const BLE_EXPIRATION_TIMEOUT = 10 * 1000 * 60;
25
+ const BLE_DEFAULT_CONNECT_TIMEOUT = 30 * 1000;
26
+ let instanceCount = 0;
27
+ class BleInterface extends events_1.default {
28
+ static getInstance(props = {}) {
29
+ if (BleInterface._instance === undefined)
30
+ BleInterface._instance = new BleInterface(props);
31
+ else {
32
+ if (props.binding) {
33
+ BleInterface._instance.setBinding(props.binding);
34
+ }
35
+ if (props.logger) {
36
+ BleInterface._instance.logger = props.logger;
37
+ }
38
+ if (props.log && !BleInterface._instance.logger) {
39
+ BleInterface._instance.logger = new gd_eventlog_1.EventLogger('BLE');
40
+ }
41
+ }
42
+ return BleInterface._instance;
43
+ }
44
+ constructor(props) {
45
+ var _a;
46
+ super();
47
+ this.services = [];
48
+ this.incompleteServices = [];
49
+ this.unsupported = [];
50
+ this.expectedServices = ['180d', '1818', '1826', '6e40fec1'];
51
+ this.matching = [];
52
+ this.connectedPeripherals = [];
53
+ this.instanceId = ++instanceCount;
54
+ this.props = props;
55
+ this.logEnabled = props.log || true;
56
+ const { binding } = props;
57
+ this.setLogger((_a = props.logger) !== null && _a !== void 0 ? _a : new gd_eventlog_1.EventLogger('Ble'));
58
+ if (binding) {
59
+ this.setBinding(binding);
60
+ }
61
+ this.internalEvents = new events_1.default();
62
+ this.onDiscovered = this.onPeripheralFound.bind(this);
63
+ if (this.binding)
64
+ this.autoConnect();
65
+ }
66
+ getLogger() {
67
+ return this.logger;
68
+ }
69
+ setLogger(logger) {
70
+ this.logger = logger;
71
+ }
72
+ getName() {
73
+ return BleInterface.INTERFACE_NAME;
74
+ }
75
+ setBinding(binding) {
76
+ this.binding = binding;
77
+ }
78
+ getBinding() {
79
+ return this.binding;
80
+ }
81
+ autoConnect() {
82
+ this.connect();
83
+ }
84
+ connect(reconnect) {
85
+ return __awaiter(this, void 0, void 0, function* () {
86
+ if (!this.getBinding()) {
87
+ this.logEvent({ message: 'BLE not available' });
88
+ return false;
89
+ }
90
+ if (this.isConnecting()) {
91
+ this.logEvent({ message: 'connect - already connecting' });
92
+ return this.connectTask.getPromise();
93
+ }
94
+ if (this.isConnected())
95
+ return true;
96
+ this.logEvent({ message: 'Ble connect request' });
97
+ this.connectTask = new task_1.InteruptableTask(this.connectBle(), {
98
+ timeout: BLE_DEFAULT_CONNECT_TIMEOUT,
99
+ name: 'connect',
100
+ errorOnTimeout: false,
101
+ log: this.logEvent.bind(this),
102
+ });
103
+ const success = yield this.connectTask.run();
104
+ if (success) {
105
+ this.startPeripheralScan();
106
+ }
107
+ this.expectedServices = factories_1.BleAdapterFactory.getInstance('ble').getAllSupportedServices();
108
+ return success;
109
+ });
110
+ }
111
+ disconnect() {
112
+ return __awaiter(this, void 0, void 0, function* () {
113
+ if (!this.getBinding()) {
114
+ return false;
115
+ }
116
+ if (!this.isConnected())
117
+ return true;
118
+ this.logEvent({ message: 'disconnect request' });
119
+ yield this.stopPeripheralScan();
120
+ const promises = this.connectedPeripherals.map(p => p.disconnect());
121
+ yield Promise.allSettled(promises);
122
+ this.connectedPeripherals = [];
123
+ yield this.connectTask.stop();
124
+ this.getBinding().removeAllListeners();
125
+ return true;
126
+ });
127
+ }
128
+ isConnected() {
129
+ var _a;
130
+ return ((_a = this.getBinding()) === null || _a === void 0 ? void 0 : _a.state) === 'poweredOn';
131
+ }
132
+ registerConnected(peripheral) {
133
+ this.connectedPeripherals.push(peripheral);
134
+ }
135
+ isConnecting() {
136
+ var _a;
137
+ return ((_a = this.connectTask) === null || _a === void 0 ? void 0 : _a.isRunning()) === true;
138
+ }
139
+ scan(props) {
140
+ return __awaiter(this, void 0, void 0, function* () {
141
+ this.resumeLogging();
142
+ if (this.isScanning()) {
143
+ this.logEvent({ message: 'starting scan - already scanning' });
144
+ return this.scanTask.getPromise()
145
+ .then(() => { return this.onScanDone(); })
146
+ .catch(() => []);
147
+ }
148
+ this.logEvent({ message: 'starting scan ..' });
149
+ this.scanTask = new task_1.InteruptableTask(this.startScan(), {
150
+ timeout: props.timeout,
151
+ name: 'scan',
152
+ errorOnTimeout: false,
153
+ log: this.logEvent.bind(this),
154
+ });
155
+ try {
156
+ yield this.scanTask.run();
157
+ }
158
+ catch (err) {
159
+ this.logError(err, 'scan');
160
+ }
161
+ return this.onScanDone();
162
+ });
163
+ }
164
+ stopScan() {
165
+ if (!this.isScanning())
166
+ return Promise.resolve(true);
167
+ this.logEvent({ message: 'stopping scan ...' });
168
+ this.scanTask.stop();
169
+ }
170
+ onScanDone() {
171
+ this.logEvent({ message: 'scan stopped' });
172
+ delete this.scanTask;
173
+ return this.buildDeviceSettings(this.matching);
174
+ }
175
+ pauseLogging() {
176
+ this.logDisabled = true;
177
+ }
178
+ resumeLogging() {
179
+ this.logDisabled = false;
180
+ }
181
+ isLoggingPaused() {
182
+ return this.logDisabled;
183
+ }
184
+ createPeripheral(announcement) {
185
+ return new peripheral_1.BlePeripheral(announcement);
186
+ }
187
+ createPeripheralFromSettings(settings) {
188
+ const info = this.getAll().find(a => a.service.name === settings.name);
189
+ if (!(info === null || info === void 0 ? void 0 : info.service))
190
+ return null;
191
+ return this.createPeripheral(info.service);
192
+ }
193
+ waitForPeripheral(settings) {
194
+ const peripheral = this.createPeripheralFromSettings(settings);
195
+ if (peripheral)
196
+ return Promise.resolve(peripheral);
197
+ return new Promise((done) => {
198
+ const onDevice = (device) => {
199
+ if (device.name === settings.name) {
200
+ const peripheral = this.createPeripheralFromSettings(settings);
201
+ if (peripheral) {
202
+ this.off('device', onDevice);
203
+ done(peripheral);
204
+ }
205
+ }
206
+ };
207
+ this.on('device', onDevice);
208
+ });
209
+ }
210
+ createDeviceSetting(service) {
211
+ const name = service.name;
212
+ return { interface: BleInterface.INTERFACE_NAME, name };
213
+ }
214
+ reconnect() {
215
+ return __awaiter(this, void 0, void 0, function* () {
216
+ yield this.disconnect();
217
+ yield this.connect(true);
218
+ });
219
+ }
220
+ startPeripheralScan() {
221
+ return __awaiter(this, arguments, void 0, function* (retry = false) {
222
+ if (!retry)
223
+ this.logEvent({ message: 'starting peripheral discovery ...' });
224
+ if (!this.isConnected() || this.isDiscovering()) {
225
+ return;
226
+ }
227
+ this.discoverTask = new task_1.InteruptableTask(this.discoverPeripherals(), {
228
+ errorOnTimeout: false,
229
+ name: 'discover',
230
+ log: this.logEvent.bind(this),
231
+ });
232
+ try {
233
+ yield this.discoverTask.run();
234
+ }
235
+ catch (err) {
236
+ this.logError(err, 'discover');
237
+ }
238
+ if (this.discoverTask.getState().result !== 'stopped') {
239
+ this.startPeripheralScan(true);
240
+ }
241
+ });
242
+ }
243
+ stopPeripheralScan() {
244
+ if (!this.isConnected() || !this.isDiscovering())
245
+ return;
246
+ this.logEvent({ message: 'stopping peripheral discovery ...' });
247
+ this.discoverTask.stop();
248
+ this.getBinding().off('discover', this.onDiscovered);
249
+ return new Promise(done => {
250
+ this.getBinding().stopScanning(() => {
251
+ done();
252
+ });
253
+ });
254
+ }
255
+ isDiscovering() {
256
+ var _a;
257
+ return ((_a = this.discoverTask) === null || _a === void 0 ? void 0 : _a.isRunning()) === true;
258
+ }
259
+ discoverPeripherals() {
260
+ return new Promise(done => {
261
+ const ble = this.getBinding();
262
+ ble.startScanning([], true, (err) => {
263
+ if (err) {
264
+ this.logEvent({ message: 'start scanning error', error: err.message });
265
+ ble.stopScanning(() => {
266
+ done();
267
+ });
268
+ }
269
+ else {
270
+ ble.on('discover', this.onDiscovered);
271
+ ble.on('error', (err) => {
272
+ this.logEvent({ message: 'error during discovery', error: err.message });
273
+ });
274
+ }
275
+ });
276
+ });
277
+ }
278
+ pauseDiscovery() {
279
+ this.getBinding().off('discover', this.onDiscovered);
280
+ return new Promise(done => {
281
+ try {
282
+ this.getBinding().stopScanning();
283
+ done();
284
+ }
285
+ catch (err) {
286
+ done();
287
+ }
288
+ });
289
+ }
290
+ resumeDiscovery() {
291
+ return this.discoverPeripherals();
292
+ }
293
+ onPeripheralFound(peripheral) {
294
+ if (!this.isConnected() || !this.isDiscovering())
295
+ return;
296
+ const announcement = this.buildAnnouncement(peripheral);
297
+ if (!announcement.name || this.isKnownUnsupported(announcement)) {
298
+ return;
299
+ }
300
+ const device = Object.assign({}, announcement);
301
+ delete device.peripheral;
302
+ if (this.find(announcement)) {
303
+ return;
304
+ }
305
+ if (announcement.serviceUUIDs.length === 0) {
306
+ if (this.isCompleting(announcement)) {
307
+ return;
308
+ }
309
+ this.addCompleting(announcement);
310
+ setTimeout(() => {
311
+ if (this.find(announcement)) {
312
+ this.removeCompleting(announcement);
313
+ return;
314
+ }
315
+ this.updateWithServices(announcement)
316
+ .then(() => {
317
+ if (this.isSupportedPeripheral(announcement))
318
+ this.addService(announcement);
319
+ });
320
+ }, 1000);
321
+ }
322
+ this.addService(announcement);
323
+ }
324
+ buildAnnouncement(peripheral) {
325
+ var _a;
326
+ return {
327
+ advertisement: peripheral.advertisement,
328
+ name: peripheral.advertisement.localName,
329
+ serviceUUIDs: (_a = peripheral.advertisement.serviceUuids) !== null && _a !== void 0 ? _a : [],
330
+ peripheral,
331
+ transport: this.getName()
332
+ };
333
+ }
334
+ updateWithServices(announcement) {
335
+ return __awaiter(this, void 0, void 0, function* () {
336
+ if (!this.isConnected() || !this.isDiscovering())
337
+ return;
338
+ try {
339
+ yield this.discoverServices(announcement);
340
+ return announcement;
341
+ }
342
+ catch (err) {
343
+ this.logError(err, 'updateWithServices');
344
+ }
345
+ this.removeCompleting(announcement);
346
+ });
347
+ }
348
+ discoverServices(announcement) {
349
+ return __awaiter(this, void 0, void 0, function* () {
350
+ const device = Object.assign({}, announcement);
351
+ delete device.peripheral;
352
+ const { peripheral } = announcement;
353
+ let paused = false;
354
+ try {
355
+ peripheral.on('error', (err) => {
356
+ peripheral.removeAllListeners();
357
+ this.logEvent({ message: 'Device error', error: err.message });
358
+ });
359
+ peripheral.on('disconnect', () => {
360
+ peripheral.removeAllListeners();
361
+ this.logEvent({ message: 'Device disconnected' });
362
+ });
363
+ yield peripheral.connectAsync();
364
+ if (peripheral.discoverServicesAsync !== undefined) {
365
+ const services = yield peripheral.discoverServicesAsync([]);
366
+ announcement.serviceUUIDs = services.map(s => s.uuid);
367
+ }
368
+ else {
369
+ const res = yield peripheral.discoverSomeServicesAndCharacteristicsAsync([], []);
370
+ announcement.serviceUUIDs = res.services.map(s => s.uuid);
371
+ }
372
+ peripheral.removeAllListeners();
373
+ }
374
+ catch (err) {
375
+ this.logEvent({ message: 'discover services failed', reason: err.message, device });
376
+ }
377
+ if (paused) {
378
+ yield this.resumeDiscovery();
379
+ }
380
+ return device.serviceUUIDs;
381
+ });
382
+ }
383
+ isScanning() {
384
+ var _a;
385
+ return ((_a = this.scanTask) === null || _a === void 0 ? void 0 : _a.isRunning()) === true;
386
+ }
387
+ startScan() {
388
+ this.logEvent({ message: 'scan started', scanning: this.isScanning() });
389
+ this.emitCachedDevices();
390
+ return new Promise(() => {
391
+ });
392
+ }
393
+ emitCachedDevices() {
394
+ const announced = this.getAll();
395
+ this.matching = announced.map(a => a.service.name);
396
+ announced.forEach(a => {
397
+ this.emitDevice(a.service);
398
+ });
399
+ }
400
+ emitDevice(service) {
401
+ const settings = this.createDeviceSetting(service);
402
+ this.emit('device', settings, service);
403
+ }
404
+ buildDeviceSettings(matching = []) {
405
+ return matching.map((name) => ({ interface: BleInterface.INTERFACE_NAME, name }));
406
+ }
407
+ addCompleting(service) {
408
+ const existing = this.incompleteServices.find(s => s.name === service.name);
409
+ if (existing) {
410
+ const idx = this.incompleteServices.indexOf(existing);
411
+ this.incompleteServices[idx] = service;
412
+ }
413
+ else {
414
+ this.incompleteServices.push(service);
415
+ }
416
+ }
417
+ addUnsupported(service) {
418
+ const existing = this.unsupported.find(s => s.name === service.name);
419
+ if (existing) {
420
+ const idx = this.unsupported.indexOf(existing);
421
+ this.unsupported[idx] = service;
422
+ }
423
+ else {
424
+ this.unsupported.push(service);
425
+ }
426
+ }
427
+ isKnownUnsupported(service) {
428
+ return this.unsupported.find(s => s.name === service.name) !== undefined;
429
+ }
430
+ removeCompleting(service) {
431
+ const existingIdx = this.incompleteServices.findIndex(s => s.name === service.name);
432
+ if (existingIdx !== -1) {
433
+ this.incompleteServices.splice(existingIdx, 1);
434
+ }
435
+ }
436
+ isCompleting(service) {
437
+ return this.incompleteServices.find(s => s.name === service.name) !== undefined;
438
+ }
439
+ addService(service) {
440
+ try {
441
+ const isSuported = this.isSupportedPeripheral(service);
442
+ if (!isSuported) {
443
+ return;
444
+ }
445
+ const existing = this.find(service);
446
+ if (existing) {
447
+ const idx = this.services.indexOf(existing);
448
+ this.services[idx] = { ts: Date.now(), service };
449
+ }
450
+ else {
451
+ const device = Object.assign({}, service);
452
+ delete device.peripheral;
453
+ this.logEvent({ message: 'device announced', device });
454
+ this.matching.push(service.name);
455
+ this.services.push({ ts: Date.now(), service });
456
+ this.emitDevice(service);
457
+ }
458
+ }
459
+ catch (err) {
460
+ this.logError(err, 'addService');
461
+ }
462
+ }
463
+ isSupportedPeripheral(service) {
464
+ var _a, _b;
465
+ if (!((_a = service.serviceUUIDs) === null || _a === void 0 ? void 0 : _a.length) || service.name === undefined)
466
+ return false;
467
+ const found = service.serviceUUIDs.map(utils_1.parseUUID);
468
+ const expected = this.expectedServices.map(utils_1.parseUUID);
469
+ const supported = (_b = found.filter(uuid => expected.includes(uuid))) !== null && _b !== void 0 ? _b : [];
470
+ if (!supported.length) {
471
+ this.logEvent({ message: 'service not supported', name: service.name, uuids: service.serviceUUIDs });
472
+ this.addUnsupported(service);
473
+ }
474
+ return supported.length > 0;
475
+ }
476
+ find(service) {
477
+ return this.services.find(a => a.service.name === service.name && a.ts > Date.now() - BLE_EXPIRATION_TIMEOUT);
478
+ }
479
+ getAll() {
480
+ return this.services.filter(a => a.ts > Date.now() - BLE_EXPIRATION_TIMEOUT);
481
+ }
482
+ setDebug(enabled) {
483
+ this.debug = enabled;
484
+ }
485
+ connectBle() {
486
+ return __awaiter(this, void 0, void 0, function* () {
487
+ const state = this.getBinding().state;
488
+ if (state === 'poweredOn') {
489
+ return true;
490
+ }
491
+ const res = yield this.waitForBleConnected();
492
+ return res;
493
+ });
494
+ }
495
+ waitForBleConnected() {
496
+ return new Promise((done) => {
497
+ this.getBinding().once('error', (err) => {
498
+ this.logEvent({ message: 'Ble connect result: error', error: err.message });
499
+ return done(false);
500
+ });
501
+ this.getBinding().on('stateChange', (state) => {
502
+ if (state === 'poweredOn') {
503
+ this.logEvent({ message: 'Ble connect result: success' });
504
+ this.getBinding().removeAllListeners('stateChange');
505
+ this.getBinding().on('stateChange', this.onBleStateChange.bind(this));
506
+ this.getBinding().on('error', console.log);
507
+ return done(true);
508
+ }
509
+ else {
510
+ this.logEvent({ message: 'BLE state change', state });
511
+ }
512
+ });
513
+ });
514
+ }
515
+ onBleStateChange(state) {
516
+ }
517
+ logEvent(event) {
518
+ if (this.logDisabled && event.message !== 'Error')
519
+ return;
520
+ this.getLogger().logEvent(event);
521
+ const emitPayload = Object.assign({}, event);
522
+ delete emitPayload.ts;
523
+ this.emit('log', emitPayload);
524
+ const w = global.window;
525
+ if (this.debug || (w === null || w === void 0 ? void 0 : w.SERVICE_DEBUG) || process.env.DEBUG)
526
+ console.log(`~~~ ${this.logger.getName().toUpperCase()}-SVC`, event);
527
+ }
528
+ logError(err, fn, args) {
529
+ const logInfo = args || {};
530
+ this.logEvent(Object.assign(Object.assign({ message: 'Error', fn }, logInfo), { error: err.message, stack: err.stack }));
531
+ }
532
+ }
533
+ exports.BleInterface = BleInterface;
534
+ BleInterface.INTERFACE_NAME = 'ble';
535
+ class BleInterfaceFactory extends types_1.InterfaceFactory {
536
+ constructor() {
537
+ super();
538
+ this.iface = BleInterface.getInstance();
539
+ }
540
+ getInterface() {
541
+ return this.iface;
542
+ }
543
+ }
544
+ exports.BleInterfaceFactory = BleInterfaceFactory;
@@ -0,0 +1,34 @@
1
+ import { BleCharacteristic, BlePeripheralAnnouncement, BleRawCharacteristic, BleRawPeripheral, BleService, BleWriteProps, IBlePeripheral } from "../types";
2
+ import { BleInterface } from "./interface";
3
+ export declare class BlePeripheral implements IBlePeripheral {
4
+ protected announcement: BlePeripheralAnnouncement;
5
+ protected connected: boolean;
6
+ protected characteristics: Record<string, BleRawCharacteristic>;
7
+ protected onDisconnectHandler?: () => void;
8
+ protected ble: BleInterface;
9
+ protected subscribed: Array<{
10
+ uuid: string;
11
+ callback: (data: Buffer) => void;
12
+ }>;
13
+ protected disconnecting: boolean;
14
+ constructor(announcement: BlePeripheralAnnouncement);
15
+ get services(): BleService[];
16
+ protected getPeripheral(): BleRawPeripheral;
17
+ connect(): Promise<boolean>;
18
+ disconnect(): Promise<boolean>;
19
+ isConnected(): boolean;
20
+ isConnecting(): boolean;
21
+ onDisconnect(callback: () => void): void;
22
+ discoverServices(): Promise<string[]>;
23
+ discoverCharacteristics(serviceUUID: string): Promise<BleCharacteristic[]>;
24
+ subscribe(characteristicUUID: string, callback: (characteristicUuid: string, data: Buffer) => void): Promise<boolean>;
25
+ unsubscribe(characteristicUUID: string): Promise<boolean>;
26
+ subscribeSelected(characteristics: string[], callback: (characteristicUuid: string, data: Buffer) => void): Promise<boolean>;
27
+ discoverAllCharacteristics(): Promise<string[]>;
28
+ subscribeAll(callback: (characteristicUuid: string, data: Buffer) => void): Promise<boolean>;
29
+ unsubscribeAll(): Promise<boolean>;
30
+ read(characteristicUUID: string): Promise<Buffer>;
31
+ write(characteristicUUID: string, data: Buffer, options?: BleWriteProps): Promise<Buffer>;
32
+ protected getRawCharacteristic(uuid: string): BleRawCharacteristic;
33
+ logEvent(event: any): void;
34
+ }