1
2
3
4
5 package oshi.hardware.platform.linux;
6
7 import static oshi.software.os.linux.LinuxOperatingSystem.HAS_UDEV;
8
9 import java.io.File;
10 import java.time.LocalDate;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16
17 import com.sun.jna.platform.linux.Udev;
18 import com.sun.jna.platform.linux.Udev.UdevContext;
19 import com.sun.jna.platform.linux.Udev.UdevDevice;
20 import com.sun.jna.platform.linux.Udev.UdevEnumerate;
21 import com.sun.jna.platform.linux.Udev.UdevListEntry;
22
23 import oshi.annotation.concurrent.ThreadSafe;
24 import oshi.hardware.PowerSource;
25 import oshi.hardware.common.AbstractPowerSource;
26 import oshi.util.Constants;
27 import oshi.util.FileUtil;
28 import oshi.util.ParseUtil;
29 import oshi.util.platform.linux.SysPath;
30
31
32
33
34 @ThreadSafe
35 public final class LinuxPowerSource extends AbstractPowerSource {
36
37 public LinuxPowerSource(String psName, String psDeviceName, double psRemainingCapacityPercent,
38 double psTimeRemainingEstimated, double psTimeRemainingInstant, double psPowerUsageRate, double psVoltage,
39 double psAmperage, boolean psPowerOnLine, boolean psCharging, boolean psDischarging,
40 CapacityUnits psCapacityUnits, int psCurrentCapacity, int psMaxCapacity, int psDesignCapacity,
41 int psCycleCount, String psChemistry, LocalDate psManufactureDate, String psManufacturer,
42 String psSerialNumber, double psTemperature) {
43 super(psName, psDeviceName, psRemainingCapacityPercent, psTimeRemainingEstimated, psTimeRemainingInstant,
44 psPowerUsageRate, psVoltage, psAmperage, psPowerOnLine, psCharging, psDischarging, psCapacityUnits,
45 psCurrentCapacity, psMaxCapacity, psDesignCapacity, psCycleCount, psChemistry, psManufactureDate,
46 psManufacturer, psSerialNumber, psTemperature);
47 }
48
49
50
51
52
53
54 public static List<PowerSource> getPowerSources() {
55 String psName;
56 String psDeviceName;
57 double psRemainingCapacityPercent = -1d;
58 double psTimeRemainingEstimated = -1d;
59 double psTimeRemainingInstant = -1d;
60 double psPowerUsageRate = 0d;
61 double psVoltage = -1d;
62 double psAmperage = 0d;
63 boolean psPowerOnLine = false;
64 boolean psCharging = false;
65 boolean psDischarging = false;
66 CapacityUnits psCapacityUnits = CapacityUnits.RELATIVE;
67 int psCurrentCapacity = -1;
68 int psMaxCapacity = -1;
69 int psDesignCapacity = -1;
70 int psCycleCount = -1;
71 String psChemistry;
72 LocalDate psManufactureDate = null;
73 String psManufacturer;
74 String psSerialNumber;
75 double psTemperature = 0d;
76
77 List<PowerSource> psList = new ArrayList<>();
78 if (HAS_UDEV) {
79 UdevContext udev = Udev.INSTANCE.udev_new();
80 try {
81 UdevEnumerate enumerate = udev.enumerateNew();
82 try {
83 enumerate.addMatchSubsystem("power_supply");
84 enumerate.scanDevices();
85 for (UdevListEntry entry = enumerate.getListEntry(); entry != null; entry = entry.getNext()) {
86 String syspath = entry.getName();
87 String name = syspath.substring(syspath.lastIndexOf(File.separatorChar) + 1);
88 if (!name.startsWith("ADP") && !name.startsWith("AC")) {
89 UdevDevice device = udev.deviceNewFromSyspath(syspath);
90 if (device != null) {
91 try {
92 if (ParseUtil.parseIntOrDefault(device.getPropertyValue("POWER_SUPPLY_PRESENT"),
93 1) > 0
94 && ParseUtil.parseIntOrDefault(
95 device.getPropertyValue("POWER_SUPPLY_ONLINE"), 1) > 0) {
96 psName = getOrDefault(device, "POWER_SUPPLY_NAME", name);
97 String status = device.getPropertyValue("POWER_SUPPLY_STATUS");
98 psCharging = "Charging".equals(status);
99 psDischarging = "Discharging".equals(status);
100 psRemainingCapacityPercent = ParseUtil.parseIntOrDefault(
101 device.getPropertyValue("POWER_SUPPLY_CAPACITY"), -100) / 100d;
102
103
104 psCurrentCapacity = ParseUtil.parseIntOrDefault(
105 device.getPropertyValue("POWER_SUPPLY_ENERGY_NOW"), -1);
106 if (psCurrentCapacity < 0) {
107 psCurrentCapacity = ParseUtil.parseIntOrDefault(
108 device.getPropertyValue("POWER_SUPPLY_CHARGE_NOW"), -1);
109 }
110 psMaxCapacity = ParseUtil.parseIntOrDefault(
111 device.getPropertyValue("POWER_SUPPLY_ENERGY_FULL"), 1);
112 if (psMaxCapacity < 0) {
113 psMaxCapacity = ParseUtil.parseIntOrDefault(
114 device.getPropertyValue("POWER_SUPPLY_CHARGE_FULL"), 1);
115 }
116 psDesignCapacity = ParseUtil.parseIntOrDefault(
117 device.getPropertyValue("POWER_SUPPLY_ENERGY_FULL_DESIGN"), 1);
118 if (psDesignCapacity < 0) {
119 psDesignCapacity = ParseUtil.parseIntOrDefault(
120 device.getPropertyValue("POWER_SUPPLY_CHARGE_FULL_DESIGN"), 1);
121 }
122
123
124
125 psVoltage = ParseUtil.parseIntOrDefault(
126 device.getPropertyValue("POWER_SUPPLY_VOLTAGE_NOW"), -1);
127
128 if (psVoltage > 0) {
129 String power = device.getPropertyValue("POWER_SUPPLY_POWER_NOW");
130 String current = device.getPropertyValue("POWER_SUPPLY_CURRENT_NOW");
131 if (power == null) {
132 psAmperage = ParseUtil.parseIntOrDefault(current, 0);
133 psPowerUsageRate = psAmperage * psVoltage;
134 } else if (current == null) {
135 psPowerUsageRate = ParseUtil.parseIntOrDefault(power, 0);
136 psAmperage = psPowerUsageRate / psVoltage;
137 } else {
138 psAmperage = ParseUtil.parseIntOrDefault(current, 0);
139 psPowerUsageRate = ParseUtil.parseIntOrDefault(power, 0);
140 }
141 }
142
143 psCycleCount = ParseUtil.parseIntOrDefault(
144 device.getPropertyValue("POWER_SUPPLY_CYCLE_COUNT"), -1);
145 psChemistry = getOrDefault(device, "POWER_SUPPLY_TECHNOLOGY",
146 Constants.UNKNOWN);
147 psDeviceName = getOrDefault(device, "POWER_SUPPLY_MODEL_NAME",
148 Constants.UNKNOWN);
149 psManufacturer = getOrDefault(device, "POWER_SUPPLY_MANUFACTURER",
150 Constants.UNKNOWN);
151 psSerialNumber = getOrDefault(device, "POWER_SUPPLY_SERIAL_NUMBER",
152 Constants.UNKNOWN);
153
154 psList.add(new LinuxPowerSource(psName, psDeviceName,
155 psRemainingCapacityPercent, psTimeRemainingEstimated,
156 psTimeRemainingInstant, psPowerUsageRate, psVoltage, psAmperage,
157 psPowerOnLine, psCharging, psDischarging, psCapacityUnits,
158 psCurrentCapacity, psMaxCapacity, psDesignCapacity, psCycleCount,
159 psChemistry, psManufactureDate, psManufacturer, psSerialNumber,
160 psTemperature));
161 }
162 } finally {
163 device.unref();
164 }
165 }
166 }
167 }
168 } finally {
169 enumerate.unref();
170 }
171 } finally {
172 udev.unref();
173 }
174 } else {
175 File psDir = new File(SysPath.POWER_SUPPLY);
176 File[] psArr = psDir.listFiles();
177 if (psArr == null) {
178 return Collections.emptyList();
179 }
180 for (File ps : psArr) {
181 String name = ps.getName();
182 if (!name.startsWith("ADP") && !name.startsWith("AC")) {
183
184 List<String> psInfo = FileUtil.readFile(SysPath.POWER_SUPPLY + "/" + name + "/uevent", false);
185 Map<String, String> psMap = new HashMap<>();
186 for (String line : psInfo) {
187 String[] split = line.split("=");
188 if (split.length > 1 && !split[1].isEmpty()) {
189 psMap.put(split[0], split[1]);
190 }
191 }
192
193 psName = psMap.getOrDefault("POWER_SUPPLY_NAME", name);
194 String status = psMap.get("POWER_SUPPLY_STATUS");
195 psCharging = "Charging".equals(status);
196 psDischarging = "Discharging".equals(status);
197
198 if (psMap.containsKey("POWER_SUPPLY_CAPACITY")) {
199 psRemainingCapacityPercent = ParseUtil.parseIntOrDefault(psMap.get("POWER_SUPPLY_CAPACITY"),
200 -100) / 100d;
201 }
202 if (psMap.containsKey("POWER_SUPPLY_ENERGY_NOW")) {
203 psCurrentCapacity = ParseUtil.parseIntOrDefault(psMap.get("POWER_SUPPLY_ENERGY_NOW"), -1);
204 } else if (psMap.containsKey("POWER_SUPPLY_CHARGE_NOW")) {
205 psCurrentCapacity = ParseUtil.parseIntOrDefault(psMap.get("POWER_SUPPLY_CHARGE_NOW"), -1);
206 }
207 if (psMap.containsKey("POWER_SUPPLY_ENERGY_FULL")) {
208 psCurrentCapacity = ParseUtil.parseIntOrDefault(psMap.get("POWER_SUPPLY_ENERGY_FULL"), 1);
209 } else if (psMap.containsKey("POWER_SUPPLY_CHARGE_FULL")) {
210 psCurrentCapacity = ParseUtil.parseIntOrDefault(psMap.get("POWER_SUPPLY_CHARGE_FULL"), 1);
211 }
212 if (psMap.containsKey("POWER_SUPPLY_ENERGY_FULL_DESIGN")) {
213 psMaxCapacity = ParseUtil.parseIntOrDefault(psMap.get("POWER_SUPPLY_ENERGY_FULL_DESIGN"), 1);
214 } else if (psMap.containsKey("POWER_SUPPLY_CHARGE_FULL_DESIGN")) {
215 psMaxCapacity = ParseUtil.parseIntOrDefault(psMap.get("POWER_SUPPLY_CHARGE_FULL_DESIGN"), 1);
216 }
217
218
219 if (psMap.containsKey("POWER_SUPPLY_VOLTAGE_NOW")) {
220 psVoltage = ParseUtil.parseIntOrDefault(psMap.get("POWER_SUPPLY_VOLTAGE_NOW"), -1);
221 }
222
223 if (psVoltage > 0) {
224 if (psMap.containsKey("POWER_SUPPLY_POWER_NOW")) {
225 psPowerUsageRate = ParseUtil.parseIntOrDefault(psMap.get("POWER_SUPPLY_POWER_NOW"), -1);
226 }
227 if (psMap.containsKey("POWER_SUPPLY_CURRENT_NOW")) {
228 psAmperage = ParseUtil.parseIntOrDefault(psMap.get("POWER_SUPPLY_CURRENT_NOW"), -1);
229 }
230 if (psPowerUsageRate < 0 && psAmperage >= 0) {
231 psPowerUsageRate = psAmperage * psVoltage;
232 } else if (psPowerUsageRate >= 0 && psAmperage < 0) {
233 psAmperage = psPowerUsageRate / psVoltage;
234 } else {
235 psAmperage = 0;
236 psPowerUsageRate = 0;
237 }
238 }
239
240 if (psMap.containsKey("POWER_SUPPLY_CYCLE_COUNT")) {
241 psCycleCount = ParseUtil.parseIntOrDefault(psMap.get("POWER_SUPPLY_CYCLE_COUNT"), -1);
242 }
243 psChemistry = psMap.getOrDefault("POWER_SUPPLY_TECHNOLOGY", Constants.UNKNOWN);
244 psDeviceName = psMap.getOrDefault("POWER_SUPPLY_MODEL_NAME", Constants.UNKNOWN);
245 psManufacturer = psMap.getOrDefault("POWER_SUPPLY_MANUFACTURER", Constants.UNKNOWN);
246 psSerialNumber = psMap.getOrDefault("POWER_SUPPLY_SERIAL_NUMBER", Constants.UNKNOWN);
247 if (ParseUtil.parseIntOrDefault(psMap.get("POWER_SUPPLY_PRESENT"), 1) > 0) {
248 psList.add(new LinuxPowerSource(psName, psDeviceName, psRemainingCapacityPercent,
249 psTimeRemainingEstimated, psTimeRemainingInstant, psPowerUsageRate, psVoltage,
250 psAmperage, psPowerOnLine, psCharging, psDischarging, psCapacityUnits,
251 psCurrentCapacity, psMaxCapacity, psDesignCapacity, psCycleCount, psChemistry,
252 psManufactureDate, psManufacturer, psSerialNumber, psTemperature));
253 }
254 }
255 }
256 }
257 return psList;
258 }
259
260 private static String getOrDefault(UdevDevice device, String property, String def) {
261 String value = device.getPropertyValue(property);
262 return value == null ? def : value;
263 }
264 }