@rhizomatics/signalk-bluetti-plugin 1.0.5-alpha → 1.0.7-alpha
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/index.js +35 -0
- package/lib/scanner.js +2 -2
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -169,6 +169,17 @@ module.exports = function (app) {
|
|
|
169
169
|
return;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
// Validate any explicitly-configured encryption CSV paths up front.
|
|
173
|
+
for (const cfg of devices) {
|
|
174
|
+
if (cfg.encryptionCsvPath) {
|
|
175
|
+
const err = validateEncryptionCsvPath(cfg.encryptionCsvPath, cfg.name);
|
|
176
|
+
if (err) {
|
|
177
|
+
app.setPluginError(err);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
172
183
|
// Build address → cfg lookup (normalise to lowercase, no colons)
|
|
173
184
|
const normalise = (addr) => addr.toLowerCase().replace(/:/g, '');
|
|
174
185
|
const pending = new Map(devices.map(cfg => [normalise(cfg.address), cfg]));
|
|
@@ -180,6 +191,9 @@ module.exports = function (app) {
|
|
|
180
191
|
if (cfg) {
|
|
181
192
|
pending.delete(normalise(address));
|
|
182
193
|
app.setPluginStatus(`Found ${name} [${address}] — connecting …`);
|
|
194
|
+
// Noble cannot scan and connect simultaneously — stop scan first.
|
|
195
|
+
// The scanComplete handler will restart scanning for any remaining pending devices.
|
|
196
|
+
scanner.stopScan();
|
|
183
197
|
startDevice(cfg, peripheral, name, deps);
|
|
184
198
|
} else {
|
|
185
199
|
log(`Discovered unconfigured Bluetti device: ${name} [${address}]`);
|
|
@@ -212,6 +226,27 @@ module.exports = function (app) {
|
|
|
212
226
|
}
|
|
213
227
|
}
|
|
214
228
|
|
|
229
|
+
function validateEncryptionCsvPath(csvPath, deviceName) {
|
|
230
|
+
try {
|
|
231
|
+
fs.accessSync(csvPath, fs.constants.R_OK);
|
|
232
|
+
} catch (_) {
|
|
233
|
+
return `[${deviceName}] Encryption CSV not found or not readable: ${csvPath}`;
|
|
234
|
+
}
|
|
235
|
+
let lines;
|
|
236
|
+
try {
|
|
237
|
+
lines = fs.readFileSync(csvPath, 'utf8').split('\n').map(l => l.trim()).filter(Boolean);
|
|
238
|
+
} catch (err) {
|
|
239
|
+
return `[${deviceName}] Could not read encryption CSV "${csvPath}": ${err.message}`;
|
|
240
|
+
}
|
|
241
|
+
if (lines[0] !== 'bluetti') {
|
|
242
|
+
return `[${deviceName}] Encryption CSV does not look like a Bluetti key file (expected first line "bluetti"): ${csvPath}`;
|
|
243
|
+
}
|
|
244
|
+
if (lines.length < 4) {
|
|
245
|
+
return `[${deviceName}] Encryption CSV is missing the key line (expected 4 lines): ${csvPath}`;
|
|
246
|
+
}
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
|
|
215
250
|
function resolveRegisterMapPath(cfg) {
|
|
216
251
|
const { builtinModel, csvPath } = cfg;
|
|
217
252
|
if (!builtinModel || builtinModel === 'custom') {
|
package/lib/scanner.js
CHANGED
|
@@ -27,9 +27,9 @@ class Scanner extends EventEmitter {
|
|
|
27
27
|
return new Promise((resolve, reject) => {
|
|
28
28
|
let noble;
|
|
29
29
|
try {
|
|
30
|
-
noble = require('@
|
|
30
|
+
noble = require('@stoprocent/noble');
|
|
31
31
|
} catch (e) {
|
|
32
|
-
return reject(new Error('@
|
|
32
|
+
return reject(new Error('@stoprocent/noble not installed — run: npm install'));
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
this._noble = noble;
|