I’ve built a bandwidth monitor based on this and this post. It almost works. I have read through this post and other related ones to see if I’ve missed something but to no avail.
My goal is to see instantaneous usage but especially daily and monthly totals. The former works, but the latter two seems to be off. I’m using a utility meter for that.
Here is my config (as a minimal example – my full config can be seen here):
input_number:
wan_traffic_delta_in:
min: 0
max: 4294967295
wan_traffic_delta_out:
min: 0
max: 4294967295
utility_meter:
daily_internet_usage_in:
source: sensor.internet_usage_in
cycle: daily
daily_internet_usage_out:
source: sensor.internet_usage_out
cycle: daily
monthly_internet_usage_in:
source: sensor.internet_usage_in
cycle: monthly
monthly_internet_usage_out:
source: sensor.internet_usage_out
cycle: monthly
automation:
- alias: "Monitor Inbound Internet Traffic"
trigger:
platform: state
entity_id: sensor.snmp_wan_in
action:
- service: input_number.set_value
data_template:
entity_id: input_number.wan_traffic_delta_in
value: '{{ ((trigger.to_state.state | int - trigger.from_state.state | int) * 8 ) / ( as_timestamp(trigger.to_state.last_updated) - as_timestamp(trigger.from_state.last_updated) ) }}'
- alias: "Monitor Outbound Internet Traffic"
trigger:
platform: state
entity_id: sensor.snmp_wan_out
action:
- service: input_number.set_value
data_template:
entity_id: input_number.wan_traffic_delta_out
value: '{{ ((trigger.to_state.state | int - trigger.from_state.state | int) * 8 ) / ( as_timestamp(trigger.to_state.last_updated) - as_timestamp(trigger.from_state.last_updated) ) }}'
sensor:
- platform: snmp
name: snmp_wan_in
host: 192.168.0.1
community: Router
version: 2c
baseoid: 1.3.6.1.2.1.2.2.1.10.18 # ifInOctets.14
unit_of_measurement: octets
- platform: snmp
name: snmp_wan_out
host: 192.168.0.1
community: Router
version: 2c
baseoid: 1.3.6.1.2.1.2.2.1.16.18 # ifOutOctets.14
unit_of_measurement: octets
- platform: statistics
name: 'Internet Traffic In'
entity_id: sensor.internet_speed_in
- platform: statistics
name: 'Internet Traffic Out'
entity_id: sensor.internet_speed_out
- platform: template
sensors:
internet_speed_in:
value_template: '{{ ((states.input_number.wan_traffic_delta_in.state | float ) / 1000000 ) | round(3) }}'
unit_of_measurement: 'Mbps'
internet_speed_out:
value_template: '{{ ((states.input_number.wan_traffic_delta_out.state | float ) / 1000000 ) | round(3) }}'
unit_of_measurement: 'Mbps'
internet_usage_in:
value_template: '{{ ((states.input_number.wan_traffic_delta_in.state | float ) / 1000000000 / 8 ) | round(3) }}'
unit_of_measurement: 'GB'
internet_usage_out:
value_template: '{{ ((states.input_number.wan_traffic_delta_out.state | float ) / 1000000000 / 8 ) | round(3) }}'
unit_of_measurement: 'GB'
In my ui-lovelace.yaml
I have:
- type: history-graph
entities:
- entity: sensor.internet_speed_in
- entity: sensor.internet_speed_out
hours_to_show: 24
refresh_interval: 60
- type: glance
title: Today
show_name: false
columns: 2
entities:
- entity: sensor.daily_internet_usage_in
name: Today
- entity: sensor.daily_internet_usage_out
name: Today
- type: glance
title: This Month
show_name: false
columns: 2
entities:
- entity: sensor.monthly_internet_usage_in
name: This Month
- entity: sensor.monthly_internet_usage_out
name: This Month
What I see:
What my ISP says:
I’m pretty confident (as can be seen from my history graph of the instantaneous usage) that that part is working correctly (it’s a 10Mbps line (downlink) and a 5Mbps uplink).
I’m not sure whether it will be sensible to start fiddling with sampling sizes and scan intervals.
Am I misunderstanding how a utility meter could be used for this or do I have an error in my calculations or config?
EDIT: Is the problem perhaps that I shouldn’t be feeding deltas to a utility meter?
UPDATE (2022-02-20): I’ve been lazy about this error for a long time, but counters like these wrap around and then will cause errors using a naive implementation. I’ve at last fixed this issue. Herewith the updated automations:
- alias: "Monitor Inbound Internet Traffic"
trigger:
platform: state
entity_id: sensor.snmp_wan_in
action:
- service: input_number.set_value
data:
entity_id: input_number.wan_traffic_delta_in
value: >-
{# safe delta catering for wrap-around of a 32-bit int (snmp counter is 32-bit unsigned int) #}
{# basically taking 2's complement #}
{% set from = trigger.from_state.state | int %}
{% set to = trigger.to_state.state | int %}
{% set traffic_delta = (to - from) if (to >= from) else (4294967295 - from + to + 1) %}
{% set time_delta = as_timestamp(trigger.to_state.last_updated) - as_timestamp(trigger.from_state.last_updated) %}
{{ (traffic_delta * 8) / time_delta }}
- alias: "Monitor Outbound Internet Traffic"
trigger:
platform: state
entity_id: sensor.snmp_wan_out
action:
- service: input_number.set_value
data:
entity_id: input_number.wan_traffic_delta_out
value: >-
{# safe delta catering for wrap-around of a 32-bit int (snmp counter is 32-bit unsigned int) #}
{# basically taking 2's complement #}
{% set from = trigger.from_state.state | int %}
{% set to = trigger.to_state.state | int %}
{% set traffic_delta = (to - from) if (to >= from) else (4294967295 - from + to + 1) %}
{% set time_delta = as_timestamp(trigger.to_state.last_updated) - as_timestamp(trigger.from_state.last_updated) %}
{{ (traffic_delta * 8) / time_delta }}