Need Help: I want a sensor for the total gigabytes in/out by day/month/year - UPnP sensor measures bytes that keeps rolling over to zero,

I’ve got the UPnP integration set up to connect to my router and give me some network stats, it’s great!
but there’s an issue… an issue that I’ve mentioned in the title of the post… it measures it in bytes. And this means that it very quickly reaches some sort of limit and resets itself to zero

I’ve got a DDWRT router, and the UPnP integration has given me…

  • bytes received
  • btyes sent
  • kB/s received
  • kB/s sent
  • packets received
  • packets sent
  • packets /s received
  • packets /s sent

I want…

  • Gigabytes Sent this day

  • Gigabtyes Sent this month

  • Gigabytes Sent this year

  • Gigabytes Received this day

  • Gigabytes Received this month

  • Gigabytes Received this year

Does anyone know how I can get the end result I want?

Or maybe instead of trying to do something with the UPnP is there a way to get the data straight out of DDWRT?


My router has the information in it, and I know there is some sort of API or some way to get that data out because this app exists and is able to pull that data.

Here’s an idea,

What if I figure out what the max value is (found it, it’s the 32bit integer limit, 4billion-sh), the value that it resets at… then make an automation where anytime the sensor goes down from the previous reading, it increments a counter, and then use that to calculate out the gigabytes… and repeat for all 6 sensors I want.

Maybe you can convert to GB first and then use the statistic sensors.

If you want some values that are going to outlive HA reboots, we’ll need some input_numbers.

I like your idea of rollovers, but…if the router reboots, is the data cleared? Our code will probably assume this was a rollover and incorrectly add 4gb. Maybe it doesn’t reset the values on reboot?

Well, let’s hope not!

We could just store the rollover counter in these inputs. I’d do one for day/month/year tx and rx (so 6 booleans)

# in configuration.yaml
input_number:
  ddwrt_tx_day:
    name: DDWRT tx rollovers day
    min: 0
    max: 5000
  ddwrt_tx_month:
    name: DDWRT tx rollovers month
    min: 0
    max: 5000
  ddwrt_tx_year:
    name: DDWRT tx rollovers year
    min: 0
    max: 5000
  ddwrt_rx_day:
    name: DDWRT rx rollovers day
    min: 0
    max: 5000
  ddwrt_rx_month:
    name: DDWRT rx rollovers month
    min: 0
    max: 5000
  ddwrt_rx_year:
    name: DDWRT rx rollovers year
    min: 0
    max: 5000

Also, create our 6 template sensors

sensor:
  - platform: template
    sensors:
      ddwrt_gb_day:
        friendly_name: "DDWRT GB Per Day"
        # Add current usage to rollover value. Add uint32 max / 1000000 to the value.
        value_template: "{{ state_attr('sensor.ddwrt_bytes_received') | float / 1000000 + (states('input_number.ddwrt_tx_day') | float) * 4.295 }}"
      ddwrt_gb_month:
        friendly_name: "DDWRT GB Per Month"
        # Add current usage to rollover value
        value_template: "{{ state_attr('sensor.ddwrt_bytes_received') | float / 1000000+ (states('input_number.ddwrt_tx_month') | float) * 4.295 }}"
      ddwrt_gb_year:
        friendly_name: "DDWRT GB Per Year"
        # Add current usage to rollover value
        value_template: "{{ state_attr('sensor.ddwrt_bytes_received') | float / 1000000 + (states('input_number.ddwrt_tx_year') | float) * 4.295 }}"
        ...
        # Repeat for Rx sensors

Now just need to handle rollover condition.

- alias: DDWRT Rollover
  trigger:
    platform: state
    entity_id: sensor.ddwrt_gb_day
  condition:
     # The only way for from_state to be less than to_state is if there was a rollover
     # ...OR if it's a new day and the rollover counter reset. 
    - condition: template
      entity_id: input_number.ddwrt_tx_day
      # When this value is reset (set to 0), skip this trigger.
      value_template "{{ not is_state('input_number.ddwrt_tx_day', '0') }}" 
    - condition: template
      # Otherwise, only process if this state decreases in value. 
      value_template: "{{ (trigger.from_state.state | float) < (trigger.to_state.state | float) }}"
  action:
    - service: input_number.set_value
      data_template:
        entity_id: input_number.ddwrt_tx_day
        # Add another rollover to the value
        value: "{{ states('input_number.ddwrt_tx_day') + 1}}"
    - service: input_number.set_value
      data_template:
        entity_id: input_number.ddwrt_tx_month
        # Add another rollover to the value
        value: "{{ states('input_number.ddwrt_tx_month') + 1}}"
    - service: input_number.set_value
      data_template:
        entity_id: input_number.ddwrt_tx_year
        # Add another rollover to the value
        value: "{{ states('input_number.ddwrt_tx_year') + 1}}"

# Clear the daily counter every day.
# Also do one for monthly counter and yearly counter....
- alias: DDWRT Daily Clear
  trigger:
    platform: time
    at: "00:00:00"
  action:
    - service: input_number.set_value
    data:
      entity_id: input_number.ddrwt_tx_day
      value: 0
1 Like

You are an absolute boss. I was waking up this morning about to go the counter route, realized the counters got reset upon reboot and came here to see if any other suggestions were made, and here you are totally solving my problem entirely! You’re amazing!

Keep in mind, there will be syntax errors galore probably! And hopefully as you’re writing it it will spark other ideas.

I thought about just keeping the actual GB in the input_numbers rather than a rollover, but the way I’m using it, it makes no difference.

Good luck!

1 Like

Yeah, I’m struggling at the moment to get things working. I had to adjust from what you gave me a bit, and it’s mosty working, but the roll-over automation isn’t triggering. This is what I’ve got, do you see the issue?




This is everything I’ve got, everything but the automatons seem to be working fine so far.

in my Sensors.yaml

- platform: template
  sensors:
    router_gbtx_day:
      friendly_name: "router Upload GB Per Day"
      # Add current usage to rollover value. Add uint32 max / 1000000 to the value.
      value_template: "{{ (states('sensor.router_bytes_sent') | float / 1000000 + (states('input_number.router_tx_day') | float) * 4.295 ) | round(2)}}"
      entity_id: sensor.router_bytes_sent
      unit_of_measurement: 'GB'
    router_gbtx_month:
      friendly_name: "router UploadGB Per Month"
      # Add current usage to rollover value
      value_template: "{{ (states('sensor.router_bytes_sent') | float / 1000000+ (states('input_number.router_tx_month') | float) * 4.295 ) | round(2)}}"
      entity_id: sensor.router_bytes_sent
      unit_of_measurement: 'GB'
    router_gbtx_year:
      friendly_name: "router UploadGB Per Year"
      # Add current usage to rollover value
      value_template: "{{ (states('sensor.router_bytes_sent') | float / 1000000 + (states('input_number.router_tx_year') | float) * 4.295 ) | round(2)}}"
      entity_id: sensor.router_bytes_sent
      unit_of_measurement: 'GB'
    router_gbrx_day:
      friendly_name: "router DownloadGB Per Day"
      # Add current usage to rollover value. Add uint32 max / 1000000 to the value.
      value_template: "{{ (states('sensor.router_bytes_received') | float / 1000000 + (states('input_number.router_rx_day') | float) * 4.295 ) | round(2)}}"
      entity_id: sensor.router_bytes_received
      unit_of_measurement: 'GB'
    router_gbrx_month:
      friendly_name: "router DownloadGB Per Month"
      # Add current usage to rollover value
      value_template: "{{ (states('sensor.router_bytes_received') | float / 1000000+ (states('input_number.router_rx_month') | float) * 4.295 ) | round(2)}}"
      entity_id: sensor.router_bytes_received
      unit_of_measurement: 'GB'
    router_gbrx_year:
      friendly_name: "router DownloadGB Per Year"
      # Add current usage to rollover value
      value_template: "{{ (states('sensor.router_bytes_received') | float / 1000000 + (states('input_number.router_rx_year') | float) * 4.295 ) | round(2)}}"
      entity_id: sensor.router_bytes_received
      unit_of_measurement: 'GB'

In my input_number.yaml

router_tx_day:
  name: router tx rollovers day
  min: 0
  max: 5000
router_tx_month:
  name: router tx rollovers month
  min: 0
  max: 500000
router_tx_year:
  name: router tx rollovers year
  min: 0
  max: 5000000
router_rx_day:
  name: router rx rollovers day
  min: 0
  max: 5000
router_rx_month:
  name: router rx rollovers month
  min: 0
  max: 500000
router_rx_year:
  name: router rx rollovers year
  min: 0
  max: 5000000

In my automations.yaml

- id: '1581528526781'
  alias: Router Bytes Sent Rollover
  description: ''
  trigger:
  - entity_id: sensor.router_bytes_sent
    platform: state
  condition:
  - condition: template
    value_template: '{{ not is_state(''input_number.router_tx_day'', ''0'') }}"'
  - condition: template
    value_template: '{{ (trigger.from_state.state | float) < (trigger.to_state.state
      | float) }}'
  action:
  - data_template:
      entity_id: input_number.ddwrt_tx_day
      value: '{{ states(''input_number.ddwrt_tx_day'') + 1}}'
    service: input_number.set_value
  - data_template:
      entity_id: input_number.ddwrt_tx_day
      value: '{{ states(''input_number.ddwrt_tx_month'') + 1}}'
    service: input_number.set_value
  - data_template:
      entity_id: input_number.ddwrt_tx_day
      value: '{{ states(''input_number.ddwrt_tx_year'') + 1}}'
    service: input_number.set_value
- id: '1581530992277'
  alias: Router Daily GB Clear
  description: ''
  trigger:
  - at: 00:00:00
    platform: time
  condition: []
  action:
  - entity_id: input_number.router_rx_day
    service: input_number.set_value
  - entity_id: input_number.router_tx_day
    service: input_number.set_value
- id: '1581531132181'
  alias: Router Monthly GB Clear
  description: ''
  trigger:
  - at: 00:00:00
    platform: time
  condition:
  - condition: template
    value_template: '{{ now().day == 1 }}'
  action:
  - entity_id: input_number.router_rx_month
    service: input_number.set_value
  - entity_id: input_number.router_tx_month
    service: input_number.set_value
- id: '1581531556327'
  alias: Router Yearly GB Reset
  description: ''
  trigger:
  - at: 00:00:00
    platform: time
  condition:
  - condition: template
    value_template: '{{ (utcnow().month == 1) + (utcnow().day == 1) == 2 }}'
  action:
  - entity_id: input_number.router_rx_year
    service: input_number.set_value
  - entity_id: input_number.router_tx_year
    service: input_number.set_value

This line has too many quotes.

Also, while using 2 single quotes is valid, I would recommend mixing double and single quotes. My guess is you’re using the gui? It has a strange preference to use those double single quotes…I don’t get it.

Either way, there is a random double quote at the end of that followed by a single quote. Remove the double quote.

ah! Yes, I’m an idiot. I didn’t notice that extra quote snuck in. Fingers crossed that it triggers on roll over this time…

Just open dev tools >> states

Find the sensor.router_bytes_sent

Change the number to something lower manually. It should trigger without you having to do it yourself. No need to change it back, it will update to the correct value on the next upnp poll interval.

You’ll want a way to reset those rollover counters though. Just open the service tab and set them all to 0 if this actually works.

1 Like

I just had my attention directed to this thread, and it’s seemingly a better solution to this problem.

I added sensor as per described here , with my router sensor (i have tplink mr200)
But above entities it said not available

I added sensor as per described here , with my router sensor (i have tplink mr200)
But above entities it said unavailable

Some good looking solutions in this thread.

I just downloaded the app dd wrt companion but cannot log in! I’ve tried root/admin, root/(router maintenance password), admin/(router maintenance password) and lots more besides.
HA found it’s way in to get the data without me doing anything, the device and its entities just suddenly appeared, so it cannot be that hard.
Any advice?

I’ve also just set up the utility meter to gather energy usage weekly and monthly. I’ll see how that goes.

can someone post their final code that works?

Since I keep getting errors and the values: sensor.fritzbox_received_gb_day = unavailable
are always set to unavailable.

after testing, the daily clearing dont work. the daily_gb_clear dont work

i debugging a little bit:

now it work, the “daily_gb_clear”, he set it on “0” at time: “00:00:00”

But i dont know, HA build for all automation two output:
automation.ing_fritzbox_rollover / automation.ing_fritzbox_rollover_2
automation.ing_fritzbox_daily_gb_clear / automation.ing_fritzbox_daily_gb_clear_2

Developer Tools:

[automation.ing_fritzbox_rollover]
ING-Fritzbox Rollover unavailable
restored: true
friendly_name: ING-Fritzbox Rollover
supported_features: 0

[automation.ing_fritzbox_rollover_2]
ING-Fritzbox Rollover on
last_triggered: 2023-02-07T10:46:53.680575+00:00
mode: single
current: 0
id: ing_fritzbox_rollover
friendly_name: ING-Fritzbox Rollover

here the yaml code

automations:

- id: ing_fritzbox_rollover
  alias: ING-Fritzbox Rollover
  description: "ING-Fritzbox Rollover"
  mode: single
  trigger:
    - entity_id: sensor.ing_fritzbox_sent_gb_day
      platform: state
  condition:
    - condition: template
      value_template: '{{ not is_state("input_number.ing_fritzbox_sent_day", 0) }}'
    - condition: template
      value_template: '{{ (trigger.from_state.state | float) < (trigger.to_state.state | float) }}'
  action:
    - service: input_number.set_value
      data_template:
        entity_id: input_number.ing_fritzbox_sent_day
        value: '{{ states("input_number.ing_fritzbox_sent_day") | int + 1}}'
    - service: input_number.set_value
      data_template:
        entity_id: input_number.ing_fritzbox_sent_month
        value: '{{ states("input_number.ing_fritzbox_sent_month") | int + 1 }}'
    - service: input_number.set_value
      data_template:
        entity_id: input_number.ing_fritzbox_sent_year
        value: '{{ states("input_number.ing_fritzbox_sent_year") | int + 1 }}'
    - service: input_number.set_value
      data_template:
        entity_id: input_number.ing_fritzbox_received_day
        value: '{{ states("input_number.ing_fritzbox_received_day") | int + 1}}'
    - service: input_number.set_value
      data_template:
        entity_id: input_number.ing_fritzbox_received_month
        value: '{{ states("input_number.ing_fritzbox_received_month") | int + 1 }}'
    - service: input_number.set_value
      data_template:
        entity_id: input_number.ing_fritzbox_received_year
        value: '{{ states("input_number.ing_fritzbox_received_year") | int + 1 }}'


# Clear ING Fritzbox Data
- id: ing_fritzbox_daily_gb_clear
  alias: ING-Fritzbox Daily GB Clear
  description: "ING-Fritzbox Daily GB Clear"
  mode: single
  trigger:
    - platform: time
      at: "00:00:00"
  action:
    - service: input_number.set_value
      entity_id: input_number.ing_fritzbox_sent_day
      data:
        value: "0"
    - service: input_number.set_value
      entity_id: input_number.ing_fritzbox_received_day
      data:
        value: "0"
    - service: notify.ha_message_group
      data:
        title: Daily GB Clear
        message: ING-Fritzbox Daily GB Clear

- id: ing_fritzbox_monthly_gb_clear
  alias: ING-Fritzbox Monthly GB Clear
  description: "ING-Fritzbox Monthly GB Clear"
  trigger:
    - platform: time
      at: "00:00:00"
  condition:
    - condition: template
      value_template: '{{ now().day == 1 }}'
  action:
    - service: input_number.set_value
      entity_id: input_number.ing_fritzbox_sent_month
      data:
        value: "0"
    - service: input_number.set_value
      entity_id: input_number.ing_fritzbox_received_month
      data:
        value: "0"
    - service: notify.ha_message_group
      data:
        title: Monthly GB Clear
        message: ING-Fritzbox Monthly GB Clear

- id: ing_fritzbox_yearly_gb_clear
  alias: ING-Fritzbox Yearly GB Reset
  description: "ING-Fritzbox Yearly GB Reset"
  trigger:
    - platform: time
      at: "00:00:00"
  condition:
    - condition: template
      value_template: '{{ (utcnow().month == 1) + (utcnow().day == 1) == 2 }}'
  action:
    - service: input_number.set_value
      entity_id: input_number.ing_fritzbox_sent_year
      data:
        value: "0"
    - service: input_number.set_value
      entity_id: input_number.ing_fritzbox_received_year
      data:
        value: "0"
    - service: notify.ha_message_group
      data:
        title: Yearly GB Clear
        message: ING-Fritzbox Yearly GB Clear

input_number:

ing_fritzbox_sent_day:
  name: ING-Fritzbox Upload day
  min: 0
  max: 500000
ing_fritzbox_sent_month:
  name: ING-Fritzbox Upload month
  min: 0
  max: 500000
ing_fritzbox_sent_year:
  name: ING-Fritzbox Upload year
  min: 0
  max: 5000000
ing_fritzbox_received_day:
  name: ING-Fritzbox Download day
  min: 0
  max: 500000
ing_fritzbox_received_month:
  name: ING-Fritzbox Download month
  min: 0
  max: 500000
ing_fritzbox_received_year:
  name: ING-Fritzbox Download year
  min: 0
  max: 5000000

sensor:

- platform: template
  sensors:
    ing_fritzbox_sent_gb_day:
      friendly_name: "ING-Fritzbox Upload GB Per Day"
      # Add current usage to rollover value. Add uint32 max / 1000000 to the value.
      value_template: "{{ (states('sensor.ing_fritzbox_kb_s_sent') | float / 1000000 + (states('input_number.ing_fritzbox_sent_day') | float) * 4.295 ) | round(2) | default('unknown')}}"
      unit_of_measurement: 'GB'
    ing_fritzbox_sent_gb_month:
      friendly_name: "ING-Fritzbox Upload GB Per Month"
      # Add current usage to rollover value
      value_template: "{{ (states('sensor.ing_fritzbox_kb_s_sent') | float / 1000000 + (states('input_number.ing_fritzbox_sent_month') | float) * 4.295 ) | round(2) | default('unknown')}}"
      unit_of_measurement: 'GB'
    ing_fritzbox_sent_gb_year:
      friendly_name: "ING-Fritzbox Upload GB Per Year"
      # Add current usage to rollover value
      value_template: "{{ (states('sensor.ing_fritzbox_kb_s_sent') | float / 1000000 + (states('input_number.ing_fritzbox_sent_year') | float) * 4.295 ) | round(2) | default('unknown')}}"
      unit_of_measurement: 'GB'
    ing_fritzbox_received_gb_day:
      friendly_name: "ING-Fritzbox Download GB Per Day"
      # Add current usage to rollover value. Add uint32 max / 1000000 to the value.
      value_template: "{{ (states('sensor.ing_fritzbox_kb_s_received') | float / 1000000 + (states('input_number.ing_fritzbox_received_day') | float) * 4.295 ) | round(2) | default('unknown')}}"
      unit_of_measurement: 'GB'
    ing_fritzbox_received_gb_month:
      friendly_name: "ING-Fritzbox Download GB Per Month"
      # Add current usage to rollover value
      value_template: "{{ (states('sensor.ing_fritzbox_kb_s_received') | float / 1000000 + (states('input_number.ing_fritzbox_received_month') | float) * 4.295 ) | round(2) | default('unknown')}}"
      unit_of_measurement: 'GB'
    ing_fritzbox_received_gb_year:
      friendly_name: "ING-Fritzbox Download GB Per Year"
      # Add current usage to rollover value
      value_template: "{{ (states('sensor.ing_fritzbox_kb_s_received') | float / 1000000 + (states('input_number.ing_fritzbox_received_year') | float) * 4.295 ) | round(2) | default('unknown')}}"
      unit_of_measurement: 'GB'

Template Output:

          # Network Transfer per Day for 7 Days
          - type: 'custom:button-card'
            template: card_graph
            entity: sensor.ing_fritzbox_received_gb_day
            variables:
              ulm_card_graph_color: "var(--google-blue)"
              ulm_card_graph_name: Tagestransfer
              ulm_card_graph_entity: sensor.ing_fritzbox_received_gb_day
              ulm_card_graph_color2: "var(--google-green)"
              ulm_card_graph_entity2: sensor.ing_fritzbox_sent_gb_day
              ulm_card_graph_hours: 168
              ulm_card_graph_type: fill
              ulm_card_graph_points: 0.04166666666
              ulm_card_graph_group_by: date