sysiddr5 1.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sysiddr5 might be problematic. Click here for more details.

package/lib/audio.js ADDED
@@ -0,0 +1,222 @@
1
+ 'use strict';
2
+ // @ts-check
3
+ // ==================================================================================
4
+ // audio.js
5
+ // ----------------------------------------------------------------------------------
6
+ // Description: System Information - library
7
+ // for Node.js
8
+ // Copyright: (c) 2014 - 2023
9
+ // Author: Sebastian Hildebrandt
10
+ // ----------------------------------------------------------------------------------
11
+ // License: MIT
12
+ // ==================================================================================
13
+ // 16. audio
14
+ // ----------------------------------------------------------------------------------
15
+
16
+ const exec = require('child_process').exec;
17
+ const execSync = require('child_process').execSync;
18
+ const util = require('./util');
19
+
20
+ let _platform = process.platform;
21
+
22
+ const _linux = (_platform === 'linux' || _platform === 'android');
23
+ const _darwin = (_platform === 'darwin');
24
+ const _windows = (_platform === 'win32');
25
+ const _freebsd = (_platform === 'freebsd');
26
+ const _openbsd = (_platform === 'openbsd');
27
+ const _netbsd = (_platform === 'netbsd');
28
+ const _sunos = (_platform === 'sunos');
29
+
30
+ function parseAudioType(str, input, output) {
31
+ str = str.toLowerCase();
32
+ let result = '';
33
+
34
+ if (str.indexOf('input') >= 0) { result = 'Microphone'; }
35
+ if (str.indexOf('display audio') >= 0) { result = 'Speaker'; }
36
+ if (str.indexOf('speak') >= 0) { result = 'Speaker'; }
37
+ if (str.indexOf('laut') >= 0) { result = 'Speaker'; }
38
+ if (str.indexOf('loud') >= 0) { result = 'Speaker'; }
39
+ if (str.indexOf('head') >= 0) { result = 'Headset'; }
40
+ if (str.indexOf('mic') >= 0) { result = 'Microphone'; }
41
+ if (str.indexOf('mikr') >= 0) { result = 'Microphone'; }
42
+ if (str.indexOf('phone') >= 0) { result = 'Phone'; }
43
+ if (str.indexOf('controll') >= 0) { result = 'Controller'; }
44
+ if (str.indexOf('line o') >= 0) { result = 'Line Out'; }
45
+ if (str.indexOf('digital o') >= 0) { result = 'Digital Out'; }
46
+ if (str.indexOf('smart sound technology') >= 0) { result = 'Digital Signal Processor'; }
47
+ if (str.indexOf('high definition audio') >= 0) { result = 'Sound Driver'; }
48
+
49
+ if (!result && output) {
50
+ result = 'Speaker';
51
+ } else if (!result && input) {
52
+ result = 'Microphone';
53
+ }
54
+ return result;
55
+ }
56
+
57
+
58
+ function getLinuxAudioPci() {
59
+ let cmd = 'lspci -v 2>/dev/null';
60
+ let result = [];
61
+ try {
62
+ const parts = execSync(cmd).toString().split('\n\n');
63
+ parts.forEach(element => {
64
+ const lines = element.split('\n');
65
+ if (lines && lines.length && lines[0].toLowerCase().indexOf('audio') >= 0) {
66
+ const audio = {};
67
+ audio.slotId = lines[0].split(' ')[0];
68
+ audio.driver = util.getValue(lines, 'Kernel driver in use', ':', true) || util.getValue(lines, 'Kernel modules', ':', true);
69
+ result.push(audio);
70
+ }
71
+ });
72
+ return result;
73
+ } catch (e) {
74
+ return result;
75
+ }
76
+ }
77
+
78
+ function parseLinuxAudioPciMM(lines, audioPCI) {
79
+ const result = {};
80
+ const slotId = util.getValue(lines, 'Slot');
81
+
82
+ const pciMatch = audioPCI.filter(function (item) { return item.slotId === slotId; });
83
+
84
+ result.id = slotId;
85
+ result.name = util.getValue(lines, 'SDevice');
86
+ result.manufacturer = util.getValue(lines, 'SVendor');
87
+ result.revision = util.getValue(lines, 'Rev');
88
+ result.driver = pciMatch && pciMatch.length === 1 && pciMatch[0].driver ? pciMatch[0].driver : '';
89
+ result.default = null;
90
+ result.channel = 'PCIe';
91
+ result.type = parseAudioType(result.name, null, null);
92
+ result.in = null;
93
+ result.out = null;
94
+ result.status = 'online';
95
+
96
+ return result;
97
+ }
98
+
99
+ function parseDarwinChannel(str) {
100
+ let result = '';
101
+
102
+ if (str.indexOf('builtin') >= 0) { result = 'Built-In'; }
103
+ if (str.indexOf('extern') >= 0) { result = 'Audio-Jack'; }
104
+ if (str.indexOf('hdmi') >= 0) { result = 'HDMI'; }
105
+ if (str.indexOf('displayport') >= 0) { result = 'Display-Port'; }
106
+ if (str.indexOf('usb') >= 0) { result = 'USB'; }
107
+ if (str.indexOf('pci') >= 0) { result = 'PCIe'; }
108
+
109
+ return result;
110
+ }
111
+
112
+ function parseDarwinAudio(audioObject, id) {
113
+ const result = {};
114
+ const channelStr = ((audioObject.coreaudio_device_transport || '') + ' ' + (audioObject._name || '')).toLowerCase();
115
+
116
+ result.id = id;
117
+ result.name = audioObject._name;
118
+ result.manufacturer = audioObject.coreaudio_device_manufacturer;
119
+ result.revision = null;
120
+ result.driver = null;
121
+ result.default = !!(audioObject.coreaudio_default_audio_input_device || '') || !!(audioObject.coreaudio_default_audio_output_device || '');
122
+ result.channel = parseDarwinChannel(channelStr);
123
+ result.type = parseAudioType(result.name, !!(audioObject.coreaudio_device_input || ''), !!(audioObject.coreaudio_device_output || ''));
124
+ result.in = !!(audioObject.coreaudio_device_input || '');
125
+ result.out = !!(audioObject.coreaudio_device_output || '');
126
+ result.status = 'online';
127
+
128
+ return result;
129
+ }
130
+
131
+ function parseWindowsAudio(lines) {
132
+ const result = {};
133
+ const status = util.getValue(lines, 'StatusInfo', ':');
134
+
135
+ result.id = util.getValue(lines, 'DeviceID', ':'); // PNPDeviceID??
136
+ result.name = util.getValue(lines, 'name', ':');
137
+ result.manufacturer = util.getValue(lines, 'manufacturer', ':');
138
+ result.revision = null;
139
+ result.driver = null;
140
+ result.default = null;
141
+ result.channel = null;
142
+ result.type = parseAudioType(result.name, null, null);
143
+ result.in = null;
144
+ result.out = null;
145
+ result.status = status;
146
+
147
+ return result;
148
+ }
149
+
150
+ function audio(callback) {
151
+
152
+ return new Promise((resolve) => {
153
+ process.nextTick(() => {
154
+ let result = [];
155
+ if (_linux || _freebsd || _openbsd || _netbsd) {
156
+ let cmd = 'lspci -vmm 2>/dev/null';
157
+ exec(cmd, function (error, stdout) {
158
+ // PCI
159
+ if (!error) {
160
+ const audioPCI = getLinuxAudioPci();
161
+ const parts = stdout.toString().split('\n\n');
162
+ parts.forEach(element => {
163
+ const lines = element.split('\n');
164
+ if (util.getValue(lines, 'class', ':', true).toLowerCase().indexOf('audio') >= 0) {
165
+ const audio = parseLinuxAudioPciMM(lines, audioPCI);
166
+ result.push(audio);
167
+ }
168
+ });
169
+ }
170
+ if (callback) {
171
+ callback(result);
172
+ }
173
+ resolve(result);
174
+ });
175
+ }
176
+ if (_darwin) {
177
+ let cmd = 'system_profiler SPAudioDataType -json';
178
+ exec(cmd, function (error, stdout) {
179
+ if (!error) {
180
+ try {
181
+ const outObj = JSON.parse(stdout.toString());
182
+ if (outObj.SPAudioDataType && outObj.SPAudioDataType.length && outObj.SPAudioDataType[0] && outObj.SPAudioDataType[0]['_items'] && outObj.SPAudioDataType[0]['_items'].length) {
183
+ for (let i = 0; i < outObj.SPAudioDataType[0]['_items'].length; i++) {
184
+ const audio = parseDarwinAudio(outObj.SPAudioDataType[0]['_items'][i], i);
185
+ result.push(audio);
186
+ }
187
+ }
188
+ } catch (e) {
189
+ util.noop();
190
+ }
191
+ }
192
+ if (callback) {
193
+ callback(result);
194
+ }
195
+ resolve(result);
196
+ });
197
+ }
198
+ if (_windows) {
199
+ util.powerShell('Get-CimInstance Win32_SoundDevice | select DeviceID,StatusInfo,Name,Manufacturer | fl').then((stdout, error) => {
200
+ if (!error) {
201
+ const parts = stdout.toString().split(/\n\s*\n/);
202
+ parts.forEach(element => {
203
+ const lines = element.split('\n');
204
+ if (util.getValue(lines, 'name', ':')) {
205
+ result.push(parseWindowsAudio(lines));
206
+ }
207
+ });
208
+ }
209
+ if (callback) {
210
+ callback(result);
211
+ }
212
+ resolve(result);
213
+ });
214
+ }
215
+ if (_sunos) {
216
+ resolve(null);
217
+ }
218
+ });
219
+ });
220
+ }
221
+
222
+ exports.audio = audio;
package/lib/battery.js ADDED
@@ -0,0 +1,308 @@
1
+ 'use strict';
2
+ // @ts-check;
3
+ // ==================================================================================
4
+ // battery.js
5
+ // ----------------------------------------------------------------------------------
6
+ // Description: System Information - library
7
+ // for Node.js
8
+ // Copyright: (c) 2014 - 2023
9
+ // Author: Sebastian Hildebrandt
10
+ // ----------------------------------------------------------------------------------
11
+ // License: MIT
12
+ // ==================================================================================
13
+ // 6. Battery
14
+ // ----------------------------------------------------------------------------------
15
+
16
+ const exec = require('child_process').exec;
17
+ const fs = require('fs');
18
+ const util = require('./util');
19
+
20
+ let _platform = process.platform;
21
+
22
+ const _linux = (_platform === 'linux' || _platform === 'android');
23
+ const _darwin = (_platform === 'darwin');
24
+ const _windows = (_platform === 'win32');
25
+ const _freebsd = (_platform === 'freebsd');
26
+ const _openbsd = (_platform === 'openbsd');
27
+ const _netbsd = (_platform === 'netbsd');
28
+ const _sunos = (_platform === 'sunos');
29
+
30
+ function parseWinBatteryPart(lines, designedCapacity, fullChargeCapacity) {
31
+ const result = {};
32
+ let status = util.getValue(lines, 'BatteryStatus', ':').trim();
33
+ // 1 = "Discharging"
34
+ // 2 = "On A/C"
35
+ // 3 = "Fully Charged"
36
+ // 4 = "Low"
37
+ // 5 = "Critical"
38
+ // 6 = "Charging"
39
+ // 7 = "Charging High"
40
+ // 8 = "Charging Low"
41
+ // 9 = "Charging Critical"
42
+ // 10 = "Undefined"
43
+ // 11 = "Partially Charged"
44
+ if (status >= 0) {
45
+ const statusValue = status ? parseInt(status) : 0;
46
+ result.status = statusValue;
47
+ result.hasBattery = true;
48
+ result.maxCapacity = fullChargeCapacity || parseInt(util.getValue(lines, 'DesignCapacity', ':') || 0);
49
+ result.designedCapacity = parseInt(util.getValue(lines, 'DesignCapacity', ':') || designedCapacity);
50
+ result.voltage = parseInt(util.getValue(lines, 'DesignVoltage', ':') || 0) / 1000.0;
51
+ result.capacityUnit = 'mWh';
52
+ result.percent = parseInt(util.getValue(lines, 'EstimatedChargeRemaining', ':') || 0);
53
+ result.currentCapacity = parseInt(result.maxCapacity * result.percent / 100);
54
+ result.isCharging = (statusValue >= 6 && statusValue <= 9) || statusValue === 11 || ((statusValue !== 3) && (statusValue !== 1) && result.percent < 100);
55
+ result.acConnected = result.isCharging || statusValue === 2;
56
+ result.model = util.getValue(lines, 'DeviceID', ':');
57
+ } else {
58
+ result.status = -1;
59
+ }
60
+
61
+ return result;
62
+ }
63
+
64
+ module.exports = function (callback) {
65
+
66
+ return new Promise((resolve) => {
67
+ process.nextTick(() => {
68
+ let result = {
69
+ hasBattery: false,
70
+ cycleCount: 0,
71
+ isCharging: false,
72
+ designedCapacity: 0,
73
+ maxCapacity: 0,
74
+ currentCapacity: 0,
75
+ voltage: 0,
76
+ capacityUnit: '',
77
+ percent: 0,
78
+ timeRemaining: null,
79
+ acConnected: true,
80
+ type: '',
81
+ model: '',
82
+ manufacturer: '',
83
+ serial: ''
84
+ };
85
+
86
+ if (_linux) {
87
+ let battery_path = '';
88
+ if (fs.existsSync('/sys/class/power_supply/BAT1/uevent')) {
89
+ battery_path = '/sys/class/power_supply/BAT1/';
90
+ } else if (fs.existsSync('/sys/class/power_supply/BAT0/uevent')) {
91
+ battery_path = '/sys/class/power_supply/BAT0/';
92
+ }
93
+
94
+ let acConnected = false;
95
+ let acPath = '';
96
+ if (fs.existsSync('/sys/class/power_supply/AC/online')) {
97
+ acPath = '/sys/class/power_supply/AC/online';
98
+ } else if (fs.existsSync('/sys/class/power_supply/AC0/online')) {
99
+ acPath = '/sys/class/power_supply/AC0/online';
100
+ }
101
+
102
+ if (acPath) {
103
+ const file = fs.readFileSync(acPath);
104
+ acConnected = file.toString().trim() === '1';
105
+ }
106
+
107
+ if (battery_path) {
108
+ fs.readFile(battery_path + 'uevent', function (error, stdout) {
109
+ if (!error) {
110
+ let lines = stdout.toString().split('\n');
111
+
112
+ result.isCharging = (util.getValue(lines, 'POWER_SUPPLY_STATUS', '=').toLowerCase() === 'charging');
113
+ result.acConnected = acConnected || result.isCharging;
114
+ result.voltage = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_VOLTAGE_NOW', '='), 10) / 1000000.0;
115
+ result.capacityUnit = result.voltage ? 'mWh' : 'mAh';
116
+ result.cycleCount = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CYCLE_COUNT', '='), 10);
117
+ result.maxCapacity = Math.round(parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CHARGE_FULL', '=', true, true), 10) / 1000.0 * (result.voltage || 1));
118
+ const desingedMinVoltage = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_VOLTAGE_MIN_DESIGN', '='), 10) / 1000000.0;
119
+ result.designedCapacity = Math.round(parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CHARGE_FULL_DESIGN', '=', true, true), 10) / 1000.0 * (desingedMinVoltage || result.voltage || 1));
120
+ result.currentCapacity = Math.round(parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CHARGE_NOW', '='), 10) / 1000.0 * (result.voltage || 1));
121
+ if (!result.maxCapacity) {
122
+ result.maxCapacity = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_ENERGY_FULL', '=', true, true), 10) / 1000.0;
123
+ result.designedCapacity = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_ENERGY_FULL_DESIGN', '=', true, true), 10) / 1000.0 | result.maxCapacity;
124
+ result.currentCapacity = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_ENERGY_NOW', '='), 10) / 1000.0;
125
+ }
126
+ const percent = util.getValue(lines, 'POWER_SUPPLY_CAPACITY', '=');
127
+ const energy = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_ENERGY_NOW', '='), 10);
128
+ const power = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_POWER_NOW', '='), 10);
129
+ const current = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CURRENT_NOW', '='), 10);
130
+
131
+ result.percent = parseInt('0' + percent, 10);
132
+ if (result.maxCapacity && result.currentCapacity) {
133
+ result.hasBattery = true;
134
+ if (!percent) {
135
+ result.percent = 100.0 * result.currentCapacity / result.maxCapacity;
136
+ }
137
+ }
138
+ if (result.isCharging) {
139
+ result.hasBattery = true;
140
+ }
141
+ if (energy && power) {
142
+ result.timeRemaining = Math.floor(energy / power * 60);
143
+ } else if (current && result.currentCapacity) {
144
+ result.timeRemaining = Math.floor(result.currentCapacity / current * 60);
145
+ }
146
+ result.type = util.getValue(lines, 'POWER_SUPPLY_TECHNOLOGY', '=');
147
+ result.model = util.getValue(lines, 'POWER_SUPPLY_MODEL_NAME', '=');
148
+ result.manufacturer = util.getValue(lines, 'POWER_SUPPLY_MANUFACTURER', '=');
149
+ result.serial = util.getValue(lines, 'POWER_SUPPLY_SERIAL_NUMBER', '=');
150
+ if (callback) { callback(result); }
151
+ resolve(result);
152
+ } else {
153
+ if (callback) { callback(result); }
154
+ resolve(result);
155
+ }
156
+ });
157
+ } else {
158
+ if (callback) { callback(result); }
159
+ resolve(result);
160
+ }
161
+ }
162
+ if (_freebsd || _openbsd || _netbsd) {
163
+ exec('sysctl -i hw.acpi.battery hw.acpi.acline', function (error, stdout) {
164
+ let lines = stdout.toString().split('\n');
165
+ const batteries = parseInt('0' + util.getValue(lines, 'hw.acpi.battery.units'), 10);
166
+ const percent = parseInt('0' + util.getValue(lines, 'hw.acpi.battery.life'), 10);
167
+ result.hasBattery = (batteries > 0);
168
+ result.cycleCount = null;
169
+ result.isCharging = util.getValue(lines, 'hw.acpi.acline') !== '1';
170
+ result.acConnected = result.isCharging;
171
+ result.maxCapacity = null;
172
+ result.currentCapacity = null;
173
+ result.capacityUnit = 'unknown';
174
+ result.percent = batteries ? percent : null;
175
+ if (callback) { callback(result); }
176
+ resolve(result);
177
+ });
178
+ }
179
+
180
+ if (_darwin) {
181
+ exec('ioreg -n AppleSmartBattery -r | egrep "CycleCount|IsCharging|DesignCapacity|MaxCapacity|CurrentCapacity|BatterySerialNumber|TimeRemaining|Voltage"; pmset -g batt | grep %', function (error, stdout) {
182
+ if (stdout) {
183
+ let lines = stdout.toString().replace(/ +/g, '').replace(/"+/g, '').replace(/-/g, '').split('\n');
184
+ result.cycleCount = parseInt('0' + util.getValue(lines, 'cyclecount', '='), 10);
185
+ result.voltage = parseInt('0' + util.getValue(lines, 'voltage', '='), 10) / 1000.0;
186
+ result.capacityUnit = result.voltage ? 'mWh' : 'mAh';
187
+ result.maxCapacity = Math.round(parseInt('0' + util.getValue(lines, 'applerawmaxcapacity', '='), 10) * (result.voltage || 1));
188
+ result.currentCapacity = Math.round(parseInt('0' + util.getValue(lines, 'applerawcurrentcapacity', '='), 10) * (result.voltage || 1));
189
+ result.designedCapacity = Math.round(parseInt('0' + util.getValue(lines, 'DesignCapacity', '='), 10) * (result.voltage || 1));
190
+ result.manufacturer = 'Apple';
191
+ result.serial = util.getValue(lines, 'BatterySerialNumber', '=');
192
+ let percent = null;
193
+ const line = util.getValue(lines, 'internal', 'Battery');
194
+ let parts = line.split(';');
195
+ if (parts && parts[0]) {
196
+ let parts2 = parts[0].split('\t');
197
+ if (parts2 && parts2[1]) {
198
+ percent = parseFloat(parts2[1].trim().replace(/%/g, ''));
199
+ }
200
+ }
201
+ if (parts && parts[1]) {
202
+ result.isCharging = (parts[1].trim() === 'charging');
203
+ result.acConnected = (parts[1].trim() !== 'discharging');
204
+ } else {
205
+ result.isCharging = util.getValue(lines, 'ischarging', '=').toLowerCase() === 'yes';
206
+ result.acConnected = result.isCharging;
207
+ }
208
+ if (result.maxCapacity && result.currentCapacity) {
209
+ result.hasBattery = true;
210
+ result.type = 'Li-ion';
211
+ result.percent = percent !== null ? percent : Math.round(100.0 * result.currentCapacity / result.maxCapacity);
212
+ if (!result.isCharging) {
213
+ result.timeRemaining = parseInt('0' + util.getValue(lines, 'TimeRemaining', '='), 10);
214
+ }
215
+ }
216
+ }
217
+ if (callback) { callback(result); }
218
+ resolve(result);
219
+ });
220
+ }
221
+ if (_sunos) {
222
+ if (callback) { callback(result); }
223
+ resolve(result);
224
+ }
225
+ if (_windows) {
226
+ try {
227
+ const workload = [];
228
+ workload.push(util.powerShell('Get-CimInstance Win32_Battery | select BatteryStatus, DesignCapacity, DesignVoltage, EstimatedChargeRemaining, DeviceID | fl'));
229
+ workload.push(util.powerShell('(Get-CimInstance -Class BatteryStaticData -Namespace ROOT/WMI).DesignedCapacity'));
230
+ workload.push(util.powerShell('(Get-CimInstance -Class BatteryFullChargedCapacity -Namespace ROOT/WMI).FullChargedCapacity'));
231
+ util.promiseAll(
232
+ workload
233
+ ).then((data) => {
234
+ if (data) {
235
+ let parts = data.results[0].split(/\n\s*\n/);
236
+ let batteries = [];
237
+ const hasValue = value => /\S/.test(value);
238
+ for (let i = 0; i < parts.length; i++) {
239
+ if (hasValue(parts[i]) && (!batteries.length || !hasValue(parts[i - 1]))) {
240
+ batteries.push([]);
241
+ }
242
+ if (hasValue(parts[i])) {
243
+ batteries[batteries.length - 1].push(parts[i]);
244
+ }
245
+ }
246
+ let designCapacities = data.results[1].split('\r\n').filter(e => e);
247
+ let fullChargeCapacities = data.results[2].split('\r\n').filter(e => e);
248
+ if (batteries.length) {
249
+ let first = false;
250
+ let additionalBatteries = [];
251
+ for (let i = 0; i < batteries.length; i++) {
252
+ let lines = batteries[i][0].split('\r\n');
253
+ const designedCapacity = designCapacities && designCapacities.length >= (i + 1) && designCapacities[i] ? util.toInt(designCapacities[i]) : 0;
254
+ const fullChargeCapacity = fullChargeCapacities && fullChargeCapacities.length >= (i + 1) && fullChargeCapacities[i] ? util.toInt(fullChargeCapacities[i]) : 0;
255
+ const parsed = parseWinBatteryPart(lines, designedCapacity, fullChargeCapacity);
256
+ if (!first && parsed.status > 0 && parsed.status !== 10) {
257
+ result.hasBattery = parsed.hasBattery;
258
+ result.maxCapacity = parsed.maxCapacity;
259
+ result.designedCapacity = parsed.designedCapacity;
260
+ result.voltage = parsed.voltage;
261
+ result.capacityUnit = parsed.capacityUnit;
262
+ result.percent = parsed.percent;
263
+ result.currentCapacity = parsed.currentCapacity;
264
+ result.isCharging = parsed.isCharging;
265
+ result.acConnected = parsed.acConnected;
266
+ result.model = parsed.model;
267
+ first = true;
268
+ } else if (parsed.status !== -1) {
269
+ additionalBatteries.push(
270
+ {
271
+ hasBattery: parsed.hasBattery,
272
+ maxCapacity: parsed.maxCapacity,
273
+ designedCapacity: parsed.designedCapacity,
274
+ voltage: parsed.voltage,
275
+ capacityUnit: parsed.capacityUnit,
276
+ percent: parsed.percent,
277
+ currentCapacity: parsed.currentCapacity,
278
+ isCharging: parsed.isCharging,
279
+ timeRemaining: null,
280
+ acConnected: parsed.acConnected,
281
+ model: parsed.model,
282
+ type: '',
283
+ manufacturer: '',
284
+ serial: ''
285
+ }
286
+ );
287
+ }
288
+ }
289
+ if (!first && additionalBatteries.length) {
290
+ result = additionalBatteries[0];
291
+ additionalBatteries.shift();
292
+ }
293
+ if (additionalBatteries.length) {
294
+ result.additionalBatteries = additionalBatteries;
295
+ }
296
+ }
297
+ }
298
+ if (callback) { callback(result); }
299
+ resolve(result);
300
+ });
301
+ } catch (e) {
302
+ if (callback) { callback(result); }
303
+ resolve(result);
304
+ }
305
+ }
306
+ });
307
+ });
308
+ };