incyclist-services 1.0.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.
- package/LICENSE +21 -0
- package/README.MD +28 -0
- package/lib/devices/access/index.d.ts +2 -0
- package/lib/devices/access/index.js +18 -0
- package/lib/devices/access/model.d.ts +24 -0
- package/lib/devices/access/model.js +2 -0
- package/lib/devices/access/service.d.ts +35 -0
- package/lib/devices/access/service.js +288 -0
- package/lib/devices/configuration/index.d.ts +2 -0
- package/lib/devices/configuration/index.js +18 -0
- package/lib/devices/configuration/model/app/index.d.ts +17 -0
- package/lib/devices/configuration/model/app/index.js +2 -0
- package/lib/devices/configuration/model/index.d.ts +3 -0
- package/lib/devices/configuration/model/index.js +19 -0
- package/lib/devices/configuration/model/repository/index.d.ts +35 -0
- package/lib/devices/configuration/model/repository/index.js +17 -0
- package/lib/devices/configuration/model/repository/legacy.d.ts +57 -0
- package/lib/devices/configuration/model/repository/legacy.js +2 -0
- package/lib/devices/configuration/model/service/index.d.ts +13 -0
- package/lib/devices/configuration/model/service/index.js +2 -0
- package/lib/devices/configuration/service.d.ts +53 -0
- package/lib/devices/configuration/service.js +585 -0
- package/lib/devices/consume/service.js +19 -0
- package/lib/devices/index.d.ts +3 -0
- package/lib/devices/index.js +19 -0
- package/lib/devices/ride/index.d.ts +2 -0
- package/lib/devices/ride/index.js +18 -0
- package/lib/devices/ride/model.d.ts +28 -0
- package/lib/devices/ride/model.js +2 -0
- package/lib/devices/ride/service.d.ts +44 -0
- package/lib/devices/ride/service.js +439 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +23 -0
- package/lib/settings/index.d.ts +3 -0
- package/lib/settings/index.js +9 -0
- package/lib/settings/user/bindings/index.d.ts +2 -0
- package/lib/settings/user/bindings/index.js +5 -0
- package/lib/settings/user/bindings/json.d.ts +15 -0
- package/lib/settings/user/bindings/json.js +112 -0
- package/lib/settings/user/bindings/types.d.ts +13 -0
- package/lib/settings/user/bindings/types.js +9 -0
- package/lib/settings/user/service.d.ts +23 -0
- package/lib/settings/user/service.js +174 -0
- package/lib/utils/clone.d.ts +1 -0
- package/lib/utils/clone.js +6 -0
- package/lib/utils/merge.d.ts +1 -0
- package/lib/utils/merge.js +21 -0
- package/lib/utils/sleep.d.ts +1 -0
- package/lib/utils/sleep.js +14 -0
- package/lib/utils/valid.d.ts +1 -0
- package/lib/utils/valid.js +15 -0
- package/package.json +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Incyclist
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.MD
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# incyclist-services
|
|
2
|
+
|
|
3
|
+
This Library contains the business logic used by the React components of the [Incyclist](https://incyclist.com) Indoor Cycling App.
|
|
4
|
+
|
|
5
|
+
Incyclist uses React to render the App Front-End for PC platforms ( Windows, Mac. Linux). It is planned that in the future, React Native will be used to render the Front-Ends for other platforms ( Android, IOS, AppleTV,...)
|
|
6
|
+
|
|
7
|
+
All Services will be accessed by the Front-End using
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
import {useXXX, initXXX} from {incyclist-devices}
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- useXXX can be used to consume a Service (e.g. `useDeviceConfiguration()` )
|
|
15
|
+
- initXXX can be used to perform a lazy initialization of the Service (e.g. `initUserSettings(binding)` )
|
|
16
|
+
|
|
17
|
+
where XXX represents the Service name
|
|
18
|
+
|
|
19
|
+
The following Services are currently implemented in this library:
|
|
20
|
+
|
|
21
|
+
## Settings
|
|
22
|
+
- [UserSettings](./doc/classes/UserSettingsService.md): manages the user settings
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## Devices
|
|
26
|
+
- [DeviceConfiguration](./doc/classes/DeviceConfigurationService.md): manages the user configuration of scanned/added/selected devices
|
|
27
|
+
- [DeviceAccess](./doc/classes/DeviceAccessService.md): manages the basic communication to the device (setting up interfacs, scanning,... )
|
|
28
|
+
- [Device](./src/devices/device/README.MD): allows the Front-End to communicate with a device (reading, writing data)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./model"), exports);
|
|
18
|
+
__exportStar(require("./service"), exports);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { IncyclistCapability } from "incyclist-devices";
|
|
2
|
+
export type InterfaceState = 'connected' | 'disconnected' | 'unknown' | 'connecting' | 'disconnecting' | 'unavailable';
|
|
3
|
+
export type ScanState = 'start-requested' | 'started' | 'stop-requested' | 'stopped' | 'idle';
|
|
4
|
+
export interface InterfaceInfo {
|
|
5
|
+
name: string;
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
state: InterfaceState;
|
|
8
|
+
isScanning: boolean;
|
|
9
|
+
properties?: InterfaceAccessProps;
|
|
10
|
+
}
|
|
11
|
+
export interface InterfaceAccessProps {
|
|
12
|
+
connectTimeout?: number;
|
|
13
|
+
scanTimeout?: number;
|
|
14
|
+
port?: number;
|
|
15
|
+
protocol?: string;
|
|
16
|
+
autoConnect?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface InterfaceList {
|
|
19
|
+
[index: string]: InterfaceInfo;
|
|
20
|
+
}
|
|
21
|
+
export interface ScanFilter {
|
|
22
|
+
interfaces?: string[];
|
|
23
|
+
capabilities?: (IncyclistCapability | 'bike')[];
|
|
24
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import EventEmitter from "events";
|
|
3
|
+
import { EventLogger } from "gd-eventlog";
|
|
4
|
+
import { DeviceSettings, IncyclistInterface } from "incyclist-devices";
|
|
5
|
+
import { InterfaceList, ScanFilter, InterfaceInfo, InterfaceAccessProps, ScanState } from "./model";
|
|
6
|
+
interface InternalScanState {
|
|
7
|
+
promises: (Promise<DeviceSettings[]>)[];
|
|
8
|
+
interfaces: IncyclistInterface[];
|
|
9
|
+
}
|
|
10
|
+
export declare class DeviceAccessService extends EventEmitter {
|
|
11
|
+
protected static _instance: DeviceAccessService;
|
|
12
|
+
protected interfaces: InterfaceList;
|
|
13
|
+
protected scanState: InternalScanState;
|
|
14
|
+
protected logger: EventLogger;
|
|
15
|
+
protected defaultProps: InterfaceAccessProps;
|
|
16
|
+
static getInstance(): DeviceAccessService;
|
|
17
|
+
constructor();
|
|
18
|
+
setDefaultInterfaceProperties(props: InterfaceAccessProps): void;
|
|
19
|
+
enableInterface(ifaceName: string, binding?: any, props?: InterfaceAccessProps): void;
|
|
20
|
+
disableInterface(ifaceName: string): void;
|
|
21
|
+
setInterfaceProperties(ifaceName: string, props: InterfaceAccessProps): void;
|
|
22
|
+
getInterfaceInfo(ifaceName: string): InterfaceInfo;
|
|
23
|
+
protected getInterface(ifaceName: string): IncyclistInterface;
|
|
24
|
+
connect(ifaceName: string): Promise<boolean>;
|
|
25
|
+
disconnect(ifaceName?: string): Promise<boolean>;
|
|
26
|
+
scan(filter?: ScanFilter): Promise<DeviceSettings[]>;
|
|
27
|
+
getProtocols(ifaceName: string): string[];
|
|
28
|
+
protected dummyScan(): Promise<DeviceSettings[]>;
|
|
29
|
+
protected emitScanStateChange(state: ScanState): void;
|
|
30
|
+
stopScan(): Promise<boolean>;
|
|
31
|
+
isScanning(ifaceName?: string): boolean;
|
|
32
|
+
protected getInterfacesForScan(filter?: ScanFilter): IncyclistInterface[];
|
|
33
|
+
}
|
|
34
|
+
export declare const useDeviceAccess: () => DeviceAccessService;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,288 @@
|
|
|
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.useDeviceAccess = exports.DeviceAccessService = void 0;
|
|
16
|
+
const events_1 = __importDefault(require("events"));
|
|
17
|
+
const gd_eventlog_1 = require("gd-eventlog");
|
|
18
|
+
const incyclist_devices_1 = require("incyclist-devices");
|
|
19
|
+
const clone_1 = __importDefault(require("../../utils/clone"));
|
|
20
|
+
const merge_1 = require("../../utils/merge");
|
|
21
|
+
const sleep_1 = require("../../utils/sleep");
|
|
22
|
+
const configuration_1 = require("../configuration");
|
|
23
|
+
class DeviceAccessService extends events_1.default {
|
|
24
|
+
static getInstance() {
|
|
25
|
+
if (!DeviceAccessService._instance)
|
|
26
|
+
DeviceAccessService._instance = new DeviceAccessService();
|
|
27
|
+
return DeviceAccessService._instance;
|
|
28
|
+
}
|
|
29
|
+
constructor() {
|
|
30
|
+
super();
|
|
31
|
+
this.interfaces = {};
|
|
32
|
+
this.scanState = null;
|
|
33
|
+
this.logger = new gd_eventlog_1.EventLogger('DeviceAccess');
|
|
34
|
+
this.defaultProps = {};
|
|
35
|
+
}
|
|
36
|
+
setDefaultInterfaceProperties(props) {
|
|
37
|
+
this.defaultProps = props;
|
|
38
|
+
}
|
|
39
|
+
enableInterface(ifaceName, binding, props = {}) {
|
|
40
|
+
const existing = this.interfaces[ifaceName];
|
|
41
|
+
if (!binding && !existing) {
|
|
42
|
+
throw new Error('Interface has not been initialized with binding');
|
|
43
|
+
}
|
|
44
|
+
if (!existing) {
|
|
45
|
+
const properties = (0, clone_1.default)(this.defaultProps);
|
|
46
|
+
(0, merge_1.merge)(properties, props);
|
|
47
|
+
const info = { name: ifaceName, interface: incyclist_devices_1.InterfaceFactory.create(ifaceName, { binding }), enabled: true, isScanning: false, properties, state: 'unknown' };
|
|
48
|
+
this.interfaces[ifaceName] = info;
|
|
49
|
+
info.interface.setBinding(binding);
|
|
50
|
+
const keys = Object.keys(this.interfaces);
|
|
51
|
+
const interfaces = keys.map(name => (Object.assign(Object.assign({}, this.interfaces[name]), { name })));
|
|
52
|
+
this.emit('interface-changed', ifaceName, this.interfaces[ifaceName], interfaces);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
if (this.isScanning(ifaceName)) {
|
|
56
|
+
throw new Error('Illegal State, enable Interface cannot be called during an ongoing scan');
|
|
57
|
+
}
|
|
58
|
+
if (binding)
|
|
59
|
+
existing.interface.setBinding(binding);
|
|
60
|
+
existing.enabled = true;
|
|
61
|
+
(0, merge_1.merge)(existing.properties || this.defaultProps, props);
|
|
62
|
+
this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
disableInterface(ifaceName) {
|
|
66
|
+
const existing = this.interfaces[ifaceName];
|
|
67
|
+
if (!existing)
|
|
68
|
+
return;
|
|
69
|
+
if (this.isScanning(ifaceName)) {
|
|
70
|
+
const info = this.interfaces[ifaceName];
|
|
71
|
+
info.interface.stopScan().then((stopped) => {
|
|
72
|
+
this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
|
|
73
|
+
info.isScanning = !stopped;
|
|
74
|
+
if (stopped)
|
|
75
|
+
this.disableInterface(ifaceName);
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
existing.enabled = false;
|
|
80
|
+
this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
|
|
81
|
+
}
|
|
82
|
+
setInterfaceProperties(ifaceName, props) {
|
|
83
|
+
if (this.isScanning(ifaceName)) {
|
|
84
|
+
const info = this.interfaces[ifaceName];
|
|
85
|
+
info.interface.stopScan().then((stopped) => {
|
|
86
|
+
this.emit('interface-changed', 'ifaceName', this.interfaces[ifaceName]);
|
|
87
|
+
info.isScanning = !stopped;
|
|
88
|
+
if (stopped)
|
|
89
|
+
this.setInterfaceProperties(ifaceName, props);
|
|
90
|
+
});
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const info = this.interfaces[ifaceName];
|
|
94
|
+
if (!info)
|
|
95
|
+
return;
|
|
96
|
+
const properties = (0, clone_1.default)(this.defaultProps);
|
|
97
|
+
(0, merge_1.merge)(properties, props);
|
|
98
|
+
info.properties = properties;
|
|
99
|
+
info.isScanning = false;
|
|
100
|
+
this.emit('interface-changed', 'ifaceName', this.interfaces[ifaceName]);
|
|
101
|
+
}
|
|
102
|
+
getInterfaceInfo(ifaceName) {
|
|
103
|
+
return this.interfaces[ifaceName];
|
|
104
|
+
}
|
|
105
|
+
getInterface(ifaceName) {
|
|
106
|
+
const info = this.interfaces[ifaceName];
|
|
107
|
+
return info === null || info === void 0 ? void 0 : info.interface;
|
|
108
|
+
}
|
|
109
|
+
connect(ifaceName) {
|
|
110
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
const impl = this.getInterface(ifaceName);
|
|
112
|
+
if (!impl) {
|
|
113
|
+
this.emit('interface-changed', ifaceName, { name: ifaceName, state: 'unavailable', isScanning: false });
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const prevState = this.interfaces[ifaceName].state;
|
|
117
|
+
if (prevState === 'connected')
|
|
118
|
+
return true;
|
|
119
|
+
this.interfaces[ifaceName].state = 'connecting';
|
|
120
|
+
this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
|
|
121
|
+
const connected = yield impl.connect();
|
|
122
|
+
const state = connected ? 'connected' : 'disconnected';
|
|
123
|
+
this.interfaces[ifaceName].state = state;
|
|
124
|
+
this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
|
|
125
|
+
return connected;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
disconnect(ifaceName) {
|
|
129
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
130
|
+
if (!ifaceName) {
|
|
131
|
+
const promises = Object.keys(this.interfaces).map(i => this.disconnect(i));
|
|
132
|
+
const result = yield Promise.allSettled(promises);
|
|
133
|
+
const failed = result.find(res => (res.status === 'rejected' || (res.value === true)));
|
|
134
|
+
this.removeAllListeners();
|
|
135
|
+
return failed === undefined;
|
|
136
|
+
}
|
|
137
|
+
const impl = this.getInterface(ifaceName);
|
|
138
|
+
if (!impl)
|
|
139
|
+
return true;
|
|
140
|
+
const prevState = this.interfaces[ifaceName].state;
|
|
141
|
+
this.interfaces[ifaceName].state = 'disconnecting';
|
|
142
|
+
this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
|
|
143
|
+
const disconnected = yield impl.disconnect();
|
|
144
|
+
const state = disconnected ? 'disconnected' : prevState;
|
|
145
|
+
this.interfaces[ifaceName].state = state;
|
|
146
|
+
this.emit('interface-changed', ifaceName, this.interfaces[ifaceName]);
|
|
147
|
+
return disconnected;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
scan(filter = {}) {
|
|
151
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
152
|
+
this.logger.logEvent({ message: 'device scan start', filter });
|
|
153
|
+
const detected = [];
|
|
154
|
+
const startedAdapters = [];
|
|
155
|
+
if (!this.isScanning()) {
|
|
156
|
+
this.emitScanStateChange('start-requested');
|
|
157
|
+
this.scanState = {
|
|
158
|
+
promises: [],
|
|
159
|
+
interfaces: []
|
|
160
|
+
};
|
|
161
|
+
const interfaces = this.scanState.interfaces = this.getInterfacesForScan(filter);
|
|
162
|
+
const adapters = [];
|
|
163
|
+
interfaces.forEach((i) => {
|
|
164
|
+
i.on('device', (deviceSettings) => __awaiter(this, void 0, void 0, function* () {
|
|
165
|
+
if (adapters.find(a => a.isEqual(deviceSettings)))
|
|
166
|
+
return;
|
|
167
|
+
this.emit('device', deviceSettings);
|
|
168
|
+
const adapter = incyclist_devices_1.AdapterFactory.create(deviceSettings);
|
|
169
|
+
adapters.push(adapter);
|
|
170
|
+
adapter.on('device-info', (settings, info) => {
|
|
171
|
+
this.emit('device-info', deviceSettings, Object.assign(Object.assign({}, info), { displayName: adapter.getUniqueName() }));
|
|
172
|
+
});
|
|
173
|
+
detected.push(deviceSettings);
|
|
174
|
+
if (adapter.getSettings().interface !== 'ble') {
|
|
175
|
+
try {
|
|
176
|
+
yield adapter.start();
|
|
177
|
+
while (this.scanState) {
|
|
178
|
+
yield (0, sleep_1.sleep)(100);
|
|
179
|
+
}
|
|
180
|
+
yield adapter.stop();
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
console.log('~~~ start error', err);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}));
|
|
187
|
+
const ifaceName = i.getName();
|
|
188
|
+
const info = this.interfaces[ifaceName];
|
|
189
|
+
info.isScanning = true;
|
|
190
|
+
const props = info.properties || this.defaultProps;
|
|
191
|
+
const { scanTimeout, port, protocol } = props;
|
|
192
|
+
const properties = ifaceName === 'tcpip' || ifaceName === 'serial' ? { timeout: scanTimeout, port: port === null || port === void 0 ? void 0 : port.toString(), protocol } : { timeout: scanTimeout };
|
|
193
|
+
this.scanState.promises.push(i.scan(properties));
|
|
194
|
+
});
|
|
195
|
+
this.emitScanStateChange('started');
|
|
196
|
+
try {
|
|
197
|
+
if (this.scanState.promises.length === 0) {
|
|
198
|
+
this.scanState.promises.push(this.dummyScan());
|
|
199
|
+
}
|
|
200
|
+
yield Promise.allSettled(this.scanState.promises);
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
this.logger.logEvent({ message: 'device scan finished with errors', filter, error: err.message, stack: err.stack });
|
|
204
|
+
}
|
|
205
|
+
this.scanState = null;
|
|
206
|
+
interfaces.forEach((i) => {
|
|
207
|
+
i.removeAllListeners('device');
|
|
208
|
+
this.interfaces[i.getName()].isScanning = false;
|
|
209
|
+
if (i.getName() === 'tcpip')
|
|
210
|
+
this.interfaces[i.getName()];
|
|
211
|
+
});
|
|
212
|
+
this.emitScanStateChange('stopped');
|
|
213
|
+
this.logger.logEvent({ message: 'device scan finished', filter, detected });
|
|
214
|
+
return detected;
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
getProtocols(ifaceName) {
|
|
219
|
+
if (ifaceName !== 'serial' && ifaceName !== 'tcpip')
|
|
220
|
+
return [];
|
|
221
|
+
if (ifaceName === 'tcpip')
|
|
222
|
+
return ['Daum Premium'];
|
|
223
|
+
return incyclist_devices_1.SerialAdapterFactory.getInstance().adapters.map(a => a.protocol);
|
|
224
|
+
}
|
|
225
|
+
dummyScan() {
|
|
226
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
227
|
+
return new Promise(done => {
|
|
228
|
+
const timeout = this.defaultProps.scanTimeout || 5000;
|
|
229
|
+
const timeDone = Date.now() + timeout;
|
|
230
|
+
const iv = setInterval(() => {
|
|
231
|
+
if (Date.now() > timeDone) {
|
|
232
|
+
clearInterval(iv);
|
|
233
|
+
done([]);
|
|
234
|
+
}
|
|
235
|
+
}, 100);
|
|
236
|
+
this.once('stop-requested', () => {
|
|
237
|
+
clearInterval(iv);
|
|
238
|
+
done([]);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
emitScanStateChange(state) {
|
|
244
|
+
this.emit('scanstate-changed', state);
|
|
245
|
+
}
|
|
246
|
+
stopScan() {
|
|
247
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
248
|
+
if (!this.isScanning())
|
|
249
|
+
return;
|
|
250
|
+
this.emitScanStateChange('stop-requested');
|
|
251
|
+
const interfaces = this.scanState.interfaces;
|
|
252
|
+
const promises = interfaces.map(i => i.stopScan().catch());
|
|
253
|
+
let result;
|
|
254
|
+
try {
|
|
255
|
+
result = yield Promise.allSettled(promises);
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
this.logger.logEvent({ message: 'stop device scan finished with errors', error: err.message, stack: err.stack });
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
this.scanState.promises = [];
|
|
262
|
+
this.emitScanStateChange('stopped');
|
|
263
|
+
this.logger.logEvent({ message: 'stop device scan finished', stopScanresult: result });
|
|
264
|
+
return true;
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
isScanning(ifaceName) {
|
|
268
|
+
if (!ifaceName)
|
|
269
|
+
return this.scanState !== null && this.scanState.promises !== null && this.scanState.promises.length > 0;
|
|
270
|
+
else
|
|
271
|
+
return this.interfaces[ifaceName].isScanning;
|
|
272
|
+
}
|
|
273
|
+
getInterfacesForScan(filter) {
|
|
274
|
+
const keys = Object.keys(this.interfaces);
|
|
275
|
+
const config = (0, configuration_1.useDeviceConfiguration)();
|
|
276
|
+
const enabledInterfaces = keys.filter(i => this.interfaces[i].enabled && config.isInterfaceEnabled(i));
|
|
277
|
+
const interfaceFilter = filter === null || filter === void 0 ? void 0 : filter.interfaces;
|
|
278
|
+
let interfaces = enabledInterfaces.map(name => this.interfaces[name].interface);
|
|
279
|
+
if (interfaceFilter) {
|
|
280
|
+
const remaining = enabledInterfaces.filter(i => interfaceFilter.includes(i));
|
|
281
|
+
interfaces = remaining.map(name => this.interfaces[name].interface);
|
|
282
|
+
}
|
|
283
|
+
return interfaces;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
exports.DeviceAccessService = DeviceAccessService;
|
|
287
|
+
const useDeviceAccess = () => DeviceAccessService.getInstance();
|
|
288
|
+
exports.useDeviceAccess = useDeviceAccess;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./model"), exports);
|
|
18
|
+
__exportStar(require("./service"), exports);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { IncyclistCapability } from 'incyclist-devices';
|
|
2
|
+
export type ExtendedIncyclistCapability = IncyclistCapability | 'bike';
|
|
3
|
+
export interface DeviceInformation {
|
|
4
|
+
udid: string;
|
|
5
|
+
name: string;
|
|
6
|
+
selected: boolean;
|
|
7
|
+
mode?: string;
|
|
8
|
+
modeSetting?: any;
|
|
9
|
+
}
|
|
10
|
+
export interface CapabilityInformation {
|
|
11
|
+
capability: ExtendedIncyclistCapability;
|
|
12
|
+
devices: DeviceInformation[];
|
|
13
|
+
disabled: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface DeviceConfigurationInfo {
|
|
16
|
+
[index: string]: CapabilityInformation;
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./app"), exports);
|
|
18
|
+
__exportStar(require("./repository"), exports);
|
|
19
|
+
__exportStar(require("./service"), exports);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { SerialDeviceSettings, AntDeviceSettings, BleDeviceSettings } from 'incyclist-devices';
|
|
2
|
+
import { ExtendedIncyclistCapability } from '../app';
|
|
3
|
+
export type IncyclistDeviceSettings = SerialDeviceSettings | AntDeviceSettings | BleDeviceSettings;
|
|
4
|
+
export * from './legacy';
|
|
5
|
+
export interface DeviceListEntry {
|
|
6
|
+
udid: string;
|
|
7
|
+
settings: IncyclistDeviceSettings;
|
|
8
|
+
displayName?: string;
|
|
9
|
+
mode?: string;
|
|
10
|
+
modes?: {
|
|
11
|
+
[index: string]: any;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export interface InterfaceSetting {
|
|
15
|
+
name: string;
|
|
16
|
+
enabled: boolean;
|
|
17
|
+
port?: number | string;
|
|
18
|
+
protocol?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ModeListEntry {
|
|
21
|
+
mid: string;
|
|
22
|
+
mode: string;
|
|
23
|
+
setting: any;
|
|
24
|
+
}
|
|
25
|
+
export type CapabilitySetting = {
|
|
26
|
+
selected: string | undefined;
|
|
27
|
+
capability: ExtendedIncyclistCapability;
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
devices: string[];
|
|
30
|
+
};
|
|
31
|
+
export interface DeviceConfigurationSettings {
|
|
32
|
+
interfaces?: InterfaceSetting[];
|
|
33
|
+
capabilities?: CapabilitySetting[];
|
|
34
|
+
devices?: DeviceListEntry[];
|
|
35
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./legacy"), exports);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface LegacyGearSetting {
|
|
2
|
+
name: string;
|
|
3
|
+
displayName?: string;
|
|
4
|
+
selected: boolean;
|
|
5
|
+
protocol: string;
|
|
6
|
+
deviceID?: string;
|
|
7
|
+
profile?: string;
|
|
8
|
+
host?: string;
|
|
9
|
+
port?: string;
|
|
10
|
+
interface: string;
|
|
11
|
+
}
|
|
12
|
+
export interface LegacyDeviceSelectionSettings {
|
|
13
|
+
bikes?: LegacyGearSetting[];
|
|
14
|
+
hrms?: LegacyGearSetting[];
|
|
15
|
+
disableHrm?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface LegacySerialPortInfo {
|
|
18
|
+
[index: string]: {
|
|
19
|
+
name: string;
|
|
20
|
+
enabled: boolean;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export interface LegacySerialSettings {
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
protocols: {
|
|
26
|
+
name: string;
|
|
27
|
+
selected: boolean;
|
|
28
|
+
id: number;
|
|
29
|
+
}[];
|
|
30
|
+
}
|
|
31
|
+
export interface LegacyAntSettings {
|
|
32
|
+
enabled: boolean;
|
|
33
|
+
bike: boolean;
|
|
34
|
+
hrm: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface LegacyDeviceConnectionSettings {
|
|
37
|
+
serial: LegacySerialSettings & LegacySerialPortInfo;
|
|
38
|
+
ant: LegacyAntSettings;
|
|
39
|
+
tcpip: {
|
|
40
|
+
enabled: boolean;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export interface IncyclistModeSettings {
|
|
44
|
+
mode: string;
|
|
45
|
+
settings: any;
|
|
46
|
+
}
|
|
47
|
+
export interface LegacyModeSettings {
|
|
48
|
+
[index: string]: IncyclistModeSettings;
|
|
49
|
+
}
|
|
50
|
+
export interface LegacyPreferences {
|
|
51
|
+
gear: LegacyModeSettings;
|
|
52
|
+
}
|
|
53
|
+
export interface LegacySettings {
|
|
54
|
+
connections?: LegacyDeviceConnectionSettings;
|
|
55
|
+
gearSelection?: LegacyDeviceSelectionSettings;
|
|
56
|
+
modeSettings?: LegacyModeSettings;
|
|
57
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { IncyclistDeviceAdapter } from "incyclist-devices";
|
|
2
|
+
import { ExtendedIncyclistCapability } from "../app";
|
|
3
|
+
export interface AdapterInfo {
|
|
4
|
+
udid: string;
|
|
5
|
+
adapter: IncyclistDeviceAdapter;
|
|
6
|
+
capabilities: ExtendedIncyclistCapability[];
|
|
7
|
+
}
|
|
8
|
+
export interface DeviceModeInfo {
|
|
9
|
+
udid: string;
|
|
10
|
+
mode: string;
|
|
11
|
+
settings: any;
|
|
12
|
+
options?: string[];
|
|
13
|
+
}
|