Sunday, March 10, 2013

Adding CPU Temperature Monitoring to pfSense

One thing that I noticed after installing pfSense 2.0.2-RELEASE was that temperature was conspicuously absent from the Dashboard System Information widget.  Since the pfSense widgets are built using PHP, I figured it wouldn't be too hard to add the required functionality.  The first step was figuring out how to read the CPU temperatures.  My pfSense setup is a repurposed 2.4 GHz Pentium 4 computer w/ 1 GB memory I built circa 2003.  Pretty ancient.

FreeBSD provides modules for reading motherboard temperatures on late model Intel (Core Duo) and AMD CPUs.  The modules can be found in /boot/kernel as coretemp.ko and amdtemp.ko respectfully.  Use kdload to install the appropriate module and sysctl to access the temperature values.

 $> kldload coretemp # amdtemp  
 $> sysctl -a | grep -i temperature  

For my motherboard I need to go a little more old school and use mbmon (MotherBoard Monitor).  pfSense does not include the mbmon package by default so we need to install it.  Unfortunately I got the following error when I tried installing mbmon:

 $> pkg_add -r mbmon  
 Error: Unable to get ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-8.1-release/Latest/mbmon.tbz: File unavailable (e.g., file not found, no access)  
 pkg_add: unable to fetch 'ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-8.1-release/Latest/mbmon.tbz' by URL  

Looks like 8.1-release is no longer maintained on the main FreeBSD package site.  A little quick reading and I found the answer in the pfSense documentation.

 $> pkg_add -r ftp://ftp-archive.freebsd.org/pub/FreeBSD-Archive/ports/i386/packages-8.1-release/Latest/mbmon.tbz  
 $> rehash  

 $> mbmon  
 ioctl(smb0:open): No such file or directory  
 No Hardware Monitor found!!  
 InitMBInfo: Bad file descriptor  

The "No Hardware Monitor found!!!" indicates that I don't have some needed modules loaded for it to be able to read the hardware.  I found the modules in /boot/kernel and loaded them.

 $> kldload ichsmb  
 $> kldload smbus  
 $> kldstat  
 Id Refs Address  Size   Name  
  1  8 0xc0400000 117c18c kernel  
  3  2 0xc5350000 2000   smbus.ko  
  5  1 0xc5355000 3000   smb.ko  
  6  1 0xc535e000 4000   ichsmb.ko  

 $> mbmon -r -c1  
 Temp.= 21.0, 26.2, 22.5; Rot.=  0, 1380,  0  
 Vcore = 1.50, 1.48; Volt. = 3.36, 5.15, 12.07,  0.00, 0.00  

Success!

To get the modules to load automatically on boot add the following to /boot/loader.conf.local.  Using loader.conf.local will allow the changes to persist after a pfSense update.

 ichsmb_load="YES"  
 smb_load="YES"  

Searching through pfSense php files I noticed that the framework for handling temperature is already there, we just need to provide the implementation.

Open /usr/local/www/includes/functions.inc.php, search for the function has_temp() and modify it to return true.


Replace the contents of get_temp() with:


Now save the file and go to the pfSense dashboard in your browser

System Information widget w/ Temperature


Not too shabby, but with a few modifications, we can show all the temperature values returned from mbmon.

Modify the get_temp() function to be


Then edit /usr/local/www/widgets/widgets/system_information.widget.php and search for where has_temp() is called.  The code snippet will look similar to the following depending on your pfSense version:


Change it to be


I simply added a foreach to loop through the returned temperature array.

System Information widget w/ multiple Temperatures


Enjoy!

2 comments:

  1. nice article.. thanks for taking time to post this. i was able to use amdtemp, and version 2.1 just required returning true for 'has_temp'.

    ReplyDelete
  2. Thanks for that tip!

    pfsense 2.2.* has "Thermal Sensors" widget. You can use it for display temperature information from mbmon with minimal change. You must change in file /usr/local/www/widgets/include/thermal_sensors.inc function for this:

    function getThermalSensorsData() {
    //$_gb = exec("/sbin/sysctl -a | grep temperature", $dfout);
    $_gb = exec("/usr/local/bin/mbmon -r -c1 | grep TEMP", $dfout);
    $thermalSensorsData = join("|", $dfout);
    return $thermalSensorsData;
    }

    ...and after that standard "Thermal Sensors" widget will show you temperature values from mbmon.

    ReplyDelete