]> git.basschouten.com Git - openhab-addons.git/commitdiff
[systeminfo] Add CPU load channel, update dependencies (#13292)
authorMark Herwege <mherwege@users.noreply.github.com>
Sun, 11 Sep 2022 09:06:52 +0000 (11:06 +0200)
committerGitHub <noreply@github.com>
Sun, 11 Sep 2022 09:06:52 +0000 (11:06 +0200)
* Add CPU load channel, update dependencies
* use PercentType, correct process CPU load
* Add and fix test

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
bundles/org.openhab.binding.systeminfo/README.md
bundles/org.openhab.binding.systeminfo/pom.xml
bundles/org.openhab.binding.systeminfo/src/main/feature/feature.xml
bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/handler/SysteminfoHandler.java
bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/OSHISysteminfo.java
bundles/org.openhab.binding.systeminfo/src/main/java/org/openhab/binding/systeminfo/internal/model/SysteminfoInterface.java
bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/i18n/systeminfo.properties
bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/thing/channels.xml
itests/org.openhab.binding.systeminfo.tests/itest.bndrun
itests/org.openhab.binding.systeminfo.tests/pom.xml
itests/org.openhab.binding.systeminfo.tests/src/main/java/org/openhab/binding/systeminfo/test/SysteminfoOSGiTest.java

index 713f160abf20f4499ea5759b1aa7c4e1f9fb75a4..197482b835e74a0992679ed64359f39bdaaaa034 100644 (file)
@@ -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"    <returnpipe>     { chann
 /* CPU information*/
 String CPU_Name                   "Name"                <none>           { channel="systeminfo:computer:work:cpu#name" }
 String CPU_Description            "Description"         <none>           { channel="systeminfo:computer:work:cpu#description" }
+Number CPU_Load                   "CPU Load"            <none>           { channel="systeminfo:computer:work:cpu#load" }
 Number CPU_Load1                  "Load (1 min)"        <none>           { channel="systeminfo:computer:work:cpu#load1" }
 Number CPU_Load5                  "Load (5 min)"        <none>           { channel="systeminfo:computer:work:cpu#load5" }
 Number CPU_Load15                 "Load (15 min)"       <none>           { channel="systeminfo:computer:work:cpu#load15" }
index 82856fecb11e49b6ccdf030d0f73580c6f8c56f1..5ba2291d156c13d097017fdd3bb79c3b2c79271e 100644 (file)
     <dependency>
       <groupId>net.java.dev.jna</groupId>
       <artifactId>jna-platform</artifactId>
-      <version>5.9.0</version>
+      <version>5.12.1</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>net.java.dev.jna</groupId>
       <artifactId>jna</artifactId>
-      <version>5.9.0</version>
+      <version>5.12.1</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>com.github.oshi</groupId>
       <artifactId>oshi-core</artifactId>
-      <version>5.8.2</version>
+      <version>6.2.2</version>
       <scope>compile</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-api</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
   </dependencies>
 
index 28179ca46f4d925121e4fedc2a5a12950e23bb51..ea3cbed6ae137e4ca5c71b0d930cad6cfdc1a130 100644 (file)
@@ -4,9 +4,9 @@
 
        <feature name="openhab-binding-systeminfo" description="System Info Binding" version="${project.version}">
                <feature>openhab-runtime-base</feature>
-               <bundle dependency="true">mvn:net.java.dev.jna/jna/5.9.0</bundle>
-               <bundle dependency="true">mvn:net.java.dev.jna/jna-platform/5.9.0</bundle>
-               <bundle dependency="true">mvn:com.github.oshi/oshi-core/5.8.2</bundle>
+               <bundle dependency="true">mvn:net.java.dev.jna/jna/5.12.1</bundle>
+               <bundle dependency="true">mvn:net.java.dev.jna/jna-platform/5.12.1</bundle>
+               <bundle dependency="true">mvn:com.github.oshi/oshi-core/6.2.2</bundle>
                <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.systeminfo/${project.version}</bundle>
        </feature>
 </features>
index 396fc0cf46a515cfb4bfb7ba478c293a93686239..50be4a14ca5510b97780edf94b12c6802bdfc07b 100644 (file)
@@ -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);
index 8fc9f8e68f7d8018a99cfa43056d8d9b0b777c80..5ab70b3adc764fad55bfb605c53c6063cd90cdaa 100644 (file)
@@ -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<PowerSource> powerSources;
     private @NonNullByDefault({}) List<HWDiskStore> 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<Integer, OSProcess> 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;
         }
index d19f3c1bacf95713c8842983823822bea5e871c2..a606f7a26c81d252c68aa54c01b2f89aa9ea60cd 100644 (file)
@@ -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
index a46a9b2eb58c65fa553043b8362c8da413c0654b..ebb3eded3dba0494e1ca3a5d2a45ce223eeeb9d0 100644 (file)
@@ -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
index dc24d1075033e67d083e30a4b2ded055b1f4c277..16ddabce8ebc76aec5de3d7708f82994668c69f6 100644 (file)
                <channels>
                        <channel id="name" typeId="name"/>
                        <channel id="description" typeId="description"/>
+                       <channel id="load" typeId="cpuLoad"/>
                        <channel id="load1" typeId="loadAverage"/>
                        <channel id="load5" typeId="loadAverage"/>
                        <channel id="load15" typeId="loadAverage"/>
        </channel-type>
 
        <channel-type id="load_process">
-               <item-type>Number</item-type>
+               <item-type>Number:Dimensionless</item-type>
                <label>Load</label>
                <description>Load in percent</description>
                <state readOnly="true" pattern="%.1f %%"/>
                <config-description-ref uri="channel-type:systeminfo:highpriority_process"/>
        </channel-type>
 
+       <channel-type id="cpuLoad">
+               <item-type>Number:Dimensionless</item-type>
+               <label>CPU Load</label>
+               <description>CPU load in percent</description>
+               <state readOnly="true" pattern="%.1f %%"/>
+               <config-description-ref uri="channel-type:systeminfo:highpriority"/>
+       </channel-type>
+
        <channel-type id="loadAverage" advanced="true">
                <item-type>Number</item-type>
                <label>Load Average</label>
index 5e68a1d9e62a3dc49a50b699d7afa3ed6df07210..146b3bc64202658435aadca6a6b2ffaf4f7cfcf8 100644 (file)
@@ -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)',\
index 5e348361259a8e54ab808545280dcf3f0853d483..17a434817f1823d7664a630d3f5e55439cdd858a 100644 (file)
     <dependency>
       <groupId>net.java.dev.jna</groupId>
       <artifactId>jna-platform</artifactId>
-      <version>5.9.0</version>
+      <version>5.12.1</version>
     </dependency>
     <dependency>
       <groupId>net.java.dev.jna</groupId>
       <artifactId>jna</artifactId>
-      <version>5.9.0</version>
+      <version>5.12.1</version>
     </dependency>
     <dependency>
       <groupId>com.github.oshi</groupId>
       <artifactId>oshi-core</artifactId>
-      <version>5.8.2</version>
+      <version>6.2.2</version>
       <exclusions>
         <exclusion>
           <groupId>org.slf4j</groupId>
index d649f49fa227284e509f9f5293762fb74187d6b6..24d90803624e046c19a28815fae317ec860efb36 100644 (file)
@@ -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);