diff --git a/docs/bluetooth.html b/docs/bluetooth.html
index 7af5d7d..b310b11 100644
--- a/docs/bluetooth.html
+++ b/docs/bluetooth.html
@@ -98,13 +98,23 @@
|
- [0].address |
+ [0].macDevice |
X |
|
X |
X |
|
- address |
+ MAC address device |
+
+
+ |
+ [0].macHost |
+ X |
+ |
+ X |
+ X |
+ |
+ MAC address host |
|
@@ -158,18 +168,20 @@ si.bluetoothDevices().then(data => console.log(data));
diff --git a/lib/bluetooth.js b/lib/bluetooth.js
index 643f351..0b6dd5b 100644
--- a/lib/bluetooth.js
+++ b/lib/bluetooth.js
@@ -15,8 +15,9 @@
const exec = require('child_process').exec;
const execSync = require('child_process').execSync;
+const path = require('path');
const util = require('./util');
-// const fs = require('fs');
+const fs = require('fs');
let _platform = process.platform;
@@ -28,79 +29,45 @@ const _openbsd = (_platform === 'openbsd');
const _netbsd = (_platform === 'netbsd');
const _sunos = (_platform === 'sunos');
-function getLinuxAudioPci() {
- let cmd = 'lspci -v 2>/dev/null'
- let result = [];
- try {
- const parts = execSync(cmd).toString().split('\n\n');
- for (let i = 0; i < parts.length; i++) {
- const lines = parts[i].split('\n');
- if (lines && lines.length && lines[0].toLowerCase().indexOf('audio') >= 0) {
- const audio = {};
- audio.slotId = lines[0].split(' ')[0];
- audio.driver = util.getValue(lines, 'Kernel driver in use', ':', true) || util.getValue(lines, 'Kernel modules', ':', true)
- result.push(audio);
- }
- }
- return result;
- } catch (e) {
- return result;
- }
-}
-
-// device("device_services")
-// name-- > Key
-// address-- > "device_addr"
-// batteryPercent-- > "device_batteryPercent"
-// manufacturer-- > "device_manufacturer"
-// type(keyboard, ...)-- > ("device_majorClassOfDevice_string"), "device_minorClassOfDevice_string"
-// connected
-
-
-
-function parseLinuxAudioPciMM(lines, audioPCI) {
- const result = {};
- const slotId = util.getValue(lines, 'Slot');
-
- const pciMatch = audioPCI.filter(function (item) { return item.slotId === slotId })
-
- result.id = slotId;
- result.name = util.getValue(lines, 'SDevice');
- // result.type = util.getValue(lines, 'Class');
- result.manufacturer = util.getValue(lines, 'SVendor');
- result.revision = util.getValue(lines, 'Rev');
- result.driver = pciMatch && pciMatch.length === 1 && pciMatch[0].driver ? pciMatch[0].driver : '';
- result.default = null;
- result.channel = 'PCIe';
- result.in = null;
- result.out = null;
- result.status = 'online';
-
- return result;
-}
-
-function parseDarwinBluetoothTyoe(str) {
+function parseBluetoothTyoe(str) {
let result = '';
if (str.indexOf('keyboard') >= 0) { result = 'Keyboard'; }
if (str.indexOf('mouse') >= 0) { result = 'Mouse'; }
if (str.indexOf('speaker') >= 0) { result = 'Speaker'; }
if (str.indexOf('headset') >= 0) { result = 'Headset'; }
+ if (str.indexOf('phone') >= 0) { result = 'Phone'; }
// to be continued ...
return result;
}
-function parseDarwinBluetoothDevices(bluetoothObject) {
+function parseLinuxBluetoothInfo(lines, macAddr1, macAddr2) {
+ const result = {};
+
+ result.device = null;
+ result.name = util.getValue(lines, 'name', '=');
+ result.manufacturer = null;
+ result.macDevice = macAddr1;
+ result.macHost = macAddr2;
+ result.batteryPercent = null;
+ result.type = parseBluetoothTyoe(result.name.toLowerCase());
+ result.connected = false;
+
+ return result;
+}
+
+function parseDarwinBluetoothDevices(bluetoothObject, macAddr2) {
const result = {};
const typeStr = ((bluetoothObject.device_minorClassOfDevice_string || bluetoothObject.device_majorClassOfDevice_string || '') + (bluetoothObject.device_name || '')).toLowerCase();
result.device = bluetoothObject.device_services || '';
result.name = bluetoothObject.device_name || '';
result.manufacturer = bluetoothObject.device_manufacturer || '';
- result.address = bluetoothObject.device_addr || '';
+ result.macDevice = (bluetoothObject.device_addr || '').toLowerCase().replace(/-/g, ':');;
+ result.macHost = macAddr2;
result.batteryPercent = bluetoothObject.device_batteryPercent || null;
- result.tyoe = parseDarwinBluetoothTyoe(typeStr);
+ result.type = parseBluetoothTyoe(typeStr);
result.connected = bluetoothObject.device_isconnected === 'attrib_Yes' || false;
return result;
@@ -108,19 +75,15 @@ function parseDarwinBluetoothDevices(bluetoothObject) {
function parseWindowsBluetooth(lines) {
const result = {};
- const status = util.getValue(lines, 'StatusInfo', '=');
- // const description = util.getValue(lines, 'Description', '=');
result.device = null;
result.name = util.getValue(lines, 'name', '=');
result.manufacturer = util.getValue(lines, 'manufacturer', '=');
- result.address = null;
- result.batteryPercent = null
- result.default = null
- result.in = null
- result.out = null
- result.interfaceType = null
- result.status = status
+ result.macDevice = null;
+ result.macHost = null;
+ result.batteryPercent = null;
+ result.type = parseBluetoothTyoe(result.name.toLowerCase());
+ result.connected = null;
return result;
}
@@ -130,26 +93,35 @@ function bluetoothDevices(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let result = [];
- if (_linux || _freebsd || _openbsd || _netbsd) {
- let cmd = 'lspci -vmm 2>/dev/null'
- exec(cmd, function (error, stdout) {
- // PCI
- if (!error) {
- const audioPCI = getLinuxAudioPci();
- const parts = stdout.toString().split('\n\n');
- for (let i = 0; i < parts.length; i++) {
- const lines = parts[i].split('\n');
- if (util.getValue(lines, 'class', ':', true).toLowerCase().indexOf('audio') >= 0) {
- const audio = parseLinuxAudioPciMM(lines, audioPCI);
- result.push(audio);
- }
+ if (_linux) {
+ // get files in /var/lib/bluetooth/ recursive
+ const btFiles = util.getFilesInPath('/var/lib/bluetooth/');
+ for (let i = 0; i < btFiles.length; i++) {
+ const filename = path.basename(btFiles[i]);
+ const pathParts = btFiles[i].split('/');
+ const macAddr1 = pathParts.length >= 6 ? pathParts[pathParts.length - 2] : null;
+ const macAddr2 = pathParts.length >= 7 ? pathParts[pathParts.length - 3] : null;
+ if (filename === 'info') {
+ const infoFile = fs.readFileSync(btFiles[i], { encoding: 'utf8' }).split('\n');
+ result.push(parseLinuxBluetoothInfo(infoFile, macAddr1, macAddr2));
+ }
+ }
+ // determine "connected" with hcitool con
+ try {
+ const hdicon = execSync('hditool con').toString().toLowerCase();
+ for (let i = 0; i < result.length; i++) {
+ if (result[i].macAddr1 && result[i].macAddr1.length > 10 && hdicon.indexOf(result[i].macAddr1) >= 0) {
+ result[i].connected = true;
}
}
- if (callback) {
- callback(result);
- }
- resolve(result);
- });
+ } catch (e) {
+ util.noop();
+ }
+
+ if (callback) {
+ callback(result);
+ }
+ resolve(result);
}
if (_darwin) {
let cmd = 'system_profiler SPBluetoothDataType -json'
@@ -158,17 +130,21 @@ function bluetoothDevices(callback) {
try {
const outObj = JSON.parse(stdout.toString());
if (outObj.SPBluetoothDataType && outObj.SPBluetoothDataType.length && outObj.SPBluetoothDataType[0] && outObj.SPBluetoothDataType[0]['device_title'] && outObj.SPBluetoothDataType[0]['device_title'].length) {
+ // missing: host BT Adapter macAddr ()
+ let macAddr2 = null;
+ if (outObj.SPBluetoothDataType[0]['local_device_title'] && outObj.SPBluetoothDataType[0].local_device_title.general_address) {
+ macAddr2 = outObj.SPBluetoothDataType[0].local_device_title.general_address.toLowerCase().replace(/-/g, ':');
+ }
+
for (let i = 0; i < outObj.SPBluetoothDataType[0]['device_title'].length; i++) {
const obj = outObj.SPBluetoothDataType[0]['device_title'][i];
const objKey = Object.keys(obj);
if (objKey && objKey.length === 1) {
const innerObject = obj[objKey[0]];
innerObject.device_name = objKey[0];
- const bluetoothDevice = parseDarwinBluetoothDevices(innerObject);
+ const bluetoothDevice = parseDarwinBluetoothDevices(innerObject, macAddr2);
result.push(bluetoothDevice);
-
}
-
}
}
} catch (e) {
@@ -197,7 +173,7 @@ function bluetoothDevices(callback) {
resolve(result);
});
}
- if (_sunos) {
+ if (_freebsd || _netbsd || _openbsd || _sunos) {
resolve(null);
}
});
diff --git a/lib/index.d.ts b/lib/index.d.ts
index 569b861..6843e48 100644
--- a/lib/index.d.ts
+++ b/lib/index.d.ts
@@ -746,7 +746,8 @@ export namespace Systeminformation {
interface BluetoothDeviceData {
device: string;
name: string;
- address: string;
+ macDevice: string;
+ macHost: string;
batteryPercent: number;
manufacturer: string;
type: string;
diff --git a/lib/osinfo.js b/lib/osinfo.js
index fc97676..4dc5d6f 100644
--- a/lib/osinfo.js
+++ b/lib/osinfo.js
@@ -978,7 +978,7 @@ function uuid(callback) {
if (jsonObj.SPHardwareDataType && jsonObj.SPHardwareDataType.length > 0) {
const spHardware = jsonObj.SPHardwareDataType[0];
// result.os = parts.length > 1 ? parts[1].trim().toLowerCase() : '';
- result.os = spHardware.platform_UUID;
+ result.os = spHardware.platform_UUID.toLowerCase();
result.hardware = spHardware.serial_number;
}
} catch (e) {
diff --git a/lib/util.js b/lib/util.js
index 93dd839..476de3b 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -15,6 +15,7 @@
const os = require('os');
const fs = require('fs');
+const path = require('path');
const spawn = require('child_process').spawn;
const exec = require('child_process').exec;
const execSync = require('child_process').execSync;
@@ -593,6 +594,38 @@ function hex2bin(hex) {
return ("00000000" + (parseInt(hex, 16)).toString(2)).substr(-8);
}
+function getFilesInPath(source) {
+ const lstatSync = fs.lstatSync;
+ const readdirSync = fs.readdirSync;
+ const join = path.join;
+
+ function isDirectory(source) {
+ return lstatSync(source).isDirectory();
+ }
+ function isFile(source) { return lstatSync(source).isFile(); }
+
+ function getDirectories(source) {
+ return readdirSync(source).map(function (name) { return join(source, name); }).filter(isDirectory)
+ }
+ function getFiles(source) {
+ return readdirSync(source).map(function (name) { return join(source, name); }).filter(isFile)
+ }
+
+ function getFilesRecursively(source) {
+ let dirs = getDirectories(source);
+ let files = dirs
+ .map(function (dir) { return getFilesRecursively(dir); })
+ .reduce(function (a, b) { return a.concat(b); }, []);
+ return files.concat(getFiles(path));
+ }
+
+ if (fs.existsSync(source)) {
+ return getFilesRecursively(source);
+ } else {
+ return [];
+ }
+}
+
function decodePiCpuinfo(lines) {
// https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
@@ -831,3 +864,4 @@ exports.stringToString = stringToString;
exports.stringSubstr = stringSubstr;
exports.stringTrim = stringTrim;
exports.WINDIR = WINDIR;
+exports.getFilesInPath = getFilesInPath;
diff --git a/package.json b/package.json
index 6fbeb45..ad158de 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,7 @@
{
"name": "systeminformation",
"version": "4.34.9",
+ "prereleaseversion": "5.0-alpha.0116",
"description": "Simple system and OS information library",
"license": "MIT",
"author": "Sebastian Hildebrandt (https://plus-innovations.com)",
diff --git a/test/si.js b/test/si.js
index 354077d..c586421 100644
--- a/test/si.js
+++ b/test/si.js
@@ -19,7 +19,7 @@ function test(f) {
else if (f === 'g') { si.graphics().then(data => { if (data !== null) { resolve({ data, title: 'Graphics' }); } else { resolve('not_supported') } }) }
else if (f === 'h') { si.bluetoothDevices().then(data => { if (data !== null) { resolve({ data, title: 'Bluetooth' }); } else { resolve('not_supported') } }) }
else if (f === 'i') { si.inetLatency().then(data => { if (data !== null) { resolve({ data, title: 'Internet Latency' }); } else { resolve('not_supported') } }) }
- else if (f === 'I') { si.inetChecksite('https://www.plus-innovations.com').then(data => { if (data !== null) { resolve({ data, title: 'Internet Check Site' }); } else { resolve('not_supported') } }) }
+ else if (f === 'I') { si.inetChecksite('https://systeminformation.io').then(data => { if (data !== null) { resolve({ data, title: 'Internet Check Site' }); } else { resolve('not_supported') } }) }
else if (f === 'j') { si.cpuCurrentSpeed().then(data => { if (data !== null) { resolve({ data, title: 'CPU Current Speed' }); } else { resolve('not_supported') } }) }
else if (f === 'l') { si.currentLoad().then(data => { if (data !== null) { resolve({ data, title: 'CPU Current Load' }); } else { resolve('not_supported') } }) }
else if (f === 'L') { si.fullLoad().then(data => { if (data !== null) { resolve({ data, title: 'CPU Full Load' }); } else { resolve('not_supported') } }) }