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)