CPU Temperature Display in Conky

Background

I’m using Conky for monitoring the system. After a system upgrade, the CPU temperatures were gone. Conky’s standard error showed the following.

Conky: can't open '/sys/class/hwmon/hwmon0/temp3_input': No such file or
directory please check your device or remove this var from Conky...

Source of message: https://bbs.archlinux.org/viewtopic.php?id=82231

An easy fix would be to adjust the following lines in .conkyrc according to the number N in /sys/class/hwmon/hwmonN containing the file temp3_input. (You may adjust the number 3 according to the number of CPU of your device.) The number of CPU can be found using grep -c ^processor /proc/cpuinfo.

CPU 1: ${hwmon 0 temp 1}°C ${cpu cpu1}% ${alignr} CPU 2: ${hwmon 0 temp 2}°C ${cpu cpu2}%
${cpugraph cpu1 60,120} ${alignr} ${cpugraph cpu2 60,120}

To find out what the above paths represent, issue tree /sys/class/hwmon

$ tree /sys/class/hwmon/
/sys/class/hwmon/
├── hwmon0 -> ../../devices/virtual/hwmon/hwmon0
├── hwmon1 -> ../../devices/platform/coretemp.0/hwmon/hwmon1
└── hwmon2 -> ../../devices/pci0000:00/0000:00:1c.0/0000:01:00.0/hwmon/hwmon2

3 directories, 0 files

coretemp.0 represents the CPU temperatures. It’s linked to hwmon1, so for the current session, the right config should be ${hwmon 1 temp m}. However, as written in the linked forum message, after a system upgrade, the digit would shift.

Problem

How to configure Conky properly so that the CPU temperatures will be shown despite the shifting of temp3_input’s path?

Difficulty

Start with a simple idea.

  1. Test the existence of temp3_input for directories hwmonN, where N = 0,...,3. Only one N would give positive result. Assign this to some variable ${myvar}.

    for (( i=0; i<3; i++ )); do
      test -e /sys/class/hwmon/hwmon$i/temp3_crit && echo $i || echo -n
    done
    # returns `1`
    

    Wrap this shell command with ${exec ...} in .conkyrc.

  2. Write something like ${hwmon ${myvar} temp m} for m = 1,... in .conkyrc.

This leads us to a deadend. The syntax in item 2 doesn’t work. One has to use a Conky Lua script to make things work. Note that the .conkyrc syntax has changed so significantly that the TEXT section has been replaced by a conky.text = [[ ... ]] block. It took me an hour to find the right wiki page. This line in .conkyrc inside conky.config = { ... } calls the Lua script.

lua_load = '/home/username/scripts/script.lua'

I’m not sure whether relative path is allowed. You may test and let me know in the comments below.

Since I don’t know Lua, my script won’t be as fancy as the official sample. It took me some time to learn these basics in Conky Lua scripts.

  1. All Lua functions directly called from .conkyrc with the syntax ${lua myfct[ params]} has to be written as function conky_myfct ([parmas]) in the Lua script file. The examples that I’ve seen use ${lua conky_myfct}, but skipping conky_ in the previous expression still gives me the desired result, as you can see from the animated screenshot below.
  2. The arguments for functions in ${lua myfct args} in .conkyrc don’t need to be surrounded by parenthesis (), contrarily to the Conky Lua script myfct(args).
  3. Any function directly called by .conkyrc has to return a string. Other return types are discarded. Use tostring() to convert other data types to strings.
  4. Multiple argument in print("arg1", var2, "arg3") is possible, but the output string will be delimited by tabs by default. That’s not desirable in some cases.
  5. The syntax for string concatenation is ... Subtraction - has a higher precedence than string concatenation .., so quantities like n-1 has to be enclosed with a pair of parenthesis () when used with ...
  6. conky_parse("${...}") returns a string.

Solution

The actual Conky Lua script will be divided into three stages for the ease of maintenance.

  1. Verify whether file_exists by its file name.

    function file_exists(name)
      local f=io.open(name,"r")
      if f~=nil then io.close(f) return true else return false end
    end
    

    Source: https://stackoverflow.com/a/4991602/3184351

  2. Find the right N so that /sys/class/hwmon/hwmonN/temp3_crit exists.

    function findHwmonNum()
      for i = 0,10,1 do
        if file_exists("/sys/class/hwmon/hwmon"..i.."/temp3_crit") then
            return i
        end
      end
    end
    
  3. To replace ${hwmon N temp n} with the function ${lua cputemp n} in .conkyrc, we need to read Conky’s string output with conky_parse(${...}). The string inside is the concatenation of ${hwmon , findHwmonNum() (representing N in the previous section), temp, n (the input argument) and }. I’ve hard-coded CPU 1, …, CPU 3 in .conkyrc because of the alignment of CPU info. I would like to keep the code maintainable with my basic knowledge in Lua. This gives the following function.

    function conky_cputemp(n)
      return conky_parse("${hwmon "..findHwmonNum().." temp "..n.."}")
    end
    

Visual result

Conky’s output

Conky  CPU  Linux 

1 comment

Your email address will not be published. Required fields are marked *.