# Speedtest-cli Internet Up-/Downlink Measurement Integration

**URL:** <https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611>\
**Category:** Tutorials & Examples\
**Created:** [February 16, 2016, 2:25am UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611 "2016-02-16T02:25:15Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![ThomDietrich](https://community.openhab.org/user_avatar/community.openhab.org/thomdietrich/32/71239_2.png) [@ThomDietrich](https://community.openhab.org/u/ThomDietrich)\
**Post date:** [February 16, 2016, 2:25am UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/1 "2016-02-16T02:25:15Z")

</div>

Below you’ll find a complete solution on integrating the internet connection bandwidth speed test from [Speedtest.net](http://www.speedtest.net) in your OpenHAB setup. This is accomplished by using the [`speedtest-cli`](https://github.com/sivel/speedtest-cli) script, which you have to provide on your system.

**Version Info:** The guide was updated for openHAB 2.0 but should work on other versions as well.

**Functionality:**

- execute speed test once or twice a day, every hour or upon command
- show summarized results on the sitemap
- show all results on an extra page after click
- a button is defined to start the speedtest, either through the sitemap or your own rules

 ![](https://community-openhab-org.s3-eu-central-1.amazonaws.com/original/2X/2/2b3ee536c3026d68191802329246b3bca6a7dd3f.png)

## Installation and Test

### Linux

```bash
#Install easy_install if not yet available
sudo apt-get install python-setuptools
# Installation of speedtest-cli
sudo easy_install speedtest-cli
# Testing
speedtest-cli
speedtest-cli --simple

```

Please make sure the script is working before you continue.

**openHAB:** You’ll need the [Exec Binding](http://docs.openhab.org/addons/bindings/exec/readme.html). Please install and configure it in your preferred way.

### Windows

You can find an unofficial speedtest-cli for Windows here: [GitHub - zpeters/speedtest: Command line client for speedtest.net written in Go · GitHub](https://github.com/zpeters/speedtest)

Place the executable on your harddrive, e.g. “`C:\openHAB\speedtest.exe`”. All further steps are descried below.

## OpenHAB files

### Icons

All png and svg icons in one archive:  
[  
  ![](https://community-openhab-org.s3-eu-central-1.amazonaws.com/original/2X/a/a0d062a8dbb8d1c4ee9cad907c94e7e139a96978.png)  
Click image to download](https://github.com/ThomDietrich/openhab-config/raw/0c271418debee20f8b78a7cacbbb17397d671d39/additionalFiles/Speedtest_icons_svg.rar)

Extract all icons to the icons folder under `$OPENHAB_CONF/icons/classic/`   
 (openHAB 1.x: `$OPENHAB_HOME/webapps/images/`)

Icons source (free for non-commercial use): [Long Shadow Polygon Iconpack (200 icons) | GraphicLoads](http://www.iconarchive.com/show/polygon-icons-by-graphicloads.html)

### Items (`speedtest.items`)

```php
Group gSpeedtest <"network-icon"> (Whg)

String SpeedtestSummary "Speedtest [%s]" <"speedtest_network"> (gSpeedtest)
Number SpeedtestResultPing "Ping [%.3f ms]" <"speedtest_next5"> (gSpeedtest)
Number SpeedtestResultDown "Downlink [%.2f Mbit/s]" <"speedtest_download"> (gSpeedtest)
Number SpeedtestResultUp "Uplink [%.2f Mbit/s]" <"speedtest_upload"> (gSpeedtest)
String SpeedtestRunning "Speedtest running ... [%s]" <"speedtest_new"> (gSpeedtest)
Switch SpeedtestRerun "Start manually" <"speedtest_reload2"> (gSpeedtest)
DateTime SpeedtestResultDate "Last executed [%1$td.%1$tm.%1$tY, %1$tH:%1$tM Uhr]" <"speedtest_problem4"> (gSpeedtest)

```

### Sitemap (Part of `myhome.sitemap`)

```php
...
Text item=SpeedtestSummary {
  Frame label="Ergebnisse" {
    Text item=SpeedtestResultDown
    Text item=SpeedtestResultUp
    Text item=SpeedtestResultPing
  }
  Frame label="Steuerung" {
    Text item=SpeedtestResultDate
    Text item=SpeedtestRunning label="Speedtest [%s]" visibility=[SpeedtestRunning != "-"]
    Switch item=SpeedtestRerun mappings=[ON="Start"]
  }
  Frame label="Statistik" {
    Text label="..." icon="speedtest_analytics8"
  }
}
...

```

_Side Note on Statistics:_ The three dots under statistics are just a placeholder for whatever statistics you want to generate and present out of your measurements over time (see [persistence](http://docs.openhab.org/configuration/persistence.html)).

One option is to persist the introduced items to InfluxDB and am drawing Grafana graphs from them. These are then displayed under statistics. For more details check the [InfluxDB+Grafana tutorial](https://community.openhab.org/t/influxdb-grafana-persistence-and-graphing/13761) (a speedtest graph example can be seen in the middle of the first posting).

### Rule (Linux `speedtest.rules`)

```php
val String filename = "speedtest.rules"

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

```

```php
rule "Speedtest"
when
    //Time cron "0 0 5,13 * * ?" or
    Time cron "0 0 * * * ?" or
    Item SpeedtestRerun received command ON
then
    logInfo(filename, "--> speedtest executed...")
    SpeedtestRunning.postUpdate("Messung läuft...")

    // 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)

    // 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("Datenauswertung...")

    // starts off with a fairly simple error check, should be enough to catch all problems I can think of
    if (speedtestCliOutput.startsWith("Ping") && speedtestCliOutput.endsWith("Mbit/s")) {
        var String[] results = speedtestCliOutput.split("\\r?\\n")
        var float ping = new java.lang.Float(results.get(0).split(" ").get(1))
        var float down = new java.lang.Float(results.get(1).split(" ").get(1))
        var float up = new java.lang.Float(results.get(2).split(" ").get(1))
        SpeedtestResultPing.postUpdate(ping)
        SpeedtestResultDown.postUpdate(down)
        SpeedtestResultUp.postUpdate(up)
        SpeedtestSummary.postUpdate(String::format("ᐁ %.1f Mbit/s ᐃ %.1f Mbit/s (%.0f ms)", down, up, ping))
        SpeedtestRunning.postUpdate("-")
        logInfo(filename, "--> speedtest finished.")
    } else {
        SpeedtestResultPing.postUpdate(0)
        SpeedtestResultDown.postUpdate(0)
        SpeedtestResultUp.postUpdate(0)
        SpeedtestSummary.postUpdate("(unbekannt)")
        SpeedtestRunning.postUpdate("Fehler bei der Ausführung")
        logError(filename, "--> speedtest failed. Output:\n" + speedtestCliOutput + "\n\n")
    }
    SpeedtestRerun.postUpdate(OFF)
end

// vim: syntax=Xtend

```

That’s it. If you have problems, just activate the logging lines and have a look in your `openhab.log` to get an idea of what’s going on.

### Rule (Windows `speedtest.rules`)

The following changes are needed compared to the Linux rule above:

```php
...
var String speedtestCliOutput = executeCommandLine("c:\\openHAB\\speedtest.exe@@--report", 120*1000)
...
if (speedtestCliOutput.startsWith("201")) {        
    var String[] results = speedtestCliOutput.split("\\|")
    var float ping = new java.lang.Float(results.get(3))
    var float down = new java.lang.Float(results.get(4))
    var float up = new java.lang.Float(results.get(5))
    SpeedtestResultPing.postUpdate(ping)
    SpeedtestResultDown.postUpdate(down/1024)
    SpeedtestResultUp.postUpdate(up/1024)
...

```

---

<div class="post-metadata">

**Author:** ![ben\_jones12](https://community.openhab.org/user_avatar/community.openhab.org/ben_jones12/32/52_2.png) [@ben\_jones12](https://community.openhab.org/u/ben_jones12)\
**Post date:** [February 16, 2016, 4:01am UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/2 "2016-02-16T04:01:52Z")

</div>

By jeez I love open source software! This is a great little script - I will be doing something very similar - thank you so much for sharing!

---

<div class="post-metadata">

**Author:** ![tracstarr](https://community.openhab.org/letter_avatar_proxy/v4/letter/t/b782af/32.png) [@tracstarr](https://community.openhab.org/u/tracstarr)\
**Post date:** [February 16, 2016, 8:43pm UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/3 "2016-02-16T20:43:18Z")

</div>

I like this one. The wife has been complaining that speeds decrease in the evening, so this is a good way to keep track and for her to easily view the results.

I’ve updated your rule so that I don’t have to call a script that calls the script. I also run every hour and will add a graph result as well.

My items:

```
String SpeedtestPingResult "Ping [%s ms]" 
String SpeedtestDownResult "Downlink [%s MBit/s]"
String SpeedtestUpResult "Uplink [%s MBit/s]"

```

My rule:

```
rule "Speedtest every hour"
when
  Time cron "0 0 * * * ?"
then 
    logInfo("RULE", "speedtest started...")
//var String results = "Ping: 108.311 ms\nDownload: 12.26 Mbit/s\nUpload: 0.99 Mbit/s"
    var String results = executeCommandLine("/opt/scripts/speedtest-cli@@--simple", 120*1000)
    var textStr = results.split("\\r?\\n")
if (textStr != null)
{		
	SpeedtestPingResult.postUpdate(textStr.get(0).split(" ").get(1))
	SpeedtestDownResult.postUpdate(textStr.get(1).split(" ").get(1))
	SpeedtestUpResult.postUpdate(textStr.get(2).split(" ").get(1))
}	
end

```

---

<div class="post-metadata">

**Author:** ![tinkerfailure](https://community.openhab.org/user_avatar/community.openhab.org/tinkerfailure/32/71056_2.png) [@tinkerfailure](https://community.openhab.org/u/tinkerfailure)\
**Post date:** [February 16, 2016, 9:59pm UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/4 "2016-02-16T21:59:51Z")

</div>

Nice work fellas.

I installed it myself. I’m getting errors when it attempts to run, sounds like it’s indexing the array wrong?

```auto
2016-02-16 21:54:01.716 [ERROR] [.o.m.r.i.engine.ExecuteRuleJob] - Error during the execution of rule Speedtest every hour
java.lang.ArrayIndexOutOfBoundsException: 1
    at org.eclipse.xtext.xbase.lib.Conversions$WrappedArray.get(Conversions.java:183) ~[na:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0]
    at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0]

```

But also, when I ran the test in the shell, I got a download speed of 75.46Mbits/sec. I ran the Speedtest app on my iPhone to check and got 126.59Mbits/sec..!

It’s also running once a minute, not once an hour!

C

---

<div class="post-metadata">

**Author:** ![ThomDietrich](https://community.openhab.org/user_avatar/community.openhab.org/thomdietrich/32/71239_2.png) [@ThomDietrich](https://community.openhab.org/u/ThomDietrich)\
**Post date:** [February 18, 2016, 12:13am UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/5 "2016-02-18T00:13:26Z")

</div>

Hey @tracstarr, great input!  
I was mainly interested in my downlink connection but especially for graphs all three values are nice. I updated the first posting with your additions, combined things in a String representation for the sitemap and added a bit of logging. The extra variables are mainly for clarity.  
I’m not sure if I like the idea to run this script hourly. I’m running it twice per day when nobody is active in my network. If wife/son/dog is watching netflix, the results will go down, that’s a self-fulfilling prophecy and will create trouble for you 😃 Maybe you could graph the speedtest in conjunction with the current traffic from your router (SNMP?) to get the overall bandwidth…

Hey @tinkerfailure, can you try again with the updated code?

---

<div class="post-metadata">

**Author:** ![tracstarr](https://community.openhab.org/letter_avatar_proxy/v4/letter/t/b782af/32.png) [@tracstarr](https://community.openhab.org/u/tracstarr)\
**Post date:** [February 18, 2016, 2:41am UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/6 "2016-02-18T02:41:03Z")

</div>

Excellent! I like the additions. Not much error checking on the arrays etc, but to be honest it’s not worth it. Either it works or it doesn’t. I agree with the hourly, too much.

---

<div class="post-metadata">

**Author:** ![ThomDietrich](https://community.openhab.org/user_avatar/community.openhab.org/thomdietrich/32/71239_2.png) [@ThomDietrich](https://community.openhab.org/u/ThomDietrich)\
**Post date:** [February 18, 2016, 11:54am UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/7 "2016-02-18T11:54:00Z")

</div>

Thanks! I added another condition. Now error checking ins done by checking if the output of speedtest-cli is something like “Ping…MBit/s”. If that’s the case than I guess everything went fine. Otherwise we’ll get the error logging we can work with. Just to be sure that the summary element doesn’t stay in it’s old state on an exception, I did another small modification and moved the reset to the top.

Btw. can somebody help with the `String::format`? The line throws an exception and I can’t figure out why…

---

<div class="post-metadata">

**Author:** ![samverner777](https://community.openhab.org/letter_avatar_proxy/v4/letter/s/aeb1de/32.png) [@samverner777](https://community.openhab.org/u/samverner777)\
**Post date:** [February 18, 2016, 6:10pm UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/8 "2016-02-18T18:10:22Z")

</div>

your variables are all string. if you want to have float, your should cast them when you use get.split.get

---

<div class="post-metadata">

**Author:** ![ThomDietrich](https://community.openhab.org/user_avatar/community.openhab.org/thomdietrich/32/71239_2.png) [@ThomDietrich](https://community.openhab.org/u/ThomDietrich)\
**Post date:** [February 18, 2016, 6:42pm UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/9 "2016-02-18T18:42:45Z")

</div>

Ouch! 😵 that’s what I was thinking I’m doing haha. Somehow I forgot to move the “new DecimalType” up into the variable creations. It was late yesterday ^^ nevermind

---

<div class="post-metadata">

**Author:** ![samverner777](https://community.openhab.org/letter_avatar_proxy/v4/letter/s/aeb1de/32.png) [@samverner777](https://community.openhab.org/u/samverner777)\
**Post date:** [February 18, 2016, 6:52pm UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/10 "2016-02-18T18:52:15Z")

</div>

😉 it’s always easier when you check someone else code.

---

<div class="post-metadata">

**Author:** ![ThomDietrich](https://community.openhab.org/user_avatar/community.openhab.org/thomdietrich/32/71239_2.png) [@ThomDietrich](https://community.openhab.org/u/ThomDietrich)\
**Post date:** [February 24, 2016, 11:39pm UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/11 "2016-02-24T23:39:22Z")

</div>

A last update. Now with more info and control on the sitemap, including a button to manually start a speedtest.  
@tracstarr I was surprised how stable the results are, even with clients active in the network. So I included hourly as a default option 😉

---

<div class="post-metadata">

**Author:** ![ben\_jones12](https://community.openhab.org/user_avatar/community.openhab.org/ben_jones12/32/52_2.png) [@ben\_jones12](https://community.openhab.org/u/ben_jones12)\
**Post date:** [February 25, 2016, 12:25am UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/12 "2016-02-25T00:25:59Z")

</div>

This really needs a page in the wiki - would you mind transferring it across so it isn’t lost in these forums?

---

<div class="post-metadata">

**Author:** ![ThomDietrich](https://community.openhab.org/user_avatar/community.openhab.org/thomdietrich/32/71239_2.png) [@ThomDietrich](https://community.openhab.org/u/ThomDietrich)\
**Post date:** [February 25, 2016, 1:20am UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/13 "2016-02-25T01:20:26Z")

</div>

good idea - done 🙂 Check the first posting.  
Added some explanation and the icons I use.

 ![](https://community-openhab-org.s3-eu-central-1.amazonaws.com/original/2X/2/2b3ee536c3026d68191802329246b3bca6a7dd3f.png)

---

<div class="post-metadata">

**Author:** ![3DJupp](https://community.openhab.org/user_avatar/community.openhab.org/3djupp/32/105950_2.png) [@3DJupp](https://community.openhab.org/u/3DJupp)\
**Post date:** [March 1, 2016, 2:16pm UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/14 "2016-03-01T14:16:56Z")

</div>

I saw the idea of integrating a Speedtest here:

> **[Internetgeschwindigkeit auf der Linuxkonsole messen – :: Klenzel ::](https://klenzel.de/2665)**

Modifications i did with his help:

netstat.sh:

```
#!/bin/bash 
WGET="/usr/bin/wget"
$WGET -q --tries=2 -4 --timeout=10 http://www.google.com -O /tmp/google.idx &> /dev/null
if [! -s /tmp/google.idx]
then
PING=0
DOWN=0
UP=0
IP="127.0.0.1"
else
/volume1/public/OpenHAB/configurations/scripts/speedtest-cli --simple >> /tmp/speedresult.txt
PING=$(cat /tmp/speedresult.txt |grep Ping |cut -d " " -f 2)
DOWN=$(cat /tmp/speedresult.txt |grep Download |cut -d " " -f 2)
UP=$(cat /tmp/speedresult.txt |grep Upload |cut -d " " -f 2) 
IP="`wget http://www.wieistmeineip.de -U "" -qO - | egrep -o '[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}' | uniq`"
fi
/usr/bin/curl -s --header "Content-Type: text/plain" --request POST --data $PING http://127.0.0.1:8081/rest/items/Inet_P 
/usr/bin/curl -s --header "Content-Type: text/plain" --request POST --data $DOWN http://127.0.0.1:8081/rest/items/Inet_D
/usr/bin/curl -s --header "Content-Type: text/plain" --request POST --data $UP http://127.0.0.1:8081/rest/items/Inet_U
/usr/bin/curl -s --header "Content-Type: text/plain" --request POST --data $IP http://127.0.0.1:8081/rest/items/Inet_IP
DATE=`date +'%d.%m.%Y - %T'`
#echo "$DATE: Internet-Speedtest wurde durchgefuehrt (Down: $DOWN, UP: $UP, PING: $PING, Public IP: $IP)"'\n' > /volume1/public/OpenHAB/configurations/scripts/log.txt
rm -f /tmp/speedresult.txt
rm -f /tmp/google.idx

```

main.rules:

```
rule "Cron 30 Minutes"
when
	Time cron "0 */30 * * * ?"
then
	executeCommandLine("sh /volume1/public/OpenHAB/configurations/scripts/netstat.sh")
end

```

---

<div class="post-metadata">

**Author:** ![ThomDietrich](https://community.openhab.org/user_avatar/community.openhab.org/thomdietrich/32/71239_2.png) [@ThomDietrich](https://community.openhab.org/u/ThomDietrich)\
**Post date:** [March 2, 2016, 3:51pm UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/15 "2016-03-02T15:51:13Z")

</div>

Hey Dominic,  
what’s the benefit of this approach?  
Besides having the IP as an additional information (which seems unrelated to the rest), why would you bother and go “von hinten durch die Brust ins Auge”? 😉

---

<div class="post-metadata">

**Author:** ![Farhanito](https://community.openhab.org/letter_avatar_proxy/v4/letter/f/34f0e0/32.png) [@Farhanito](https://community.openhab.org/u/Farhanito)\
**Post date:** [March 3, 2016, 2:50pm UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/16 "2016-03-03T14:50:11Z")

</div>

Since “speedtest-cli --simple --share” will also give you image url of the result, can that image shown in the sitemap?

---

<div class="post-metadata">

**Author:** ![watou](https://community.openhab.org/user_avatar/community.openhab.org/watou/32/70595_2.png) [@watou](https://community.openhab.org/u/watou)\
**Post date:** [March 3, 2016, 2:55pm UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/17 "2016-03-03T14:55:23Z")

</div>

> [@Farhanito](#):
>
> Since “speedtest-cli --simple --share” will also give you image url of the result, can that image shown in the sitemap?

I don’t believe that there is a way to feed a dynamic URL into a sitemap (short of rewriting the sitemap file on the fly). I would love to be proven wrong, though. Giving meaning to the widget `Image item=MyDynamicURL` would be great.

---

<div class="post-metadata">

**Author:** ![ThomDietrich](https://community.openhab.org/user_avatar/community.openhab.org/thomdietrich/32/71239_2.png) [@ThomDietrich](https://community.openhab.org/u/ThomDietrich)\
**Post date:** [March 7, 2016, 12:13pm UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/18 "2016-03-07T12:13:39Z")

</div>

I am personally not really interested in the share-image but if you find a way to include it, tell us! 😉

---

<div class="post-metadata">

**Author:** ![yancym](https://community.openhab.org/letter_avatar_proxy/v4/letter/y/ad7895/32.png) [@yancym](https://community.openhab.org/u/yancym)\
**Post date:** [March 7, 2016, 12:22pm UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/19 "2016-03-07T12:22:27Z")

</div>

The problem is getting the image updated because once the first one is loaded, OH has it locked and you can’t rewrite it without first existing out of OH and freeing the file up. If someone has a solution to that then it would be easy to set up a job to copy the generated image to your image file location.

---

<div class="post-metadata">

**Author:** ![watou](https://community.openhab.org/user_avatar/community.openhab.org/watou/32/70595_2.png) [@watou](https://community.openhab.org/u/watou)\
**Post date:** [March 8, 2016, 7:48am UTC](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611/20 "2016-03-08T07:48:01Z")

</div>

> [@yancym](#):
>
> once the first one is loaded, OH has it locked and you can’t rewrite it without first existing out of OH

That would be a bug if openHAB was responsible for leaving an image file locked. Is there any chance that the code you use to copy the dynamic image to a well-known name is leaving the target file open, or that the copy is happening when the Jetty embedded web server is read the file? Is this on Windows by any chance?

[Next page](https://community.openhab.org/t/speedtest-cli-internet-up-downlink-measurement-integration/7611.md?page=2)
