This tutorial is based on this, this, this and a lot of threads and tutorials i had to read till i got it working.
I try to give a step by step Tutorial how to get a temperature chart with OpenHAB2 and the ExecBinding 2 using the RRD4J database for persistency.
I will not explain everything in detail, please read this post to get an basic understanding of how OpenHAB works. And use the tutorials and the manual to get deeper insight of how the different parts work.
Now to read out the CPU temperatur we can use following command. The temperature will be return as milli degree celsius so we will need to devide it later by thausend to have it as degrees.
cat /sys/class/thermal/thermal_zone0/temp
48312
Testing if the user openhab can execute this command is a good idea for all commands we try to execute later from OpenHAB. As this works we can continue configuring our setup.
sudo -u openhab cat /sys/class/thermal/thermal_zone0/temp
47774
We need to install the ExecBinding and the Persistence database RRD4J Addon. As i never know how they are called and which are available, i use the Karaf console to retrieve the full name. feature:list
will return all available features.
Also the REGEX and EXEC transformation have to be installed.
ssh -p 8101 openhab@localhost
habopen
feature:list |grep rrd4j
feature:install openhab-persistence-rrd4j
feature:list |grep exec
feature:install openhab-binding-exec
feature:list |grep regex
feature:install openhab-transformation-regex
feature:list |grep exec
feature:install openhab-transformation-exec
logout
Persistence means to store the states of items over time. For that we use the simple RRD4J database. Which is explained here or here.
We need to set up a rule which defines when which data schould be stored. RRD4J will take care to minimize the database but only provides summerized data of the past. We create the config file as user openhab so we do not have to hassl with file access rights later on.
sudo -u openhab nano /etc/openhab2/persistence/rrd4j.persist
The first part configures when to store the data and the second part which items to store. We use a group item which will be stored, this will make it easier to add more values later on.
Strategies {
// for rrd charts, we need a cron strategy, every Minute is a must have.
everyMinute : "0 * * * * ?"
// get the data reduced for older values to keep database small
everyHour : "0 0 * * * ?"
everyDay : "0 0 0 * * ?"
default = everyChange
}
Items {
// additionally persist Items
System_Temperature_Chart* : strategy = everyUpdate, everyMinute
}
Now we have to set up Things, Items, a Sitemap and a Rule.
sudo nano /etc/openhab2/things/exec.things
Thing exec:command:cpuTemp [
// Command to execute
command="cat /sys/class/thermal/thermal_zone0/temp",
// interval time in seconds
interval=10,
// should it run when input channel is changed
autorun=false,
// REGEX transformation to make 44007/1000 => 44.007
// explanation for the regex
// s/ - substitute
// (.{2})(.{3}) - a a number with 5 characters, split in two groups
// /$1.$2/g - returned value= first group, a dot, then second group, used to devide by 1000
transform="REGEX(s/(.{2})(.{3})/$1.$2/g)"
// alternative EXEC transformation with python
//transform="EXEC(python3 -c \"print(%s/1000)\")"
]
sudo nano /etc/openhab2/items/SysTemp.items
// System temperatures
Group System_Temperature_Chart (System, Charts)
Number System_Temperature_Chart_Period "Periode" (System)
Number System_Temperature_CPU "Temperature CPU [%.1f °C]" <temperature> (System_Temperature_Chart)
// Output of command line execution
String System_Temperature_CPU_out { channel="exec:command:cpuTemp:output" }
sudo nano /etc/openhab2/sitemaps/SysTemp.sitemap
// Name of file and name of sitemap has to be the same
sitemap SysTemp label="System Temperature RPI"
{
Frame {
Text item=System_Temperature_CPU
}
Frame {
Switch item=System_Temperature_Chart_Period mappings=[0="1h", 1="4h", 2="8h", 3="12h", 4="24h"]
Chart item=System_Temperature_Chart period=h refresh=60000 visibility=[System_Temperature_Chart_Period==0, System_Temperature_Chart_Period=="Uninitialized"]
Chart item=System_Temperature_Chart period=4h refresh=60000 visibility=[System_Temperature_Chart_Period==1]
Chart item=System_Temperature_Chart period=8h refresh=60000 visibility=[System_Temperature_Chart_Period==2]
Chart item=System_Temperature_Chart period=12h refresh=60000 visibility=[System_Temperature_Chart_Period==3]
Chart item=System_Temperature_Chart period=D refresh=60000 visibility=[System_Temperature_Chart_Period==4]
}
}
This rule is used to update the Number itmes out of the returned String itmes from the command line. Only Works since openhab 2.2.
This is necessary as RRD4j only accepts numbers and the Exec Binding returns strings.
sudo nano /etc/openhab2/rules/SysTemp.rules
rule "Convert String to Item Type"
when
Item System_Temperature_CPU_out changed
then
// Get name of Number Item by removing "_out" from the name of the String Item
val toUpdate = triggeringItem.name.toString.split("_out").get(0)
// post the new value to the Number Item
postUpdate( toUpdate.toString , triggeringItem.state.toString )
logInfo("Convert", "Item "+ toUpdate +" state "+ triggeringItem.state)
end
If we keep the Karaf console open while we copy paste the files we can see if everything went as it should. We can also see the logInfo massages we added in the rule.
ssh -p 8101 openhab@localhost
habopen
openhab> log:tail
[INFO ] [ipse.smarthome.model.script.CPU Temp] - 48312
[INFO ] [ipse.smarthome.model.script.CPU Temp] - 48.31200000
[INFO ] [marthome.event.ItemStateChangedEvent] - System_Temperature_CPU changed from 49.38800000 to 48.31200000
On our sitemap we can now see the CPU temperature and a chart which shows the progress. We have to wait a while till there is something to plot.
Also adding the GPU Temperature can easily achieved, the command to get the value is as follows and returns an string which we well have to parse by a regex.
pi@raspberrypi:~ $ /opt/vc/bin/vcgencmd measure_temp
temp=48.3'C
Testing if user openhab can also access this value.
sudo -u openhab /opt/vc/bin/vcgencmd measure_temp
VCHI initialization failed
So something does not work, mostly it is the user rights to execute this command. As we saw user pi was able to execute it. A google search points us to which user group we have to add openhab to. We need to add openhab to to the video group, the new rights will be available after a reboot.
sudo usermod -a -G video openhab
sudo reboot
When we test it again we should be able to run it as openhab user and get the same result as without sudo -u openhab
.
Now we need to add a Things, a Item, an entry to the Sitemap and one to the Rule to the existing files.
sudo nano /etc/openhab2/things/exec.things
Thing exec:command:gpuTemp [
// Command to execute
command="/opt/vc/bin/vcgencmd measure_temp",
// interval time in seconds
interval=10,
// should it run when input channel is changed
autorun=false,
// REGEX transformation to make "temp=44.0'C" => 44.0
transform="REGEX(temp=(.*?)'C)" ]
As the chart and the rrd4j database where defined to use the group System_Temperature_Chart
we only need to add a new item for the GPU Temperature to this group. And also an item to store the return value of the command line execution.
sudo nano /etc/openhab2/items/SysTemp.items
// System temperatures
Number System_Temperature_GPU "Temperature GPU [%.1f °C]" <temperature> (System_Temperature_Chart)
// Output of command line execution
String System_Temperature_CPU_out { channel="exec:command:cpuTemp:output" }
String System_Temperature_GPU_out { channel="exec:command:gpuTemp:output" }
sudo nano /etc/openhab2/sitemaps/SysTemp.sitemap
// Name of file and name of sitemap has to be the same
sitemap SysTemp label="System Temperature RPI"
{
Frame {
Text item=System_Temperature_CPU
// This line is new
Text item=System_Temperature_GPU
}
Frame {
Switch item=System_Temperature_Chart_Period label="Periode" mappings=[0="1h", 1="4h", 2="8h", 3="12h", 4="24h"]
Chart item=System_Temperature_Chart period=h refresh=60000 visibility=[System_Temperature_Chart_Period==0, System_Temperature_Chart_Period=="Uninitialized"]
Chart item=System_Temperature_Chart period=4h refresh=60000 visibility=[System_Temperature_Chart_Period==1]
Chart item=System_Temperature_Chart period=8h refresh=60000 visibility=[System_Temperature_Chart_Period==2]
Chart item=System_Temperature_Chart period=12h refresh=60000 visibility=[System_Temperature_Chart_Period==3]
Chart item=System_Temperature_Chart period=D refresh=60000 visibility=[System_Temperature_Chart_Period==4]
}
}
sudo nano /etc/openhab2/rules/SysTemp.rules
rule "Convert String to Item Type"
when
Item System_Temperature_CPU_out changed or //here new or
// and this line is new
Item System_Temperature_GPU_out changed
then
// Get name of Number Item by removing "_out" from the name of the String Item
val toUpdate = triggeringItem.name.toString.split("_out").get(0)
// post the new value to the Number Item
postUpdate( toUpdate.toString , triggeringItem.state.toString )
logInfo("Convert", "Item "+ toUpdate +" state "+ triggeringItem.state)
end
As always this is just how i got it work. I would apriciate every amendment or improvement by the pro openHAB user. Is there anything that is done bad, or decreases performance? Is there an other better way todo this, besides using nicer charts like explained here.
Update:
The Regex output channel is a string, added the simplest way to get all returned strings to the Number Item with only one rule.
Using InfluxDB persistence and graphing with Grafana a 2 element solution with one Item and one Thing can be achieved. Explained here.
Last but not least i prefer the console and explaining how to install a binding/addon is 4 lines instead of a book with pictures to explain where to find what.
It is also much faster and can be used as copy paste instructions.
Thank your your comments @rlkoshak.
Update:
Got some DS18B20 OneWire Temperature sensors and did a quick installation. following this guide, sorry its german. But in the official rpi docs it is also described.
I added a new thing and also used the regex to filter the value and divde it by 1000.
Thing exec:command:ds18b20_1 [
// Command to execute
command="cat /sys/bus/w1/devices/28-0516b0780eff/w1_slave",
// interval time in seconds
interval=5,
// should it run when input channel is changed
autorun=false,
// explanation for the regex
// s/ - substitute
// .+\\s.+t= - all char, a linebreack (with "\" to escape), all char, t=
// (.{2})(.{3}) - a number with 5 characters, split in two groups
// /$1.$2/g - returned value= first group, a dot, then second group, used to devide by 1000
transform="REGEX(s/.+\\s.+t=(.{2})(.{3})/$1.$2/g)" ]
the rest is is done es explained above.