bluetooth linux implementation
This commit is contained in:
parent
142a0b5557
commit
65d67fe0a6
@ -98,13 +98,23 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>[0].address</td>
|
||||
<td>[0].macDevice</td>
|
||||
<td>X</td>
|
||||
<td></td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td></td>
|
||||
<td>address</td>
|
||||
<td>MAC address device</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>[0].macHost</td>
|
||||
<td>X</td>
|
||||
<td></td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td></td>
|
||||
<td>MAC address host</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
@ -158,18 +168,20 @@ si.bluetoothDevices().then(data => console.log(data));</code></pre class="exampl
|
||||
device: 'Magic Mouse 2',
|
||||
name: 'My Maus',
|
||||
manufacturer: 'Broadcom (0x5, 0x240C)',
|
||||
address: '10-XX-XX-XX-XX-XX',
|
||||
macDevice: '10-XX-XX-XX-XX-XX',
|
||||
macHost: null,
|
||||
batteryPercent: '74%',
|
||||
tyoe: 'Mouse',
|
||||
type: 'Mouse',
|
||||
connected: true
|
||||
},
|
||||
{
|
||||
device: 'Magic Keyboard with Numeric Keypad',
|
||||
name: 'My Keyboard',
|
||||
manufacturer: 'Broadcom (0x5, 0x240C)',
|
||||
address: '10-XX-XX-XX-XX-XX',
|
||||
macDevice: '10-XX-XX-XX-XX-XX',
|
||||
macHost: null,
|
||||
batteryPercent: '75%',
|
||||
tyoe: 'Keyboard',
|
||||
type: 'Keyboard',
|
||||
connected: true
|
||||
},
|
||||
]</pre>
|
||||
|
||||
150
lib/bluetooth.js
150
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);
|
||||
}
|
||||
});
|
||||
|
||||
3
lib/index.d.ts
vendored
3
lib/index.d.ts
vendored
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
34
lib/util.js
34
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;
|
||||
|
||||
@ -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 <hildebrandt@plus-innovations.com> (https://plus-innovations.com)",
|
||||
|
||||
@ -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') } }) }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user