Grafana: Unterschied zwischen den Versionen
Andies (Diskussion | Beiträge) (→MySQL-Queries: query angepasst) Markierungen: mobile edit mobile web edit |
Krueuw (Diskussion | Beiträge) (Randnotiz für den ersten Start eingefügt.) |
||
(5 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt) | |||
Zeile 33: | Zeile 33: | ||
:<code>;http_port = 3000</code> | :<code>;http_port = 3000</code> | ||
Hier den führenden Semicolon entfernen und den Port entsprechend abändern. Zuletzt ist die Datenbank auszuwählen, in der die Daten von FHEM abgelegt sind (grafana greift standardmäßig auf eine Datenbank mit dem Namen grafana zurück). | Hier den führenden Semicolon entfernen und den Port entsprechend abändern. Zuletzt ist die Datenbank auszuwählen, in der die Daten von FHEM abgelegt sind (grafana greift standardmäßig auf eine Datenbank mit dem Namen grafana zurück). | ||
{{Randnotiz|RNText=http://pi:3000 im Browser zeigt die Login-Seite von Grafana. | |||
Nach Anmeldung mit admin/admin kann das Passwort auf einen sicheren Wert geändert werden.|RNTyp=Erfolgskontrolle}} | |||
== Erstellen von Grafiken == | == Erstellen von Grafiken == | ||
Zeile 44: | Zeile 48: | ||
UNIX_TIMESTAMP(< time >) as time_sec, | UNIX_TIMESTAMP(< time >) as time_sec, | ||
< column > as value, | < column > as value, | ||
< name > as metric FROM < table name > | < name > as metric | ||
FROM < table name > | |||
WHERE $__timeFilter(time_column) | WHERE $__timeFilter(time_column) | ||
ORDER BY < time > ASC | ORDER BY < time > ASC | ||
Zeile 50: | Zeile 55: | ||
Grafana benötigt in diesem Query mindestens drei Spalten mit der richtigen Benennung, die durch <>-Klammern vorgezeichnet sind. | Grafana benötigt in diesem Query mindestens drei Spalten mit der richtigen Benennung, die durch <>-Klammern vorgezeichnet sind. | ||
* time_sec muss Zeitwerte im UNIX-Timestamp Format (Sekunden seit 01.01.1970) enthalten. Meist | * time_sec muss Zeitwerte im UNIX-Timestamp Format (Sekunden seit 01.01.1970) enthalten. Meist wählt man für < time > daher den TIMESTAMP Eintrag aus der Datenbank. | ||
* value muss Werte für die Y-Achse liefern, welche den Zeitstempeln aus time_sec zuzuordnen sind. Meist | * value muss Werte für die Y-Achse liefern, welche den Zeitstempeln aus time_sec zuzuordnen sind. Meist wählt man für < column > daher den VALUE Eintrag aus der Datenbank. | ||
* metric ist der Text, der für die Kurve in der Legende angezeigt wird. | * metric ist der Text, der für die Kurve in der Legende angezeigt wird. Daher ist < name > frei wählbar. | ||
Die Namen der einzelnen Spalten werden durch FHEM selbst vergeben. Man muss also bei der Verwendung der Queries herausfinden, wie die Werte intern gespeichert werden. Das klingt schwerer als es ist, weil sich FHEM dabei an Konventionen hält, die leicht geraten werden können. Der nebenstehende Screenshot zeigt einen typischen Eintrag in der DBLog von FHEM. | Die Namen der einzelnen Spalten werden durch FHEM selbst vergeben. Man muss also bei der Verwendung der Queries herausfinden, wie die Werte intern gespeichert werden. Das klingt schwerer als es ist, weil sich FHEM dabei an Konventionen hält, die leicht geraten werden können. Der nebenstehende Screenshot zeigt einen typischen Eintrag in der DBLog von FHEM. | ||
Zeile 64: | Zeile 69: | ||
UNIX_TIMESTAMP(TIMESTAMP) as time_sec, | UNIX_TIMESTAMP(TIMESTAMP) as time_sec, | ||
VALUE as value, "Kurvenbezeichnung" as metric | VALUE as value, "Kurvenbezeichnung" as metric | ||
FROM history WHERE READING="state" AND DEVICE="MyDummy" AND $__timeFilter( TIMESTAMP ) | |||
</syntaxhighlight> | |||
Solltet Ihr numerische Werte in einer Grafik ausgeben wollen, müsst Ihr das Text-Feld VALUE mittels '''cast(VALUE as signed)''' konvertieren | |||
<syntaxhighlight lang="SQL"> | |||
SELECT | |||
UNIX_TIMESTAMP(TIMESTAMP) as time_sec, | |||
cast(VALUE as signed) as value, "Kurvenbezeichnung" as metric | |||
FROM history WHERE READING="state" AND DEVICE="MyDummy" AND $__timeFilter( TIMESTAMP ) | FROM history WHERE READING="state" AND DEVICE="MyDummy" AND $__timeFilter( TIMESTAMP ) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Zeile 76: | Zeile 89: | ||
=== Beispiele === | === Beispiele === | ||
Sehr viele Beispiele hat Thyraz in diesem {{Link2Forum|Topic=77724|LinkText=Foreneintrag}} bereitgestellt. | Sehr viele Beispiele hat Thyraz in diesem {{Link2Forum|Topic=77724|LinkText=Foreneintrag}} bereitgestellt. Eine ausführliche Erläuterung zu einen Anzeige von Differenzwerten finden sich in diesem [https://forum.fhem.de/index.php/topic,77724.msg1023943.html#msg1023943 Foreneintrag]. | ||
=== Einbindung in FHEM (und andere Seiten) === | === Einbindung in FHEM (und andere Seiten) === | ||
Zeile 112: | Zeile 125: | ||
Auf der Shell-Ebene würde nun der folgende Befehl das Dashboard rendern und speichern | Auf der Shell-Ebene würde nun der folgende Befehl das Dashboard rendern und speichern | ||
curl -H "Authorization: Bearer <Schluessel>" "<Link>" <Dateiname> | curl -H "Authorization: Bearer <Schluessel>" "<Link>" <Dateiname> | ||
Da in der neuen Grafana-Version das Rendern ''auf einem Raspberry Pi'' nicht ohne Weiteres unterstützt wird, kann es sein, dass die oben genannten Versuche fehlschlagen. Hier bietet sich eine andere Lösung an, die zwar nicht so elegant wie die obige ist, aber dafür funktioniert: Man installiert Firefox auf dem Raspberry und lässt ihn "headless" einen Screenshot erstellen. Dieses kann man dann weiterverarbeiten. Diese Lösung hat den Nachteil, dass dann nur die Auflösung des Raspberry erreicht wird. Dazu sind folgende Schritte noztwendig. Zuerst Firefox installieren | |||
sudo apt install firefox-esr | |||
danach ein neues Profil in Firefox erstellen (sonst stürzt Firefox ab), das ist sehr umständlich: Auf Hilfe gehen, dann steht dort irgendwo "install new profile" und dieses Profil beispielsweise headless_profil nennen und zuletzt kann dann endlich mit einem Terminal-Befehl ein Screenshot erstellt werden | |||
/pfad/zu/firefox -P headless_profile -headless --screenshot <hier die www-Adresse der Webseite angeben> | |||
Mehr dazu auf [https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode dieser Webseite] | |||
==== Zweiter Schritt: Senden mit Telegram ==== | ==== Zweiter Schritt: Senden mit Telegram ==== |
Aktuelle Version vom 29. April 2023, 19:00 Uhr
Einführung
Die Grafana-Software stellt einen Server zur Verfügung, mit dem Zeitreihen von Zahlenwerten auf sehr handliche Weise dargestellt und manipuliert werden können. Die Auswahl bestimmter Zeitfenster, das Anlegen von Dashboards und die Gestaltung der Achsen (Minimum. Maximum) ist so sehr einfach möglich. Zudem gibt es verschiedene Paneltypen, die neben dem klassischen Chart (Line / Bar / Point) auch Pie Charts oder Tabellen beinhalten. Seit November 2017 kann Grafana mit MySQL umgehen, was eine Einbindung in FHEM (via DBLog) ermöglicht. Die Benutzeroberfläche lädt sehr schnell und ist auf vielen Geräten flüssig und einfach zu bedienen.
Installation
Hier sind mehrere Schritte (einmalig) durchzuführen. Für Grafana muss ein eigener Server installiert werden und für die Grafiken müssen MySQL-Queries angelegt werden.
Installation und Einrichtung einer DBLog Instanz mit MySQL
Details sind auf der Seite Anlegen einer MySQL_Datenbank beschrieben.
Wenn schon eine Datenbank angelegt wurde und man Daten umziehen muss, helfen andere Einträge weiter. Sollen zum Beispiel Altdaten aus SQLite gesichert und wieder in MySQL eingespielt werden, hilft dieser Eintrag. Dieses Beispiel sichert nur Logdaten für ein einzelnes Gerät und nicht für alles aus der DB. Das lässt sich aber problemlos anpassen, indem man das Attribut device in der DBRep Instanz nicht belegt.
Ein Umstieg von Filelog auf DBLog geht ebenfalls. Sollen Altdaten aus den Filelogs übertragen werden, hilft dieser Thread.
Installation des Grafana Servers
Es gibt einen offiziellen Download. Der ist nicht ganz unproblematisch, und will man auf einem Raspberry Pi installieren, sollten eher vorkompilierte Pakete genutzt werden. Sie sind unter diesem Link zu finden.
Damit Grafana automatisch mit dem System startet, muss der Grafana Server noch aktiviert werden. Bei Verwendung von Systemd wäre das mit folgendem Befehl zu erledigen:
sudo /bin/systemctl enable grafana-server
Im Grafana Webinterface muss dann eine neue Datasource vom Typ MySQL angelegt werden. Die Daten der FHEM-MYSQL Datenbank eintragen (Port/User/Passwort).
Grafana lauscht per default auf Port 3000. Dies kann ein Problem sein, falls man Alexa mit Custom Skill nutzt. Dieser Dienst belegt ebenfalls schon Port 3000. In dem Fall mit
sudo nano /etc/grafana/grafana.ini
und die Konfiguration anpassen:
;http_port = 3000
Hier den führenden Semicolon entfernen und den Port entsprechend abändern. Zuletzt ist die Datenbank auszuwählen, in der die Daten von FHEM abgelegt sind (grafana greift standardmäßig auf eine Datenbank mit dem Namen grafana zurück).
Erstellen von Grafiken
MySQL-Queries
Zeitreihen werden in Grafana durch MySQL-Queries angelegt. Jede Zeitreihe benötigt dabei einen eigenen Query. Grafana legt dabei einen Musterquery an, bei dem drei Werte geändert werden müssen.
Man klickt im Dashboard von Grafana auf AddRow. Durch einen Klick auf den Titel der neuen Grafik erscheint ein Menü ("View", "Edit", "Share") und wählt Edit. Dann wählt man die FHEM-Datenbank aus, siehe Screenshot. Eine Musterabfrage sieht wie folgt aus:
SELECT
UNIX_TIMESTAMP(< time >) as time_sec,
< column > as value,
< name > as metric
FROM < table name >
WHERE $__timeFilter(time_column)
ORDER BY < time > ASC
Grafana benötigt in diesem Query mindestens drei Spalten mit der richtigen Benennung, die durch <>-Klammern vorgezeichnet sind.
- time_sec muss Zeitwerte im UNIX-Timestamp Format (Sekunden seit 01.01.1970) enthalten. Meist wählt man für < time > daher den TIMESTAMP Eintrag aus der Datenbank.
- value muss Werte für die Y-Achse liefern, welche den Zeitstempeln aus time_sec zuzuordnen sind. Meist wählt man für < column > daher den VALUE Eintrag aus der Datenbank.
- metric ist der Text, der für die Kurve in der Legende angezeigt wird. Daher ist < name > frei wählbar.
Die Namen der einzelnen Spalten werden durch FHEM selbst vergeben. Man muss also bei der Verwendung der Queries herausfinden, wie die Werte intern gespeichert werden. Das klingt schwerer als es ist, weil sich FHEM dabei an Konventionen hält, die leicht geraten werden können. Der nebenstehende Screenshot zeigt einen typischen Eintrag in der DBLog von FHEM.
Beim den VALUE Einträgen von FHEM muss man beachten, dass diese (da sie auch Text beinhalten können) nicht numerisch sind. Soll schon intern im SELECT eine Berechnung durchgeführt werden wie AVG oder MIN/MAX, dann muss man hier CONVERT(VALUE, DOUBLE) oder CONVERT(VALUE, INTEGER) verwenden.
Ein Beispieleintrag sieht wie folgt aus
SELECT
UNIX_TIMESTAMP(TIMESTAMP) as time_sec,
VALUE as value, "Kurvenbezeichnung" as metric
FROM history WHERE READING="state" AND DEVICE="MyDummy" AND $__timeFilter( TIMESTAMP )
Solltet Ihr numerische Werte in einer Grafik ausgeben wollen, müsst Ihr das Text-Feld VALUE mittels cast(VALUE as signed) konvertieren
SELECT
UNIX_TIMESTAMP(TIMESTAMP) as time_sec,
cast(VALUE as signed) as value, "Kurvenbezeichnung" as metric
FROM history WHERE READING="state" AND DEVICE="MyDummy" AND $__timeFilter( TIMESTAMP )
Macros
Grafana bietet ein paar Macros die man in den MySQL Selects verwenden kann, um die zu ladenden Daten auf den angezeigten Zeitraum zu begrenzen.
- $__timeFilter(TIMESTAMP) liefert eine Überprüfung auf einen Zeitraum zurück, die man in der WHERE Bedingung verwenden kann (siehe obiges Beispiel)
- $__timeFrom() liefert den Startzeitpunkt des angezeigten Zeitraums als "YYYY-MM-DD HH:MM:SS" zurück.
- $__timeTo() liefert den Endzeitpunkt des angezeigten Zeitraums als "YYYY-MM-DD HH:MM:SS" zurück (so loggt auch DBLog in die Datenbank).
- $__unixEpochFrom() liefert den Startzeitpunkt des angezeigten Zeitraums als UNIX-Timestamp Format (Sekunden seit 01.01.1970) zurück.
- $__unixEpochTo liefert den Endzeitpunkt des angezeigten Zeitraums als UNIX-Timestamp Format (Sekunden seit 01.01.1970) zurück.
Beispiele
Sehr viele Beispiele hat Thyraz in diesem Foreneintrag bereitgestellt. Eine ausführliche Erläuterung zu einen Anzeige von Differenzwerten finden sich in diesem Foreneintrag.
Einbindung in FHEM (und andere Seiten)
Die Grafiken können mit einem URL einfach in FHEM und andere Seiten eingebunden werden. Die entsprechende Adresse lautet dann
http://<URL-Grafana-Server>:3000/render/dashboard/db/<Name-des-Dashboards>?orgId=2&from=now%2Fd&to=now&panelId=1&width=750&height=300&tz=UTC%2B02%3A00
Dabei ist der Teil der URL from=now%2Fd&to=now individuell veränderbar. Standardmäßig sind das fixe Zeitpunkte (wie im Beispiel mit 1507705926296). Mit "Now" etc. kann man das dynamisch gestalten und so einen alternativen, dynamischen Plot im FHEM darstellen:
- from=now%2Fd&to=now: Today so far
- from=now-30d&to=now: Die letzten 30 Tage
- from=now-395d&to=now-365d: Die letzten 30 Tage vor einem Jahr (Temperaturvergleich zum Vorjahr z.B.)
Das entsprechende device, das in FHEMWEB die Grafik zur Verfügung stellt, ist dann weblink:
defmod <device_name> weblink image <HTTP-Adresse>:3000/render/dashboard-solo/db/<Datenbankname>?orgId=2&from=now%2Fd&to=now&panelId=1&width=750&height=300&tz=UTC%2B02%3A00
Entsprechende Attribute sind auch möglich:
attr <device-name> htmlattr width="750" height="300" frameborder="0" title="Aktueller Verlauf"
Bei FTUI würde man das Image Widget verwenden. Will man die Grafiken mit iframe einbinden, so muss zuerst in Grafana eine Sicherheitseinstellung verändert werden, die eigentlich eine solche iframe-Einbindung verhindert. Dazu fügt man im Security-Abschnitt der grafana.ini folgende Zeile ein
[security] allow_embedding = true
und startet danach den grafana-server neu.
Speichern und Senden von Grafiken (z.B. mit Telegram)
Will man Grafiken von Grafana mit Telegram oder anderen Messenger-Programmen versenden, sind mehrere Schritte notwendig. Zuerst muss die Datei "gerendert" und lokal gespeichert werden, danach kann man sie versenden. Da das Rendern mehrere Sekunden dauern kann, sollte dieser Vorgang entweder nonblocking oder sogar außerhalb von FHEM erfolgen.
Erster Schritt: Rendern
Grafana verwendet eine Authentifizierungsmethode, die beim Rendern zu berücksichtigen ist. Tut man das nicht, so erhält man keine Grafik, sondern nur eine HTML-Datei die eben anzeigt, dass der Zugriff nicht authentifiziert erfolgte. Um sich zu authentifizieren, muss man einen neuen Nutzer anlegen und einen API-Key anfordern.
Im Hauptmenü von Grafana wählt man links oben unter "admin" den Eintrag API-Key aus. Dort legt man einen neuen Benutzer an und notiert sich den Schlüssel (er wird nur einmal angezeigt). Dieser Schlüssel ist eine sehr lange Zeichenkette, beispielsweise "0NWcWRCVjZtSkd81NG1EOEprdVYxRUJtZWZeyJrIjoidUNycWRCVjZtSkd0NW81NGX0=". Im Folgenden möge die Zeichenkette mit <Schluessel> bezeichnet werden.
Mit dieser Authentifizierungsschlüssel kann man nun auf Grafana zugreifen. Beispielsweise möchte man ein dashboard, das mehrere Temperaturen enthält, rendern. Dazu benötigt man nun die Zugriffsadresse dieses Dashboards. Man klickt auf die Überschrift des Boards und wählt "Share" aus. Es erscheint ein Share Panel, so wie im Screenshot angezeigt.
Unten im Panel ist ein Link mit den Worten "Direct link rendered image" zu sehen. Diesen Link notiert man. Im folgenden möge der Link mit <Link> bezeichnet werden.
Auf der Shell-Ebene würde nun der folgende Befehl das Dashboard rendern und speichern
curl -H "Authorization: Bearer <Schluessel>" "<Link>" <Dateiname>
Da in der neuen Grafana-Version das Rendern auf einem Raspberry Pi nicht ohne Weiteres unterstützt wird, kann es sein, dass die oben genannten Versuche fehlschlagen. Hier bietet sich eine andere Lösung an, die zwar nicht so elegant wie die obige ist, aber dafür funktioniert: Man installiert Firefox auf dem Raspberry und lässt ihn "headless" einen Screenshot erstellen. Dieses kann man dann weiterverarbeiten. Diese Lösung hat den Nachteil, dass dann nur die Auflösung des Raspberry erreicht wird. Dazu sind folgende Schritte noztwendig. Zuerst Firefox installieren
sudo apt install firefox-esr
danach ein neues Profil in Firefox erstellen (sonst stürzt Firefox ab), das ist sehr umständlich: Auf Hilfe gehen, dann steht dort irgendwo "install new profile" und dieses Profil beispielsweise headless_profil nennen und zuletzt kann dann endlich mit einem Terminal-Befehl ein Screenshot erstellt werden
/pfad/zu/firefox -P headless_profile -headless --screenshot <hier die www-Adresse der Webseite angeben>
Mehr dazu auf dieser Webseite
Zweiter Schritt: Senden mit Telegram
Im zweiten Schritt soll nun die Datei gesendet werden. Dazu kann man etwa den Telegram-Bot verwenden. Der Sendebefehl lautet
set <TelegramBotDevice-Name> sendImage <Dateiname>
Dabei ist der Dateiname des Bild (png-Format) anzugeben.