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