1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
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');
|
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 | module.exports = function (callback) {
|
31 |
|
32 | return new Promise((resolve) => {
|
33 | process.nextTick(() => {
|
34 | let result = {
|
35 | hasbattery: false,
|
36 | cyclecount: 0,
|
37 | ischarging: false,
|
38 | designedcapacity: 0,
|
39 | maxcapacity: 0,
|
40 | currentcapacity: 0,
|
41 | voltage: 0,
|
42 | capacityUnit: '',
|
43 | percent: 0,
|
44 | timeremaining: -1,
|
45 | acconnected: true,
|
46 | type: '',
|
47 | model: '',
|
48 | manufacturer: '',
|
49 | serial: ''
|
50 | };
|
51 |
|
52 | if (_linux) {
|
53 | let battery_path = '';
|
54 | if (fs.existsSync('/sys/class/power_supply/BAT1/uevent')) {
|
55 | battery_path = '/sys/class/power_supply/BAT1/';
|
56 | } else if (fs.existsSync('/sys/class/power_supply/BAT0/uevent')) {
|
57 | battery_path = '/sys/class/power_supply/BAT0/';
|
58 | }
|
59 | if (battery_path) {
|
60 | fs.readFile(battery_path + 'uevent', function (error, stdout) {
|
61 | if (!error) {
|
62 | let lines = stdout.toString().split('\n');
|
63 |
|
64 | result.ischarging = (util.getValue(lines, 'POWER_SUPPLY_STATUS', '=').toLowerCase() === 'charging');
|
65 | result.acconnected = result.ischarging;
|
66 | result.voltage = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_VOLTAGE_NOW', '='), 10) / 1000000.0;
|
67 | result.capacityUnit = result.voltage ? 'mWh' : 'mAh';
|
68 | result.cyclecount = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CYCLE_COUNT', '='), 10);
|
69 | result.maxcapacity = Math.round(parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CHARGE_FULL', '='), 10) / 1000.0 / (result.voltage || 1));
|
70 | result.designedcapacity = Math.round(parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CHARGE_FULL_DESIGN', '='), 10) / 1000.0 / (result.voltage || 1)) | result.maxcapacity;
|
71 | result.currentcapacity = Math.round(parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CHARGE_NOW', '='), 10) / 1000.0 / (result.voltage || 1));
|
72 | if (!result.maxcapacity) {
|
73 | result.maxcapacity = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_ENERGY_FULL', '='), 10) / 1000.0;
|
74 | result.designcapacity = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_ENERGY_FULL_DESIGN', '='), 10) / 1000.0 | result.maxcapacity;
|
75 | result.currentcapacity = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_ENERGY_NOW', '='), 10) / 1000.0;
|
76 | }
|
77 | const percent = util.getValue(lines, 'POWER_SUPPLY_CAPACITY', '=');
|
78 | const energy = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_ENERGY_NOW', '='), 10);
|
79 | const power = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_POWER_NOW', '='), 10);
|
80 | const current = parseInt('0' + util.getValue(lines, 'POWER_SUPPLY_CURRENT_NOW', '='), 10);
|
81 |
|
82 | result.percent = parseInt('0' + percent, 10);
|
83 | if (result.maxcapacity && result.currentcapacity) {
|
84 | result.hasbattery = true;
|
85 | if (!percent) {
|
86 | result.percent = 100.0 * result.currentcapacity / result.maxcapacity;
|
87 | }
|
88 | }
|
89 | if (result.ischarging) {
|
90 | result.hasbattery = true;
|
91 | }
|
92 | if (energy && power) {
|
93 | result.timeremaining = Math.floor(energy / power * 60);
|
94 | } else if (current && result.currentcapacity) {
|
95 | result.timeremaining = Math.floor(result.currentcapacity / current * 60);
|
96 | }
|
97 | result.type = util.getValue(lines, 'POWER_SUPPLY_TECHNOLOGY', '=');
|
98 | result.model = util.getValue(lines, 'POWER_SUPPLY_MODEL_NAME', '=');
|
99 | result.manufacturer = util.getValue(lines, 'POWER_SUPPLY_MANUFACTURER', '=');
|
100 | result.serial = util.getValue(lines, 'POWER_SUPPLY_SERIAL_NUMBER', '=');
|
101 | if (callback) { callback(result); }
|
102 | resolve(result);
|
103 | } else {
|
104 | if (callback) { callback(result); }
|
105 | resolve(result);
|
106 | }
|
107 | });
|
108 | } else {
|
109 | if (callback) { callback(result); }
|
110 | resolve(result);
|
111 | }
|
112 | }
|
113 | if (_freebsd || _openbsd || _netbsd) {
|
114 | exec('sysctl hw.acpi.battery hw.acpi.acline', function (error, stdout) {
|
115 | let lines = stdout.toString().split('\n');
|
116 | const batteries = parseInt('0' + util.getValue(lines, 'hw.acpi.battery.units'), 10);
|
117 | const percent = parseInt('0' + util.getValue(lines, 'hw.acpi.battery.life'), 10);
|
118 | result.hasbattery = (batteries > 0);
|
119 | result.cyclecount = -1;
|
120 | result.ischarging = util.getValue(lines, 'hw.acpi.acline') !== '1';
|
121 | result.acconnected = result.ischarging;
|
122 | result.maxcapacity = -1;
|
123 | result.currentcapacity = -1;
|
124 | result.capacityUnit = 'unknown';
|
125 | result.percent = batteries ? percent : -1;
|
126 | if (callback) { callback(result); }
|
127 | resolve(result);
|
128 | });
|
129 | }
|
130 |
|
131 | if (_darwin) {
|
132 | exec('ioreg -n AppleSmartBattery -r | egrep "CycleCount|IsCharging|DesignCapacity|MaxCapacity|CurrentCapacity|BatterySerialNumber|TimeRemaining|Voltage"; pmset -g batt | grep %', function (error, stdout) {
|
133 | if (stdout) {
|
134 | let lines = stdout.toString().replace(/ +/g, '').replace(/"+/g, '').replace(/-/g, '').split('\n');
|
135 | result.cyclecount = parseInt('0' + util.getValue(lines, 'cyclecount', '='), 10);
|
136 | result.voltage = parseInt('0' + util.getValue(lines, 'voltage', '='), 10) / 1000.0;
|
137 | result.capacityUnit = result.voltage ? 'mWh' : 'mAh';
|
138 | result.maxcapacity = Math.round(parseInt('0' + util.getValue(lines, 'maxcapacity', '='), 10) * (result.voltage || 1));
|
139 | result.currentcapacity = Math.round(parseInt('0' + util.getValue(lines, 'currentcapacity', '='), 10) * (result.voltage || 1));
|
140 | result.designedcapacity = Math.round(parseInt('0' + util.getValue(lines, 'DesignCapacity', '='), 10) * (result.voltage || 1));
|
141 | result.manufacturer = 'Apple';
|
142 | result.serial = util.getValue(lines, 'BatterySerialNumber', '=');
|
143 | let percent = -1;
|
144 | const line = util.getValue(lines, 'internal', 'Battery');
|
145 | let parts = line.split(';');
|
146 | if (parts && parts[0]) {
|
147 | let parts2 = parts[0].split('\t');
|
148 | if (parts2 && parts2[1]) {
|
149 | percent = parseFloat(parts2[1].trim().replace(/%/g, ''));
|
150 | }
|
151 | }
|
152 | if (parts && parts[1]) {
|
153 | result.ischarging = (parts[1].trim() === 'charging');
|
154 | result.acconnected = (parts[1].trim() !== 'discharging');
|
155 | } else {
|
156 | result.ischarging = util.getValue(lines, 'ischarging', '=').toLowerCase() === 'yes';
|
157 | result.acconnected = result.ischarging;
|
158 | }
|
159 | if (result.maxcapacity && result.currentcapacity) {
|
160 | result.hasbattery = true;
|
161 | result.type = 'Li-ion';
|
162 | result.percent = percent !== -1 ? percent : Math.round(100.0 * result.currentcapacity / result.maxcapacity);
|
163 | if (!result.ischarging) {
|
164 | result.timeremaining = parseInt('0' + util.getValue(lines, 'TimeRemaining', '='), 10);
|
165 | }
|
166 | }
|
167 | }
|
168 | if (callback) { callback(result); }
|
169 | resolve(result);
|
170 | });
|
171 | }
|
172 | if (_sunos) {
|
173 | if (callback) { callback(result); }
|
174 | resolve(result);
|
175 | }
|
176 | if (_windows) {
|
177 | try {
|
178 | util.wmic('Path Win32_Battery Get BatteryStatus, DesignCapacity, EstimatedChargeRemaining, DesignVoltage, FullChargeCapacity /value').then((stdout) => {
|
179 | if (stdout) {
|
180 | let lines = stdout.split('\r\n');
|
181 | let status = util.getValue(lines, 'BatteryStatus', '=').trim();
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 | if (status && status != '10') {
|
194 | const statusValue = parseInt(status);
|
195 | result.hasbattery = true;
|
196 | result.maxcapacity = parseInt(util.getValue(lines, 'DesignCapacity', '=') || 0);
|
197 | result.designcapacity = parseInt(util.getValue(lines, 'DesignCapacity', '=') || 0);
|
198 | result.voltage = parseInt(util.getValue(lines, 'DesignVoltage', '=') || 0) / 1000.0;
|
199 | result.capacityUnit = 'mWh';
|
200 | result.percent = parseInt(util.getValue(lines, 'EstimatedChargeRemaining', '=') || 0);
|
201 | result.currentcapacity = parseInt(result.maxcapacity * result.percent / 100);
|
202 | result.ischarging = (statusValue >= 6 && statusValue <= 9) || statusValue === 11 || (!(statusValue === 3) && !(statusValue === 1) && result.percent < 100);
|
203 | result.acconnected = result.ischarging || statusValue === 2;
|
204 | }
|
205 | }
|
206 | if (callback) { callback(result); }
|
207 | resolve(result);
|
208 | });
|
209 | } catch (e) {
|
210 | if (callback) { callback(result); }
|
211 | resolve(result);
|
212 | }
|
213 | }
|
214 | });
|
215 | });
|
216 | };
|