incyclist-devices 3.0.25 → 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.
@@ -253,6 +253,8 @@ class BleAdapter extends adpater_js_1.default {
253
253
  }
254
254
  async initControl(_props) {
255
255
  }
256
+ async initControlBestEffort(_props) {
257
+ }
256
258
  getStartLogProps(props) {
257
259
  const capabilities = this.props?.capabilities;
258
260
  const { user, userWeight, bikeWeight, timeout, wheelDiameter, restart, scanOnly } = props ?? {};
@@ -288,11 +290,16 @@ class BleAdapter extends adpater_js_1.default {
288
290
  this.stopped = true;
289
291
  return false;
290
292
  }
291
- await this.waitForInitialData(timeout);
292
293
  await this.checkCapabilities();
293
294
  const skipControl = this.props.capabilities && !this.props.capabilities.includes(index_js_1.IncyclistCapability.Control);
294
- if (this.hasCapability(index_js_1.IncyclistCapability.Control) && !skipControl)
295
+ const isControllable = this.hasCapability(index_js_1.IncyclistCapability.Control) && !skipControl;
296
+ if (isControllable) {
295
297
  await this.initControl(startProps);
298
+ }
299
+ else {
300
+ await this.initControlBestEffort(startProps);
301
+ }
302
+ await this.waitForInitialData(timeout);
296
303
  this.stopped = false;
297
304
  this.started = true;
298
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);
@@ -248,6 +248,8 @@ export default class BleAdapter extends IncyclistDevice {
248
248
  }
249
249
  async initControl(_props) {
250
250
  }
251
+ async initControlBestEffort(_props) {
252
+ }
251
253
  getStartLogProps(props) {
252
254
  const capabilities = this.props?.capabilities;
253
255
  const { user, userWeight, bikeWeight, timeout, wheelDiameter, restart, scanOnly } = props ?? {};
@@ -283,11 +285,16 @@ export default class BleAdapter extends IncyclistDevice {
283
285
  this.stopped = true;
284
286
  return false;
285
287
  }
286
- await this.waitForInitialData(timeout);
287
288
  await this.checkCapabilities();
288
289
  const skipControl = this.props.capabilities && !this.props.capabilities.includes(IncyclistCapability.Control);
289
- if (this.hasCapability(IncyclistCapability.Control) && !skipControl)
290
+ const isControllable = this.hasCapability(IncyclistCapability.Control) && !skipControl;
291
+ if (isControllable) {
290
292
  await this.initControl(startProps);
293
+ }
294
+ else {
295
+ await this.initControlBestEffort(startProps);
296
+ }
297
+ await this.waitForInitialData(timeout);
291
298
  this.stopped = false;
292
299
  this.started = true;
293
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);
@@ -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>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incyclist-devices",
3
- "version": "3.0.25",
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",