So I was sent here by Google through forte’s original post, and it’s helped me figure out exactly how to set this up. Wanted to post up here with my entire process cuz I think it could help the next guy (or girl) understand why a lot of this works the way it does, and how to make it all work out well.
So, starting from the beginning, we have the following outputs from your DDWRT or UPnP router:
sensor.[router]_b_received
sensor.[router]_b_sent
sensor.[router]_kib_s_received
sensor.[router]_kib_s_sent
(note that [router]
will be variable depending on what you have, and I’m also ignoring the outputs for packets)
The important things here are that sensor.[router]_b_received
and sensor.[router]_b_sent
are measured in “B” for “Bytes”, and sensor.[router]_kib_s_received
and sensor.[router]_kib_s_sent
are measured in “KiB”, meaning kibibytes. Not kilobytes. Kibibytes are based on powers of two, kilobytes on powers of ten. This is key.
So, the issue here is that we want to calculate total data received and sent, but both b_received
and sent
reset when they go above around 4,000,000,000. We also want the measurement in something more sensible then bytes.
Now, considering that the router is outputting the speed in KiB, I decided the obvious choice for total data is GiB, or Gibibytes, because computers. One GiB is equal to 10243 bytes. Therefore, we simply divide the output from b_received
and sent
by 10243, or 1073741824. I also rounded to three decimal places, because I wanted to:
sensor:
- platform: template
sensors:
gib_received:
friendly_name: "GiB Received"
value_template: "{{ ((float(states('sensor.[router]_b_received')) / 1073741824) | round(3)) }}"
unit_of_measurement: "GiB"
gib_sent:
friendly_name: "GiB Sent"
value_template: "{{ ((float(states('sensor.[router]_b_sent')) / 1073741824) | round(3)) }}"
unit_of_measurement: "GiB"
This actually caused an interesting discovery for me: both _b_received
and sent
don’t reset at some random point above 4,000,000,000; they actually reset at near
4,294,967,296, which is 4 GiB. It’s likely that it actually resets at 4,294,967,295, one byte below 4 GiB, because that would be hex FFFF FFFF
, a sensible place to cut off. The rollover to hex 1 0000 0000
is why it keeps resetting. The more you knowwwww~
Now, if you wanted to convert it to gigabytes instead of gibibytes, simply change “1073741824” above to “1000000000”. Then you’ll have your boring power of 10 gigabytes.
So, now that it’s in a sensible measurement, we throw it into the above mentioned utility meter integration:
utility_meter:
gib_sent_per_period:
source: sensor.gib_sent
name: GiB Sent / Month
cycle: monthly
gib_received_per_period:
source: sensor.gib_received
name: GiB Received / Month
cycle: monthly
And that should work perfectly; it does for me! Change “monthly” to whatever you want, based on the integration documentation.
The other question here is how to convert from your router output to a different speed metric. In my case, my router outputs sensor.[router]_kib_s_received
and sensor.[router]_kib_s_sent
. Again, these are kibibytes, not kilobytes. That said, at the very top of this post, Rdoull says they have router_kbyte_sec_received
/ sent
; I’m assuming that kbyte_sec
means that Rdoull’s metrics are indeed in kilobytes and not kibibytes, so what I’m saying below mostly doesn’t apply. To answer their question directly, converting from KB/s to MB/s is easy; divide by 1000 and you’re done.
The worst thing you can do is confuse a KiB for a KB or vice versa. They are different metrics, and are often mistaken. To convert accurately from kibibytes to megabytes, you first multiply by 1024 to get the amount in bytes, then divide by 1,000,000 to get megabytes.
For me, I want the speed in megabits per second (Mbps), since that is what most internet speeds are quoted in. One megabit is one million bits, not bytes; 1 byte is 8 bits. Therefore, to convert from kibibytes to megabits accurately, we want to multiply by 8192 to get the number of bits, and then divide by 1,000,000 to get megabits:
sensor:
- platform: template
sensors:
mbps_received:
friendly_name: "Mbps Received"
value_template: "{{ (((float(states('sensor.[router]_kib_s_received')) * 8192) / 1000000) | round(3)) }}"
unit_of_measurement: "Mbps"
mbps_sent:
friendly_name: "Mbps Sent"
value_template: "{{ (((float(states('sensor.[router]_kib_s_sent')) * 8192) / 1000000) | round(3)) }}"
unit_of_measurement: "Mbps"
Again, I decided to round to 3 decimal places. To convert to a different metric, keep in mind what your router is outputting, then convert it based on that. To get megabytes/sec from KiB/s, as mentioned, multiply by 1024 then divide by 1,000,000.
And yes, to be clear, there are other ways to convert the numbers using built in functions, but those ways don’t explain the full reason why you’re doing it; they just do it. My way does the conversion manually for explanation’s sake, but also works fine as a final answer.
Aaaand that’s that. Hopefully this helps the next person who comes along and finds these threads.