[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 <mark.herwege@telenet.be>
This commit is contained in:
Mark Herwege
2022-09-11 11:06:52 +02:00
committed by GitHub
parent 55e27c8c12
commit 909d390581
11 changed files with 97 additions and 29 deletions

View 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>

View 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);

View 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;
}

View 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

View 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

View File

@@ -107,6 +107,7 @@
<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"/>
@@ -288,13 +289,21 @@
</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>