Ich wollte in unserem SmartHome einen regelmäßigen Speedtest unserer Internetverbindung regelmäßig durchführen lassen. Damit wollte ich herausfinden, ob die zugesicherten Bandbreiten unseres Glasfaser-Anschlusses immer eingehalten werden. Da in openHAB 3 automatisch alle Items persistiert werden, war das nach der Umstellung eine gute Möglichkeit.
Die Erste Idee für die Geschwindigkeitsmessung war das Network Binding. Das habe ich aber dann nicht verwendet, da dies eine ISO-Datei für den Test benötigt (das wollte ich so nicht umsetzen).
Im openHAB-Forum habe ich dann eine individuelle Scripting-Lösung auf Basis Speedtest CLI by Ookla gefunden.
Die Umsetzung war dort sehr gut dort beschrieben. Man muss nur die Systemvoraussetzungen beachten, nicht das hier etwas auf dem eigenen System fehlt (das kann zum Teil im Debugging des Scripts etwas aufwändiger sein).
Die Scripte stellen für mich eine sehr runde Lösung dar, die alle Informationen incl. graphischer Aufbereitung / Icons enthält. In openHAB 3.x werden die Daten automatisch persistiert und damit dann auch längerfristig auswertbar gespeichert.
Ein paar Anpassungen für openHAB 3.x mussten durchgeführt werden:
SpeedTest.items
Die Items werden wie folgt definiert:
Group gSpeedtest <"speedtest">
Group gSpeedChart
String SpeedtestCharts
String SpeedtestSummary "Speedtest [%s]" <"speedtest_summary"> (gSpeedtest, gPersist)
Number SpeedtestResultPing "Ping [%.3f ms]" <"speedtest_ping"> (gSpeedtest, gSpeedChart)
Number SpeedtestResultDown "Download [%.2f Mbit/s]" <"speedtest_download"> (gSpeedtest, gSpeedChart)
Number SpeedtestResultUp "Upload [%.2f Mbit/s]" <"speedtest_upload"> (gSpeedtest, gSpeedChart)
String SpeedtestRunning "Speedtest läuft ... [%s]" <"speedtest_run"> (gSpeedtest)
Switch SpeedtestRerun "Manuell starten" <"speedtest_reload"> (gSpeedtest)
DateTime SpeedtestResultDate "Letzte Ausführung [%1$td.%1$tm.%1$tY, %1$tH:%1$tM]" <"speedtest_date"> (gSpeedtest, gPersist)
String SpeedtestResultError "Fehlermeldung [%s]" <"speedtest_error"> (gSpeedtest, gPersist)
String SpeedtestResultImage "Bild"
SpeedTest.rules
Die Regel steuert dann die gesamte Logik an (hier ist eine automatischer und eine manueller Start möglich). Hier habe ich meine Anpassungen im Kommentar erfasst:
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
// 1 x am Tag 4 Uhr früh
Time cron "0 0 4 * * ?" or
//Time cron "0 0/15 * * * ?" or // alle 15 Minuten
Item SpeedtestRerun changed from OFF to ON or
Item SpeedtestRerun received command ON
then
//logInfo(ruleId, "--> speedtest executed...")
SpeedtestRunning.postUpdate("Messung läuft...")
// 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 = "speedtest -f json"
// 13.02.2021 - Anpassung damit Lizenz akzeptiert wird
//val speedtestExecute = "sudo -u openhab /usr/bin/speedtest -f json --accept-license --accept-gdpr"
//val speedtestExecute = "speedtest -f json"
//var speedtestCliOutput = executeCommandLine(speedtestExecute, 120*1000)
// 13.02.2021 - Anpassung für openHAB 3
var speedtestCliOutput = executeCommandLine(Duration.ofSeconds(120), "speedtest", "-f", "json")
// 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("Datenauswertung...")
// starts off with a fairly simple error check, should be enough to catch all problems I can think of
// 13.02.2021 - Anpassung notwendig zum Beispiel
//if (speedtestCliOutput.startsWith("{\"type\":\"result\",") && speedtestCliOutput.endsWith("}}"))
if (speedtestCliOutput.startsWith("{\"type\":\"result\","))
{
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 DateTimeType ResultDate = DateTimeType.valueOf(transform("JSONPATH", "$.timestamp", speedtestCliOutput))
SpeedtestResultDate.postUpdate(ResultDate)
}
else
{
SpeedtestResultPing.postUpdate(0)
SpeedtestResultDown.postUpdate(0)
SpeedtestResultUp.postUpdate(0)
SpeedtestSummary.postUpdate("(unbekannt)")
SpeedtestRunning.postUpdate("Fehler")
logError(ruleId, "--> speedtest failed. Output:\n" + speedtestCliOutput + "\n\n")
}
SpeedtestRerun.postUpdate(OFF)
end
Sitemap
Die Visualisierung erfolgt dann in der Sitemap wie folgt:
Text item=SpeedtestSummary icon="speedtest" {
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 != "-"]
Text item=SpeedtestResultError visibility=[SpeedtestRunning == "Fehler"]
Switch item=SpeedtestRerun mappings=[ON="Start"]
}
Frame label="Statistik" {
Switch item=Chart_Zeitraum_D_W_M_Y label="" mappings=[0="Woche", 1="Monat", 2="Jahr"]
Chart item=gSpeedtest service="rrd4j" period=W refresh=15000 visibility=[Chart_Zeitraum_D_W_M_Y==0, Chart_Zeitraum_D_W_M_Y=="Uninitialized"]
Chart item=gSpeedtest service="rrd4j" period=M refresh=15000 visibility=[Chart_Zeitraum_D_W_M_Y==1]
Chart item=gSpeedtest service="rrd4j" period=Y refresh=15000 visibility=[Chart_Zeitraum_D_W_M_Y==2]
}
}
Fazit
Damit konnte ich recht einfach die Messung der Bandbreite bei uns zu Hause in openHAB integrieren. Eine schöne Erweiterung wäre noch die Verfügbarkeit des Internetzugangs regelmäßig zu protokollieren.
Wie messt Ihr in eurem SmartHome die Bandbreite eurer Internetverbindung? Habt Ihr eine bessere Variante als diese manuelle Scripting-Lösung?