SNMP Bandwidth Monitor

More big image :slight_smile:

I think you missed the last digit for snmp_wan_in, also make sure that 2 is actually the proper interface for your WAN port. You can check what interfaces map to which numbers by doing snmpwalk to 1.3.6.1.2.1.2.2.1.2, though it changes occasionally in my experience, also on my old router it said something like vlan2 for the WAN interface so just be aware it might be something like that.

Other than that, some of the object names have changed since the original post. input_slider should be changed to input_number for example. I can’t remember off the top of my head if anything else needed to be changed, but your log should probably let you know if you put anything in there it can’t deal with.

Hi. Can you paste your full config of bandwidth monitor? I can’t get it working with current HA version.

Hey there,

Thanks to this thread, I have had a functional bandwidth monitor based on SNMP metrics for a while. This week, I wanted to add a utility meter-like sensor, so I could monitor my usage, and make sure I didn’t go over my monthly quota.

While reading around, I realised that HA now supports templated sensors (see Template - Home Assistant), which means the input_number and automation helpers are no longer needed.

Here is my updated, simplified, config.

sensor:
  # Based on https://community.home-assistant.io/t/snmp-bandwidth-monitor/7122; This hasn't changed
  # Get raw SNMP readings
  - platform: snmp
    name: snmp_wan_in
    host: 192.2.0.1
    baseoid: 1.3.6.1.2.1.2.2.1.10.20  # the second last integer should match your WAN interface
  - platform: snmp
    name: snmp_wan_out
    host: 192.2.0.1
    baseoid: 1.3.6.1.2.1.2.2.1.16.20  # the second last integer should match your WAN interface

  # Calculate the mean from templated speed sensors below
  - platform: statistics
    unique_id: internet_speed_down_mean
    name: 'Internet Speed Down (mean)'
    entity_id: sensor.internet_speed_down
    state_characteristic: mean
    sampling_size: 20
  - platform: statistics
    unique_id: internet_speed_up_mean
    name: 'Internet Speed Up (mean)'
    entity_id: sensor.internet_speed_up
    state_characteristic: mean
    sampling_size: 20

template:
  # Templated internet_speed_down and internet_speed_up sensor, that update automatically when the snmp sensors do
  - trigger:
    - platform: state
      entity_id: sensor.snmp_wan_in
    sensor:
    - unique_id: internet_speed_down
      name: 'Internet Speed Down'
      state: >
        {{ (
          ( (trigger.to_state.state | int - trigger.from_state.state | int) * 8 / 1000000 )
          / ( as_timestamp(trigger.to_state.last_updated) - as_timestamp(trigger.from_state.last_updated))
          ) | round(2)
        }}
      state_class: measurement
      device_class: data_rate
      unit_of_measurement: 'Mbit/s'
      icon: mdi:download
  - trigger:
    - platform: state
      entity_id: sensor.snmp_wan_out
    sensor:
    - unique_id: internet_speed_up
      name: 'Internet Speed Up'
      state: >
        {{ (
          ( (trigger.to_state.state | int - trigger.from_state.state | int) * 8 / 1000000 )
          / ( as_timestamp(trigger.to_state.last_updated) - as_timestamp(trigger.from_state.last_updated))
          ) | round(2)
        }}
      state_class: measurement
      device_class: data_rate
      unit_of_measurement: 'Mbit/s'
      icon: mdi:upload

Based on the SNMP sensor, I also created an total_increasing counter of the sum of up and down traffic, as well as a monthly-resetting (on the 23rd) utility meter.

template:
  [...]
  - sensor:
    - unique_id: internet_total_usage
      name: 'Internet Total Usage'
      state: >
        {{ (
          (states("sensor.snmp_wan_in")|int + states("sensor.snmp_wan_out")|int)
          / (1024*1024)
          ) | round(2)
        }}
      state_class: total_increasing
      device_class: data_size
      unit_of_measurement: 'MiB'
      icon: mdi:chart-bell-curve-cumulative

utility_meter:
  internet_usage:
    unique_id: internet_usage
    name: "Internet Usage"
    source: sensor.internet_total_usage
    cycle: monthly
    offset:
      days: 22  # offset from day 1
    periodically_resetting: true

For ease of update of the monthly quota, I added a couple of input_number to set the quota and the reset date (unfortunately, I haven’t found a way to reuse it in the utility_meter)

input_number:
  internet_quota:
    name: "Internet Quota"
    initial: 500000
    min: 0
    max: inf
    icon: mdi:chart-multiline
    mode: box
    unit_of_measurement: MiB
  internet_quota_rollover_day:
    name: "Internet Quota Rollover Day"
    initial: 23
    min: 1
    max: 31
    icon: mdi:calendar-refresh
    mode: box

This allowed me to calculate an ideal usage given the date, i.e., if my current usage is above the ideal usage, I’m at risk of exceeding the quota before the end of the month. A binary_sensor just does that comparison; if it’s on, I’m in trouble.

template:
  [...]
    - unique_id: internet_ideal_usage
      name: 'Internet Ideal Usage'
      state: >
        {% set day = now().date().day %}
        {% set month = now().month %}

        {% set rollover = states("input_number.internet_quota_rollover_day")|int %}

        {% if day >= rollover %}
          {% set start = now().date().replace(day=rollover) %}
          {% set next_month = start.replace(day=28) + timedelta(days=4) %}
          {% set end = next_month.replace(day=rollover) %}

        {% else %}
          {% set end = now().date().replace(day=rollover) %}
          {% set last_month = end.replace(day=1) - timedelta(days=1) %}
          {% set start = last_month.replace(day=rollover) %}

        {% endif %}

        {% set full_period = (as_timestamp(end) - as_timestamp(start))|int %}
        {% set current_period = (as_timestamp(now()) - as_timestamp(start))|int %}
  
        {% set quota = states("input_number.internet_quota")|int %}

        {% set ideal = ((quota*current_period)/full_period)|float %}

        {{ ideal }}
      state_class: total_increasing
      device_class: data_size
      unit_of_measurement: 'MiB'
      icon: mdi:chart-bell-curve-cumulative
  - binary_sensor:
    - unique_id: internet_usage_warning
      name: 'Internet Usage Warning'
      state: '{{ (states("sensor.internet_usage")|int) > (states("sensor.internet_ideal_usage")|int) }}'
      icon: >
        {% if is_state('binary_sensor.internet_usage_warning', 'on') %}
        mdi:alert
        {% else %}
        mdi:check-circle-outline
        {% endif %}

And to tie it neatly, I added an automatic (daily) notification in case the warning is triggered.

automation:
  - alias: "Notification: Internet usage"
    description: ""
    trigger:
      - platform: state
        entity_id:
          - binary_sensor.internet_usage_warning
        for:
          hours: 1
        from: "off"
        to: "on"
    condition:
      - >-
        {{ now() - (state_attr(this.entity_id, 'last_triggered') or
        datetime.datetime(1, 1, 1, 0, 0) ) > timedelta(hours=12) }}
    action:
      - service: notify.persistent_notification
        data:
          title: Internet usage over quota
          message: >
            {{state_attr('sensor.internet_usage', 'friendly_name')}}
            ({{states('sensor.internet_usage')|round(2)}} MiB) is higher than ideal
            ({{states('sensor.internet_ideal_usage')|round(2)}} MiB)

            Turn things off!
    mode: single
1 Like