react-native-ble-mesh 1.1.1 → 2.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/README.md +288 -172
- package/docs/IOS-BACKGROUND-BLE.md +231 -0
- package/docs/OPTIMIZATION.md +70 -0
- package/docs/SPEC-v2.1.md +308 -0
- package/package.json +1 -1
- package/src/MeshNetwork.js +659 -465
- package/src/constants/index.js +1 -0
- package/src/crypto/AutoCrypto.js +79 -0
- package/src/crypto/CryptoProvider.js +99 -0
- package/src/crypto/index.js +15 -63
- package/src/crypto/providers/ExpoCryptoProvider.js +125 -0
- package/src/crypto/providers/QuickCryptoProvider.js +134 -0
- package/src/crypto/providers/TweetNaClProvider.js +124 -0
- package/src/crypto/providers/index.js +11 -0
- package/src/errors/MeshError.js +2 -1
- package/src/expo/withBLEMesh.js +102 -0
- package/src/hooks/useMesh.js +30 -9
- package/src/hooks/useMessages.js +2 -0
- package/src/index.js +23 -8
- package/src/mesh/dedup/DedupManager.js +36 -10
- package/src/mesh/fragment/Assembler.js +5 -0
- package/src/mesh/index.js +1 -1
- package/src/mesh/monitor/ConnectionQuality.js +408 -0
- package/src/mesh/monitor/NetworkMonitor.js +327 -316
- package/src/mesh/monitor/index.js +7 -3
- package/src/mesh/peer/PeerManager.js +6 -1
- package/src/mesh/router/MessageRouter.js +26 -15
- package/src/mesh/router/RouteTable.js +7 -1
- package/src/mesh/store/StoreAndForwardManager.js +295 -297
- package/src/mesh/store/index.js +1 -1
- package/src/service/BatteryOptimizer.js +282 -278
- package/src/service/EmergencyManager.js +224 -214
- package/src/service/HandshakeManager.js +167 -13
- package/src/service/MeshService.js +72 -6
- package/src/service/SessionManager.js +77 -2
- package/src/service/audio/AudioManager.js +8 -2
- package/src/service/file/FileAssembler.js +106 -0
- package/src/service/file/FileChunker.js +79 -0
- package/src/service/file/FileManager.js +307 -0
- package/src/service/file/FileMessage.js +122 -0
- package/src/service/file/index.js +15 -0
- package/src/service/text/broadcast/BroadcastManager.js +16 -0
- package/src/transport/BLETransport.js +131 -9
- package/src/transport/MockTransport.js +1 -1
- package/src/transport/MultiTransport.js +305 -0
- package/src/transport/WiFiDirectTransport.js +295 -0
- package/src/transport/adapters/NodeBLEAdapter.js +34 -0
- package/src/transport/adapters/RNBLEAdapter.js +56 -1
- package/src/transport/index.js +6 -0
- package/src/utils/compression.js +291 -291
- package/src/crypto/aead.js +0 -189
- package/src/crypto/chacha20.js +0 -181
- package/src/crypto/hkdf.js +0 -187
- package/src/crypto/hmac.js +0 -143
- package/src/crypto/keys/KeyManager.js +0 -271
- package/src/crypto/keys/KeyPair.js +0 -216
- package/src/crypto/keys/SecureStorage.js +0 -219
- package/src/crypto/keys/index.js +0 -32
- package/src/crypto/noise/handshake.js +0 -410
- package/src/crypto/noise/index.js +0 -27
- package/src/crypto/noise/session.js +0 -253
- package/src/crypto/noise/state.js +0 -268
- package/src/crypto/poly1305.js +0 -113
- package/src/crypto/sha256.js +0 -240
- package/src/crypto/x25519.js +0 -154
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @fileoverview Battery Optimizer with Adaptive Power Modes
|
|
5
5
|
* @module service/BatteryOptimizer
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* Provides three power profiles (high/balanced/low) with automatic
|
|
8
8
|
* scanning adjustments based on battery level and network activity.
|
|
9
|
-
*
|
|
9
|
+
*
|
|
10
10
|
* Target: <5% battery drain per hour in balanced mode.
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -17,10 +17,10 @@ const EventEmitter = require('../utils/EventEmitter');
|
|
|
17
17
|
* @constant {Object}
|
|
18
18
|
*/
|
|
19
19
|
const BATTERY_MODE = Object.freeze({
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
HIGH_PERFORMANCE: 'high',
|
|
21
|
+
BALANCED: 'balanced',
|
|
22
|
+
LOW_POWER: 'low',
|
|
23
|
+
AUTO: 'auto'
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -39,39 +39,39 @@ const BATTERY_MODE = Object.freeze({
|
|
|
39
39
|
* @constant {Object.<string, BatteryProfile>}
|
|
40
40
|
*/
|
|
41
41
|
const DEFAULT_PROFILES = Object.freeze({
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
42
|
+
[BATTERY_MODE.HIGH_PERFORMANCE]: {
|
|
43
|
+
scanIntervalMs: 100,
|
|
44
|
+
scanWindowMs: 50,
|
|
45
|
+
connectionIntervalMs: 7.5,
|
|
46
|
+
advertisingIntervalMs: 100,
|
|
47
|
+
heartbeatIntervalMs: 10000,
|
|
48
|
+
description: 'Maximum performance, high battery usage'
|
|
49
|
+
},
|
|
50
|
+
[BATTERY_MODE.BALANCED]: {
|
|
51
|
+
scanIntervalMs: 500,
|
|
52
|
+
scanWindowMs: 100,
|
|
53
|
+
connectionIntervalMs: 30,
|
|
54
|
+
advertisingIntervalMs: 500,
|
|
55
|
+
heartbeatIntervalMs: 30000,
|
|
56
|
+
description: 'Balanced performance and battery, <5% drain/hour'
|
|
57
|
+
},
|
|
58
|
+
[BATTERY_MODE.LOW_POWER]: {
|
|
59
|
+
scanIntervalMs: 2000,
|
|
60
|
+
scanWindowMs: 200,
|
|
61
|
+
connectionIntervalMs: 100,
|
|
62
|
+
advertisingIntervalMs: 2000,
|
|
63
|
+
heartbeatIntervalMs: 60000,
|
|
64
|
+
description: 'Minimum battery usage, reduced responsiveness'
|
|
65
|
+
},
|
|
66
|
+
[BATTERY_MODE.AUTO]: {
|
|
67
|
+
// Auto mode uses balanced as base, adjusts dynamically
|
|
68
|
+
scanIntervalMs: 500,
|
|
69
|
+
scanWindowMs: 100,
|
|
70
|
+
connectionIntervalMs: 30,
|
|
71
|
+
advertisingIntervalMs: 500,
|
|
72
|
+
heartbeatIntervalMs: 30000,
|
|
73
|
+
description: 'Automatic adjustment based on battery level'
|
|
74
|
+
}
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
/**
|
|
@@ -79,10 +79,10 @@ const DEFAULT_PROFILES = Object.freeze({
|
|
|
79
79
|
* @constant {Object}
|
|
80
80
|
*/
|
|
81
81
|
const BATTERY_THRESHOLDS = Object.freeze({
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
HIGH: 50, // Above 50%: high performance
|
|
83
|
+
MEDIUM: 20, // 20-50%: balanced
|
|
84
|
+
LOW: 10, // 10-20%: low power
|
|
85
|
+
CRITICAL: 5 // Below 5%: ultra low power
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
/**
|
|
@@ -90,408 +90,412 @@ const BATTERY_THRESHOLDS = Object.freeze({
|
|
|
90
90
|
* @constant {Object}
|
|
91
91
|
*/
|
|
92
92
|
const DEFAULT_CONFIG = Object.freeze({
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
93
|
+
/** Initial battery mode */
|
|
94
|
+
initialMode: BATTERY_MODE.BALANCED,
|
|
95
|
+
/** Enable automatic mode switching */
|
|
96
|
+
autoAdjust: true,
|
|
97
|
+
/** Battery check interval (ms) */
|
|
98
|
+
batteryCheckIntervalMs: 60000,
|
|
99
|
+
/** Activity-based adjustment enabled */
|
|
100
|
+
activityAdjust: true,
|
|
101
|
+
/** Inactivity timeout for power reduction (ms) */
|
|
102
|
+
inactivityTimeoutMs: 5 * 60 * 1000
|
|
103
103
|
});
|
|
104
104
|
|
|
105
105
|
/**
|
|
106
106
|
* Battery Optimizer for adaptive power management.
|
|
107
|
-
*
|
|
107
|
+
*
|
|
108
108
|
* @class BatteryOptimizer
|
|
109
109
|
* @extends EventEmitter
|
|
110
110
|
* @example
|
|
111
111
|
* const optimizer = new BatteryOptimizer();
|
|
112
|
-
*
|
|
112
|
+
*
|
|
113
113
|
* // Set mode manually
|
|
114
114
|
* await optimizer.setMode(BATTERY_MODE.BALANCED);
|
|
115
|
-
*
|
|
115
|
+
*
|
|
116
116
|
* // Enable auto-adjustment
|
|
117
117
|
* optimizer.setAutoAdjust(true);
|
|
118
|
-
*
|
|
118
|
+
*
|
|
119
119
|
* // Report battery level
|
|
120
120
|
* optimizer.updateBatteryLevel(75);
|
|
121
|
-
*
|
|
121
|
+
*
|
|
122
122
|
* // Get current profile
|
|
123
123
|
* const profile = optimizer.getCurrentProfile();
|
|
124
124
|
*/
|
|
125
125
|
class BatteryOptimizer extends EventEmitter {
|
|
126
|
-
|
|
126
|
+
/**
|
|
127
127
|
* Creates a new BatteryOptimizer instance.
|
|
128
128
|
* @param {Object} [options={}] - Configuration options
|
|
129
129
|
*/
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
constructor(options = {}) {
|
|
131
|
+
super();
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
/**
|
|
134
134
|
* Configuration
|
|
135
135
|
* @type {Object}
|
|
136
136
|
* @private
|
|
137
137
|
*/
|
|
138
|
-
|
|
138
|
+
this._config = { ...DEFAULT_CONFIG, ...options };
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
/**
|
|
141
141
|
* Battery profiles
|
|
142
142
|
* @type {Object.<string, BatteryProfile>}
|
|
143
143
|
* @private
|
|
144
144
|
*/
|
|
145
|
-
|
|
145
|
+
this._profiles = { ...DEFAULT_PROFILES };
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
/**
|
|
148
148
|
* Current battery mode
|
|
149
149
|
* @type {string}
|
|
150
150
|
* @private
|
|
151
151
|
*/
|
|
152
|
-
|
|
152
|
+
this._currentMode = this._config.initialMode;
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
/**
|
|
155
155
|
* Current battery level (0-100)
|
|
156
156
|
* @type {number}
|
|
157
157
|
* @private
|
|
158
158
|
*/
|
|
159
|
-
|
|
159
|
+
this._batteryLevel = 100;
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
/**
|
|
162
162
|
* Is charging
|
|
163
163
|
* @type {boolean}
|
|
164
164
|
* @private
|
|
165
165
|
*/
|
|
166
|
-
|
|
166
|
+
this._isCharging = false;
|
|
167
167
|
|
|
168
|
-
|
|
168
|
+
/**
|
|
169
169
|
* Last activity timestamp
|
|
170
170
|
* @type {number}
|
|
171
171
|
* @private
|
|
172
172
|
*/
|
|
173
|
-
|
|
173
|
+
this._lastActivityTime = Date.now();
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
/**
|
|
176
176
|
* Auto adjustment enabled
|
|
177
177
|
* @type {boolean}
|
|
178
178
|
* @private
|
|
179
179
|
*/
|
|
180
|
-
|
|
180
|
+
this._autoAdjust = this._config.autoAdjust;
|
|
181
181
|
|
|
182
|
-
|
|
182
|
+
/**
|
|
183
183
|
* Battery check timer
|
|
184
184
|
* @type {number|null}
|
|
185
185
|
* @private
|
|
186
186
|
*/
|
|
187
|
-
|
|
187
|
+
this._batteryCheckTimer = null;
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
/**
|
|
190
190
|
* Transport reference for applying settings
|
|
191
191
|
* @type {Object|null}
|
|
192
192
|
* @private
|
|
193
193
|
*/
|
|
194
|
-
|
|
194
|
+
this._transport = null;
|
|
195
195
|
|
|
196
|
-
|
|
196
|
+
/**
|
|
197
197
|
* Statistics
|
|
198
198
|
* @type {Object}
|
|
199
199
|
* @private
|
|
200
200
|
*/
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
201
|
+
this._stats = {
|
|
202
|
+
modeChanges: 0,
|
|
203
|
+
autoAdjustments: 0,
|
|
204
|
+
lastModeChange: null
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// Start battery monitoring if auto-adjust enabled
|
|
208
|
+
if (this._autoAdjust) {
|
|
209
|
+
this._startBatteryMonitoring();
|
|
211
210
|
}
|
|
211
|
+
}
|
|
212
212
|
|
|
213
|
-
|
|
213
|
+
/**
|
|
214
214
|
* Sets the transport to control.
|
|
215
215
|
* @param {Object} transport - Transport instance
|
|
216
216
|
*/
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
217
|
+
setTransport(transport) {
|
|
218
|
+
this._transport = transport;
|
|
219
|
+
}
|
|
220
220
|
|
|
221
|
-
|
|
221
|
+
/**
|
|
222
222
|
* Sets the battery mode.
|
|
223
223
|
* @param {string} mode - Battery mode
|
|
224
224
|
* @returns {Promise<void>}
|
|
225
225
|
*/
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
226
|
+
async setMode(mode) {
|
|
227
|
+
if (!Object.values(BATTERY_MODE).includes(mode)) {
|
|
228
|
+
throw new Error(`Invalid battery mode: ${mode}`);
|
|
229
|
+
}
|
|
230
230
|
|
|
231
|
-
|
|
232
|
-
|
|
231
|
+
const previousMode = this._currentMode;
|
|
232
|
+
this._currentMode = mode;
|
|
233
233
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
234
|
+
// If switching to AUTO, determine actual profile from battery level
|
|
235
|
+
const activeProfile = mode === BATTERY_MODE.AUTO
|
|
236
|
+
? this._getProfileForBatteryLevel(this._batteryLevel)
|
|
237
|
+
: this._profiles[mode];
|
|
238
238
|
|
|
239
|
-
|
|
240
|
-
|
|
239
|
+
// Apply to transport
|
|
240
|
+
await this._applyProfile(activeProfile);
|
|
241
241
|
|
|
242
|
-
|
|
243
|
-
|
|
242
|
+
this._stats.modeChanges++;
|
|
243
|
+
this._stats.lastModeChange = Date.now();
|
|
244
244
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
245
|
+
this.emit('mode-changed', {
|
|
246
|
+
previous: previousMode,
|
|
247
|
+
current: mode,
|
|
248
|
+
profile: activeProfile
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
251
|
|
|
252
|
-
|
|
252
|
+
/**
|
|
253
253
|
* Gets the current battery mode.
|
|
254
254
|
* @returns {string} Current mode
|
|
255
255
|
*/
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
256
|
+
getMode() {
|
|
257
|
+
return this._currentMode;
|
|
258
|
+
}
|
|
259
259
|
|
|
260
|
-
|
|
260
|
+
/**
|
|
261
261
|
* Gets the current active profile.
|
|
262
262
|
* @returns {BatteryProfile} Active profile
|
|
263
263
|
*/
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
return this._profiles[this._currentMode];
|
|
264
|
+
getCurrentProfile() {
|
|
265
|
+
if (this._currentMode === BATTERY_MODE.AUTO) {
|
|
266
|
+
return this._getProfileForBatteryLevel(this._batteryLevel);
|
|
269
267
|
}
|
|
268
|
+
return this._profiles[this._currentMode];
|
|
269
|
+
}
|
|
270
270
|
|
|
271
|
-
|
|
271
|
+
/**
|
|
272
272
|
* Gets all available profiles.
|
|
273
273
|
* @returns {Object.<string, BatteryProfile>} Profiles
|
|
274
274
|
*/
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
275
|
+
getProfiles() {
|
|
276
|
+
return { ...this._profiles };
|
|
277
|
+
}
|
|
278
278
|
|
|
279
|
-
|
|
279
|
+
/**
|
|
280
280
|
* Updates the battery level and triggers auto-adjustment if enabled.
|
|
281
281
|
* @param {number} level - Battery level (0-100)
|
|
282
282
|
* @param {boolean} [isCharging=false] - Whether device is charging
|
|
283
283
|
*/
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
284
|
+
async updateBatteryLevel(level, isCharging = false) {
|
|
285
|
+
const previousLevel = this._batteryLevel;
|
|
286
|
+
this._batteryLevel = Math.max(0, Math.min(100, level));
|
|
287
|
+
this._isCharging = isCharging;
|
|
288
|
+
|
|
289
|
+
this.emit('battery-updated', {
|
|
290
|
+
level: this._batteryLevel,
|
|
291
|
+
isCharging,
|
|
292
|
+
previousLevel
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// Auto-adjust if enabled and in AUTO mode
|
|
296
|
+
if (this._autoAdjust && this._currentMode === BATTERY_MODE.AUTO) {
|
|
297
|
+
await this._autoAdjustMode();
|
|
299
298
|
}
|
|
299
|
+
}
|
|
300
300
|
|
|
301
|
-
|
|
301
|
+
/**
|
|
302
302
|
* Enables or disables auto-adjustment.
|
|
303
303
|
* @param {boolean} enabled - Whether to enable
|
|
304
304
|
*/
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
if (enabled && !this._batteryCheckTimer) {
|
|
309
|
-
this._startBatteryMonitoring();
|
|
310
|
-
} else if (!enabled && this._batteryCheckTimer) {
|
|
311
|
-
this._stopBatteryMonitoring();
|
|
312
|
-
}
|
|
305
|
+
setAutoAdjust(enabled) {
|
|
306
|
+
this._autoAdjust = enabled;
|
|
313
307
|
|
|
314
|
-
|
|
308
|
+
if (enabled && !this._batteryCheckTimer) {
|
|
309
|
+
this._startBatteryMonitoring();
|
|
310
|
+
} else if (!enabled && this._batteryCheckTimer) {
|
|
311
|
+
this._stopBatteryMonitoring();
|
|
315
312
|
}
|
|
316
313
|
|
|
317
|
-
|
|
314
|
+
this.emit('auto-adjust-changed', { enabled });
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
318
|
* Checks if auto-adjustment is enabled.
|
|
319
319
|
* @returns {boolean} True if enabled
|
|
320
320
|
*/
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
321
|
+
isAutoAdjustEnabled() {
|
|
322
|
+
return this._autoAdjust;
|
|
323
|
+
}
|
|
324
324
|
|
|
325
|
-
|
|
325
|
+
/**
|
|
326
326
|
* Records user activity (for activity-based optimization).
|
|
327
327
|
*/
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
328
|
+
recordActivity() {
|
|
329
|
+
this._lastActivityTime = Date.now();
|
|
330
|
+
}
|
|
331
331
|
|
|
332
|
-
|
|
332
|
+
/**
|
|
333
333
|
* Gets the battery level.
|
|
334
334
|
* @returns {number} Battery level (0-100)
|
|
335
335
|
*/
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
336
|
+
getBatteryLevel() {
|
|
337
|
+
return this._batteryLevel;
|
|
338
|
+
}
|
|
339
339
|
|
|
340
|
-
|
|
340
|
+
/**
|
|
341
341
|
* Checks if device is charging.
|
|
342
342
|
* @returns {boolean} True if charging
|
|
343
343
|
*/
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
344
|
+
isCharging() {
|
|
345
|
+
return this._isCharging;
|
|
346
|
+
}
|
|
347
347
|
|
|
348
|
-
|
|
348
|
+
/**
|
|
349
349
|
* Gets optimizer statistics.
|
|
350
350
|
* @returns {Object} Statistics
|
|
351
351
|
*/
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
352
|
+
getStats() {
|
|
353
|
+
return {
|
|
354
|
+
...this._stats,
|
|
355
|
+
currentMode: this._currentMode,
|
|
356
|
+
batteryLevel: this._batteryLevel,
|
|
357
|
+
isCharging: this._isCharging,
|
|
358
|
+
autoAdjust: this._autoAdjust
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
363
|
* Destroys the optimizer.
|
|
364
364
|
*/
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
365
|
+
destroy() {
|
|
366
|
+
this._stopBatteryMonitoring();
|
|
367
|
+
this._transport = null;
|
|
368
|
+
this.removeAllListeners();
|
|
369
|
+
}
|
|
370
370
|
|
|
371
|
-
|
|
371
|
+
/**
|
|
372
372
|
* Gets the appropriate profile for a battery level.
|
|
373
373
|
* @param {number} level - Battery level
|
|
374
374
|
* @returns {BatteryProfile} Profile
|
|
375
375
|
* @private
|
|
376
376
|
*/
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
377
|
+
_getProfileForBatteryLevel(level) {
|
|
378
|
+
if (this._isCharging) {
|
|
379
|
+
return this._profiles[BATTERY_MODE.HIGH_PERFORMANCE];
|
|
380
|
+
}
|
|
381
381
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
}
|
|
382
|
+
if (level > BATTERY_THRESHOLDS.HIGH) {
|
|
383
|
+
return this._profiles[BATTERY_MODE.HIGH_PERFORMANCE];
|
|
384
|
+
} else if (level > BATTERY_THRESHOLDS.MEDIUM) {
|
|
385
|
+
return this._profiles[BATTERY_MODE.BALANCED];
|
|
386
|
+
} else {
|
|
387
|
+
return this._profiles[BATTERY_MODE.LOW_POWER];
|
|
389
388
|
}
|
|
389
|
+
}
|
|
390
390
|
|
|
391
|
-
|
|
391
|
+
/**
|
|
392
392
|
* Auto-adjusts mode based on battery level.
|
|
393
393
|
* @returns {Promise<void>}
|
|
394
394
|
* @private
|
|
395
395
|
*/
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
}
|
|
396
|
+
async _autoAdjustMode() {
|
|
397
|
+
const profile = this._getProfileForBatteryLevel(this._batteryLevel);
|
|
398
|
+
const currentProfile = this.getCurrentProfile();
|
|
399
|
+
|
|
400
|
+
// Only apply if profile actually changed
|
|
401
|
+
if (profile.scanIntervalMs !== currentProfile.scanIntervalMs) {
|
|
402
|
+
await this._applyProfile(profile);
|
|
403
|
+
this._stats.autoAdjustments++;
|
|
404
|
+
|
|
405
|
+
this.emit('auto-adjusted', {
|
|
406
|
+
batteryLevel: this._batteryLevel,
|
|
407
|
+
profile
|
|
408
|
+
});
|
|
410
409
|
}
|
|
410
|
+
}
|
|
411
411
|
|
|
412
|
-
|
|
412
|
+
/**
|
|
413
413
|
* Applies a battery profile to the transport.
|
|
414
414
|
* @param {BatteryProfile} profile - Profile to apply
|
|
415
415
|
* @returns {Promise<void>}
|
|
416
416
|
* @private
|
|
417
417
|
*/
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
try {
|
|
424
|
-
// Apply scan parameters
|
|
425
|
-
if (typeof this._transport.setScanParameters === 'function') {
|
|
426
|
-
await this._transport.setScanParameters({
|
|
427
|
-
interval: profile.scanIntervalMs,
|
|
428
|
-
window: profile.scanWindowMs,
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// Apply connection parameters
|
|
433
|
-
if (typeof this._transport.setConnectionParameters === 'function') {
|
|
434
|
-
await this._transport.setConnectionParameters({
|
|
435
|
-
interval: profile.connectionIntervalMs,
|
|
436
|
-
});
|
|
437
|
-
}
|
|
418
|
+
async _applyProfile(profile) {
|
|
419
|
+
if (!this._transport) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
438
422
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
423
|
+
try {
|
|
424
|
+
// Apply scan parameters
|
|
425
|
+
if (typeof this._transport.setScanParameters === 'function') {
|
|
426
|
+
await this._transport.setScanParameters({
|
|
427
|
+
interval: profile.scanIntervalMs,
|
|
428
|
+
window: profile.scanWindowMs
|
|
429
|
+
});
|
|
430
|
+
}
|
|
443
431
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
432
|
+
// Apply connection parameters
|
|
433
|
+
if (typeof this._transport.setConnectionParameters === 'function') {
|
|
434
|
+
await this._transport.setConnectionParameters({
|
|
435
|
+
interval: profile.connectionIntervalMs
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Apply advertising parameters
|
|
440
|
+
if (typeof this._transport.setAdvertisingInterval === 'function') {
|
|
441
|
+
await this._transport.setAdvertisingInterval(profile.advertisingIntervalMs);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
this.emit('profile-applied', { profile });
|
|
445
|
+
} catch (error) {
|
|
446
|
+
this.emit('error', {
|
|
447
|
+
message: 'Failed to apply battery profile',
|
|
448
|
+
error: error.message
|
|
449
|
+
});
|
|
451
450
|
}
|
|
451
|
+
}
|
|
452
452
|
|
|
453
|
-
|
|
453
|
+
/**
|
|
454
454
|
* Starts battery monitoring timer.
|
|
455
455
|
* @private
|
|
456
456
|
*/
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
457
|
+
_startBatteryMonitoring() {
|
|
458
|
+
if (this._batteryCheckTimer) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
461
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
462
|
+
this._batteryCheckTimer = setInterval(
|
|
463
|
+
async () => {
|
|
464
|
+
// Check for inactivity
|
|
465
|
+
if (this._config.activityAdjust) {
|
|
466
|
+
const inactiveTime = Date.now() - this._lastActivityTime;
|
|
467
|
+
if (inactiveTime > this._config.inactivityTimeoutMs) {
|
|
468
|
+
// Switch to low power if inactive
|
|
469
|
+
if (this._currentMode === BATTERY_MODE.AUTO) {
|
|
470
|
+
await this._applyProfile(this._profiles[BATTERY_MODE.LOW_POWER]);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
this._config.batteryCheckIntervalMs
|
|
476
|
+
);
|
|
477
|
+
// Don't prevent process exit (important for tests and cleanup)
|
|
478
|
+
if (this._batteryCheckTimer && typeof this._batteryCheckTimer.unref === 'function') {
|
|
479
|
+
this._batteryCheckTimer.unref();
|
|
477
480
|
}
|
|
481
|
+
}
|
|
478
482
|
|
|
479
|
-
|
|
483
|
+
/**
|
|
480
484
|
* Stops battery monitoring timer.
|
|
481
485
|
* @private
|
|
482
486
|
*/
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
}
|
|
487
|
+
_stopBatteryMonitoring() {
|
|
488
|
+
if (this._batteryCheckTimer) {
|
|
489
|
+
clearInterval(this._batteryCheckTimer);
|
|
490
|
+
this._batteryCheckTimer = null;
|
|
488
491
|
}
|
|
492
|
+
}
|
|
489
493
|
}
|
|
490
494
|
|
|
491
495
|
module.exports = {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
496
|
+
BatteryOptimizer,
|
|
497
|
+
BATTERY_MODE,
|
|
498
|
+
BATTERY_THRESHOLDS,
|
|
499
|
+
DEFAULT_PROFILES,
|
|
500
|
+
DEFAULT_CONFIG
|
|
497
501
|
};
|