Hi guys, I have not yet seen that there is already a solution for this. However, I am still using openHAB 2 and the old MQTT 1 binding. But maybe there are people who will write a newer tutorial on this, just because I still haven’t made any progress with conversions.
Motivation and Background
What I am generally trying to do is to have each device display information in an administrative overview. In a simple case, this goes from a simple display of the network binding and ping to whether various devices are switched on or reachable. I am currently starting, stopping/shutting down or restarting openHAB and the devices on which openHAB is running. From this way of thinking, a first step was to use the Systeminfo Binding to get more information about the status of the devices, such as the CPU load, the memory used, etc. The goal is to make the entire system as maintainable as possible.
The problem
The problem is actually relatively simple to explain. The Systeminfo Binding requires a Thing. This refers to the local computer. Depending on the setup of the entire openHAB system, it is not possible to exchange the system information.
Preparation
At first you have to install the MQTT bindings. In my case:
- openHAB → PaperUI → Settings → Configuration → System → Addon Management → Include Legacy 1.x Bindings → Save
- openHAB → PaperUI → Addons → Bindings → MQTT Action (1.x) → install
- openHAB → PaperUI → Addons → Actions → MQTT Binding (1.x) → install
- openHAB → PaperUI → Addons → Bindings → System Info Binding → install
This installation is the same on all openHAB devices.
MQTT configuration
I use an Ubuntu VM with openHAB installed and 8 Raspberry Pi`s running openHABian. The VM publishes the item states and subscribes the commands of the items.
cat $OPENHAB_CONF/services/mqtt.cfg
:
#
# Define your MQTT broker connections here for use in the MQTT Binding or MQTT
# Persistence bundles. Replace <broker> with an ID you choose.
#
# URL to the MQTT broker, e.g. tcp://localhost:1883 or ssl://localhost:8883
MQTTBroker.url=tcp://localhost:1883
# Optional. Client id (max 23 chars) to use when connecting to the broker.
# If not provided a random default is generated.
#<broker>.clientId=<clientId>
# Optional. True or false. If set to true, allows the use of clientId values
# up to 65535 characters long. Defaults to false.
# NOTE: clientId values longer than 23 characters may not be supported by all
# MQTT servers. Check the server documentation.
#<broker>.allowLongerClientIds=false
# Optional. User id to authenticate with the broker.
#MQTTBroker.user=
# Optional. Password to authenticate with the broker.
#MQTTBroker.pwd=
# Optional. Set the quality of service level for sending messages to this broker.
# Possible values are 0 (Deliver at most once),1 (Deliver at least once) or 2
# (Deliver exactly once). Defaults to 0.
MQTTBroker.qos=0
# Optional. True or false. Defines if the broker should retain the messages sent to
# it. Defaults to false.
#<broker>.retain=<retain>
# Optional. True or false. Defines if messages are published asynchronously or
# synchronously. Defaults to true.
MQTTBroker.async=false
# Optional. Defines the last will and testament that is sent when this client goes offline
# Format: topic:message:qos:retained <br/>
#<broker>.lwt=<last will definition>
cat $OPENHAB_CONF/services/mqtt-eventbus.cfg
:
# Name of the broker as it is defined in the openhab.cfg. If this property is not available, no event bus MQTT binding will be created.
broker=MQTTBroker
# When available, all status updates which occur on the openHAB event bus are published to the provided topic. The message content will
# be the status. The variable ${item} will be replaced during publishing with the item name for which the state was received.
statePublishTopic=/messages/states/${item}
# When available, all commands which occur on the openHAB event bus are published to the provided topic. The message content will be the
# command. The variable ${item} will be replaced during publishing with the item name for which the command was received.
#commandPublishTopic=
# When available, all status updates received on this topic will be posted to the openHAB event bus. The message content is assumed to be
# a string representation of the status. The topic should include the variable ${item} to indicate which part of the topic contains the
# item name which can be used for posting the received value to the event bus.
#stateSubscribeTopic=
# When available, all commands received on this topic will be posted to the openHAB event bus. The message content is assumed to be a
# string representation of the command. The topic should include the variable ${item} to indicate which part of the topic contains the
# item name which can be used for posting the received value to the event bus.
commandSubscribeTopic=/messages/commands/${item}
And on the Raspberry Pi’s I have a configuration like that:
cat $OPENHAB_CONF/services/mqtt.cfg
:
#
# Define your MQTT broker connections here for use in the MQTT Binding or MQTT
# Persistence bundles. Replace <broker> with an ID you choose.
#
# URL to the MQTT broker, e.g. tcp://localhost:1883 or ssl://localhost:8883
MQTTBroker.url=tcp://192.168.0.X:1883
# Optional. Client id (max 23 chars) to use when connecting to the broker.
# If not provided a default one is generated.
#<broker>.clientId=<clientId>
# Optional. User id to authenticate with the broker.
#MQTTBroker.user=
# Optional. Password to authenticate with the broker.
#MQTTBroker.pwd=
# Optional. Set the quality of service level for sending messages to this broker.
# Possible values are 0 (Deliver at most once),1 (Deliver at least once) or 2
# (Deliver exactly once). Defaults to 0.
#<broker>.qos=<qos>
# Optional. True or false. Defines if the broker should retain the messages sent to
# it. Defaults to false.
#MQTTBroker.retain=false
# Optional. True or false. Defines if messages are published asynchronously or
# synchronously. Defaults to true.
MQTTBroker.async=false
# Optional. Defines the last will and testament that is sent when this client goes offline
# Format: topic:message:qos:retained <br/>
#<broker>.lwt=<last will definition>
cat $OPENHAB_CONF/services/mqtt-eventbus.cfg
:
# Name of the broker as it is defined in the openhab.cfg. If this property is not available, no event bus MQTT binding will be created.
broker=MQTTBroker
# When available, all status updates which occur on the openHAB event bus are published to the provided topic. The message content will
# be the status. The variable ${item} will be replaced during publishing with the item name for which the state was received.
#statePublishTopic=
# When available, all commands which occur on the openHAB event bus are published to the provided topic. The message content will be the
# command. The variable ${item} will be replaced during publishing with the item name for which the command was received.
commandPublishTopic=/messages/commands/${item}
# When available, all status updates received on this topic will be posted to the openHAB event bus. The message content is assumed to be
# a string representation of the status. The topic should include the variable ${item} to indicate which part of the topic contains the
# item name which can be used for posting the received value to the event bus.
stateSubscribeTopic=/messages/states/${item}
# When available, all commands received on this topic will be posted to the openHAB event bus. The message content is assumed to be a
# string representation of the command. The topic should include the variable ${item} to indicate which part of the topic contains the
# item name which can be used for posting the received value to the event bus.
#commandSubscribeTopic=
(The rule files could also work without this setup.)
So in my setup, the Raspberry Pi and the VM would have system information independently. The VM does not know the values of the individual Raspberry Pi`s. So it only has null values or undef values.
Get the local system infos
The first thing to do is to get the local system information on each device.
cat $OPENHAB_CONF/things/system.things
:
Thing exec:command:uptime [command="/etc/openhab2/scripts/uptime.sh", interval=60, timeout=2]
Thing systeminfo:computer:shlPiGeneral [interval_high=2, interval_medium=60]
or:
Thing exec:command:uptime [command="/etc/openhab2/scripts/uptime.sh", interval=60, timeout=2]
Thing systeminfo:computer:OpenHABVM [interval_high=2, interval_medium=60]
As you can see on the VM I named the thing OpenHABVM and on one of the Raspberry Pi`s shlPiGeneral. On both you can name the thing as you want. For example local or localmachine. The second thing you noticed is that I followd this tutorial to show the server and the openHAB uptime. This is not needed, but if you are already interested in, very helpful.
Then you need an item for the local system infos. Let call it system.items:
/* Network information*/
String Network_AdapterName "Adapter name" <network> { channel="systeminfo:computer:work:network#networkDisplayName" }
String Network_Name "Name" <network> { channel="systeminfo:computer:work:network#networkName" }
String Network_IP "IP address" <network> { channel="systeminfo:computer:work:network#ip" }
String Network_Mac "Mac address" <network> { channel="systeminfo:computer:work:network#mac" }
Number Network_DataSent "Data sent" <flowpipe> { channel="systeminfo:computer:work:network#dataSent" }
Number Network_DataReceived "Data received" <returnpipe> { channel="systeminfo:computer:work:network#dataReceived" }
Number Network_PacketsSent "Packets sent" <flowpipe> { channel="systeminfo:computer:work:network#packetsSent" }
Number Network_PacketsReceived "Packets received" <returnpipe> { channel="systeminfo:computer:work:network#packetsReceived" }
/* 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_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" }
Number CPU_Threads "Threads" <none> { channel="systeminfo:computer:work:cpu#threads" }
Number CPU_Uptime "Uptime" <time> { channel="systeminfo:computer:work:cpu#uptime" }
/* Drive information*/
String Drive_Name "Name" <none> { channel="systeminfo:computer:work:drive#name" }
String Drive_Model "Model" <none> { channel="systeminfo:computer:work:drive#model" }
String Drive_Serial "Serial" <none> { channel="systeminfo:computer:work:drive#serial" }
/* Storage information*/
String Storage_Name "Name" <none> { channel="systeminfo:computer:work:storage#name" }
String Storage_Type "Type" <none> { channel="systeminfo:computer:work:storage#type" }
String Storage_Description "Description" <none> { channel="systeminfo:computer:work:storage#description" }
Number Storage_Available "Available" <none> { channel="systeminfo:computer:work:storage#available" }
Number Storage_Used "Used" <none> { channel="systeminfo:computer:work:storage#used" }
Number Storage_Total "Total" <none> { channel="systeminfo:computer:work:storage#total" }
Number Storage_Available_Percent "Available (%)" <none> { channel="systeminfo:computer:work:storage#availablePercent" }
Number Storage_Used_Percent "Used (%)" <none> { channel="systeminfo:computer:work:storage#usedPercent" }
/* Memory information*/
Number Memory_Available "Available" <none> { channel="systeminfo:computer:work:memory#available" }
Number Memory_Used "Used" <none> { channel="systeminfo:computer:work:memory#used" }
Number Memory_Total "Total" <none> { channel="systeminfo:computer:work:memory#total" }
Number Memory_Available_Percent "Available (%)" <none> { channel="systeminfo:computer:work:memory#availablePercent" }
Number Memory_Used_Percent "Used (%)" <none> { channel="systeminfo:computer:work:memory#usedPercent" }
/* Swap memory information*/
Number Swap_Available "Available" <none> { channel="systeminfo:computer:work:swap#available" }
Number Swap_Used "Used" <none> { channel="systeminfo:computer:work:swap#used" }
Number Swap_Total "Total" <none> { channel="systeminfo:computer:work:swap#total" }
Number Swap_Available_Percent "Available (%)" <none> { channel="systeminfo:computer:work:swap#availablePercent" }
Number Swap_Used_Percent "Used (%)" <none> { channel="systeminfo:computer:work:swap#usedPercent" }
/* Battery information*/
String Battery_Name "Name" <batterylevel> { channel="systeminfo:computer:work:battery#name" }
Number Battery_RemainingCapacity "Remaining Capacity" <batterylevel> { channel="systeminfo:computer:work:battery#remainingCapacity" }
Number Battery_RemainingTime "Remaining Time" <batterylevel> { channel="systeminfo:computer:work:battery#remainingTime" }
/* Display information*/
String Display_Description "Display description" <screen> { channel="systeminfo:computer:work:display#information" }
/* Sensors information*/
Number Sensor_CPUTemp "CPU Temperature" <temperature> { channel="systeminfo:computer:work:sensors#cpuTemp" }
Number Sensor_CPUVoltage "CPU Voltage" <energy> { channel="systeminfo:computer:work:sensors#cpuVoltage" }
Number Sensor_FanSpeed "Fan speed" <fan> { channel="systeminfo:computer:work:sensors#fanSpeed" }
/* Process information*/
Number Process_load "Load" <none> { channel="systeminfo:computer:work:process#load" }
Number Process_used "Used" <none> { channel="systeminfo:computer:work:process#used" }
String Process_name "Name" <none> { channel="systeminfo:computer:work:process#name" }
Number Process_threads "Threads" <none> { channel="systeminfo:computer:work:process#threads" }
String Process_path "Path" <none> { channel="systeminfo:computer:work:process#path" }
Inside the VM is replaced work
with OpenHABVM
and on the Raspberry Pi I replaced it with shlPiGeneral
. So please remember that you have to use the given name of the thing. So if you call it local
or localmachine
then you have to use it.
Note: I think a good practice is to name your Thing equal to the hostname of the computer.
Inside your sitemap you have to add following:
Text label="Systeminfo" {
Frame label="Network Information" {
Default item=Network_AdapterName
Default item=Network_Name
Default item=Network_IP
Default item=Network_Mac
Default item=Network_DataSent
Default item=Network_DataReceived
Default item=Network_PacketsSent
Default item=Network_PacketsReceived
}
Frame label="CPU Information" {
Default item=CPU_Name
Default item=CPU_Description
Default item=CPU_Load1
Default item=CPU_Load5
Default item=CPU_Load15
Default item=CPU_Threads
Default item=CPU_Uptime
}
Frame label="Drive Information" {
Default item=Drive_Name
Default item=Drive_Model
Default item=Drive_Serial
}
Frame label="Storage Information" {
Default item=Storage_Name
Default item=Storage_Type
Default item=Storage_Description
Default item=Storage_Available
Default item=Storage_Used
Default item=Storage_Total
Default item=Storage_Available_Percent
Default item=Storage_Used_Percent
}
Frame label="Memory Information" {
Default item=Memory_Available
Default item=Memory_Used
Default item=Memory_Total
Default item=Memory_Available_Percent
Default item=Memory_Used_Percent
}
Frame label="Swap Memory Information" {
Default item=Swap_Available
Default item=Swap_Used
Default item=Swap_Total
Default item=Swap_Available_Percent
Default item=Swap_Used_Percent
}
Frame label="Battery, Display and Sensor Information" {
Default item=Battery_Name
Default item=Battery_RemainingCapacity
Default item=Battery_RemainingTime
Default item=Display_Description
Default item=Sensor_CPUTemp
Default item=Sensor_CPUVoltage
Default item=Sensor_FanSpeed
}
Frame label="Process Information" {
Default item=Process_load
Default item=Process_used
Default item=Process_name
Default item=Process_threads
Default item=Process_path
}
}
Congratulation, the first important step is done. Check if it work. As example you can see something like that:
…
Share the system infos
So which is in my opinion a better aproach is that you not use as example the item name Network_AdapterName
on multiple devices. I used a prefix like the machine hostname. So I used OpenHABVM_Network_AdapterName
and shlPiGeneral_Network_AdapterName
in my example. So one every device I don`t use the example names for the items which was given in the documentation.
Be careful that you have to update the sitemap as well!
For sharing the local system infos you need a rule file. Let`s call it sytem.rules. Here I have following example for you:
cat $OPENHAB_CONF/rules/system.rules
var loggerName = "system rules"
var device = "OpenHABVM"
var broker = "MQTTBroker"
var topic = "/messages/states"
rule "System State rule"
when
// jede Minute
Time cron "0 0/1 * * * ?"
then
publish(broker, topic + "/" + device+ "/" + "Network_AdapterName", OpenHABVM_Network_AdapterName.state.toString)
publish(broker, topic + "/" + device+ "/" + "Network_Name", OpenHABVM_Network_Name.state.toString)
publish(broker, topic + "/" + device+ "/" + "Network_IP", OpenHABVM_Network_IP.state.toString)
publish(broker, topic + "/" + device+ "/" + "Network_Mac", OpenHABVM_Network_Mac.state.toString)
publish(broker, topic + "/" + device+ "/" + "Network_DataSent", OpenHABVM_Network_DataSent.state.toString)
publish(broker, topic + "/" + device+ "/" + "Network_DataReceived", OpenHABVM_Network_DataReceived.state.toString)
publish(broker, topic + "/" + device+ "/" + "Network_PacketsSent", OpenHABVM_Network_PacketsSent.state.toString)
publish(broker, topic + "/" + device+ "/" + "Network_PacketsReceived", OpenHABVM_Network_PacketsReceived.state.toString)
/* CPU information*/
publish(broker, topic + "/" + device+ "/" + "CPU_Name", OpenHABVM_CPU_Name.state.toString)
publish(broker, topic + "/" + device+ "/" + "CPU_Description", OpenHABVM_CPU_Description.state.toString)
publish(broker, topic + "/" + device+ "/" + "CPU_Load1", OpenHABVM_CPU_Load1.state.toString)
publish(broker, topic + "/" + device+ "/" + "CPU_Load5", OpenHABVM_CPU_Load5.state.toString)
publish(broker, topic + "/" + device+ "/" + "CPU_Load15", OpenHABVM_CPU_Load15.state.toString)
publish(broker, topic + "/" + device+ "/" + "CPU_Threads", OpenHABVM_CPU_Threads.state.toString)
publish(broker, topic + "/" + device+ "/" + "CPU_Uptime", OpenHABVM_CPU_Uptime.state.toString)
/* Drive information*/
publish(broker, topic + "/" + device+ "/" + "Drive_Name", OpenHABVM_Drive_Name.state.toString)
publish(broker, topic + "/" + device+ "/" + "Drive_Model", OpenHABVM_Drive_Model.state.toString)
publish(broker, topic + "/" + device+ "/" + "Drive_Serial", OpenHABVM_Drive_Serial.state.toString)
/* Storage information*/
publish(broker, topic + "/" + device+ "/" + "Storage_Name", OpenHABVM_Storage_Name.state.toString)
publish(broker, topic + "/" + device+ "/" + "Storage_Type", OpenHABVM_Storage_Type.state.toString)
publish(broker, topic + "/" + device+ "/" + "Storage_Description", OpenHABVM_Storage_Description.state.toString)
publish(broker, topic + "/" + device+ "/" + "Storage_Available", OpenHABVM_Storage_Available.state.toString)
publish(broker, topic + "/" + device+ "/" + "Storage_Used", OpenHABVM_Storage_Used.state.toString)
publish(broker, topic + "/" + device+ "/" + "Storage_Total", OpenHABVM_Storage_Total.state.toString)
publish(broker, topic + "/" + device+ "/" + "Storage_Available_Percent", OpenHABVM_Storage_Available_Percent.state.toString)
publish(broker, topic + "/" + device+ "/" + "Storage_Used_Percent", OpenHABVM_Storage_Used_Percent.state.toString)
/* Memory information*/
publish(broker, topic + "/" + device+ "/" + "Memory_Available", OpenHABVM_Memory_Available.state.toString)
publish(broker, topic + "/" + device+ "/" + "Memory_Used", OpenHABVM_Memory_Used.state.toString)
publish(broker, topic + "/" + device+ "/" + "Memory_Total", OpenHABVM_Memory_Total.state.toString)
publish(broker, topic + "/" + device+ "/" + "Memory_Available_Percent", OpenHABVM_Memory_Available_Percent.state.toString)
publish(broker, topic + "/" + device+ "/" + "Memory_Used_Percent", OpenHABVM_Memory_Used_Percent.state.toString)
/* Swap memory information*/
publish(broker, topic + "/" + device+ "/" + "Swap_Available", OpenHABVM_Swap_Available.state.toString)
publish(broker, topic + "/" + device+ "/" + "Swap_Used", OpenHABVM_Swap_Used.state.toString)
publish(broker, topic + "/" + device+ "/" + "Swap_Total", OpenHABVM_Swap_Total.state.toString)
publish(broker, topic + "/" + device+ "/" + "Swap_Available_Percent", OpenHABVM_Swap_Available_Percent.state.toString)
publish(broker, topic + "/" + device+ "/" + "Swap_Used_Percent", OpenHABVM_Swap_Used_Percent.state.toString)
/* Battery information*/
publish(broker, topic + "/" + device+ "/" + "Battery_Name", OpenHABVM_Battery_Name.state.toString)
publish(broker, topic + "/" + device+ "/" + "Battery_RemainingCapacity", OpenHABVM_Battery_RemainingCapacity.state.toString)
publish(broker, topic + "/" + device+ "/" + "Battery_RemainingTime", OpenHABVM_Battery_RemainingTime.state.toString)
/* Display information*/
publish(broker, topic + "/" + device+ "/" + "Display_Description", OpenHABVM_Display_Description.state.toString)
/* Sensors information*/
publish(broker, topic + "/" + device+ "/" + "Sensor_CPUTemp", OpenHABVM_Sensor_CPUTemp.state.toString)
publish(broker, topic + "/" + device+ "/" + "Sensor_CPUVoltage", OpenHABVM_Sensor_CPUVoltage.state.toString)
publish(broker, topic + "/" + device+ "/" + "Sensor_FanSpeed", OpenHABVM_Sensor_FanSpeed.state.toString)
/* Process information*/
publish(broker, topic + "/" + device+ "/" + "Process_load", OpenHABVM_Process_load.state.toString)
publish(broker, topic + "/" + device+ "/" + "Process_used", OpenHABVM_Process_used.state.toString)
publish(broker, topic + "/" + device+ "/" + "Process_name", OpenHABVM_Process_name.state.toString)
publish(broker, topic + "/" + device+ "/" + "Process_threads", OpenHABVM_Process_threads.state.toString)
publish(broker, topic + "/" + device+ "/" + "Process_path", OpenHABVM_Process_path.state.toString)
A few things you maybe have to change:
-
var device = "OpenHABVM"
on each device the name of the device because you will later subscribe separated by the device name. -
var broker = "MQTTBroker"
you have to use the given name from yourmqtt.cfg
file. -
var topic = "/messages/states"
you have to use the given base path from yourmqtt-eventbus.cfg
file.
And last but not least you have to change the prefix for each device.
Note: If you use Visual Studio Code press Ctrl + H
and search for OpenHABVM
and do a replace all with your local machine name.