added graphics info (controller and display)

This commit is contained in:
Sebastian Hildebrandt 2016-09-14 09:31:28 +02:00
parent 705ec26e98
commit 1db7161687
3 changed files with 333 additions and 19 deletions

View File

@ -42,6 +42,7 @@ si.cpu()
### Latest Activity
- Version 3.5.0: added graphics info (controller and display).
- Version 3.4.0: rewritten currentLoad and CPU load for processes (linux). This is now much more accurate.
- Version 3.3.0: added process list. Get full process list including details like cpu and mem usage, status, command, ...
- Version 3.2.0: added battery support. If a battery is installed, you get information about status and current capacity level
@ -68,6 +69,7 @@ Here all changes more detailed:
New Functions
- `graphics`: returns arrays of graphics controllers and displays (new in version 3.5)
- `networkInterfaceDefault`: returns default network interface (new in version 3.4)
- `processes`: now returns also a process list with all process details (new in version 3.3)
- `battery`: retrieves battery status and charging level (new in version 3.2)
@ -215,6 +217,21 @@ This library is splitted in several sections:
| - maxcapacity | X | X | max capacity of battery |
| - currentcapacity | X | X | current capacity of battery |
| - percent | X | X | charging level in percent |
| si.graphics(cb) | X | X | arrays of graphics controllers and displays |
| - controllers[0].model | X | X | graphics controller model |
| - controllers[0].vendor | X | X | e.g. ATI |
| - controllers[0].bus | X | X | on which bus (e.g. PCIe) |
| - controllers[0].vram | X | X | VRAM size (in MB) |
| - controllers[0].vramDynamic | X | X | true if dynamicly allocated ram |
| - displays[0].model | X | X | Monitor/Display Model |
| - displays[0].main | X | X | true if main monitor |
| - displays[0].builtin | X | X | true if built in monitor |
| - displays[0].connection | X | X | e.g. DisplayPort or HDMI |
| - displays[0].resolutionx | X | X | pixel horizontal |
| - displays[0].resolutiony | X | X | pixel vertical |
| - displays[0].depth | X | X | color depth in bits |
| - displays[0].sizex | X | X | size in mm horizontal |
| - displays[0].sizey | X | X | size in mm vertical |
| si.fsSize(cb) | X | X | returns array of mounted file systems |
| - [0].fs | X | X | name of file system |
| - [0].size | X | X | sizes in Bytes |
@ -377,6 +394,7 @@ I am happy to discuss any comments and suggestions. Please feel free to contact
| Version | Date | Comment |
| -------------- | -------------- | -------- |
| 3.5.0 | 2016-09-14 | added graphics info (controller, display) |
| 3.4.4 | 2016-09-02 | tiny fixes system.model, getDefaultNetworkInterface |
| 3.4.3 | 2016-09-02 | tiny bug fix fsStats, disksIO OSX |
| 3.4.2 | 2016-09-01 | improved default network interface |

View File

@ -23,13 +23,14 @@
// 4. CPU
// 5. Memory
// 6. Battery
// 7. File System
// 8. Network
// 9. Processes
// 10. Users/Sessions
// 11. Internet
// 12. Docker
// 13. GetAll - get all data
// 7. Graphics
// 8. File System
// 9. Network
// 10. Processes
// 11. Users/Sessions
// 12. Internet
// 13. Docker
// 14. GetAll - get all data
//
// ==================================================================================
//
@ -80,6 +81,7 @@
// --------------------------------
//
// version date comment
// 3.5.0 2016-09-14 added graphics info (controller, display)
// 3.4.4 2016-09-02 tiny fixes system.model, getDefaultNetworkInterface
// 3.4.3 2016-09-02 tiny bug fix fsStats, disksIO OSX
// 3.4.2 2016-09-01 improved default network interface
@ -908,7 +910,294 @@ function battery(callback) {
exports.battery = battery;
// ----------------------------------------------------------------------------------
// 7. File System
// 7. Graphics (controller, display)
// ----------------------------------------------------------------------------------
function graphics(callback) {
function parseLinesDarwin(lines) {
let starts = [];
let level = -1;
let lastlevel = -1;
let controllers = [];
let displays = [];
let currentController = {};
let currentDisplay = {};
for (let i = 0; i < lines.length; i++) {
if ('' != lines[i].trim()) {
let start = lines[i].search(/\S|$/);
if (-1 == starts.indexOf(start)) {
starts.push(start);
}
level = starts.indexOf(start);
if (level < lastlevel) {
if (Object.keys(currentController).length > 0) {// just changed to Displays
controllers.push(currentController);
currentController = {};
}
if (Object.keys(currentDisplay).length > 0) {// just changed to Displays
displays.push(currentDisplay);
currentDisplay = {};
}
}
lastlevel = level;
let parts = lines[i].split(':');
if (2 == level) { // grafics controller level
if (parts.length > 1 && parts[0].replace(/ +/g, "").toLowerCase().indexOf('chipsetmodel') != -1) currentController.model = parts[1].trim();
if (parts.length > 1 && parts[0].replace(/ +/g, "").toLowerCase().indexOf('bus') != -1) currentController.bus = parts[1].trim();
if (parts.length > 1 && parts[0].replace(/ +/g, "").toLowerCase().indexOf('vendor') != -1) currentController.vendor = parts[1].split('(')[0].trim();
if (parts.length > 1 && parts[0].replace(/ +/g, "").toLowerCase().indexOf('vram(total)') != -1) {
currentController.vram = parseInt(parts[1]); // in MB
currentController.vramDynamic = false;
}
if (parts.length > 1 && parts[0].replace(/ +/g, "").toLowerCase().indexOf('vram(dynamic,max)') != -1) {
currentController.vram = parseInt(parts[1]); // in MB
currentController.vramDynamic = true;
}
}
if (3 == level) { // display controller level
if (parts.length > 1 && '' == parts[1]) {
currentDisplay.model = parts[0].trim();
currentDisplay.main = false;
currentDisplay.builtin = false;
currentDisplay.connection = '';
currentDisplay.sizex = -1;
currentDisplay.sizey = -1;
}
}
if (4 == level) { // display controller details level
if (parts.length > 1 && parts[0].replace(/ +/g, "").toLowerCase().indexOf('resolution') != -1) {
let resolution = parts[1].split('x');
currentDisplay.resolutionx = (resolution.length > 1 ? parseInt(resolution[0]) : 0);
currentDisplay.resolutiony = (resolution.length > 1 ? parseInt(resolution[1]) : 0);
}
if (parts.length > 1 && parts[0].replace(/ +/g, "").toLowerCase().indexOf('pixeldepth') != -1) currentDisplay.pixeldepth = parseInt(parts[1]); // in BIT
if (parts.length > 1 && parts[0].replace(/ +/g, "").toLowerCase().indexOf('maindisplay') != -1 && parts[1].replace(/ +/g, "").toLowerCase() == 'yes') currentDisplay.main = true;
if (parts.length > 1 && parts[0].replace(/ +/g, "").toLowerCase().indexOf('built-in') != -1 && parts[1].replace(/ +/g, "").toLowerCase() == 'yes') {
currentDisplay.builtin = true;
currentDisplay.connection = '';
}
if (parts.length > 1 && parts[0].replace(/ +/g, "").toLowerCase().indexOf('connectiontype') != -1) {
currentDisplay.builtin = false;
currentDisplay.connection = parts[1].trim();
}
}
}
}
if (Object.keys(currentController).length > 0) {// just changed to Displays
controllers.push(currentController);
}
if (Object.keys(currentDisplay).length > 0) {// just changed to Displays
displays.push(currentDisplay);
}
return ({
controllers: controllers,
displays: displays
})
}
function parseLinesLinuxControllers(lines) {
let controllers = [];
let currentController = {};
let is_vga = false;
for (let i = 0; i < lines.length; i++) {
if ('' != lines[i].trim()) {
if (' ' != lines[i][0] && '\t' != lines[i][0]) { // first line of new entry
let vgapos = lines[i].toLowerCase().indexOf('vga');
if (vgapos != -1) { // VGA
if (Object.keys(currentController).length > 0) {// already a controller found
controllers.push(currentController);
currentController = {};
}
is_vga = true;
let endpos = lines[i].search(/\[[0-9a-f]{4}:[0-9a-f]{4}]|$/);
let parts = lines[i].substr(vgapos, endpos - vgapos).split(':');
if (parts.length > 1)
{
parts[1] = parts[1].trim();
if (parts[1].toLowerCase().indexOf('corporation')) {
currentController.vendor = parts[1].substr(0, parts[1].toLowerCase().indexOf('corporation') + 11).trim();
currentController.model = parts[1].substr(parts[1].toLowerCase().indexOf('corporation') + 11, 200).trim().split('(')[0];
currentController.bus = '';
currentController.vram = -1;
currentController.vramDynamic = false;
}
}
} else {
is_vga = false;
}
}
if (is_vga) { // within VGA details
let parts = lines[i].split(':');
if (parts.length > 1 && parts[0].replace(/ +/g, "").toLowerCase().indexOf('devicename') != -1 && parts[0].toLowerCase().indexOf('onboard') != -1) currentController.bus = 'Onboard';
if (parts.length > 1 && parts[0].replace(/ +/g, "").toLowerCase().indexOf('region') != -1 && parts[1].toLowerCase().indexOf('memory') != -1) {
let memparts = parts[1].split("=");
if (memparts.length > 1) {
currentController.vram = parseInt(memparts[1]);
}
}
}
}
}
if (Object.keys(currentController).length > 0) {// still controller information available
controllers.push(currentController);
}
return (controllers)
}
function parseLinesLinuxEdid(edid) {
// parsen EDID
// --> model
// --> resolutionx
// --> resolutiony
// --> builtin = false
// --> pixeldepth (?)
// --> sizex
// --> sizey
let result = {};
// find first "Detailed Timing Description"
let start = 108;
if (edid.substr(start,6) == '000000') {
start += 36;
}
if (edid.substr(start,6) == '000000') {
start += 36;
}
if (edid.substr(start,6) == '000000') {
start += 36;
}
if (edid.substr(start,6) == '000000') {
start += 36;
}
result.resolutionx = parseInt('0x0' + edid.substr(start + 8,1) + edid.substr(start + 4,2));
result.resolutiony = parseInt('0x0' + edid.substr(start + 14,1) + edid.substr(start + 10,2));
result.sizex = parseInt('0x0' + edid.substr(start + 28,1) + edid.substr(start + 24,2));
result.sizey = parseInt('0x0' + edid.substr(start + 29,1) + edid.substr(start + 26,2));
// monitor name
start = edid.indexOf('000000fc00'); // find first "Monitor Description Data"
if (start >= 0) {
let model_raw = edid.substr(start+10, 26);
if (model_raw.indexOf('0a') != -1) {
model_raw = model_raw.substr(0,model_raw.indexOf('0a'))
}
result.model = model_raw.match(/.{1,2}/g).map(function(v){
return String.fromCharCode(parseInt(v, 16));
}).join('');
} else {
result.model = '';
}
return result;
}
function parseLinesLinuxDisplays(lines, depth) {
let displays = [];
let currentDisplay = {};
let is_edid = false;
let edid_raw = '';
let start = 0;
for (let i = 1; i < lines.length; i++) { // start with second line
if ('' != lines[i].trim()) {
if (' ' != lines[i][0] && '\t' != lines[i][0] && lines[i].toLowerCase().indexOf(' connected ') != -1 ) { // first line of new entry
if (Object.keys(currentDisplay).length > 0) { // push last display to array
displays.push(currentDisplay);
currentDisplay = {};
}
let parts = lines[i].split(' ');
currentDisplay.connection = parts[0];
currentDisplay.main = (parts[2] == 'primary');
currentDisplay.builtin = (parts[0].toLowerCase().indexOf('edp') >= 0)
}
// try to read EDID information
if (is_edid) {
if (lines[i].search(/\S|$/) > start) {
edid_raw += lines[i].toLowerCase().trim();
} else {
// parsen EDID
let edid_decoded = parseLinesLinuxEdid(edid_raw);
currentDisplay.model = edid_decoded.model;
currentDisplay.resolutionx = edid_decoded.resolutionx;
currentDisplay.resolutiony = edid_decoded.resolutiony;
currentDisplay.sizex = edid_decoded.sizex;
currentDisplay.sizey = edid_decoded.sizey;
currentDisplay.pixeldepth = depth;
is_edid = false;
}
}
if (lines[i].toLowerCase().indexOf('edid:') != -1 ) {
is_edid = true;
start = lines[i].search(/\S|$/);
}
}
}
// pushen displays
if (Object.keys(currentDisplay).length > 0) { // still information there
displays.push(currentDisplay);
}
return displays
}
// function starts here
return new Promise((resolve, reject) => {
process.nextTick(() => {
if (_windows) {
let error = new Error(NOT_SUPPORTED);
if (callback) {
callback(NOT_SUPPORTED)
}
reject(error);
}
let result = {};
if (_darwin) {
let cmd = 'system_profiler SPDisplaysDataType';
exec(cmd, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
result = parseLinesDarwin(lines);
}
if (callback) {
callback(result)
}
resolve(result);
})
}
if (_linux) {
let cmd = 'lspci -vvv 2>/dev/null';
exec(cmd, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
result.controllers = parseLinesLinuxControllers(lines);
let cmd = "xdpyinfo 2>/dev/null | grep 'depth of root window' | awk '{ print $5 }'";
exec(cmd, function (error, stdout) {
let depth = 0;
if (!error) {
let lines = stdout.toString().split('\n');
depth = parseInt(lines[0]) || 0;
}
let cmd = 'xrandr --verbose 2>/dev/null';
exec(cmd, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
result.displays = parseLinesLinuxDisplays(lines, depth);
}
if (callback) {
callback(result)
}
resolve(result);
})
})
}
})
}
});
});
}
exports.graphics = graphics;
// ----------------------------------------------------------------------------------
// 8. File System
// ----------------------------------------------------------------------------------
// --------------------------
@ -1166,7 +1455,7 @@ function disksIO(callback) {
exports.disksIO = disksIO;
// ----------------------------------------------------------------------------------
// 8. Network
// 9. Network
// ----------------------------------------------------------------------------------
function getDefaultNetworkInterface() {
@ -1528,7 +1817,7 @@ function networkConnections(callback) {
exports.networkConnections = networkConnections;
// ----------------------------------------------------------------------------------
// 9. Processes
// 10. Processes
// ----------------------------------------------------------------------------------
// --------------------------
@ -2057,7 +2346,7 @@ function processLoad(proc, callback) {
exports.processLoad = processLoad;
// ----------------------------------------------------------------------------------
// 10. Users/Sessions
// 11. Users/Sessions
// ----------------------------------------------------------------------------------
// --------------------------
@ -2240,7 +2529,7 @@ function users(callback) {
exports.users = users;
// ----------------------------------------------------------------------------------
// 11. Internet
// 12. Internet
// ----------------------------------------------------------------------------------
// --------------------------
@ -2329,7 +2618,7 @@ function inetLatency(host, callback) {
exports.inetLatency = inetLatency;
// ----------------------------------------------------------------------------------
// 12. Docker
// 13. Docker
// ----------------------------------------------------------------------------------
// --------------------------
@ -2615,7 +2904,7 @@ function dockerAll(callback) {
exports.dockerAll = dockerAll;
// ----------------------------------------------------------------------------------
// 13. get all
// 14. get all
// ----------------------------------------------------------------------------------
// --------------------------
@ -2641,10 +2930,13 @@ function getStaticData(callback) {
data.os = res;
cpu().then(res => {
data.cpu = res;
networkInterfaces().then(res => {
data.net = res;
if (callback) { callback(data) }
resolve(data);
graphics().then(res => {
data.graphics = res;
networkInterfaces().then(res => {
data.net = res;
if (callback) { callback(data) }
resolve(data);
})
})
})
})

View File

@ -30,7 +30,11 @@
"users",
"internet",
"battery",
"docker"
"docker",
"graphics",
"graphic card",
"graphic controller",
"display"
],
"repository": {
"type": "git",