pfSense stat monitor

Hi, the link for fauxapi_lib.py is no longer valid. Could you provide a new link?.. thanks

One question. We have to put the fauxapi_lib.py and python-lib-iterate.py in Hassio config folder (where the configuration.yaml resides), right?

Thank you.

Hi @bthoven, it looks like the python library has been moved over to a separate github project: https://github.com/ndejong/pfsense_fauxapi_client_python

It also looks like @ndejong has updated the FauxAPI since I posted this. I should probably make sure that my implementation works with the new version before updating my post. Please feel free to be the guinea pig :wink: and test it.

As far as where you put your python files… it doesn’t matter where you put them, but you should make sure that the script that you call from the command line sensor is in the same directory as the library file. I put them all in my python_scripts directory, for my own organization… but that might not be the best place, because HA will discover them and make them available from the python script service… even though they will fail out if you try to run them (the python script service doesn’t allow you to import the required libraries). Maybe you want to put them in /config/pffa_scripts or something like that. Just make sure you account for the sub-directory in your command line sensors.

Thanks. Let me try. It’s quite difficult for me if no detailed walkthrough step by step; but well worth trying.

I’m also interested in this, but I can’t find those two lib files on the provided link. Are they named differently, perhaps?

Follow the link above, it’s been moved to it’s own repository.

Ok, you’re now the second person to ask for help. I guess this means I should stop being lazy and setup and test the new version and then update my original post. :grin:

1 Like

The post has been updated. Looks like he just changed the name of the class and moved the files over to a new repository.

Just come back to try installing this again. I put all following files in ‘/usr/share/hassio/homeassistant/custom_components/pfSense’ folder:

I tried running the python directly by command line and got the import error (either using sudo or not, get the same error)
image

I’m not sure why it got import error. Need your help…thanks.

OK. I managed to get it working. Here are what the instruction may have to be amended on the HASSIO installation side (step 4 in OP onwards):
0. There are 3 files that we need to put into our Homeassistant folder (for me, I put them into /usr/share/hassio/homeassistant/custom_components/pfSense):
PfsenseFauxapi.py, pffa_get_system_stats.py (can be any name), and "_version_.py"

  1. All the three .py files must be in a same directory

  2. Inside the PfsenseFauxapi.py, line no. 24, we have to delete the ‘.’ (dot) from the "from .__version__ import __version__", to read as "from __version__ import __version__"; otherwise, it will report error

  3. Inside the pffa_get_system_stats.py, I need to change every ‘Fauxapi’ to be ‘PfsenseFauxapi’; otherwise, it will report ImportError: cannot import name ‘Fauxapi’. I don’t know why, but changing it makes it work.

  4. The sample configuration.yaml above needs to insert “Platform: file” and “file_path” after the command-line (see my config below).

Here is the result from direct run by command line: python3 pffa_get_system_stats 192.xxx.x.x api-key secrekey
image

Last warning, the api-key length must be between 12 and 40 characters (alphanumeric) and the secret-key length must be between 41 and 128 characters. We can define them ourselves. I made it too short and it didn’t work until I make the secret-key long enough.

Next steps are to add its sensors in my HASSIO configuration.yaml and display as a group.
Here is the result:
image
As I put all fauxapi files in “/usr/share/hassio/homeassistant/custom_components/pfSense” folder, I have to define like these in my configuration.yaml

......
.....
  whitelist_external_dirs:
    - /config/custom_components/pfSense
    - /config
....
....
sensor:
....
....
#-- pfSense -----
  #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 custom_components/pfSense/pffa_get_system_stats.py 192.168.x.x ...your fauxapi api-key....  ...your fauxapi-secrit-key..."
  - platform: file    
    file_path: pfSense_stats.json
    name: pfSense_CPU_temp
    value_template: '{{ value_json["data"]["stats"]["temp"] }}'
    unit_of_measurement : '°C'
    
  - platform: file
    file_path: pfSense_stats.json
    name: pfSense_uptime
    value_template: '{{ value_json["data"]["stats"]["uptime"] }}'
  
  - platform: file
    file_path: pfSense_stats.json
    name: pfSense_mem
    value_template: '{{ value_json["data"]["stats"]["mem"] }}'
    unit_of_measurement : '%'
    
  - platform: file
    file_path: 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: pfSense_stats.json
    name: pfSense_mbufpercent
    value_template: '{{ value_json["data"]["stats"]["mbufpercent"] }}'
    unit_of_measurement : '%'
....
.....

In the groups.yaml

....
....
pfSense Monitor:
  control: hidden
  entities:
    - sensor.pfsense_cpu
    - sensor.pfsense_cpu_temp
    - sensor.pfsense_mbufpercent
    - sensor.pfsense_mem
    - sensor.pfsense_uptime
...
...

working pffa_get_system_stats.py, amended as described above:

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 PfsenseFauxapi import PfsenseFauxapi


# 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]

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


# system_stats
# =============================================================================
print(json.dumps(
    PfsenseFauxapi.system_stats())
)
open('pfSense_stats.json', 'w').close()  # clear data
with open('pfSense_stats.json', 'a') as stat_file:
    print(json.dumps(
    PfsenseFauxapi.system_stats()), file=stat_file)
1 Like

Could you help me with the command_line sensor? I have done everything on PfSense side and the python script (pffa_get_system_stats.py) works when tested on Windows Python but Hass.io says only “Command failed: python3 custom_components/pfSense/pff_get_system_stats.py <api_secret>”.

Any ideas what could be wrong? The pffa_get_system_stats.py is copied from your (bthoven) message. I have hass.io installed on raspberry pi 3 and I am on the newest HA version. Also tried to change the path of the script to “config/custom_components/pfSense/pff_get_system_stats.py”

Edit: There is typo in bthoven’s code, pffa_get_system_stats.py is missing letter ‘a’ in its name but this does not change the fact that I still do not get it working.

Edit2: Got it working with @gremblin first messages command_line method. So I put the .py files to python_scripts folder and call it there. Thanks gremblin for this guide!

1 Like

Just one more question. I got all the data in hass now. But I try to parse gateway_status to sensor but I’m not getting it. Could anyone help with that?

Basically the json in like this
data: gateway_status: ipv4 address: delay

Compared to the system_stats json that is in this thread
data: stats: temp

so there is one extra step. The system_stats is parsed like this:
value_template: ‘{{ value_json[“data”][“stats”][“temp”] }}’

But I’m not getting any value from gateway_status with this
value_template: ‘{{ value_json[“data”][“gateway_status”][“ipv4 address”][“delay”] }}’

The ipv4 address is my ip. And there is also ipv6 address in the json, thats why there is one extra layer compared to the system_stats.

Edit: Got it working again, the problem was that the data was in the same file so I just added another json file where to save the data from pfsense and now the parsing works like this:
value_template: ‘{{ value_json[“data”][“gateway_status”][“ipv4 address”][“delay”] }}’
Any ideas how to get the value with value_template?

Sorry for the flood!

1 Like

I was just about to reply to ask for more info, and the page refreshed with your update. :+1: glad you got it working.

1 Like

Just notice that the cpu temperature is updated at much higher frequency (in seconds) than the cpu load and memory usage (in several hours, when checking from HA ui). It is strange because all these values are derived from the same json file. Do you know why?

Hi,

How are your values for cpu usage compared to what top or vmstat report?

When running top command (on v2.4.4) it takes about 2 seconds to populate the cpu row (all the other rows are populated instantly).

This is a bit off topic, but I figured a few of you might be interested in this. Here is how to setup a bandwidth SNMP polling for your pfSence WAN interface. This will give you the following entities for your viewing pleasure:

image

You will need to enable SNMP read access on your firewall, I used the community string of “public”. Be sure to change the host IP below to your pfSense internal interface.

sensor:
  - platform: snmp
    name: 'pfsense WAN in'
    host: 10.1.1.1
    baseoid: 1.3.6.1.2.1.31.1.1.1.6.2
    community: 'public'
    version: '2c'
    scan_interval: 60

  - platform: snmp
    name: 'pfsense WAN out'
    host: 10.1.1.1
    baseoid: 1.3.6.1.2.1.31.1.1.1.10.2
    community: 'public'
    version: '2c'
    scan_interval: 60

  - platform: statistics
    name: 'pfsense WAN in Stats'
    entity_id: sensor.pfsense_wan_in
    sampling_size: 4
    max_age:
      hours: 24

  - platform: statistics
    name: 'pfsense WAN out Stats'
    entity_id: sensor.pfsense_wan_out
    sampling_size: 4
    max_age:
      hours: 24

  - platform: template
    sensors:
      internet_in_mbps:
        icon_template: mdi:cloud-download-outline
        value_template: "{{ (state_attr('sensor.pfsense_wan_in_stats','change_rate')|float*8*(state_attr('sensor.pfsense_wan_in_stats', 'sampling_size')-1)/1000000)|round(2) }}"
        unit_of_measurement: 'Mbps'
        entity_id: sensor.pfsense_wan_in_stats
      internet_out_mbps:
        icon_template: mdi:cloud-upload-outline
        value_template: "{{ (state_attr('sensor.pfsense_wan_out_stats','change_rate')|float*8*(state_attr('sensor.pfsense_wan_out_stats', 'sampling_size')-1)/1000000)|round(2) }}"
        unit_of_measurement: 'Mbps'
        entity_id: sensor.pfsense_wan_out_stats
8 Likes

I think we should keep on topic or post links to complete and/or improved alternatives (Faux API includes significantly more sensors than the bandwidth).

Did you figure out how to parse the ip4 address? I was looking at this and could only get it to work by hard coding the IP, which I would rather not do.

No, I just hard coded it in since that IP is not changing since it is the monitor IP of PFSense.

Hi I see this topic is a few months old but I’m having the same problem mentioned above; I have Home Assistant (not Hass.io) running in a docker container; when I run the python instruction in the command line I get the following error:

Traceback (most recent call last):
  File "custom_components/pfSense/pffa_get_system_stats.py", line 3, in <module>
    from PfsenseFauxapi import PfsenseFauxapi
  File "/config/home-assistant/custom_components/pfSense/PfsenseFauxapi.py", line 24, in <module>
    from __version__ import __version__
  File "/config/home-assistant/custom_components/pfSense/__version__.py", line 1
    <!DOCTYPE html>
    ^
SyntaxError: invalid syntax

I tried the solution @bthoven sugested but no changes. Any clue or suggestion?

I dont think you really need the version. It doesn’t look like it’s being used for any logic. Try deleting that import and just hard code it. You could just hard code it to what’s in that file. Something like:

__version__ = '20190317.1'

You can just delete that line and replace it with the above.

I modify it a now is not generating any error when executing from command line, but when I press CTRL+C I get the following:

Traceback (most recent call last):
  File "custom_components/pfSense/pffa_get_system_stats.py", line 27, in <module>
    PfsenseFauxapi.system_stats())
  File "/config/home-assistant/custom_components/pfSense/PfsenseFauxapi.py", line 91, in system_stats
    return self._api_request('GET', 'system_stats')
  File "/config/home-assistant/custom_components/pfSense/PfsenseFauxapi.py", line 125, in _api_request
    verify=self.use_verified_https
  File "/home/chapter/.local/lib/python3.6/site-packages/requests/api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "/home/chapter/.local/lib/python3.6/site-packages/requests/api.py", line 60, in request
    return session.request(method=method, url=url, **kwargs)
  File "/home/chapter/.local/lib/python3.6/site-packages/requests/sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File "/home/chapter/.local/lib/python3.6/site-packages/requests/sessions.py", line 646, in send
    r = adapter.send(request, **kwargs)
  File "/home/chapter/.local/lib/python3.6/site-packages/requests/adapters.py", line 449, in send
    timeout=timeout
  File "/home/chapter/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 672, in urlopen
    chunked=chunked,
  File "/home/chapter/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 376, in _make_request
    self._validate_conn(conn)
  File "/home/chapter/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 994, in _validate_conn
    conn.connect()
  File "/home/chapter/.local/lib/python3.6/site-packages/urllib3/connection.py", line 334, in connect
    conn = self._new_conn()
  File "/home/chapter/.local/lib/python3.6/site-packages/urllib3/connection.py", line 157, in _new_conn
    (self._dns_host, self.port), self.timeout, **extra_kw
  File "/home/chapter/.local/lib/python3.6/site-packages/urllib3/util/connection.py", line 74, in create_connection
    sock.connect(sa)
KeyboardInterrupt