pfSense stat monitor


#1

It took a bit of work to put this together, so I thought I’d share it with the community. pfSense does not have a native API for pulling/pushing information, but with a little work you can get it to send stats to HA and you can also send commands to your pfSense router if you so desire. Be careful, this API is quite powerful. Make sure you don’t mess something up.

How to set up:

  1. Install Faux API for pfSense (PFFA) from here: https://github.com/ndejong/pfsense_fauxapi#installation

    fetch https://raw.githubusercontent.com/ndejong/pfsense_fauxapi/master/package/pfSense-pkg-FauxAPI-1.3_1.txz
    pkg-static install pfSense-pkg-FauxAPI-1.3_1.txz

The UI will load Faux API here:
fauxapi

  1. Update /etc/fauxapi/credentials.ini file after install to add a new user. By default, Faux API has no user… there are two examples, but they are hardcoded not to work for security reasons. @ndejong offers some bash scripts to create your keys, but I had trouble with them for some reason. You don’t have to use them, you just have to make sure to follow the rules:

    The API key + API secret values that you will need to create in /etc/fauxapi/credentials.ini have the following rules:-
    
    <apikey_value> and <apisecret_value> may have alphanumeric chars ONLY!
    <apikey_value> MUST start with the prefix PFFA (pfSense Faux API)
    <apikey_value> MUST be >= 12 chars AND <= 40 chars in total length
    <apisecret_value> MUST be >= 40 chars AND <= 128 chars in length 
    you must not use the sample key/secret in the credentials.ini since they are hard coded to fail.
    

    [PFFAexample01] #<apikey_value>
    secret = abcdefghijklmnopqrstuvwxyz0123456789abcd #<apisecret_value>
    permit = alias_, config_, gateway_, rule_, send_, system_, function_* #authorization
    comment = anything you want can go here. it will be visible in the Faux API in pfSense

You can edit the file using vi in the ssh shell or from the pfSense UI: Diagnostics > Edit File > ‘enter the path /etc/fauxapi/credentials.ini

  1. Set up authorization. This is a really nice feature with Faux API, you can control what the user can actually do and only give permission to that. I was only interested in getting stat information so this is what I used so that my user didn’t have access to do anything but get stats from the router:

    [PFFAexample01]
    secret = abcdefghijklmnopqrstuvwxyz0123456789abcd
    permit = system_stats
    comment = example key PFFAexample01 - hardcoded to be inoperative

  2. GET the JSON formatted information. The Faux API uses a timestamp and a nonce for authorization. Not a simple username and password like most APIs. So you can’t use the JSON Sensor. You’ll have to utilize the provided python library from @ndejong. https://github.com/ndejong/pfsense_fauxapi/blob/master/extras/client-libs/python/fauxapi_lib.py
    Download that file and place it in your /config directory. Then you need a python script to use the library. I used a modified version of this: https://github.com/ndejong/pfsense_fauxapi/blob/master/extras/tests/python-lib-iterate.py

import os, sys, json

sys.path.append(os.path.abspath(os.path.join(os.path.curdir, '../client-libs/python')))     # hack to make this work in-place
from fauxapi_lib import FauxapiLib


# check args exist
if(len(sys.argv) < 4):
    print()
    print('usage: ' + sys.argv[0] + ' <host> <apikey> <apisecret>')
    print()
    print('pipe JSON output through jq for easy pretty print output:-')
    print(' $ ' + sys.argv[0] + ' <host> <apikey> <apisecret> | jq .')
    print()
    sys.exit(1)

# config
fauxapi_host=sys.argv[1]
fauxapi_apikey=sys.argv[2]
fauxapi_apisecret=sys.argv[3]

FauxapiLib = FauxapiLib(fauxapi_host, fauxapi_apikey, fauxapi_apisecret, debug=False)


# system_stats
# =============================================================================
print(json.dumps(
    FauxapiLib.system_stats())
)
open('/config/python_scripts/pfSense_stats.json', 'w').close()  # clear data
with open('/config/pfSense_stats.json', 'a') as stat_file:
    print(json.dumps(
    FauxapiLib.system_stats()), file=stat_file)

As you can see. I got rid of all the calls I wasn’t interested in and just kept the system_stats call. I also am dumping the JSON data into a file in my config directory (another directory could also be used if desired.

  1. Set up sensors in config.yaml.
sensor:
   #this will call the python script and store the cpu temp information in a sensor. the script will export 
   #the rest of the data into a file. we cant dump all of the data into 1 sensor since there is a 255 character 
   #limit for the sensor.
 - platform: command_line
    command: "python3 /config/pffa_get_system_stats.py <_host_> <apikey_value> <apisecret_value>"
    name: pfSense_CPU_temp
    value_template: '{{ value_json["data"]["stats"]["temp"] }}'
    unit_of_measurement : 'C'
    
  - platform: file
    file_path: /config/pfSense_stats.json
    name: pfSense_uptime
    value_template: '{{ value_json["data"]["stats"]["uptime"] }}'
  
  - platform: file
    file_path: /config/pfSense_stats.json
    name: pfSense_mem
    value_template: '{{ value_json["data"]["stats"]["mem"] }}'
    unit_of_measurement : '%'
    
  - platform: file
    file_path: /config/pfSense_stats.json
    name: pfSense_cpu
    value_template: '{{ ( ( ((value_json["data"]["stats"]["cpu"].split("|")[0] | float) / (value_json["data"]["stats"]["cpu"].split("|")[1] | float)) - 1.0 ) * 100.0 ) | round(1) }}'
    unit_of_measurement : '%'

  - platform: file
    file_path: /config/pfSense_stats.json
    name: pfSense_mbufpercent
    value_template: '{{ value_json["data"]["stats"]["mbufpercent"] }}'
    unit_of_measurement : '%'
  • Make sure your quote charaters are correct. Sometimes they copy over wrong.
  • Replace <host> with the internal IP of your pfSense router (ie. 192.168.1.1).
  • Replace <apikey_value> with your api_key (ie PFFArandomalphanumeric902)
  • Replace <apisecret_value> with your api_secret (ie abcdefghijklmnopqrstuvwxyz1234567890abcde)
  1. Add a group with your new sensors. They should update every minute.
pfSense Monitor:
  view: no
  entities:
    - sensor.pfSense_cpu
    - sensor.pfsense_cpu_temp
    - sensor.pfsense_mbufpercent
    - sensor.pfsense_mem
    - sensor.pfsense_uptime

I hope this helps someone. You could also use the other calls to perform actions based on HA events. ie, if HA loses internet, you could reboot the router or pull the gateway status… https://github.com/ndejong/pfsense_fauxapi#api-action-summary


Tracking Devices with PfSense router
FreeNAS Stat Monitor
FreeNAS Stat Monitor
Tracking Devices with PfSense router
#2

Nice work!!


#3

Hey.
I tried to install the package in pfsense but a get a ssl error when I run fetch https://raw.githubusercontent.com/ndejong/pfsense_fauxapi/master/package/pfSense-pkg-FauxAPI-1.3_1.txz in ssh.


#4

Hrm. Just tried mine, did a copy and paste and it downloaded no problem. How are you attempting this? SSH? Or from the web GUI (Diagnostics>Command Prompt)?


#5

Also tried it on another FreeBSD box… worked no problem there too.


#6

Worked like a charm to install and configure the api itself on pfsense. I’m confused on where all the other files come from and are supposed to be places. Configuring sensors is also OK I think, but I get this error:

File "/home/.homeassistant/config/pfstats.py", line 4, in <module>
Jan 27 16:47:11 ProLiant hass[6482]:     from fauxapi_lib import FauxapiLib
Jan 27 16:47:11 ProLiant hass[6482]: ImportError: No module named 'fauxapi_lib'
Jan 27 16:47:11 ProLiant hass[6482]: /homehomeassistant/lib/python3.5/site-packages/urllib3/connectionpool.py:857: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-us
Jan 27 16:47:11 ProLiant hass[6482]:   InsecureRequestWarning)
Jan 27 16:47:11 ProLiant hass[6482]: /home/homeassistant/lib/python3.5/site-packages/urllib3/connectionpool.py:857: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-us
Jan 27 16:47:11 ProLiant hass[6482]:   InsecureRequestWarning)
Jan 27 16:47:11 ProLiant hass[6482]: /home/homeassistant/lib/python3.5/site-packages/urllib3/connectionpool.py:857: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-us
Jan 27 16:47:11 ProLiant hass[6482]:   InsecureRequestWarning)
Jan 27 16:47:11 ProLiant hass[6482]: 2019-01-27 16:47:11 ERROR (Thread-3) [homeassistant.components.sensor.command_line] Command failed: python3 /home/.homeassistant/config/pfstats.py serverIP apikey api_scret_value
lines 1-18/18 (END)

Ofc ip/api/value is another (just for this post).
created /home/homeassistant/config and I’m not really sure if it’s supposed to be like that, also created /home/homeassistant/client-libs/python which I placed fauxapi_lib.py (unchanged file).
pfstats.py:

import os, sys, json

sys.path.append(os.path.abspath(os.path.join(os.path.curdir, '../client-libs/python')))     # hack to make this work in-place
from fauxapi_lib import FauxapiLib


# check args exist
if(len(sys.argv) < 4):
    print()
    print('usage: ' + sys.argv[0] + ' <host> <apikey> <apisecret>')
    print()
    print('pipe JSON output through jq for easy pretty print output:-')
    print(' $ ' + sys.argv[0] + ' <host> <apikey> <apisecret> | jq .')
    print()
    sys.exit(1)

# config
fauxapi_host=sys.argv[1]
fauxapi_apikey=sys.argv[2]
fauxapi_apisecret=sys.argv[3]

FauxapiLib = FauxapiLib(fauxapi_host, fauxapi_apikey, fauxapi_apisecret, debug=False)


# system_stats
# =============================================================================
print(json.dumps(
    FauxapiLib.system_stats())
)
open('/home/.homeassistant/config/pfSense_stats.json', 'w').close()  # clear data
with open('/home/.homeassistant/config/pfSense_stats.json', 'a') as stat_file:
    print(json.dumps(
    FauxapiLib.system_stats()), file=stat_file)

Not sure why it can’t find the library, or where should it be placed, am I going about this wrong?


#7

The insecure requests warning that you are getting is because your using SSL (https) to connect to a url that has an self signed certificate. This is normal and expected. Pfsense by default uses a self-signed certificate for the encrypted connection. You are being warned because your machine isn’t sure that the information passed can be trusted, but since this is your machine you know that you can trust it. I can’t remember doing anything to prevent this warning. Maybe the library takes care of this? I can’t remember.

How are you running HA? In my example, I am using hassio on a raspberry pi. It looks like your running things a bit differently and it looks like your python script is not finding the library file. Are they in the same directory? Maybe there are permission issues on the library file?

What does your HA config entry look like for the sensor?


#8

I worked on that for several days, didn’t get it to work.
It’s running esxi/debian/container. Oh well I tried it; didn’t work.

Cheers!


#9

I could not get the python script to work. I’m using hassio on ubuntu 18.04 on top unraid. What I ended doing was to write a bash script to accomplish the same thing. It can be found here. Thank you for the hard work.