Measure internet loadtime using curl

Hi there!

I wanted to implement an “easy speedtest” to see if internet connection is working. It should be more than just a latency value (could be done with network:pingdevice or network:servicedevice), but less then a real speedtest (really downloading large files). I ended up using curl, which has can output a variety of statistics regarding connect, DNS lookup and total time.

Required Binding: exec

Configuration

things/network.things

Thing exec:command:Remote_Server_curl [command="curl -w {\"time_namelookup\":%%{time_namelookup},\"time_connect\":%%{time_connect},\"time_pretransfer\":%%{time_pretransfer},\"time_starttransfer\":%%{time_starttransfer},\"time_total\":%%{time_total},\"size_download\":%%{size_download}} -o /dev/null --max-time 30 -s https://detectportal.firefox.com/success.txt", interval=60]

If you are using a proxy or want to test different proxies, add a --proxy http://11.22.33.44:8080 parameter using your proxy ipaddress or hostname

items/Network.items

String Remote_Server_curl "Curl output [%s]" {channel="exec:command:Remote_Server_curl:output"}
Number:Time Remote_Server_curl_time_total "Curl time_total [%.6f s]"

rules/curl_to_numbers.rules

rule "Remote_Server_curl to numbers"
    when
        Item Remote_Server_curl changed
    then
        Remote_Server_curl_time_total.postUpdate(Float::parseFloat(transform("JSONPATH", "$.time_total", Remote_Server_curl.state.toString)) as Number)
end

Example shows only items and rule for time_total but can be easily expanded for time_namelookup, time_connect, time_pretransfer, time_starttransfer and size_download which are already provided by example curl call.
Note: Be careful expanding curl call, don’t include whitespace in write-out format string, that will produce weird results. Hint: Quotes didn’t help me…

The time values curl outputs are absolute values in seconds starting at curl call. So if you want to have relative times, you will have to substract previous value.

Further Work

I’d like to have the results parsed without having to use rules engine. I sadly didn’t get that to work - for reference, here are some of my attempts:
items/FailedAttempts.items

String Remote_Server_curl_time_total "Curl time_total [JSONPATH($.time_total):%s]" {channel="exec:command:Remote_Server_curl:output"}
Number:Time Remote_Server_curl_time_total "Curl time_total [JSONPATH($.time_total):%s s]" {channel="exec:command:Remote_Server_curl:output"}
Number:Time Remote_Server_curl_time_total "Curl time_total [JS(curl_time_total.js):%.6f s]" {channel="exec:command:Remote_Server_curl:output"}
Number Remote_Server_curl_time_total "Curl time_total [JS(curl_time_total.js):%.6f s]" {channel="exec:command:Remote_Server_curl:output"}

transform/curl_time_total.js

(function(dataString) {
    var data = JSON.parse(dataString);
    var value = parseFloat(data['time_total'].value);
    return value;
})(input)

I take it that the now built in speed test wasn’t suited to your needs?

Have you see the latest documentation for the Network binding?

No, because I didn’t want to measure the speed/bandwidth (for large files), I wanted to measure the time it takes to set up connection and download a (very small) file.

Yes, I have seen it. What do you want me to tell with that question?

1 Like