incyclist-devices 3.0.24 → 3.0.26

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.
@@ -55,7 +55,7 @@ class BleAdapter extends adpater_js_1.default {
55
55
  const info = peripheral.getInfo();
56
56
  const settings = { ...this.settings };
57
57
  settings.id = settings.id ?? info.id;
58
- settings.address = settings.address ?? info.address;
58
+ settings.address = info.address ?? settings.address;
59
59
  settings.name = settings.name ?? info.name;
60
60
  this.settings = settings;
61
61
  }
@@ -77,11 +77,13 @@ class BleAdapter extends adpater_js_1.default {
77
77
  if (as.profile || settings.profile) {
78
78
  return (as.protocol === settings.protocol && as.profile === settings.profile && as.name === settings.name);
79
79
  }
80
- else {
81
- return (as.protocol === settings.protocol && ((as.name && settings.name && as.name === settings.name) ||
82
- (as.address && settings.address && as.address === settings.address) ||
83
- (as.id && settings.id && as.id === settings.id)));
84
- }
80
+ if (as.protocol !== settings.protocol)
81
+ return false;
82
+ if (as.id && settings.id)
83
+ return as.id === settings.id;
84
+ if (as.address && settings.address)
85
+ return as.address === settings.address;
86
+ return !!(as.name && settings.name && as.name === settings.name);
85
87
  }
86
88
  isSame(adapter) {
87
89
  return this.isEqual(adapter.getSettings());
@@ -251,6 +253,8 @@ class BleAdapter extends adpater_js_1.default {
251
253
  }
252
254
  async initControl(_props) {
253
255
  }
256
+ async initControlBestEffort(_props) {
257
+ }
254
258
  getStartLogProps(props) {
255
259
  const capabilities = this.props?.capabilities;
256
260
  const { user, userWeight, bikeWeight, timeout, wheelDiameter, restart, scanOnly } = props ?? {};
@@ -286,11 +290,16 @@ class BleAdapter extends adpater_js_1.default {
286
290
  this.stopped = true;
287
291
  return false;
288
292
  }
289
- await this.waitForInitialData(timeout);
290
293
  await this.checkCapabilities();
291
294
  const skipControl = this.props.capabilities && !this.props.capabilities.includes(index_js_1.IncyclistCapability.Control);
292
- if (this.hasCapability(index_js_1.IncyclistCapability.Control) && !skipControl)
295
+ const isControllable = this.hasCapability(index_js_1.IncyclistCapability.Control) && !skipControl;
296
+ if (isControllable) {
293
297
  await this.initControl(startProps);
298
+ }
299
+ else {
300
+ await this.initControlBestEffort(startProps);
301
+ }
302
+ await this.waitForInitialData(timeout);
294
303
  this.stopped = false;
295
304
  this.started = true;
296
305
  if (wasPaused)
@@ -12,6 +12,7 @@ const adapter_js_1 = __importDefault(require("../base/adapter.js"));
12
12
  const consts_js_1 = require("./consts.js");
13
13
  const index_js_1 = require("../../types/index.js");
14
14
  const utils_js_1 = require("../../utils/utils.js");
15
+ const task_js_1 = require("../../utils/task.js");
15
16
  const index_js_2 = require("../zwift/play/index.js");
16
17
  const index_js_3 = require("../../features/index.js");
17
18
  const fm_resistance_js_1 = __importDefault(require("../../modes/fm-resistance.js"));
@@ -21,6 +22,7 @@ class BleFmAdapter extends adapter_js_1.default {
21
22
  distanceInternal = 0;
22
23
  connectPromise;
23
24
  requestControlRetryDelay = 1000;
25
+ requestControlTimeout = 10000;
24
26
  promiseSendUpdate;
25
27
  zwiftPlay;
26
28
  isHubInitialized = false;
@@ -168,8 +170,36 @@ class BleFmAdapter extends adapter_js_1.default {
168
170
  if (!this.hasCapability(index_js_1.IncyclistCapability.Control))
169
171
  return;
170
172
  await this.establishControl();
173
+ await this.attemptStartRequest();
171
174
  await this.sendInitialRequest();
172
175
  }
176
+ async initControlBestEffort(_startProps) {
177
+ if (!this.isStarting())
178
+ return;
179
+ this.setConstants();
180
+ try {
181
+ const hasControl = await this.getSensor().requestControl();
182
+ if (hasControl) {
183
+ this.logEvent({ message: 'control granted (downgraded device)', device: this.getName(), interface: this.getInterface() });
184
+ await this.attemptStartRequest();
185
+ }
186
+ else {
187
+ this.logEvent({ message: 'could not establish control (downgraded device, non-fatal)', device: this.getName(), interface: this.getInterface() });
188
+ }
189
+ }
190
+ catch (err) {
191
+ this.logEvent({ message: 'could not establish control (downgraded device, non-fatal)', device: this.getName(), interface: this.getInterface(), error: err.message });
192
+ }
193
+ }
194
+ async attemptStartRequest() {
195
+ try {
196
+ const started = await this.getSensor().startRequest();
197
+ this.logEvent({ message: started ? 'start request acknowledged' : 'start request not acknowledged (non-fatal)', device: this.getName(), interface: this.getInterface() });
198
+ }
199
+ catch (err) {
200
+ this.logEvent({ message: 'start request failed (non-fatal)', device: this.getName(), interface: this.getInterface(), error: err.message });
201
+ }
202
+ }
173
203
  setConstants() {
174
204
  const mode = this.getCyclingMode();
175
205
  const sensor = this.getSensor();
@@ -195,7 +225,7 @@ class BleFmAdapter extends adapter_js_1.default {
195
225
  let hasControl = false;
196
226
  let tryCnt = 0;
197
227
  const sensor = this.getSensor();
198
- return new Promise((resolve) => {
228
+ const controlPromise = new Promise((resolve) => {
199
229
  this.startTask.notifyOnStop(() => {
200
230
  resolve(false);
201
231
  });
@@ -219,6 +249,18 @@ class BleFmAdapter extends adapter_js_1.default {
219
249
  };
220
250
  waitUntilControl();
221
251
  });
252
+ const waitTask = new task_js_1.InteruptableTask(controlPromise, {
253
+ timeout: this.requestControlTimeout,
254
+ name: 'establishControl',
255
+ errorOnTimeout: false,
256
+ log: this.logEvent.bind(this)
257
+ });
258
+ const granted = await waitTask.run();
259
+ if (!granted && this.isStarting()) {
260
+ this.logEvent({ message: 'could not establish control', device: this.getName(), interface: this.getInterface() });
261
+ throw new Error('could not establish control');
262
+ }
263
+ return granted;
222
264
  }
223
265
  async sendInitialRequest() {
224
266
  const startRequest = this.getCyclingMode().getBikeInitRequest();
@@ -111,9 +111,6 @@ class BleFitnessMachineDevice extends sensor_js_1.TBleSensor {
111
111
  }
112
112
  if (!this.isSubscribed())
113
113
  return false;
114
- if (this.features?.setPower === false && this.features?.setSlope === false && this.features?.setResistance === false) {
115
- return true;
116
- }
117
114
  this.logEvent({ message: 'requestControl' });
118
115
  this.isCheckingControl = true;
119
116
  const data = Buffer.alloc(1);
@@ -72,14 +72,18 @@ class DirectConnectInterface extends node_events_1.EventEmitter {
72
72
  const protocol = this.getProtocol(service);
73
73
  const address = service.address;
74
74
  const services = service.serviceUUIDs?.map(uuid => (0, index_js_1.beautifyUUID)(uuid, false))?.join(',');
75
- return { interface: DirectConnectInterface.INTERFACE_NAME, name, protocol, address, services };
75
+ const id = service.serialNo || undefined;
76
+ return { interface: DirectConnectInterface.INTERFACE_NAME, name, protocol, address, services, ...(id ? { id } : {}) };
76
77
  }
77
78
  catch {
78
79
  return null;
79
80
  }
80
81
  }
81
82
  createPeripheralFromSettings(settings) {
82
- const info = this.getAll().find(a => a.service.name === settings.name);
83
+ const bleSettings = settings;
84
+ const all = this.getAll();
85
+ const info = (bleSettings.address && all.find(a => a.service.name === settings.name && a.service.address === bleSettings.address))
86
+ ?? all.find(a => a.service.name === settings.name);
83
87
  if (!info?.service)
84
88
  return null;
85
89
  return this.createPeripheral(info.service);
@@ -247,35 +251,68 @@ class DirectConnectInterface extends node_events_1.EventEmitter {
247
251
  const src = source === 'known-device' ? 'known-device' : 'mdns';
248
252
  try {
249
253
  service.transport = this.getName();
250
- const existing = this.find(service);
251
- if (existing) {
252
- const idx = this.services.indexOf(existing);
253
- this.services[idx] = { ts: Date.now(), service };
254
- if (src !== 'known-device' && existing.source === 'known-device') {
255
- this.services[idx].source = src;
256
- this.logEvent({ message: 'device re-announced', device: service.name, announcement: service, source });
257
- this.emitDevice(service);
258
- }
254
+ const sameAddress = this.findByNameAndAddress(service.name, service.address);
255
+ if (sameAddress) {
256
+ this.refreshSameAddressEntry(sameAddress, service, src, source);
257
+ return;
258
+ }
259
+ const sameName = this.findAllByName(service.name);
260
+ if (src === 'known-device' && sameName.some(a => a.source !== 'known-device')) {
261
+ return;
262
+ }
263
+ if (sameName.length === 0) {
264
+ this.announceNewEntry(service, src, source, 'device announced');
265
+ return;
259
266
  }
260
- else {
261
- this.services.push({ ts: Date.now(), service, source: src });
262
- if (!service.serviceUUIDs?.length)
263
- return;
264
- this.logEvent({ message: 'device announced', device: service.name, announcement: service, source });
265
- this.emitDevice(service);
266
- this.matching?.push(service.name);
267
+ const realEntries = sameName.filter(a => a.source !== 'known-device');
268
+ if (src !== 'known-device' && realEntries.length >= 1) {
269
+ this.announceNewEntry(service, src, source, 'device announced (name collision, distinct address)');
270
+ return;
267
271
  }
272
+ this.reannounceExistingEntry(sameName[0], service, src, source);
268
273
  }
269
274
  catch (err) {
270
275
  this.logError(err, 'addService');
271
276
  }
272
277
  }
273
- find(service) {
274
- return this.services.find(a => a.service.name === service.name && a.ts > Date.now() - DC_EXPIRATION_TIMEOUT);
278
+ refreshSameAddressEntry(sameAddress, service, src, source) {
279
+ const idx = this.services.indexOf(sameAddress);
280
+ const wasKnownDevicePlaceholder = sameAddress.source === 'known-device';
281
+ const nextSource = (wasKnownDevicePlaceholder && src !== 'known-device') ? src : sameAddress.source;
282
+ this.services[idx] = { ts: Date.now(), service, source: nextSource };
283
+ if (src !== 'known-device' && wasKnownDevicePlaceholder) {
284
+ this.logEvent({ message: 'device re-announced', device: service.name, announcement: service, source });
285
+ this.emitDevice(service);
286
+ }
287
+ }
288
+ announceNewEntry(service, src, source, message) {
289
+ this.services.push({ ts: Date.now(), service, source: src });
290
+ if (!service.serviceUUIDs?.length)
291
+ return;
292
+ this.logEvent({ message, device: service.name, announcement: service, source });
293
+ this.emitDevice(service);
294
+ this.matching?.push(service.name);
295
+ }
296
+ reannounceExistingEntry(existing, service, src, source) {
297
+ const idx = this.services.indexOf(existing);
298
+ this.services[idx] = { ts: Date.now(), service, source: src };
299
+ if (src !== 'known-device') {
300
+ this.logEvent({ message: 'device re-announced', device: service.name, announcement: service, source });
301
+ this.emitDevice(service);
302
+ }
303
+ }
304
+ findByNameAndAddress(name, address) {
305
+ return this.services.find(a => a.service.name === name && a.service.address === address && a.ts > Date.now() - DC_EXPIRATION_TIMEOUT);
306
+ }
307
+ findAllByName(name) {
308
+ return this.services.filter(a => a.service.name === name && a.ts > Date.now() - DC_EXPIRATION_TIMEOUT);
275
309
  }
276
310
  getAll() {
277
311
  return this.services.filter(a => a.ts > Date.now() - DC_EXPIRATION_TIMEOUT);
278
312
  }
313
+ hasNameCollision(name) {
314
+ return this.findAllByName(name).length > 1;
315
+ }
279
316
  setDebug(enabled) {
280
317
  this.debug = enabled;
281
318
  }
@@ -50,7 +50,7 @@ export default class BleAdapter extends IncyclistDevice {
50
50
  const info = peripheral.getInfo();
51
51
  const settings = { ...this.settings };
52
52
  settings.id = settings.id ?? info.id;
53
- settings.address = settings.address ?? info.address;
53
+ settings.address = info.address ?? settings.address;
54
54
  settings.name = settings.name ?? info.name;
55
55
  this.settings = settings;
56
56
  }
@@ -72,11 +72,13 @@ export default class BleAdapter extends IncyclistDevice {
72
72
  if (as.profile || settings.profile) {
73
73
  return (as.protocol === settings.protocol && as.profile === settings.profile && as.name === settings.name);
74
74
  }
75
- else {
76
- return (as.protocol === settings.protocol && ((as.name && settings.name && as.name === settings.name) ||
77
- (as.address && settings.address && as.address === settings.address) ||
78
- (as.id && settings.id && as.id === settings.id)));
79
- }
75
+ if (as.protocol !== settings.protocol)
76
+ return false;
77
+ if (as.id && settings.id)
78
+ return as.id === settings.id;
79
+ if (as.address && settings.address)
80
+ return as.address === settings.address;
81
+ return !!(as.name && settings.name && as.name === settings.name);
80
82
  }
81
83
  isSame(adapter) {
82
84
  return this.isEqual(adapter.getSettings());
@@ -246,6 +248,8 @@ export default class BleAdapter extends IncyclistDevice {
246
248
  }
247
249
  async initControl(_props) {
248
250
  }
251
+ async initControlBestEffort(_props) {
252
+ }
249
253
  getStartLogProps(props) {
250
254
  const capabilities = this.props?.capabilities;
251
255
  const { user, userWeight, bikeWeight, timeout, wheelDiameter, restart, scanOnly } = props ?? {};
@@ -281,11 +285,16 @@ export default class BleAdapter extends IncyclistDevice {
281
285
  this.stopped = true;
282
286
  return false;
283
287
  }
284
- await this.waitForInitialData(timeout);
285
288
  await this.checkCapabilities();
286
289
  const skipControl = this.props.capabilities && !this.props.capabilities.includes(IncyclistCapability.Control);
287
- if (this.hasCapability(IncyclistCapability.Control) && !skipControl)
290
+ const isControllable = this.hasCapability(IncyclistCapability.Control) && !skipControl;
291
+ if (isControllable) {
288
292
  await this.initControl(startProps);
293
+ }
294
+ else {
295
+ await this.initControlBestEffort(startProps);
296
+ }
297
+ await this.waitForInitialData(timeout);
289
298
  this.stopped = false;
290
299
  this.started = true;
291
300
  if (wasPaused)
@@ -7,6 +7,7 @@ import BleAdapter from '../base/adapter.js';
7
7
  import { cRR, cwABike } from './consts.js';
8
8
  import { IncyclistCapability } from '../../types/index.js';
9
9
  import { sleep } from '../../utils/utils.js';
10
+ import { InteruptableTask } from '../../utils/task.js';
10
11
  import { BleZwiftPlaySensor } from '../zwift/play/index.js';
11
12
  import { useFeatureToggle } from '../../features/index.js';
12
13
  import FMResistanceMode from '../../modes/fm-resistance.js';
@@ -16,6 +17,7 @@ export default class BleFmAdapter extends BleAdapter {
16
17
  distanceInternal = 0;
17
18
  connectPromise;
18
19
  requestControlRetryDelay = 1000;
20
+ requestControlTimeout = 10000;
19
21
  promiseSendUpdate;
20
22
  zwiftPlay;
21
23
  isHubInitialized = false;
@@ -163,8 +165,36 @@ export default class BleFmAdapter extends BleAdapter {
163
165
  if (!this.hasCapability(IncyclistCapability.Control))
164
166
  return;
165
167
  await this.establishControl();
168
+ await this.attemptStartRequest();
166
169
  await this.sendInitialRequest();
167
170
  }
171
+ async initControlBestEffort(_startProps) {
172
+ if (!this.isStarting())
173
+ return;
174
+ this.setConstants();
175
+ try {
176
+ const hasControl = await this.getSensor().requestControl();
177
+ if (hasControl) {
178
+ this.logEvent({ message: 'control granted (downgraded device)', device: this.getName(), interface: this.getInterface() });
179
+ await this.attemptStartRequest();
180
+ }
181
+ else {
182
+ this.logEvent({ message: 'could not establish control (downgraded device, non-fatal)', device: this.getName(), interface: this.getInterface() });
183
+ }
184
+ }
185
+ catch (err) {
186
+ this.logEvent({ message: 'could not establish control (downgraded device, non-fatal)', device: this.getName(), interface: this.getInterface(), error: err.message });
187
+ }
188
+ }
189
+ async attemptStartRequest() {
190
+ try {
191
+ const started = await this.getSensor().startRequest();
192
+ this.logEvent({ message: started ? 'start request acknowledged' : 'start request not acknowledged (non-fatal)', device: this.getName(), interface: this.getInterface() });
193
+ }
194
+ catch (err) {
195
+ this.logEvent({ message: 'start request failed (non-fatal)', device: this.getName(), interface: this.getInterface(), error: err.message });
196
+ }
197
+ }
168
198
  setConstants() {
169
199
  const mode = this.getCyclingMode();
170
200
  const sensor = this.getSensor();
@@ -190,7 +220,7 @@ export default class BleFmAdapter extends BleAdapter {
190
220
  let hasControl = false;
191
221
  let tryCnt = 0;
192
222
  const sensor = this.getSensor();
193
- return new Promise((resolve) => {
223
+ const controlPromise = new Promise((resolve) => {
194
224
  this.startTask.notifyOnStop(() => {
195
225
  resolve(false);
196
226
  });
@@ -214,6 +244,18 @@ export default class BleFmAdapter extends BleAdapter {
214
244
  };
215
245
  waitUntilControl();
216
246
  });
247
+ const waitTask = new InteruptableTask(controlPromise, {
248
+ timeout: this.requestControlTimeout,
249
+ name: 'establishControl',
250
+ errorOnTimeout: false,
251
+ log: this.logEvent.bind(this)
252
+ });
253
+ const granted = await waitTask.run();
254
+ if (!granted && this.isStarting()) {
255
+ this.logEvent({ message: 'could not establish control', device: this.getName(), interface: this.getInterface() });
256
+ throw new Error('could not establish control');
257
+ }
258
+ return granted;
217
259
  }
218
260
  async sendInitialRequest() {
219
261
  const startRequest = this.getCyclingMode().getBikeInitRequest();
@@ -109,9 +109,6 @@ export default class BleFitnessMachineDevice extends TBleSensor {
109
109
  }
110
110
  if (!this.isSubscribed())
111
111
  return false;
112
- if (this.features?.setPower === false && this.features?.setSlope === false && this.features?.setResistance === false) {
113
- return true;
114
- }
115
112
  this.logEvent({ message: 'requestControl' });
116
113
  this.isCheckingControl = true;
117
114
  const data = Buffer.alloc(1);
@@ -69,14 +69,18 @@ export default class DirectConnectInterface extends EventEmitter {
69
69
  const protocol = this.getProtocol(service);
70
70
  const address = service.address;
71
71
  const services = service.serviceUUIDs?.map(uuid => beautifyUUID(uuid, false))?.join(',');
72
- return { interface: DirectConnectInterface.INTERFACE_NAME, name, protocol, address, services };
72
+ const id = service.serialNo || undefined;
73
+ return { interface: DirectConnectInterface.INTERFACE_NAME, name, protocol, address, services, ...(id ? { id } : {}) };
73
74
  }
74
75
  catch {
75
76
  return null;
76
77
  }
77
78
  }
78
79
  createPeripheralFromSettings(settings) {
79
- const info = this.getAll().find(a => a.service.name === settings.name);
80
+ const bleSettings = settings;
81
+ const all = this.getAll();
82
+ const info = (bleSettings.address && all.find(a => a.service.name === settings.name && a.service.address === bleSettings.address))
83
+ ?? all.find(a => a.service.name === settings.name);
80
84
  if (!info?.service)
81
85
  return null;
82
86
  return this.createPeripheral(info.service);
@@ -244,35 +248,68 @@ export default class DirectConnectInterface extends EventEmitter {
244
248
  const src = source === 'known-device' ? 'known-device' : 'mdns';
245
249
  try {
246
250
  service.transport = this.getName();
247
- const existing = this.find(service);
248
- if (existing) {
249
- const idx = this.services.indexOf(existing);
250
- this.services[idx] = { ts: Date.now(), service };
251
- if (src !== 'known-device' && existing.source === 'known-device') {
252
- this.services[idx].source = src;
253
- this.logEvent({ message: 'device re-announced', device: service.name, announcement: service, source });
254
- this.emitDevice(service);
255
- }
251
+ const sameAddress = this.findByNameAndAddress(service.name, service.address);
252
+ if (sameAddress) {
253
+ this.refreshSameAddressEntry(sameAddress, service, src, source);
254
+ return;
255
+ }
256
+ const sameName = this.findAllByName(service.name);
257
+ if (src === 'known-device' && sameName.some(a => a.source !== 'known-device')) {
258
+ return;
259
+ }
260
+ if (sameName.length === 0) {
261
+ this.announceNewEntry(service, src, source, 'device announced');
262
+ return;
256
263
  }
257
- else {
258
- this.services.push({ ts: Date.now(), service, source: src });
259
- if (!service.serviceUUIDs?.length)
260
- return;
261
- this.logEvent({ message: 'device announced', device: service.name, announcement: service, source });
262
- this.emitDevice(service);
263
- this.matching?.push(service.name);
264
+ const realEntries = sameName.filter(a => a.source !== 'known-device');
265
+ if (src !== 'known-device' && realEntries.length >= 1) {
266
+ this.announceNewEntry(service, src, source, 'device announced (name collision, distinct address)');
267
+ return;
264
268
  }
269
+ this.reannounceExistingEntry(sameName[0], service, src, source);
265
270
  }
266
271
  catch (err) {
267
272
  this.logError(err, 'addService');
268
273
  }
269
274
  }
270
- find(service) {
271
- return this.services.find(a => a.service.name === service.name && a.ts > Date.now() - DC_EXPIRATION_TIMEOUT);
275
+ refreshSameAddressEntry(sameAddress, service, src, source) {
276
+ const idx = this.services.indexOf(sameAddress);
277
+ const wasKnownDevicePlaceholder = sameAddress.source === 'known-device';
278
+ const nextSource = (wasKnownDevicePlaceholder && src !== 'known-device') ? src : sameAddress.source;
279
+ this.services[idx] = { ts: Date.now(), service, source: nextSource };
280
+ if (src !== 'known-device' && wasKnownDevicePlaceholder) {
281
+ this.logEvent({ message: 'device re-announced', device: service.name, announcement: service, source });
282
+ this.emitDevice(service);
283
+ }
284
+ }
285
+ announceNewEntry(service, src, source, message) {
286
+ this.services.push({ ts: Date.now(), service, source: src });
287
+ if (!service.serviceUUIDs?.length)
288
+ return;
289
+ this.logEvent({ message, device: service.name, announcement: service, source });
290
+ this.emitDevice(service);
291
+ this.matching?.push(service.name);
292
+ }
293
+ reannounceExistingEntry(existing, service, src, source) {
294
+ const idx = this.services.indexOf(existing);
295
+ this.services[idx] = { ts: Date.now(), service, source: src };
296
+ if (src !== 'known-device') {
297
+ this.logEvent({ message: 'device re-announced', device: service.name, announcement: service, source });
298
+ this.emitDevice(service);
299
+ }
300
+ }
301
+ findByNameAndAddress(name, address) {
302
+ return this.services.find(a => a.service.name === name && a.service.address === address && a.ts > Date.now() - DC_EXPIRATION_TIMEOUT);
303
+ }
304
+ findAllByName(name) {
305
+ return this.services.filter(a => a.service.name === name && a.ts > Date.now() - DC_EXPIRATION_TIMEOUT);
272
306
  }
273
307
  getAll() {
274
308
  return this.services.filter(a => a.ts > Date.now() - DC_EXPIRATION_TIMEOUT);
275
309
  }
310
+ hasNameCollision(name) {
311
+ return this.findAllByName(name).length > 1;
312
+ }
276
313
  setDebug(enabled) {
277
314
  this.debug = enabled;
278
315
  }
@@ -48,6 +48,7 @@ export default class BleAdapter<TDeviceData extends BleDeviceData, TDevice exten
48
48
  protected waitForInitialData(startupTimeout: any): Promise<void>;
49
49
  protected checkCapabilities(): Promise<void>;
50
50
  protected initControl(_props?: BleStartProperties): Promise<void>;
51
+ protected initControlBestEffort(_props?: BleStartProperties): Promise<void>;
51
52
  protected getStartLogProps(props: BleStartProperties): BleStartProperties;
52
53
  protected startAdapter(startProps?: BleStartProperties): Promise<boolean>;
53
54
  startSensor(): Promise<boolean>;
@@ -12,6 +12,7 @@ export default class BleFmAdapter extends BleAdapter<IndoorBikeData, BleFitnessM
12
12
  protected distanceInternal: number;
13
13
  protected connectPromise: Promise<boolean> | undefined;
14
14
  protected requestControlRetryDelay: number;
15
+ protected requestControlTimeout: number;
15
16
  protected promiseSendUpdate: Promise<UpdateRequest | void> | undefined;
16
17
  protected zwiftPlay: BleZwiftPlaySensor | undefined;
17
18
  protected isHubInitialized: boolean;
@@ -28,6 +29,8 @@ export default class BleFmAdapter extends BleAdapter<IndoorBikeData, BleFitnessM
28
29
  protected checkResume(): boolean[];
29
30
  protected initVirtualShifting(initHub?: boolean): Promise<void>;
30
31
  protected initControl(_startProps?: BleStartProperties): Promise<void>;
32
+ protected initControlBestEffort(_startProps?: BleStartProperties): Promise<void>;
33
+ protected attemptStartRequest(): Promise<void>;
31
34
  protected setConstants(): void;
32
35
  protected establishControl(): Promise<boolean>;
33
36
  protected sendInitialRequest(): Promise<void>;
@@ -62,8 +62,13 @@ export default class DirectConnectInterface extends EventEmitter implements IBle
62
62
  name: string;
63
63
  }[];
64
64
  protected addService(service: MulticastDnsAnnouncement, source?: string): void;
65
- protected find(service: MulticastDnsAnnouncement): Announcement;
65
+ private refreshSameAddressEntry;
66
+ private announceNewEntry;
67
+ private reannounceExistingEntry;
68
+ protected findByNameAndAddress(name: string, address: string): Announcement;
69
+ protected findAllByName(name: string): Announcement[];
66
70
  protected getAll(): Announcement[];
71
+ hasNameCollision(name: string): boolean;
67
72
  setDebug(enabled: boolean): void;
68
73
  logEvent(event: any): void;
69
74
  logError(err: Error, fn: string, args?: any): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incyclist-devices",
3
- "version": "3.0.24",
3
+ "version": "3.0.26",
4
4
  "scripts": {
5
5
  "lint": "eslint . --ext .ts",
6
6
  "build": "npm run build:esm && npm run build:cjs",