Speedtest CLI by Ookla - Internet Up-/Downlink Measurement Integration

I´m also running an rpi4 with openhabian.
Strange, as i said. I only had to accept the license and gdpr once.

Ok guys, I understand now what is the issue.
If you start speedtest without selecting a server it grab any server from server list (type speedtest -L to get the list).
In my situation it took a server that is not compatible with the requests send by speedtest app.
[15:36:55] openhabian@openhab:~$ speedtest -L
Closest servers:

ID  Name                           Location             Country
==============================================================================
 14156  STARFACE GmbH                  Karlsruhe            Germany
 18613  TelemaxX Telekommunikation GmbH Karlsruhe            Germany
  5829  Bratschnitzel.de               Karlsruhe            Germany
 27612  Rabe.Systems                   Karlsruhe            Germany
 10709  bc-networks                    Ludwigsburg          Germany
 17811  bc-networks                    Remseck              Germany
 25863  NOREST-TELECOM                 Hatten               France
 16633  Stadtwerke Schorndorf GmbH     Schorndorf           Germany
 10291  TWL-KOM                        Ludwigshafen         Germany
 28818  Pfalzkom GMBH                  Ludwigshafen         Germany

So I selected special server from speedtest -L and now perform:
speedtest --accept-license --accept-gdpr -s 18613 -f json and get correct result without any log messages in between.

As Michael mentioned add --accept-license --accept-gdpr is needed only once for first time.

btw. the position of parameters like -f json is not important in linux app see getopt() function.

/Sergej

1 Like

Thanks for clarifying!
I directly choosed a server as only this server offers me full speed almost every time.

Hi Michael,
Would be awesome if you attach chart.html or link to “how to” for beginners :wink:
Again, many thanks for guide and sharing your work.

If you use rrd4j
instead of Webview use:
Chart item=gSpeedtest service="rrd4j" period=h refresh=15000
image
Note: only Number items are displayed in Chart if you add items to persistency group

/Sergej

It´s all based on the InfluxDB+Grafana guide i already linked :slight_smile:

Just a quick note to let you know I have this up and running on Windows…it was fairly easy…

I downloaded the appropriate version of the CLI for Windows

As of now I have removed the charting as I wanted to get the basic functionality working.

My Items:

Group gSpeedtest <"speedtest">

String      SpeedtestSummary        "Speedtest [%s]"                                            <"speedtest_summary">   (gSpeedtest)
Number      SpeedtestResultPing     "Ping [%.3f ms]"                                            <"speedtest_ping">      (gSpeedtest)
Number      SpeedtestResultDown     "Download [%.2f Mbit/s]"                                    <"speedtest_download">  (gSpeedtest)
Number      SpeedtestResultUp       "Upload [%.2f Mbit/s]"                                      <"speedtest_upload">    (gSpeedtest)
String      SpeedtestRunning        "Speedtest Running ... [%s]"                                <"speedtest_run">       (gSpeedtest)
Switch      SpeedtestRerun          "Start Manually"                                            <"speedtest_reload">    (gSpeedtest)
DateTime    SpeedtestResultDate     "Last Run [%1$td.%1$tm.%1$tY, %1$tH:%1$tM Uhr]"             <"speedtest_date">      (gSpeedtest)
String      SpeedtestResultError    "Error Message [%s]"                                        <"speedtest_error">     (gSpeedtest)

String      SpeedtestResultImage    "Image"

My Rules:

val String ruleId = "Speedtest"
val Number calc = 125000 // Converting from bits to Mbits

rule "Speedtest init"

when

    System started

then

    createTimer(now.plusSeconds(195))
    [|
        if(SpeedtestRerun.state == NULL)
        {
            SpeedtestRerun.postUpdate(OFF)
        }

        if(SpeedtestRunning.state == NULL)
        {
            SpeedtestRunning.postUpdate("-")
        }

        if(SpeedtestSummary.state == NULL || SpeedtestSummary.state == "")
        {
            SpeedtestSummary.postUpdate("⁉ (unbekannt)")
        }
    ]

end

rule "Speedtest"

when

    Time cron "0 0/15 * * * ?" or
    Item SpeedtestRerun changed from OFF to ON or
    Item SpeedtestRerun received command ON

then

    //logInfo(ruleId, "--> speedtest executed...")
    SpeedtestRunning.postUpdate("Measurement in Progress...")

    // execute the script, you may have to change the path depending on your system
    // Please use -f json and not -f json-pretty
    val speedtestExecute = "D:/Tools/Speedtest/speedtest.exe -f json"
    var speedtestCliOutput = executeCommandLine(speedtestExecute, 120*1000)

    // for debugging:
    // var String speedtestCliOutput = "Ping: 43.32 ms\nDownload: 21.64 Mbit/s\nUpload: 4.27 Mbit/s"
    //logInfo(ruleId, "--> speedtest output:\n" + speedtestCliOutput + "\n\n")
    SpeedtestRunning.postUpdate("Data Analysis...")

    // starts off with a fairly simple error check, should be enough to catch all problems I can think of
    if (speedtestCliOutput.startsWith("{\"type\":\"result\",") && speedtestCliOutput.endsWith("}}"))
    {
        var ping = Float::parseFloat(transform("JSONPATH", "$.ping.latency", speedtestCliOutput))
        SpeedtestResultPing.postUpdate(ping)

        var float down = Float::parseFloat(transform("JSONPATH", "$.download.bandwidth", speedtestCliOutput))
        down = (down / calc)
        SpeedtestResultDown.postUpdate(down)

        var float up = Float::parseFloat(transform("JSONPATH", "$.upload.bandwidth", speedtestCliOutput))
        up = (up / calc)
        SpeedtestResultUp.postUpdate(up)

        var String url = transform("JSONPATH", "$.result.url", speedtestCliOutput)
        val img = url + ".png"
        SpeedtestResultImage.postUpdate(img)

        SpeedtestSummary.postUpdate(String::format("ᐁ  %.1f Mbit/s  ᐃ %.1f Mbit/s (%.0f ms)", down, up, ping))

        SpeedtestRunning.postUpdate("-")

        // update timestamp for last execution
        val String ResultDate = "" + new DateTimeType()
        SpeedtestResultDate.postUpdate(ResultDate)
    }
    else
    {
        SpeedtestResultPing.postUpdate(0)
        SpeedtestResultDown.postUpdate(0)
        SpeedtestResultUp.postUpdate(0)
        SpeedtestSummary.postUpdate("(unknown)")
        SpeedtestRunning.postUpdate("Error")

        logError(ruleId, "--> speedtest failed. Output:\n" + speedtestCliOutput + "\n\n")
    }

    SpeedtestRerun.postUpdate(OFF)

end

On line 47 note how the path to the .exe is created…you also must add the entire path to the executable in the exec.whitelist file if you are running on 2.5.2

My rendered sitemap

Only things left to do are:

1, Change time and date display :heavy_check_mark:
2. Figure out why my Gigabit services is only showing 246Mb on the download. :heavy_check_mark:
3. Make HabPanel widget :heavy_check_mark:

Squid :squid:

2 Likes

Try other servers and add -s <ID> to your rule when you found a reliable server.

For my region only one server (marked with >) is able to provide reliable bandwidth for Gigabit services.

[17:40:42] openhab@oH-Speedtest:~$ speedtest -L
Closest servers:

    ID  Name                           Location             Country
==============================================================================
   15431  Spacken.net                    Hagen                Germany
   17392  myLoc managed IT AG            Dusseldorf           Germany
   21467  InoHost                        Düsseldorf          Germany
 > 28624  Händle & Korte GmbH           Dusseldorf           Germany
   28716  ColocationIX 10G               Dusseldorf           Germany
   30906  Deutsche Telekom Technik GmbH  Dusseldorf           Germany
    6601  NetCologne                     Cologne              Germany
    6670  hotspot.koeln                  Cologne              Germany
   22274  Gemeindewerke Nümbrecht GmbH  Nümbrecht           Germany
   24887  Studenten Net Twente           Enschede             Netherlands

Could you please tell me where this directory and file should be? I can´t find it in my openhabian setup.
The docs are not a great help as there´s no full path listed.

Nevermind… i need to create it myself under /etc/openhab2/misc

@Bredmich

Question for you…I’m wanting to use the SpeedtestSummary data in a HabPanel Widget

Do to my current layout the data renders as follows:

image

How can I modify the String below to place line breaks between each of the three values so up, down, and ping are all on separate lines?

SpeedtestSummary.postUpdate(String::format("ᐁ  %.1f Mbit/s  ᐃ %.1f Mbit/s (%.0f ms)", down, up, ping))

You could try \n but i´m not sure if HABpanel will do it correctly.

SpeedtestSummary.postUpdate(String::format("ᐁ %.1f Mbit/s\nᐃ %.1f Mbit/s\n(%.0f ms)", down, up, ping))

E: The repository 'https://ookla.bintray.com/debian eoan Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.

I assume i am doing something simple, wrong. Running openhab on ubuntu 19.10

I think you need to --allow-unauthenticated to your sudo apt-get update
As i´m not using Ubuntu i´m not sure if that´s the correct way.

As an FYI -

The /n would not work in HabPanel as you mentioned might be the case…

What I ended up doing was using the individual elements and making a widget from them.

Came out very nice and fits in with the overall design of my status board.
image

Thanks again for this great addition to OH!

Squid

1 Like

Just to be sure, you used \n and not /n?

Yes, typo on my part above

Maybe someone has a good idea for the following question.
I would like to have a rule that is able to send different messages for thresholds.
My ISP has three levels of bandwidth: Maximum, Usually and Minimum
So i´ve got six states, Upload (Min,Normal,Max) and Download (Min,Normal,Max), to measure.
I already made the checks but i´m not sure what would be a good way to write a rule for this.

Edit: Ok so here´s what i did. I´m pretty sure there´s a “better” or much simplier way to do this and i´m happy if someone has a optimized version.

Code in the first post

Ok clearly, not being a programmer I’ve done something wrong, I thought I copied and pasted the code ok, and the command line speedtest creates no issues but I get a Java error


2020-03-17 17:21:11.343 [vent.ItemStateChangedEvent] - SpeedtestRunning changed from Data Analysis... to Measurement in progress...
2020-03-17 17:21:11.358 [vent.ItemStateChangedEvent] - SpeedtestResultDate changed from 2020-03-17T17:20:12.257-0400 to 2020-03-17T17:21:11.340-0400
2020-03-17 17:21:20.575 [vent.ItemStateChangedEvent] - SpeedtestRunning changed from Measurement in progress... to Data Analysis...
2020-03-17 17:21:20.577 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Speedtest': For input string: "{"type":"result","timestamp":"2020-03-17T21:21:20Z","ping":{"jitter":0.070000000000000007,"latency":4.0490000000000004},"download":{"bandwidth":10542780,"bytes":38014560,"elapsed":3610},"upload":{"bandwidth":11753696,"bytes":42415200,"elapsed":3610},"packetLoss":0,"isp":"Bell Canada","interface":{"internalIp":"192.168.1.34","name":"eth0","macAddr":"B8:27:EB:1E:8B:85","isVpn":false,"externalIp":"216.209.224.196"},"server":{"id":12159,"name":"LARG*net","location":"London, ON","country":"Canada","host":"speedtest.largnet.ca","port":8080,"ip":"198.20.48.134"},"result":{"id":"841f35c7-9e7a-4989-8a4d-d5f280f6c97b","url":"https://www.speedtest.net/result/c/841f35c7-9e7a-4989-8a4d-d5f280f6c97b"}}"
2020-03-17 17:23:27.252 [ERROR] [org.quartz.core.JobRunShell         ] - Job DEFAULT.Timer 11 2020-03-17T17:23:27.248-04:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {
  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@11d0ff7 (conditionalExpression: false)
  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@1f5aac8 (conditionalExpression: false)
  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@1905992 (conditionalExpression: false)
} ] threw an unhandled Exception: 

java.lang.NullPointerException: null
	at org.eclipse.smarthome.model.script.engine.ScriptError.<init>(ScriptError.java:65) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:140) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:991) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:954) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:235) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:857) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:231) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluateArgumentExpressions(XbaseInterpreter.java:1205) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1135) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:1081) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:991) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:237) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:469) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:255) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:458) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:239) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:201) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]
	at com.sun.proxy.$Proxy177.apply(Unknown Source) ~[?:?]
	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:48) ~[?:?]
	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) [bundleFile:?]
	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [bundleFile:?]
2020-03-17 17:23:27.309 [ERROR] [org.quartz.core.ErrorLogger         ] - Job (DEFAULT.Timer 11 2020-03-17T17:23:27.248-04:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {
  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@11d0ff7 (conditionalExpression: false)
  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@1f5aac8 (conditionalExpression: false)
  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@1905992 (conditionalExpression: false)
} ] threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception.
	at org.quartz.core.JobRunShell.run(JobRunShell.java:213) [bundleFile:?]
	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [bundleFile:?]

Caused by: java.lang.NullPointerException
	at org.eclipse.smarthome.model.script.engine.ScriptError.<init>(ScriptError.java:65) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:140) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:991) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:954) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:235) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:857) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:231) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluateArgumentExpressions(XbaseInterpreter.java:1205) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1135) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:1081) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:991) ~[?:?]
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:237) ~[?:?]
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:469) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:255) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:458) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:239) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:215) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:201) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]

	at com.sun.proxy.$Proxy177.apply(Unknown Source) ~[?:?]

	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:48) ~[?:?]

	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[?:?]

	... 1 more 
'''

Please put all your code between ```php and ```
Currently i don´t see a speedtest error.

Sorry can never remember how to get the text in those scrollable windows

Code:

// Global Variables
//
val String filename = "speedtest.rules"
val String ruleId = "Speedtest"
val Number calc = 125000 // Converting from bits to Mbits
//
rule "Speedtest init"
when
    System started
then
    createTimer(now.plusSeconds(195)) [|
        if (SpeedtestRerun.state == NULL) SpeedtestRerun.postUpdate(OFF)
        if (SpeedtestRunning.state == NULL) SpeedtestRunning.postUpdate("-")
        if (SpeedtestSummary.state == NULL || SpeedtestSummary.state == "")
            SpeedtestSummary.postUpdate("⁉ (unknown)")
    ]
end
//
rule "Speedtest"
when
    Time cron "0 0 7/4 1/1 * ?" or //every 4hrs from 7am
    Item SpeedtestRerun changed from OFF to ON or
    Item SpeedtestRerun received command ON
then
    logInfo(filename, "--> speedtest executed...")
    SpeedtestRunning.postUpdate("Measurement in progress...")

    // update timestamp for last execution
    SpeedtestResultDate.postUpdate(new DateTimeType())

    // execute the script, you may have to change the path depending on your system
    // var String speedtestCliOutput = executeCommandLine("/usr/local/bin/speedtest-cli@@--simple", 120*1000)
    // val speedtestExecute = "speedtest -f json -s 1061"
    val speedtestExecute = "speedtest -f json"
    var speedtestCliOutput = executeCommandLine(speedtestExecute, 120*1000)

    // for debugging:
    //var String speedtestCliOutput = "Ping: 43.32 ms\nDownload: 21.64 Mbit/s\nUpload: 4.27 Mbit/s"
    //logInfo(filename, "--> speedtest output:\n" + speedtestCliOutput + "\n\n")

    SpeedtestRunning.postUpdate("Data Analysis...")

 if (speedtestCliOutput.startsWith("{\"type\":\"result\",") && speedtestCliOutput.endsWith("}}"))
    {
        var ping = Float::parseFloat(transform("JSONPATH", "$.ping.latency", speedtestCliOutput))
        SpeedtestResultPing.postUpdate(ping)

        var float down = Float::parseFloat(transform("JSONPATH", "$.download.bandwidth", speedtestCliOutput))
        down = (down / calc)
        SpeedtestResultDown.postUpdate(down)

        var float up = Float::parseFloat(transform("JSONPATH", "$.upload.bandwidth", speedtestCliOutput))
        up = (up / calc)
        SpeedtestResultUp.postUpdate(up)

        //var String url = transform("JSONPATH", "$.result.url", speedtestCliOutput)
        //val img = url + ".png"
        //SpeedtestResultImage.postUpdate(img)

        SpeedtestSummary.postUpdate(String::format("ᐁ  %.1f Mbit/s  ᐃ %.1f Mbit/s (%.0f ms)", down, up, ping))

        SpeedtestRunning.postUpdate("-")

        // update timestamp for last execution
        val String ResultDate = "" + new DateTimeType()
        SpeedtestResultDate.postUpdate(ResultDate)
    }
    else
    {
        SpeedtestResultPing.postUpdate(0)
        SpeedtestResultDown.postUpdate(0)
        SpeedtestResultUp.postUpdate(0)
        SpeedtestSummary.postUpdate("(unknown)")
        SpeedtestRunning.postUpdate("Failure")

        logError(ruleId, "--> speedtest failed. Output:\n" + speedtestCliOutput + "\n\n")
    }
    SpeedtestRerun.postUpdate(OFF)
end

As I said I cut and paste it

what file is this copied from? If it’s the rule…it;s missing a large part of it from the top.

1 Like

The error’s straight from my log openhabIP:9001
The code from the speedtest.rules