Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[systeminfo] dynamic channels #13562

Merged
merged 13 commits into from Nov 4, 2022
34 changes: 28 additions & 6 deletions bundles/org.openhab.binding.systeminfo/README.md
Expand Up @@ -36,9 +36,6 @@ The discovery service implementation tries to resolve the computer name.
If the resolving process fails, the computer name is set to "Unknown".
In both cases it creates a Discovery Result with thing type **computer**.

It will be possible to implement creation of dynamic channels (e.g. the binding will scan how many storage devices are present and create channel groups for them).
At the moment this is not supported.

## Thing configuration

The configuration of the Thing gives the user the possibility to update channels at different intervals.
Expand Down Expand Up @@ -82,23 +79,34 @@ In the list below, you can find, how are channel group and channels id`s related
* **channel** `cpuTemp, cpuVoltage, fanSpeed`
* **group** `network` (deviceIndex)
* **channel** `ip, mac, networkDisplayName, networkName, packetsSent, packetsReceived, dataSent, dataReceived`
* **group** `currentProcess`
* **channel** `load, used, name, threads, path`
* **group** `process` (pid)
* **channel** `load, used, name, threads, path`

The groups marked with "(deviceIndex)" may have device index attached to the Channel Group.

- channel ::= channel_group & (deviceIndex) & # channel_id
- deviceIndex ::= number > 0
- deviceIndex ::= number >= 0
- (e.g. *storage1#available*)

The `fanSpeed` channel in the `sensors` group may have a device index attached to the Channel.

- channel ::= channel_group & # channel_id & (deviceIndex)
- deviceIndex ::= number >= 0

Channels or channel groups without a trailing index will show the data for the first device (index 0) if multiple exist.
If only one device for a group exists, no channels or channel groups with indexes will be created.

The group `process` is using a configuration parameter "pid" instead of "deviceIndex".
This makes it possible to change the tracked process at runtime.

The group `currentProcess` has the same channels as the `process` group without the "pid" configuration parameter.
The PID is dynamically set to the PID of the process running openHAB.

The binding uses this index to get information about a specific device from a list of devices (e.g on a single computer several local disks could be installed with names C:\, D:\, E:\ - the first will have deviceIndex=0, the second deviceIndex=1 etc).
If device with this index is not existing, the binding will display an error message on the console.

Unfortunately this feature can't be used at the moment without manually adding these new channel groups to the thing description (located in OH-INF/thing/computer.xml).

The table shows more detailed information about each Channel type.
The binding introduces the following channels:

Expand Down Expand Up @@ -244,6 +252,13 @@ Number Sensor_CPUTemp "CPU Temperature" <temperature> { chann
Number Sensor_CPUVoltage "CPU Voltage" <energy> { channel="systeminfo:computer:work:sensors#cpuVoltage" }
Number Sensor_FanSpeed "Fan speed" <fan> { channel="systeminfo:computer:work:sensors#fanSpeed" }

/* Current process information*/
Number Current_process_load "Load" <none> { channel="systeminfo:computer:work:currentProcess#load" }
Number Current_process_used "Used" <none> { channel="systeminfo:computer:work:currentProcess#used" }
String Current_process_name "Name" <none> { channel="systeminfo:computer:work:currentProcess#name" }
Number Current_process_threads "Threads" <none> { channel="systeminfo:computer:work:currentProcess#threads" }
String Current_process_path "Path" <none> { channel="systeminfo:computer:work:currentProcess#path" }

/* Process information*/
Number Process_load "Load" <none> { channel="systeminfo:computer:work:process#load" }
Number Process_used "Used" <none> { channel="systeminfo:computer:work:process#used" }
Expand Down Expand Up @@ -313,6 +328,13 @@ sitemap systeminfo label="Systeminfo" {
Default item=Sensor_CPUVoltage
Default item=Sensor_FanSpeed
}
Frame label="Current Process Information" {
Default item=Current_process_load
Default item=Current_process_used
Default item=Current_process_name
Default item=Current_process_threads
Default item=Current_process_path
}
Frame label="Process Information" {
Default item=Process_load
Default item=Process_used
Expand Down
Expand Up @@ -20,13 +20,15 @@
* used across the whole binding.
*
* @author Svilen Valkanov - Initial contribution
* @author Mark Herwege - Add dynamic creation of extra channels
*/
@NonNullByDefault
public class SysteminfoBindingConstants {

public static final String BINDING_ID = "systeminfo";

public static final ThingTypeUID THING_TYPE_COMPUTER = new ThingTypeUID(BINDING_ID, "computer");
public static final String THING_TYPE_COMPUTER_ID = "computer";
public static final ThingTypeUID THING_TYPE_COMPUTER = new ThingTypeUID(BINDING_ID, THING_TYPE_COMPUTER_ID);

// Thing properties
/**
Expand Down Expand Up @@ -56,6 +58,16 @@ public class SysteminfoBindingConstants {

// List of all Channel IDs

/**
* Name of the channel group type for memory information
*/
public static final String CHANNEL_GROUP_TYPE_MEMORY = "memoryGroup";

/**
* Name of the channel group for memory information
*/
public static final String CHANNEL_GROUP_MEMORY = "memory";

/**
* Size of the available memory
*/
Expand Down Expand Up @@ -91,6 +103,16 @@ public class SysteminfoBindingConstants {
*/
public static final String CHANNEL_MEMORY_HEAP_AVAILABLE = "memory#availableHeap";

/**
* Name of the channel group type for swap information
*/
public static final String CHANNEL_GROUP_TYPE_SWAP = "swapGroup";

/**
* Name of the channel group for swap information
*/
public static final String CHANNEL_GROUP_SWAP = "swap";

/**
* Total size of swap memory
*/
Expand All @@ -116,6 +138,16 @@ public class SysteminfoBindingConstants {
*/
public static final String CHANNEL_SWAP_USED_PERCENT = "swap#usedPercent";

/**
* Name of the channel group type for drive information
*/
public static final String CHANNEL_GROUP_TYPE_DRIVE = "driveGroup";

/**
* Name of the channel group for drive information
*/
public static final String CHANNEL_GROUP_DRIVE = "drive";

/**
* Physical storage drive name
*/
Expand All @@ -131,6 +163,16 @@ public class SysteminfoBindingConstants {
*/
public static final String CHANNEL_DRIVE_SERIAL = "drive#serial";

/**
* Name of the channel group type for storage information
*/
public static final String CHANNEL_GROUP_TYPE_STORAGE = "storageGroup";

/**
* Name of the channel group for storage information
*/
public static final String CHANNEL_GROUP_STORAGE = "storage";

/**
* Name of the logical volume storage
*/
Expand Down Expand Up @@ -171,6 +213,16 @@ public class SysteminfoBindingConstants {
*/
public static final String CHANNEL_STORAGE_USED_PERCENT = "storage#usedPercent";

/**
* Name of the channel group type for sensors information
*/
public static final String CHANNEL_GROUP_TYPE_SENSORS = "sensorsGroup";

/**
* Name of the channel group for sensors information
*/
public static final String CHANNEL_GROUP_SENSORS = "sensors";

/**
* Temperature of the CPU measured from the sensors.
*/
Expand All @@ -186,6 +238,16 @@ public class SysteminfoBindingConstants {
*/
public static final String CHANNEL_SENSORS_FAN_SPEED = "sensors#fanSpeed";

/**
* Name of the channel group type for battery information
*/
public static final String CHANNEL_GROUP_TYPE_BATTERY = "batteryGroup";

/**
* Name of the channel group for battery information
*/
public static final String CHANNEL_GROUP_BATTERY = "battery";

/**
* Name of the battery
*/
Expand All @@ -201,6 +263,16 @@ public class SysteminfoBindingConstants {
*/
public static final String CHANNEL_BATTERY_REMAINING_TIME = "battery#remainingTime";

/**
* Name of the channel group type for CPU information
*/
public static final String CHANNEL_GROUP_TYPE_CPU = "cpuGroup";

/**
* Name of the channel group for CPU information
*/
public static final String CHANNEL_GROUP_CPU = "cpu";

/**
* Detailed description about the CPU
*/
Expand Down Expand Up @@ -241,11 +313,31 @@ public class SysteminfoBindingConstants {
*/
public static final String CHANNEL_CPU_THREADS = "cpu#threads";

/**
* Name of the channel group type for display information
*/
public static final String CHANNEL_GROUP_TYPE_DISPLAY = "displayGroup";

/**
* Name of the channel group for display information
*/
public static final String CHANNEL_GROUP_DISPLAY = "display";

/**
* Information about the display device
*/
public static final String CHANNEL_DISPLAY_INFORMATION = "display#information";

/**
* Name of the channel group type for network information
*/
public static final String CHANNEL_GROUP_TYPE_NETWORK = "networkGroup";

/**
* Name of the channel group for network information
*/
public static final String CHANNEL_GROUP_NETWORK = "network";

/**
* Host IP address of the network
*/
Expand Down Expand Up @@ -286,6 +378,47 @@ public class SysteminfoBindingConstants {
*/
public static final String CHANNEL_NETWORK_MAC = "network#mac";

/**
* Name of the channel group type for process information
*/
public static final String CHANNEL_GROUP_TYPE_CURRENT_PROCESS = "currentProcessGroup";

/**
* Name of the channel group for process information
*/
public static final String CHANNEL_GROUP_CURRENT_PROCESS = "currentProcess";

/**
* CPU load used from a process
*/

public static final String CHANNEL_CURRENT_PROCESS_LOAD = "currentProcess#load";

/**
* Size of memory used from a process in MB
*/
public static final String CHANNEL_CURRENT_PROCESS_MEMORY = "currentProcess#used";

/**
* Name of the process
*/
public static final String CHANNEL_CURRENT_PROCESS_NAME = "currentProcess#name";

/**
* Number of threads, used form the process
*/
public static final String CHANNEL_CURRENT_PROCESS_THREADS = "currentProcess#threads";

/**
* The full path of the process
*/
public static final String CHANNEL_CURRENT_PROCESS_PATH = "currentProcess#path";

/**
* Name of the channel group type for process information
*/
public static final String CHANNEL_GROUP_TYPE_PROCESS = "processGroup";

/**
* Name of the channel group for process information
*/
Expand Down
Expand Up @@ -12,10 +12,7 @@
*/
package org.openhab.binding.systeminfo.internal;

import static org.openhab.binding.systeminfo.internal.SysteminfoBindingConstants.THING_TYPE_COMPUTER;

import java.util.Collections;
import java.util.Set;
import static org.openhab.binding.systeminfo.internal.SysteminfoBindingConstants.*;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand All @@ -36,28 +33,33 @@
* @author Svilen Valkanov - Initial contribution
* @author Lyubomir Papazov - Pass systeminfo service to the SysteminfoHandler constructor
* @author Wouter Born - Add null annotations
* @author Mark Herwege - Add dynamic creation of extra channels
*/
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.systeminfo")
public class SysteminfoHandlerFactory extends BaseThingHandlerFactory {

private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_COMPUTER);

private @NonNullByDefault({}) SysteminfoInterface systeminfo;
private @NonNullByDefault({}) SysteminfoThingTypeProvider thingTypeProvider;

@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
return BINDING_ID.equals(thingTypeUID.getBindingId())
&& thingTypeUID.getId().startsWith(THING_TYPE_COMPUTER_ID);
}

@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();

if (thingTypeUID.equals(THING_TYPE_COMPUTER)) {
return new SysteminfoHandler(thing, systeminfo);
if (supportsThingType(thingTypeUID)) {
String extString = "-" + thing.getUID().getId();
ThingTypeUID extThingTypeUID = new ThingTypeUID(BINDING_ID, THING_TYPE_COMPUTER_ID + extString);
if (thingTypeProvider.getThingType(extThingTypeUID, null) == null) {
thingTypeProvider.createThingType(extThingTypeUID);
thingTypeProvider.storeChannelsConfig(thing); // Save the current channels configs, will be restored
// after thing type change.
}
return new SysteminfoHandler(thing, thingTypeProvider, systeminfo);
}

return null;
}

Expand All @@ -69,4 +71,13 @@ public void bindSystemInfo(SysteminfoInterface systeminfo) {
public void unbindSystemInfo(SysteminfoInterface systeminfo) {
this.systeminfo = null;
}

@Reference
public void setSysteminfoThingTypeProvider(SysteminfoThingTypeProvider thingTypeProvider) {
this.thingTypeProvider = thingTypeProvider;
}

public void unsetSysteminfoThingTypeProvider(SysteminfoThingTypeProvider thingTypeProvider) {
this.thingTypeProvider = null;
}
}