From: Mark Herwege Date: Sun, 11 Sep 2022 09:06:52 +0000 (+0200) Subject: [systeminfo] Add CPU load channel, update dependencies (#13292) X-Git-Url: https://git.basschouten.com/?a=commitdiff_plain;h=909d39058107127c32960a2d7d7b271cb4b263af;p=openhab-addons.git [systeminfo] Add CPU load channel, update dependencies (#13292) * Add CPU load channel, update dependencies * use PercentType, correct process CPU load * Add and fix test Signed-off-by: Mark Herwege --- diff --git a/bundles/org.openhab.binding.systeminfo/README.md b/bundles/org.openhab.binding.systeminfo/README.md index 713f160abf..197482b835 100644 --- a/bundles/org.openhab.binding.systeminfo/README.md +++ b/bundles/org.openhab.binding.systeminfo/README.md @@ -65,7 +65,7 @@ In the list below, you can find, how are channel group and channels id`s related **thing** `computer` * **group** `memory` - * **channel** `available, total, used, availablePercent, usedPercent` + * **channel** `available, total, used, availablePercent, usedPercent, usedHeapPercent, availableHeap` * **group** `swap` * **channel** `available, total, used, availablePercent, usedPercent` * **group** `storage` (deviceIndex) @@ -77,7 +77,7 @@ In the list below, you can find, how are channel group and channels id`s related * **group** `battery` (deviceIndex) * **channel** `name, remainingCapacity, remainingTime` * **group** `cpu` - * **channel** `name, description, load1, load5, load15, uptime` + * **channel** `name, description, load, load1, load5, load15, uptime, threads` * **group** `sensors` * **channel** `cpuTemp, cpuVoltage, fanSpeed` * **group** `network` (deviceIndex) @@ -104,12 +104,14 @@ The binding introduces the following channels: | Channel ID | Channel Description | Supported item type | Default priority | Advanced | |--------------------|------------------------------------------------------------------|---------------------|------------------|----------| +| load | CPU Load (total or by process) in % | Number:Dimensionless| High | False | | load1 | Load for the last 1 minute | Number | Medium | True | | load5 | Load for the last 5 minutes | Number | Medium | True | | load15 | Load for the last 15 minutes | Number | Medium | True | -| threads | Number of threads currently running | Number | Medium | True | +| threads | Number of threads currently running or for the process | Number | Medium | True | +| path | The full path of the process | String | Low | False | | uptime | System uptime (time after start) in minutes | Number | Medium | True | -| name | Name of the device | String | Low | False | +| name | Name of the device or process | String | Low | False | | available | Available size in MB | Number | High | False | | used | Used size in MB | Number | High | False | | total | Total size in MB | Number | Low | False | @@ -148,6 +150,9 @@ It has the following options: - **Medium** - **Low** +The ''load'' channel will update total or by process CPU load at the frequency defined by the priority update interval, by default high priority, every second. +The value corresponds to the average CPU load over the interval. + Channels from group ''process'' have additional configuration parameter - PID (Process identifier). This parameter is used as 'deviceIndex' and defines which process is tracked from the channel. This makes the channels from this groups very flexible - they can change its PID dynamically. @@ -190,6 +195,7 @@ Number Network_PacketsReceived "Packets received" { chann /* CPU information*/ String CPU_Name "Name" { channel="systeminfo:computer:work:cpu#name" } String CPU_Description "Description" { channel="systeminfo:computer:work:cpu#description" } +Number CPU_Load "CPU Load" { channel="systeminfo:computer:work:cpu#load" } Number CPU_Load1 "Load (1 min)" { channel="systeminfo:computer:work:cpu#load1" } Number CPU_Load5 "Load (5 min)" { channel="systeminfo:computer:work:cpu#load5" } Number CPU_Load15 "Load (15 min)" { channel="systeminfo:computer:work:cpu#load15" } diff --git a/bundles/org.openhab.binding.systeminfo/pom.xml b/bundles/org.openhab.binding.systeminfo/pom.xml index 82856fecb1..5ba2291d15 100644 --- a/bundles/org.openhab.binding.systeminfo/pom.xml +++ b/bundles/org.openhab.binding.systeminfo/pom.xml @@ -22,20 +22,26 @@ net.java.dev.jna jna-platform - 5.9.0 + 5.12.1 compile net.java.dev.jna jna - 5.9.0 + 5.12.1 compile com.github.oshi oshi-core - 5.8.2 + 6.2.2 compile + + + org.slf4j + slf4j-api + + diff --git a/bundles/org.openhab.binding.systeminfo/src/main/feature/feature.xml b/bundles/org.openhab.binding.systeminfo/src/main/feature/feature.xml index 28179ca46f..ea3cbed6ae 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.systeminfo/src/main/feature/feature.xml @@ -4,9 +4,9 @@ openhab-runtime-base - mvn:net.java.dev.jna/jna/5.9.0 - mvn:net.java.dev.jna/jna-platform/5.9.0 - mvn:com.github.oshi/oshi-core/5.8.2 + mvn:net.java.dev.jna/jna/5.12.1 + mvn:net.java.dev.jna/jna-platform/5.12.1 + mvn:com.github.oshi/oshi-core/6.2.2 mvn:org.openhab.addons.bundles/org.openhab.binding.systeminfo/${project.version} diff --git a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/handler/SysteminfoHandler.java b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/handler/SysteminfoHandler.java index 396fc0cf46..50be4a14ca 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/handler/SysteminfoHandler.java +++ b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/handler/SysteminfoHandler.java @@ -28,7 +28,7 @@ import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.systeminfo.internal.model.DeviceNotFoundException; import org.openhab.binding.systeminfo.internal.model.SysteminfoInterface; import org.openhab.core.config.core.Configuration; -import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.unit.Units; import org.openhab.core.thing.Channel; @@ -294,8 +294,8 @@ public class SysteminfoHandler extends BaseThingHandler { state = new QuantityType<>(Runtime.getRuntime().freeMemory(), Units.BYTE); break; case CHANNEL_MEMORY_USED_HEAP_PERCENT: - state = new DecimalType((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) - * 100 / Runtime.getRuntime().maxMemory()); + state = new QuantityType<>((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) + * 100 / Runtime.getRuntime().maxMemory(), Units.PERCENT); break; case CHANNEL_DISPLAY_INFORMATION: state = systeminfo.getDisplayInformation(deviceIndex); @@ -318,6 +318,10 @@ public class SysteminfoHandler extends BaseThingHandler { case CHANNEL_SENSORS_FAN_SPEED: state = systeminfo.getSensorsFanSpeed(deviceIndex); break; + case CHANNEL_CPU_LOAD: + PercentType cpuLoad = systeminfo.getSystemCpuLoad(); + state = (cpuLoad != null) ? new QuantityType<>(cpuLoad, Units.PERCENT) : null; + break; case CHANNEL_CPU_LOAD_1: state = systeminfo.getCpuLoad1(); break; @@ -427,7 +431,8 @@ public class SysteminfoHandler extends BaseThingHandler { state = systeminfo.getNetworkPacketsSent(deviceIndex); break; case CHANNEL_PROCESS_LOAD: - state = systeminfo.getProcessCpuUsage(deviceIndex); + PercentType processLoad = systeminfo.getProcessCpuUsage(deviceIndex); + state = (processLoad != null) ? new QuantityType<>(processLoad, Units.PERCENT) : null; break; case CHANNEL_PROCESS_MEMORY: state = systeminfo.getProcessMemoryUsage(deviceIndex); diff --git a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/OSHISysteminfo.java b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/OSHISysteminfo.java index 8fc9f8e68f..5ab70b3adc 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/OSHISysteminfo.java +++ b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/OSHISysteminfo.java @@ -14,11 +14,14 @@ package org.openhab.binding.systeminfo.internal.model; import java.math.BigDecimal; import java.math.RoundingMode; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.StringType; import org.osgi.service.component.annotations.Component; import org.slf4j.Logger; @@ -74,6 +77,12 @@ public class OSHISysteminfo implements SysteminfoInterface { private @NonNullByDefault({}) List powerSources; private @NonNullByDefault({}) List drives; + // Array containing cpu tick info to calculate CPU load, according to oshi doc: + // 8 long values representing time spent in User, Nice, System, Idle, IOwait, IRQ, SoftIRQ, and Steal states + private long[] ticks = new long[8]; + // Map containing previous process state to calculate load by process + private Map processTicks = new HashMap<>(); + public static final int PRECISION_AFTER_DECIMAL_SIGN = 1; /** @@ -338,7 +347,7 @@ public class OSHISysteminfo implements SysteminfoInterface { @Override public @Nullable DecimalType getSensorsFanSpeed(int index) throws DeviceNotFoundException { int[] fanSpeeds = sensors.getFanSpeeds(); - int speed = 0;// 0 means unable to measure speed + int speed = 0; // 0 means unable to measure speed if (index < fanSpeeds.length) { speed = fanSpeeds[index]; } @@ -485,6 +494,14 @@ public class OSHISysteminfo implements SysteminfoInterface { return timeInMinutes; } + @Override + public @Nullable PercentType getSystemCpuLoad() { + PercentType load = (ticks[0] > 0) ? new PercentType(getPercentsValue(cpu.getSystemCpuLoadBetweenTicks(ticks))) + : null; + ticks = cpu.getSystemCpuLoadTicks(); + return load; + } + /** * {@inheritDoc} * @@ -518,10 +535,10 @@ public class OSHISysteminfo implements SysteminfoInterface { return avarageCpuLoad.signum() == -1 ? null : new DecimalType(avarageCpuLoad); } - private BigDecimal getAvarageCpuLoad(int timeInMunutes) { + private BigDecimal getAvarageCpuLoad(int timeInMinutes) { // This parameter is specified in OSHI Javadoc int index; - switch (timeInMunutes) { + switch (timeInMinutes) { case 1: index = 0; break; @@ -603,12 +620,14 @@ public class OSHISysteminfo implements SysteminfoInterface { } @Override - public @Nullable DecimalType getProcessCpuUsage(int pid) throws DeviceNotFoundException { + public @Nullable PercentType getProcessCpuUsage(int pid) throws DeviceNotFoundException { if (pid > 0) { OSProcess process = getProcess(pid); - double cpuUsageRaw = (process.getKernelTime() + process.getUserTime()) / process.getUpTime(); - BigDecimal cpuUsage = getPercentsValue(cpuUsageRaw); - return new DecimalType(cpuUsage); + PercentType load = (processTicks.containsKey(pid)) + ? new PercentType(getPercentsValue(process.getProcessCpuLoadBetweenTicks(processTicks.get(pid)))) + : null; + processTicks.put(pid, process); + return load; } else { return null; } diff --git a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/SysteminfoInterface.java b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/SysteminfoInterface.java index d19f3c1bac..a606f7a26c 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/SysteminfoInterface.java +++ b/bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/SysteminfoInterface.java @@ -15,6 +15,7 @@ package org.openhab.binding.systeminfo.internal.model; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.StringType; /** @@ -71,6 +72,13 @@ public interface SysteminfoInterface { */ public DecimalType getCpuPhysicalCores(); + /** + * Returns the system cpu load. + * + * @return the system cpu load between 0 and 1 or null, if no information is available + */ + public @Nullable PercentType getSystemCpuLoad(); + /** * Returns the system load average for the last minute. * @@ -411,7 +419,7 @@ public interface SysteminfoInterface { * @return - percentage value /0-100/ * @throws DeviceNotFoundException - thrown if process with this PID can not be found */ - public @Nullable DecimalType getProcessCpuUsage(int pid) throws DeviceNotFoundException; + public @Nullable PercentType getProcessCpuUsage(int pid) throws DeviceNotFoundException; /** * Returns the size of RAM memory only usage of the process diff --git a/bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/i18n/systeminfo.properties b/bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/i18n/systeminfo.properties index a46a9b2eb5..ebb3eded3d 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/i18n/systeminfo.properties +++ b/bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/i18n/systeminfo.properties @@ -62,6 +62,8 @@ channel-type.systeminfo.information.label = Display Information channel-type.systeminfo.information.description = Product, manufacturer, SN, width and height of the display in cm channel-type.systeminfo.ip.label = IP Address channel-type.systeminfo.ip.description = Host IP address of the network +channel-type.systeminfo.cpuLoad.label = CPU Load +channel-type.systeminfo.cpuLoad.description = CPU load in percent channel-type.systeminfo.loadAverage.label = Load Average channel-type.systeminfo.loadAverage.description = Load as a number of processes for the last 1,5 or 15 minutes channel-type.systeminfo.load_process.label = Load diff --git a/bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/thing/channels.xml index dc24d10750..16ddabce8e 100644 --- a/bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/thing/channels.xml @@ -107,6 +107,7 @@ + @@ -288,13 +289,21 @@ - Number + Number:Dimensionless Load in percent + + Number:Dimensionless + + CPU load in percent + + + + Number diff --git a/itests/org.openhab.binding.systeminfo.tests/itest.bndrun b/itests/org.openhab.binding.systeminfo.tests/itest.bndrun index 5e68a1d9e6..146b3bc642 100644 --- a/itests/org.openhab.binding.systeminfo.tests/itest.bndrun +++ b/itests/org.openhab.binding.systeminfo.tests/itest.bndrun @@ -34,8 +34,8 @@ Fragment-Host: org.openhab.binding.systeminfo org.jsr-305;version='[3.0.2,3.0.3)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ - com.sun.jna;version='[5.9.0,5.9.1)',\ - com.sun.jna.platform;version='[5.9.0,5.9.1)',\ + com.sun.jna;version='[5.12.1,5.12.2)',\ + com.sun.jna.platform;version='[5.12.1,5.12.2)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ diff --git a/itests/org.openhab.binding.systeminfo.tests/pom.xml b/itests/org.openhab.binding.systeminfo.tests/pom.xml index 5e34836125..17a434817f 100644 --- a/itests/org.openhab.binding.systeminfo.tests/pom.xml +++ b/itests/org.openhab.binding.systeminfo.tests/pom.xml @@ -23,17 +23,17 @@ net.java.dev.jna jna-platform - 5.9.0 + 5.12.1 net.java.dev.jna jna - 5.9.0 + 5.12.1 com.github.oshi oshi-core - 5.8.2 + 6.2.2 org.slf4j diff --git a/itests/org.openhab.binding.systeminfo.tests/src/main/java/org/openhab/binding/systeminfo/test/SysteminfoOSGiTest.java b/itests/org.openhab.binding.systeminfo.tests/src/main/java/org/openhab/binding/systeminfo/test/SysteminfoOSGiTest.java index d649f49fa2..24d9080362 100644 --- a/itests/org.openhab.binding.systeminfo.tests/src/main/java/org/openhab/binding/systeminfo/test/SysteminfoOSGiTest.java +++ b/itests/org.openhab.binding.systeminfo.tests/src/main/java/org/openhab/binding/systeminfo/test/SysteminfoOSGiTest.java @@ -45,6 +45,7 @@ import org.openhab.core.items.ItemRegistry; import org.openhab.core.library.items.NumberItem; import org.openhab.core.library.items.StringItem; import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.StringType; import org.openhab.core.test.java.JavaOSGiTest; import org.openhab.core.test.storage.VolatileStorageService; @@ -346,6 +347,18 @@ public class SysteminfoOSGiTest extends JavaOSGiTest { assertItemState(acceptedItemType, DEFAULT_TEST_ITEM_NAME, DEFAULT_CHANNEL_TEST_PRIORITY, UnDefType.UNDEF); } + @Test + public void assertChannelCpuLoadIsUpdated() { + String channnelID = SysteminfoBindingConstants.CHANNEL_CPU_LOAD; + String acceptedItemType = "Number"; + + PercentType mockedCpuLoadValue = new PercentType(9); + when(mockedSystemInfo.getSystemCpuLoad()).thenReturn(mockedCpuLoadValue); + + initializeThingWithChannel(channnelID, acceptedItemType); + assertItemState(acceptedItemType, DEFAULT_TEST_ITEM_NAME, DEFAULT_CHANNEL_TEST_PRIORITY, mockedCpuLoadValue); + } + @Test public void assertChannelCpuLoad1IsUpdated() { String channnelID = SysteminfoBindingConstants.CHANNEL_CPU_LOAD_1; @@ -1007,7 +1020,7 @@ public class SysteminfoOSGiTest extends JavaOSGiTest { // The pid of the System idle process in Windows int pid = 0; - DecimalType mockedProcessLoad = new DecimalType(3); + PercentType mockedProcessLoad = new PercentType(3); when(mockedSystemInfo.getProcessCpuUsage(pid)).thenReturn(mockedProcessLoad); initializeThingWithChannelAndPID(channnelID, acceptedItemType, pid);