]> git.basschouten.com Git - openhab-addons.git/blob
f7d6e05973cd5ef0feee818208813f0c457fff35
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.systeminfo.internal.model;
14
15 import java.math.BigDecimal;
16 import java.math.RoundingMode;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20
21 import javax.measure.quantity.ElectricPotential;
22 import javax.measure.quantity.Temperature;
23 import javax.measure.quantity.Time;
24
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.openhab.core.library.dimension.DataAmount;
28 import org.openhab.core.library.types.DecimalType;
29 import org.openhab.core.library.types.PercentType;
30 import org.openhab.core.library.types.QuantityType;
31 import org.openhab.core.library.types.StringType;
32 import org.openhab.core.library.unit.SIUnits;
33 import org.openhab.core.library.unit.Units;
34 import org.osgi.service.component.annotations.Component;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import oshi.SystemInfo;
39 import oshi.hardware.CentralProcessor;
40 import oshi.hardware.ComputerSystem;
41 import oshi.hardware.Display;
42 import oshi.hardware.GlobalMemory;
43 import oshi.hardware.HWDiskStore;
44 import oshi.hardware.HardwareAbstractionLayer;
45 import oshi.hardware.NetworkIF;
46 import oshi.hardware.PowerSource;
47 import oshi.hardware.Sensors;
48 import oshi.software.os.OSFileStore;
49 import oshi.software.os.OSProcess;
50 import oshi.software.os.OperatingSystem;
51 import oshi.util.EdidUtil;
52
53 /**
54  * This implementation of {@link SysteminfoInterface} is using the open source library OSHI to provide system
55  * information. OSHI is a free JNA-based (native) Operating System and Hardware Information library for Java.
56  *
57  * @author Svilen Valkanov - Initial contribution
58  * @author Lyubomir Papazov - Move the initialization logic that could potentially take long time to the
59  *         initializeSysteminfo method
60  * @author Christoph Weitkamp - Update to OSHI 3.13.0 - Replaced deprecated method
61  *         CentralProcessor#getSystemSerialNumber()
62  * @author Wouter Born - Update to OSHI 4.0.0 and add null annotations
63  * @author Mark Herwege - Add dynamic creation of extra channels
64  * @author Mark Herwege - Use units of measure
65  *
66  * @see <a href="https://github.com/oshi/oshi">OSHI GitHub repository</a>
67  */
68 @NonNullByDefault
69 @Component(service = SysteminfoInterface.class)
70 public class OSHISysteminfo implements SysteminfoInterface {
71
72     private final Logger logger = LoggerFactory.getLogger(OSHISysteminfo.class);
73
74     private @NonNullByDefault({}) HardwareAbstractionLayer hal;
75
76     // Dynamic objects (may be queried repeatedly)
77     private @NonNullByDefault({}) GlobalMemory memory;
78     private @NonNullByDefault({}) CentralProcessor cpu;
79     private @NonNullByDefault({}) Sensors sensors;
80
81     // Static objects, should be recreated on each request
82     private @NonNullByDefault({}) ComputerSystem computerSystem;
83     private @NonNullByDefault({}) OperatingSystem operatingSystem;
84     private @NonNullByDefault({}) List<NetworkIF> networks;
85     private @NonNullByDefault({}) List<Display> displays;
86     private @NonNullByDefault({}) List<OSFileStore> fileStores;
87     private @NonNullByDefault({}) List<PowerSource> powerSources;
88     private @NonNullByDefault({}) List<HWDiskStore> drives;
89
90     // Array containing cpu tick info to calculate CPU load, according to oshi doc:
91     // 8 long values representing time spent in User, Nice, System, Idle, IOwait, IRQ, SoftIRQ, and Steal states
92     private long[] ticks = new long[8];
93     // Map containing previous process state to calculate load by process
94     private Map<Integer, OSProcess> processTicks = new HashMap<>();
95
96     public static final int PRECISION_AFTER_DECIMAL_SIGN = 1;
97
98     /**
99      * Some of the methods used in this constructor execute native code and require execute permissions
100      *
101      */
102     public OSHISysteminfo() {
103         logger.debug("OSHISysteminfo service is created");
104     }
105
106     @Override
107     public void initializeSysteminfo() {
108         logger.debug("OSHISysteminfo service starts initializing");
109
110         SystemInfo systemInfo = new SystemInfo();
111         hal = systemInfo.getHardware();
112
113         // Doesn't need regular update, they may be queried repeatedly
114         memory = hal.getMemory();
115         cpu = hal.getProcessor();
116         sensors = hal.getSensors();
117
118         computerSystem = hal.getComputerSystem();
119         operatingSystem = systemInfo.getOperatingSystem();
120         networks = hal.getNetworkIFs();
121         displays = hal.getDisplays();
122         fileStores = operatingSystem.getFileSystem().getFileStores();
123         powerSources = hal.getPowerSources();
124         drives = hal.getDiskStores();
125     }
126
127     private <T> T getDevice(List<@Nullable T> devices, int index) throws DeviceNotFoundException {
128         if (devices.size() <= index) {
129             throw new DeviceNotFoundException("Device with index: " + index + " can not be found!");
130         }
131         return (T) devices.get(index);
132     }
133
134     private <T> T getDevice(T @Nullable [] devices, int index) throws DeviceNotFoundException {
135         if (devices == null || devices.length <= index) {
136             throw new DeviceNotFoundException("Device with index: " + index + " can not be found!");
137         }
138         return devices[index];
139     }
140
141     private OSProcess getProcess(int pid) throws DeviceNotFoundException {
142         OSProcess process = operatingSystem.getProcess(pid);
143         if (process == null) {
144             throw new DeviceNotFoundException("Error while getting information for process with PID " + pid);
145         }
146         return process;
147     }
148
149     @Override
150     public StringType getOsFamily() {
151         String osFamily = operatingSystem.getFamily();
152         return new StringType(osFamily);
153     }
154
155     @Override
156     public StringType getOsManufacturer() {
157         String osManufacturer = operatingSystem.getManufacturer();
158         return new StringType(osManufacturer);
159     }
160
161     @Override
162     public StringType getOsVersion() {
163         String osVersion = operatingSystem.getVersionInfo().toString();
164         return new StringType(osVersion);
165     }
166
167     @Override
168     public StringType getCpuName() {
169         String name = cpu.getProcessorIdentifier().getName();
170         return new StringType(name);
171     }
172
173     @Override
174     public StringType getCpuDescription() {
175         String model = cpu.getProcessorIdentifier().getModel();
176         String family = cpu.getProcessorIdentifier().getFamily();
177         String serialNumber = computerSystem.getSerialNumber();
178         String identifier = cpu.getProcessorIdentifier().getIdentifier();
179         String vendor = cpu.getProcessorIdentifier().getVendor();
180         String architecture = cpu.getProcessorIdentifier().isCpu64bit() ? "64 bit" : "32 bit";
181         String descriptionFormatString = "Model: %s %s,family: %s, vendor: %s, sn: %s, identifier: %s ";
182         String description = String.format(descriptionFormatString, model, architecture, family, vendor, serialNumber,
183                 identifier);
184
185         return new StringType(description);
186     }
187
188     @Override
189     public DecimalType getCpuLogicalCores() {
190         int logicalProcessorCount = cpu.getLogicalProcessorCount();
191         return new DecimalType(logicalProcessorCount);
192     }
193
194     @Override
195     public DecimalType getCpuPhysicalCores() {
196         int physicalProcessorCount = cpu.getPhysicalProcessorCount();
197         return new DecimalType(physicalProcessorCount);
198     }
199
200     @Override
201     public QuantityType<DataAmount> getMemoryTotal() {
202         long totalMemory = memory.getTotal();
203         totalMemory = getSizeInMB(totalMemory);
204         return new QuantityType<>(totalMemory, Units.MEBIBYTE);
205     }
206
207     @Override
208     public QuantityType<DataAmount> getMemoryAvailable() {
209         long availableMemory = memory.getAvailable();
210         availableMemory = getSizeInMB(availableMemory);
211         return new QuantityType<>(availableMemory, Units.MEBIBYTE);
212     }
213
214     @Override
215     public QuantityType<DataAmount> getMemoryUsed() {
216         long totalMemory = memory.getTotal();
217         long availableMemory = memory.getAvailable();
218         long usedMemory = totalMemory - availableMemory;
219         usedMemory = getSizeInMB(usedMemory);
220         return new QuantityType<>(usedMemory, Units.MEBIBYTE);
221     }
222
223     @Override
224     public QuantityType<DataAmount> getStorageTotal(int index) throws DeviceNotFoundException {
225         OSFileStore fileStore = getDevice(fileStores, index);
226         fileStore.updateAttributes();
227         long totalSpace = fileStore.getTotalSpace();
228         totalSpace = getSizeInMB(totalSpace);
229         return new QuantityType<>(totalSpace, Units.MEBIBYTE);
230     }
231
232     @Override
233     public QuantityType<DataAmount> getStorageAvailable(int index) throws DeviceNotFoundException {
234         OSFileStore fileStore = getDevice(fileStores, index);
235         fileStore.updateAttributes();
236         long freeSpace = fileStore.getUsableSpace();
237         freeSpace = getSizeInMB(freeSpace);
238         return new QuantityType<>(freeSpace, Units.MEBIBYTE);
239     }
240
241     @Override
242     public QuantityType<DataAmount> getStorageUsed(int index) throws DeviceNotFoundException {
243         OSFileStore fileStore = getDevice(fileStores, index);
244         fileStore.updateAttributes();
245         long totalSpace = fileStore.getTotalSpace();
246         long freeSpace = fileStore.getUsableSpace();
247         long usedSpace = totalSpace - freeSpace;
248         usedSpace = getSizeInMB(usedSpace);
249         return new QuantityType<>(usedSpace, Units.MEBIBYTE);
250     }
251
252     @Override
253     public @Nullable PercentType getStorageAvailablePercent(int deviceIndex) throws DeviceNotFoundException {
254         OSFileStore fileStore = getDevice(fileStores, deviceIndex);
255         fileStore.updateAttributes();
256         long totalSpace = fileStore.getTotalSpace();
257         long freeSpace = fileStore.getUsableSpace();
258         if (totalSpace > 0) {
259             double freePercentDecimal = (double) freeSpace / (double) totalSpace;
260             BigDecimal freePercent = getPercentsValue(freePercentDecimal);
261             return new PercentType(freePercent);
262         } else {
263             return null;
264         }
265     }
266
267     @Override
268     public @Nullable PercentType getStorageUsedPercent(int deviceIndex) throws DeviceNotFoundException {
269         OSFileStore fileStore = getDevice(fileStores, deviceIndex);
270         fileStore.updateAttributes();
271         long totalSpace = fileStore.getTotalSpace();
272         long freeSpace = fileStore.getUsableSpace();
273         long usedSpace = totalSpace - freeSpace;
274         if (totalSpace > 0) {
275             double usedPercentDecimal = (double) usedSpace / (double) totalSpace;
276             BigDecimal usedPercent = getPercentsValue(usedPercentDecimal);
277             return new PercentType(usedPercent);
278         } else {
279             return null;
280         }
281     }
282
283     @Override
284     public StringType getStorageName(int index) throws DeviceNotFoundException {
285         OSFileStore fileStore = getDevice(fileStores, index);
286         String name = fileStore.getName();
287         return new StringType(name);
288     }
289
290     @Override
291     public StringType getStorageType(int deviceIndex) throws DeviceNotFoundException {
292         OSFileStore fileStore = getDevice(fileStores, deviceIndex);
293         String type = fileStore.getType();
294         return new StringType(type);
295     }
296
297     @Override
298     public StringType getStorageDescription(int index) throws DeviceNotFoundException {
299         OSFileStore fileStore = getDevice(fileStores, index);
300         String description = fileStore.getDescription();
301         return new StringType(description);
302     }
303
304     @Override
305     public StringType getNetworkIp(int index) throws DeviceNotFoundException {
306         NetworkIF netInterface = getDevice(networks, index);
307         netInterface.updateAttributes();
308         String[] ipAddresses = netInterface.getIPv4addr();
309         String ipv4 = getDevice(ipAddresses, 0);
310         return new StringType(ipv4);
311     }
312
313     @Override
314     public StringType getNetworkName(int index) throws DeviceNotFoundException {
315         NetworkIF netInterface = getDevice(networks, index);
316         String name = netInterface.getName();
317         return new StringType(name);
318     }
319
320     @Override
321     public StringType getNetworkDisplayName(int index) throws DeviceNotFoundException {
322         NetworkIF netInterface = getDevice(networks, index);
323         String adapterName = netInterface.getDisplayName();
324         return new StringType(adapterName);
325     }
326
327     @Override
328     public StringType getDisplayInformation(int index) throws DeviceNotFoundException {
329         Display display = getDevice(displays, index);
330
331         byte[] edid = display.getEdid();
332         String manufacturer = EdidUtil.getManufacturerID(edid);
333         String product = EdidUtil.getProductID(edid);
334         String serialNumber = EdidUtil.getSerialNo(edid);
335         int width = EdidUtil.getHcm(edid);
336         int height = EdidUtil.getVcm(edid);
337
338         String edidFormatString = "Product %s, manufacturer %s, SN: %s, Width: %d, Height: %d";
339         String edidInfo = String.format(edidFormatString, product, manufacturer, serialNumber, width, height);
340         return new StringType(edidInfo);
341     }
342
343     @Override
344     public @Nullable QuantityType<Temperature> getSensorsCpuTemperature() {
345         BigDecimal cpuTemp = new BigDecimal(sensors.getCpuTemperature());
346         cpuTemp = cpuTemp.setScale(PRECISION_AFTER_DECIMAL_SIGN, RoundingMode.HALF_UP);
347         return cpuTemp.signum() == 1 ? new QuantityType<>(cpuTemp, SIUnits.CELSIUS) : null;
348     }
349
350     @Override
351     public @Nullable QuantityType<ElectricPotential> getSensorsCpuVoltage() {
352         BigDecimal cpuVoltage = new BigDecimal(sensors.getCpuVoltage());
353         cpuVoltage = cpuVoltage.setScale(PRECISION_AFTER_DECIMAL_SIGN, RoundingMode.HALF_UP);
354         return cpuVoltage.signum() == 1 ? new QuantityType<>(cpuVoltage, Units.VOLT) : null;
355     }
356
357     @Override
358     public @Nullable DecimalType getSensorsFanSpeed(int index) throws DeviceNotFoundException {
359         int[] fanSpeeds = sensors.getFanSpeeds();
360         int speed = 0; // 0 means unable to measure speed
361         if (index < fanSpeeds.length) {
362             speed = fanSpeeds[index];
363         } else {
364             throw new DeviceNotFoundException();
365         }
366         return speed > 0 ? new DecimalType(speed) : null;
367     }
368
369     @Override
370     public @Nullable QuantityType<Time> getBatteryRemainingTime(int index) throws DeviceNotFoundException {
371         PowerSource powerSource = getDevice(powerSources, index);
372         powerSource.updateAttributes();
373         double remainingTimeInSeconds = powerSource.getTimeRemainingEstimated();
374         // The getTimeRemaining() method returns (-1.0) if is calculating or (-2.0) if the time is unlimited.
375         BigDecimal remainingTime = getTimeInMinutes(remainingTimeInSeconds);
376         return remainingTime.signum() == 1 ? new QuantityType<>(remainingTime, Units.MINUTE) : null;
377     }
378
379     @Override
380     public PercentType getBatteryRemainingCapacity(int index) throws DeviceNotFoundException {
381         PowerSource powerSource = getDevice(powerSources, index);
382         powerSource.updateAttributes();
383         double remainingCapacity = powerSource.getRemainingCapacityPercent();
384         BigDecimal remainingCapacityPercents = getPercentsValue(remainingCapacity);
385         return new PercentType(remainingCapacityPercents);
386     }
387
388     @Override
389     public StringType getBatteryName(int index) throws DeviceNotFoundException {
390         PowerSource powerSource = getDevice(powerSources, index);
391         String name = powerSource.getName();
392         return new StringType(name);
393     }
394
395     @Override
396     public @Nullable PercentType getMemoryAvailablePercent() {
397         long availableMemory = memory.getAvailable();
398         long totalMemory = memory.getTotal();
399         if (totalMemory > 0) {
400             double freePercentDecimal = (double) availableMemory / (double) totalMemory;
401             BigDecimal freePercent = getPercentsValue(freePercentDecimal);
402             return new PercentType(freePercent);
403         } else {
404             return null;
405         }
406     }
407
408     @Override
409     public @Nullable PercentType getMemoryUsedPercent() {
410         long availableMemory = memory.getAvailable();
411         long totalMemory = memory.getTotal();
412         long usedMemory = totalMemory - availableMemory;
413         if (totalMemory > 0) {
414             double usedPercentDecimal = (double) usedMemory / (double) totalMemory;
415             BigDecimal usedPercent = getPercentsValue(usedPercentDecimal);
416             return new PercentType(usedPercent);
417         } else {
418             return null;
419         }
420     }
421
422     @Override
423     public StringType getDriveName(int deviceIndex) throws DeviceNotFoundException {
424         HWDiskStore drive = getDevice(drives, deviceIndex);
425         String name = drive.getName();
426         return new StringType(name);
427     }
428
429     @Override
430     public StringType getDriveModel(int deviceIndex) throws DeviceNotFoundException {
431         HWDiskStore drive = getDevice(drives, deviceIndex);
432         String model = drive.getModel();
433         return new StringType(model);
434     }
435
436     @Override
437     public StringType getDriveSerialNumber(int deviceIndex) throws DeviceNotFoundException {
438         HWDiskStore drive = getDevice(drives, deviceIndex);
439         String serialNumber = drive.getSerial();
440         return new StringType(serialNumber);
441     }
442
443     @Override
444     public QuantityType<DataAmount> getSwapTotal() {
445         long swapTotal = memory.getVirtualMemory().getSwapTotal();
446         swapTotal = getSizeInMB(swapTotal);
447         return new QuantityType<>(swapTotal, Units.MEBIBYTE);
448     }
449
450     @Override
451     public QuantityType<DataAmount> getSwapAvailable() {
452         long swapTotal = memory.getVirtualMemory().getSwapTotal();
453         long swapUsed = memory.getVirtualMemory().getSwapUsed();
454         long swapAvailable = swapTotal - swapUsed;
455         swapAvailable = getSizeInMB(swapAvailable);
456         return new QuantityType<>(swapAvailable, Units.MEBIBYTE);
457     }
458
459     @Override
460     public QuantityType<DataAmount> getSwapUsed() {
461         long swapUsed = memory.getVirtualMemory().getSwapUsed();
462         swapUsed = getSizeInMB(swapUsed);
463         return new QuantityType<>(swapUsed, Units.MEBIBYTE);
464     }
465
466     @Override
467     public @Nullable PercentType getSwapAvailablePercent() {
468         long swapTotal = memory.getVirtualMemory().getSwapTotal();
469         long swapUsed = memory.getVirtualMemory().getSwapUsed();
470         long swapAvailable = swapTotal - swapUsed;
471         if (swapTotal > 0) {
472             double swapAvailablePercentDecimal = (double) swapAvailable / (double) swapTotal;
473             BigDecimal swapAvailablePercent = getPercentsValue(swapAvailablePercentDecimal);
474             return new PercentType(swapAvailablePercent);
475         } else {
476             return null;
477         }
478     }
479
480     @Override
481     public @Nullable PercentType getSwapUsedPercent() {
482         long swapTotal = memory.getVirtualMemory().getSwapTotal();
483         long swapUsed = memory.getVirtualMemory().getSwapUsed();
484         if (swapTotal > 0) {
485             double swapUsedPercentDecimal = (double) swapUsed / (double) swapTotal;
486             BigDecimal swapUsedPercent = getPercentsValue(swapUsedPercentDecimal);
487             return new PercentType(swapUsedPercent);
488         } else {
489             return null;
490         }
491     }
492
493     private long getSizeInMB(long sizeInBytes) {
494         return Math.round(sizeInBytes / (1024D * 1024));
495     }
496
497     private BigDecimal getPercentsValue(double decimalFraction) {
498         BigDecimal result = new BigDecimal(decimalFraction * 100);
499         result = result.setScale(PRECISION_AFTER_DECIMAL_SIGN, RoundingMode.HALF_UP);
500         return result;
501     }
502
503     private BigDecimal getTimeInMinutes(double timeInSeconds) {
504         BigDecimal timeInMinutes = new BigDecimal(timeInSeconds / 60);
505         timeInMinutes = timeInMinutes.setScale(PRECISION_AFTER_DECIMAL_SIGN, RoundingMode.UP);
506         return timeInMinutes;
507     }
508
509     @Override
510     public @Nullable PercentType getSystemCpuLoad() {
511         PercentType load = (ticks[0] > 0) ? new PercentType(getPercentsValue(cpu.getSystemCpuLoadBetweenTicks(ticks)))
512                 : null;
513         ticks = cpu.getSystemCpuLoadTicks();
514         return load;
515     }
516
517     /**
518      * {@inheritDoc}
519      *
520      * This information is available only on Mac and Linux OS.
521      */
522     @Override
523     public @Nullable DecimalType getCpuLoad1() {
524         BigDecimal avarageCpuLoad = getAvarageCpuLoad(1);
525         return avarageCpuLoad.signum() == -1 ? null : new DecimalType(avarageCpuLoad);
526     }
527
528     /**
529      * {@inheritDoc}
530      *
531      * This information is available only on Mac and Linux OS.
532      */
533     @Override
534     public @Nullable DecimalType getCpuLoad5() {
535         BigDecimal avarageCpuLoad = getAvarageCpuLoad(5);
536         return avarageCpuLoad.signum() == -1 ? null : new DecimalType(avarageCpuLoad);
537     }
538
539     /**
540      * {@inheritDoc}
541      *
542      * This information is available only on Mac and Linux OS.
543      */
544     @Override
545     public @Nullable DecimalType getCpuLoad15() {
546         BigDecimal avarageCpuLoad = getAvarageCpuLoad(15);
547         return avarageCpuLoad.signum() == -1 ? null : new DecimalType(avarageCpuLoad);
548     }
549
550     private BigDecimal getAvarageCpuLoad(int timeInMinutes) {
551         // This parameter is specified in OSHI Javadoc
552         int index;
553         switch (timeInMinutes) {
554             case 1:
555                 index = 0;
556                 break;
557             case 5:
558                 index = 1;
559                 break;
560             case 15:
561                 index = 2;
562                 break;
563             default:
564                 index = 2;
565         }
566         double processorLoads[] = cpu.getSystemLoadAverage(index + 1);
567         BigDecimal result = new BigDecimal(processorLoads[index]);
568         result = result.setScale(PRECISION_AFTER_DECIMAL_SIGN, RoundingMode.HALF_UP);
569         return result;
570     }
571
572     @Override
573     public QuantityType<Time> getCpuUptime() {
574         long seconds = operatingSystem.getSystemUptime();
575         return new QuantityType<>(getTimeInMinutes(seconds), Units.MINUTE);
576     }
577
578     @Override
579     public DecimalType getCpuThreads() {
580         int threadCount = operatingSystem.getThreadCount();
581         return new DecimalType(threadCount);
582     }
583
584     @Override
585     public StringType getNetworkMac(int networkIndex) throws DeviceNotFoundException {
586         NetworkIF network = getDevice(networks, networkIndex);
587         String mac = network.getMacaddr();
588         return new StringType(mac);
589     }
590
591     @Override
592     public DecimalType getNetworkPacketsReceived(int networkIndex) throws DeviceNotFoundException {
593         NetworkIF network = getDevice(networks, networkIndex);
594         network.updateAttributes();
595         long packRecv = network.getPacketsRecv();
596         return new DecimalType(packRecv);
597     }
598
599     @Override
600     public DecimalType getNetworkPacketsSent(int networkIndex) throws DeviceNotFoundException {
601         NetworkIF network = getDevice(networks, networkIndex);
602         network.updateAttributes();
603         long packSent = network.getPacketsSent();
604         return new DecimalType(packSent);
605     }
606
607     @Override
608     public QuantityType<DataAmount> getNetworkDataSent(int networkIndex) throws DeviceNotFoundException {
609         NetworkIF network = getDevice(networks, networkIndex);
610         network.updateAttributes();
611         long bytesSent = network.getBytesSent();
612         return new QuantityType<>(getSizeInMB(bytesSent), Units.MEBIBYTE);
613     }
614
615     @Override
616     public QuantityType<DataAmount> getNetworkDataReceived(int networkIndex) throws DeviceNotFoundException {
617         NetworkIF network = getDevice(networks, networkIndex);
618         network.updateAttributes();
619         long bytesRecv = network.getBytesRecv();
620         return new QuantityType<>(getSizeInMB(bytesRecv), Units.MEBIBYTE);
621     }
622
623     @Override
624     public int getCurrentProcessID() {
625         return operatingSystem.getProcessId();
626     }
627
628     @Override
629     public @Nullable StringType getProcessName(int pid) throws DeviceNotFoundException {
630         if (pid > 0) {
631             OSProcess process = getProcess(pid);
632             String name = process.getName();
633             return new StringType(name);
634         } else {
635             return null;
636         }
637     }
638
639     @Override
640     public @Nullable DecimalType getProcessCpuUsage(int pid) throws DeviceNotFoundException {
641         if (pid > 0) {
642             OSProcess process = getProcess(pid);
643             DecimalType load = (processTicks.containsKey(pid))
644                     ? new DecimalType(getPercentsValue(process.getProcessCpuLoadBetweenTicks(processTicks.get(pid))))
645                     : null;
646             processTicks.put(pid, process);
647             return load;
648         } else {
649             return null;
650         }
651     }
652
653     @Override
654     public @Nullable QuantityType<DataAmount> getProcessMemoryUsage(int pid) throws DeviceNotFoundException {
655         if (pid > 0) {
656             OSProcess process = getProcess(pid);
657             long memortInBytes = process.getResidentSetSize();
658             long memoryInMB = getSizeInMB(memortInBytes);
659             return new QuantityType<>(memoryInMB, Units.MEBIBYTE);
660         } else {
661             return null;
662         }
663     }
664
665     @Override
666     public @Nullable StringType getProcessPath(int pid) throws DeviceNotFoundException {
667         if (pid > 0) {
668             OSProcess process = getProcess(pid);
669             String path = process.getPath();
670             return new StringType(path);
671         } else {
672             return null;
673         }
674     }
675
676     @Override
677     public @Nullable DecimalType getProcessThreads(int pid) throws DeviceNotFoundException {
678         if (pid > 0) {
679             OSProcess process = getProcess(pid);
680             int threadCount = process.getThreadCount();
681             return new DecimalType(threadCount);
682         } else {
683             return null;
684         }
685     }
686
687     @Override
688     public int getNetworkIFCount() {
689         return networks.size();
690     }
691
692     @Override
693     public int getDisplayCount() {
694         return displays.size();
695     }
696
697     @Override
698     public int getFileOSStoreCount() {
699         return fileStores.size();
700     }
701
702     @Override
703     public int getPowerSourceCount() {
704         return powerSources.size();
705     }
706
707     @Override
708     public int getDriveCount() {
709         return drives.size();
710     }
711
712     @Override
713     public int getFanCount() {
714         return sensors.getFanSpeeds().length;
715     }
716 }