Stats4Lox liefert ein Wrapper-Shellscript mit, mit dem das Influx CLI Programm ohne Eingabe von Host/User/Pass möglich ist. Dieses Wrapperscript meldet sich automatisch an der Influx-Instanz an und übergibt alle Parameter weiter an Influx
/opt/loxberry/bin/plugins/stats4lox/s4linflux -database 'stats4lox' -execute "SELECT value FROM testdata"
InfluxQL ist eine an SQL angelehnte Querysprache.
Grundsätzliches: https://docs.influxdata.com/influxdb/v1.8/query_language/
Funktionen: https://docs.influxdata.com/influxdb/v1.8/query_language/functions/
Beispielabfragen von Stats4Lox-Daten:
Verschiedene Beispielabfragen
# 10 Außentemperaturen /opt/loxberry/bin/plugins/stats4lox/s4linflux -database 'stats4lox' -execute 'SELECT "Default" FROM "Außentemperatur" LIMIT 10' time Default ---- ------- 1341153900000000000 27.531 1341154200000000000 27.437 1341154500000000000 27.219 1341154800000000000 26.722 1341155100000000000 25.7 1341155400000000000 24.528 1341155700000000000 23.725 1341156000000000000 23.25 1341156300000000000 23.031 1341156600000000000 22.875 # Außentemperaturen der letzten Stunde /opt/loxberry/bin/plugins/stats4lox/s4linflux -database 'stats4lox' -execute 'SELECT "Default" FROM "Außentemperatur" WHERE time > now()-60m' name: Außentemperatur time Default ---- ------- 1634652061000000000 13.7 1634652361000000000 13.6 1634652661000000000 13.5 1634652961000000000 13.4 1634653561000000000 13.1 1634653861000000000 13.1 # Erfasste Minimum/Maximum Temperatur seit 2020 /opt/loxberry/bin/plugins/stats4lox/s4linflux -database 'stats4lox' -execute 'SELECT MAX("Default"), MIN("Default") FROM "Außentemperatur" WHERE "Default" > -128;' name: Außentemperatur time max min ---- --- --- 0 49.625 -68.688
Wegen des Quotings sind Queries mit Zeitstempeln (WHERE time > '2020-01-01' usw.) problematisch bzw. funktionieren nicht oder nicht richtig.
Dieses Query macht Folgendes:
time >= 6h and time <= now()
Abfrage der letzten 6 StundenGROUP BY time(1h)
Werte auf 1h Werte gruppierenfill(previous)
Es wird jeweils angenommen, dass der letzte Wert solange beibehalten bleibt, bis der nächste kommt (das, was man in einer Grafik als gerade Linie sehen würde)/opt/loxberry/bin/plugins/stats4lox/s4linflux -database stats4lox -execute 'SELECT mean("Default") FROM "Außentemperatur" WHERE time >= now() - 6h and time <= now() GROUP BY time(1h) fill(previous)'
Mit diesem Script erzeugst du in Influx die Test-Datenreihe, mit der ich hier gespielt habe:
Script zum Anlegen von Beispieldaten
#!/bin/bash PLUGINNAME=stats4lox INFLUXUSERNAME=`jq -r '.influx.influxdbuser' $LBPCONFIG/$PLUGINNAME/cred.json` INFLUXPASSWORD=`jq -r '.influx.influxdbpass' $LBPCONFIG/$PLUGINNAME/cred.json` curl -k -i -XPOST "https://$INFLUXUSERNAME:$INFLUXPASSWORD@localhost:8086/write?db=stats4lox" --data-binary 'testdata value=5 1634475600000000000' curl -k -i -XPOST "https://$INFLUXUSERNAME:$INFLUXPASSWORD@localhost:8086/write?db=stats4lox" --data-binary 'testdata value=10 1634475605000000000' curl -k -i -XPOST "https://$INFLUXUSERNAME:$INFLUXPASSWORD@localhost:8086/write?db=stats4lox" --data-binary 'testdata value=1 1634475780000000000' curl -k -i -XPOST "https://$INFLUXUSERNAME:$INFLUXPASSWORD@localhost:8086/write?db=stats4lox" --data-binary 'testdata value=3 1634476200000000000'
Download: inserttestdata.sh
Beim Ausführen sollte 4x HTTP/1.1 204 No Content
dortstehen - das ist OK!
Der Influx Timestamp ist immer Epoch in Nanosekunden
1634475600000000000 ⇒ 1634475600 Sekunden EPOCH ⇒ Sonntag, 17. Oktober 2021 15:00:00 GMT+02:00 DST
loxberry@loxberry-dev:/ $ /opt/loxberry/bin/plugins/stats4lox/s4linflux -database stats4lox -execute 'SELECT value FROM "testdata"'
name: testdata
time value
---- -----
1634475600000000000 5
1634475605000000000 10
1634475780000000000 1
1634476200000000000 3
Mit dem Commandline-Parameter -precision <Format>
kann man die Zeitausgabe verändern:
loxberry@loxberry-dev:/ $ /opt/loxberry/bin/plugins/stats4lox/s4linflux -database stats4lox
-precision rfc3339
-execute 'SELECT value FROM "testdata"'
name: testdata
time value
---- -----
2021-10-17T13:00:00Z 5
2021-10-17T13:00:05Z 10
2021-10-17T13:03:00Z 1
2021-10-17T13:10:00Z 3
Die Beispielwerte könnten z.B. per MQTT Live bei jeder Änderung übertragen worden sein, ohne Intervall für einen zeitbasierten Abruf.
Dabei wurde der erste Wert 5 um 13:00:00 übertragen, dann fünf Sekunden später der Wert 10, dann nach knapp drei Minuten der Wert 1 und nach insgesamt zehn Minuten der Wert 3.
Eine normale Statistik würde die Punkte dieser Werte einfach verbinden, was aber eigentlich falsch ist.
Tatsächlich bleibt der Wert so lange konstant, bis der nächste folgt, grafisch also so:
Ziel der Übung ist es, aus einer Anzahl von zu vielen oder aber auch zu wenigen Datenpunkten einen Durchschnittswert für ein vorgegebenes Zeitintervall zu bekommen.
Ich gehe davon aus, dass ich einen zeitlich gewichteten Mittelwert über 2 Minuten haben möchte.
Um die späteren Ergebnisse zu kontrollieren, berechne ich erstmal das erwartete Ergebnis per "Hand"
Zeit | Gewichteter Mittelwert | Anmerkungen |
---|---|---|
13:00:00 | (5) | Noch kein Mittelwert möglich |
13:02:00 | 9,792 | Für 5 Sekunden Wert 5, danach Wert 10. Berechnung (5s*5 + 115s*10) / 120 |
13:04:00 | 5,5 | Für 60 Sekunden Wert 10, danach Wert 1. Berechnung (60s*10 + 60s*1) / 120 |
13:06:00 | 1 | Kein neuer Wert, daher letzter Wert 1 |
13:08:00 | 1 | Kein neuer Wert, daher letzter Wert 1 |
13:10:00 | 1 | Kein neuer Wert, daher letzter Wert 1 |
13:12:00 | 3 | Neuer Wert 3 |
/opt/loxberry/bin/plugins/stats4lox/s4linflux -database stats4lox -precision rfc3339 -execute 'SELECT time_weighted_average("value") FROM "testdata" WHERE time <= 1634476200000000000 GROUP BY time(2m) fill(previous)'
GROUP BY time(2m) gibt die Durchschnittswerte von 2 Minuten-Gruppen aus.
fill(previous) füllt nicht existierende Werte mit dem zuletzt verfügbaren Wert auf
Logisch müsste das unseren zeitlich gewichteten Mittelwert ergeben. Aber leider:
time mean
---- ----
2021-10-17T13:00:00Z 7.5
2021-10-17T13:02:00Z 1
2021-10-17T13:04:00Z 1
2021-10-17T13:06:00Z 1
2021-10-17T13:08:00Z 1
2021-10-17T13:10:00Z 3
Das fill(previous) füllt leider nur die Zeiträume der GROUP-Bedingung auf, die überhaupt keinen Wert enthalten. Es füllt allerdings nicht die Zeiträume zwischen mehreren Datenpunkten auf. Daher berechnet das GROUP BY nur das arithmetische Mittel der eingetroffenen Werte, keinen zeitlich gewichteten Mittelwert.
Wenn wir die obere Query modifizieren, dass nicht ein Durchschnittswert von 2 Minuten. sondern 1 Sekunde gebildet wird, erhalten wir eine Datenreihe mit den Werten, die zu jeder Sekunde gültig waren:
/opt/loxberry/bin/plugins/stats4lox/s4linflux -database stats4lox -precision rfc3339 -execute 'SELECT mean("value") FROM "testdata" WHERE time <= 1634476200000000000 GROUP BY time(1s) fill(previous)'
name: testdata
time mean
---- ----
2021-10-17T13:00:00Z 5
2021-10-17T13:00:01Z 5
2021-10-17T13:00:02Z 5
2021-10-17T13:00:03Z 5
2021-10-17T13:00:04Z 5
2021-10-17T13:00:05Z 10
2021-10-17T13:00:06Z 10
2021-10-17T13:00:07Z 10
2021-10-17T13:00:08Z 10
2021-10-17T13:00:09Z 10
2021-10-17T13:00:10Z 10
2021-10-17T13:00:11Z 10
2021-10-17T13:00:12Z 10
usw.
Wenn wir nun dieses Ergebnis nochmals gruppieren in 2-Minuten-Gruppen, dann sollte unser richtiger Mittelwert herauskommen:
/opt/loxberry/bin/plugins/stats4lox/s4linflux -database stats4lox -precision rfc3339 -execute 'SELECT mean("mean") FROM
(SELECT mean("value") FROM "testdata" WHERE time <= 1634476200000000000 GROUP BY time(1s) fill(previous))
WHERE time <= 1634476200000000000 GROUP BY time(2m) fill(previous)'
(ich habe das Subquery blau markiert)
name: testdata
time mean
---- ----
2021-10-17T13:00:00Z 9.791666666666666
2021-10-17T13:02:00Z 5.5
2021-10-17T13:04:00Z 1
2021-10-17T13:06:00Z 1
2021-10-17T13:08:00Z 1
2021-10-17T13:10:00Z 3
Damit haben wir für unser Beispiel tatsächlich einen zeitlich gewichteten Mittelwert berechnet!
Ich denke aber, für den "Hausgebrauch" sollten die Seiteneffekte verschmerzbar sein.
Es geht darum, dass die Ergebnisse einer Query selbst wieder in eine Zeitreihe in Influx geschrieben werden.
/opt/loxberry/bin/plugins/stats4lox/s4linflux -database stats4lox -precision rfc3339 -execute 'SELECT mean("mean")
INTO testdata_2min
FROM (SELECT mean("value") FROM "testdata" WHERE time <= 1634476200000000000 GROUP BY time(1s) fill(previous)) WHERE time <= 1634476200000000000 GROUP BY time(2m) fill(previous)'
Kontrolle:
/opt/loxberry/bin/plugins/stats4lox/s4linflux -database stats4lox -precision rfc3339 -execute 'SELECT * from testdata_2min'
name: testdata_2min
time mean
---- ----
2021-10-17T13:00:00Z 9.791666666666666
2021-10-17T13:02:00Z 5.5
2021-10-17T13:04:00Z 1
2021-10-17T13:06:00Z 1
2021-10-17T13:08:00Z 1
2021-10-17T13:10:00Z 3
/opt/loxberry/bin/plugins/stats4lox/s4linflux -database stats4lox -precision rfc3339
-format csv
-execute 'SELECT * from testdata_2min'
name,time,mean
testdata_2min,2021-10-17T13:00:00Z,9.791666666666666
testdata_2min,2021-10-17T13:02:00Z,5.5
testdata_2min,2021-10-17T13:04:00Z,1
testdata_2min,2021-10-17T13:06:00Z,1
testdata_2min,2021-10-17T13:08:00Z,1
testdata_2min,2021-10-17T13:10:00Z,3
oder direkt in eine Datei
/opt/loxberry/bin/plugins/stats4lox/s4linflux -database stats4lox -precision rfc3339
-format csv
-execute 'SELECT * from testdata_2min'
> testdata.csv
/opt/loxberry/bin/plugins/stats4lox/s4linflux
use stats4lox
show measurements
show field keys from "loxberry/mqttgateway"
select count(*) from "UG Vorlauf";
Die Query dann durchaus ein paar Sekunden dauern.
select count("pollms") from "loxberry/mqttgateway"
Das Ergebnis könnte jeweils mehrere Werte liefern
Erster Wert
SELECT * FROM "UG Vorlauf" GROUP BY * ORDER BY ASC LIMIT 1
Letzter Wert
SELECT * FROM "UG Vorlauf" GROUP BY * ORDER BY DESC LIMIT 1