CSV-Datei als FHEM-Reading einlesen

INFO: Folgende Anleitung bezieht sich auf CSV-Dateien, welche sich lokal auf dem Raspberry befinden. Befinden sich die CSV-Dateien im Netzwerk, empfehle ich euch den Beitrag von Ingo Buerfeind.

Immer mehr Hersteller implementieren in ihren Geräten eine Funktion zum Auslesen von Messwerten. Sei es eine Solaranlage oder eine Heizung. Einige Geräte besitzen dafür eine hübsche Weboberfläche. Andere dagegen erlauben das Downloaden der Messwerte als CSV-Datei. Um solche Geräte soll es in diesem Blogbeitrag gehen. Ich werde euch zeigen, wie ihr eine CSV-Datei in FHEM einliest und die Werte als Reading abspeichern könnt. 

Vorbereitung

Ich habe mich dazu entschieden, die Perl-Erweiterung "Text::CSV:Slurp" zu verwenden. Es gibt sicherlich Möglichkeiten, die ohne zusätzliche Erweiterungen auskommen. Sollen jedoch große CSV-Dateien eingelsen werden, kann es oft zu Problemen oder Leistungseinbußen kommen. 

Bevor man also mit dem eigentlichen Einlesen in FHEM beginnen kann, muss die Erweiterung "Text::CSV::Slurp" installiert werden. Dazu einfach per SSH auf euren Raspberry einloggen und folgenden Befehl ausführen.

perl -MCPAN -e'install Text::CSV::Slurp'

Die Installation dauert ein wenig, also nicht wundern. Nachdem die Erweiterung installiert wurde, kann mit der Einrichtung in FHEM begonnen werden.

Einrichtung in FHEM

Damit später aus jedem Device das Einlesen einer CSV-Datei gestartet werden kann, wird die Code dafür in eine Routine ausgelagert. Wie ihr eine Routine anlegt könnt ihr in meinem Blogbeitrag nachlesen. 

##################################################################
# Routine zum Einlesen einer CSV-Datei

#!/usr/bin/perl

package main;

use strict;
use warnings;
use POSIX;
use strict;
use warnings;
use Text::CSV::Slurp;

sub readCSVUtils_Initialize($$)
{
my ($hash) = @_;
}

####################################################################
sub readCSV ($$)
{

my ($csvDatei, $Spalte) = @_;
my $slurp = Text::CSV::Slurp->new();

my $Wert;
my $Datum;

# CSV Options - see Text::CSV
my %csv_options = (
sep_char => ';',
binary => '1',
);

# Reference to an array of hashes
my $data = $slurp->load( file => $csvDatei, %csv_options );

foreach my $row (@$data) {
 $Wert = $row->{$Spalte};
}

return $Wert
}
1;

Die Routine "readCSV" verlangt zwei Übergabewerte. Zum einen den Pfad zur CSV-Datei und zum anderen die gewünschte Spalte. Die Routine gibt dann den letzten Wert der gewünschten Spalte als Rückgabewert zurück.

Beispielanwendung - Tagesertrag vom Kaco Wechselrichter

Im folgenden werde ich euch ein Anwendungsfall als Beispiel zeigen. Zum Beispiel ein Wechselrichter der Marke Kaco erlaubt das Auslesen der Tageserträge (in Wh) als CSV-Datei. Die Datei hat folgenden Inhalt:

Hier erkennt man ab Zeile 4 die Tageserträge. Getrennt werden die Einträge in der Datei durch ein ";". In der Routine ist dies ebenfalls angegeben " sep_char => ';' " Sollte eure CSV zum Beispiel ein Komma als Trennungszeichen verwenden, könnt ihr dies in der Routine anpassen. 

Man kann nun vermuten, dass die Spalte mit den Werten den Namen "E[Wh]" hat. Durch den Aufbau der CSV-Datei ist dies jedoch nicht der Fall. Die Spalte mit den Datum hat den Namen "WR-Type" und die Spalte mit den Werten "Seriennummer". Möchte man nun also den Ertragswert vom letzten Eintrag haben, so ruft man die Routine wie folgt auf:

{readCSV("/opt/fhem/201710.csv","Seriennummer")}

Es wird nun die CSV-Datei für den Monat Oktober geladen und der letzte Eintrag der Spalte "Seriennummer" als Rückgabewert zurückgegeben. In diesem Fall als der Ertragswert in Wh vom 19.10.2017. 

Info: Die CSV-Datei muss vorher auf den Raspberry geladen werden. Dies kann entweder manuell erfolgen oder automatisch durch ein entsprechendes Script.

Damit nun alles automatisch gemacht wird, kann man sich nun noch ein at-Device einrichten. Zunächst erstmal die Grunddefinition des at-Devices:

define readCSVat at *00:05:00 a

Das at-Device wird nun jedesmal um 5 Minuten nach Mitternacht aufgerufen. Damit ist sichergegangen, dass das gewünschte CSV-File bereits mit dem Ertragswert der Vortages aktualisiert wird. Die Definition des at-Device wird nun über den DEF-Editor angepasst:

*00:05:00 {
my $CSVstring;;
my $Wert;;
my $csvMonth;;

if ($mday == "1") {
$csvMonth = $month-1;;
if ($csvMonth < "10") {$csvMonth = "0".$csvMonth;;}}
else {
 $csvMonth = $month;
  if ($csvMonth < "10") {$csvMonth = "0".$csvMonth;;}}

$CSVstring = "http://192.168.1.12/2017".$csvMonth.".csv";;
$Wert = readCSV($CSVstring,"Seriennummer");;
fhem("setreading WechselrichterErtrag Ertrag $Wert");;

}

Innerhalb des at-Devices wird zunächst überprüft ob aktuell der 1. eines Monats ist. Ist dies der Fall, wird die  Monatsvariable - 1 genommen, damit der letzte Wert aus der Vormonats-CSV genommen wird. Ist nicht der 1. eines Monats wird der aktueller Monat verwendet. Danach wird der Dateinamen abhängig vom gewünschten Monat generiert. 

Durch die Routine erhält man nun in der Variable ($Wert) den Ertrag des Vortages. Diese kann nun verwendet werden um zum Beispiel ein Reading eines Dummys zu setzen. Wie in diesem Fall das Dummy "WechselrichterErtrag".

Durch ein Logdevice (zum Beispiel dbLog) kann man nun den Wert des Dummys jeden Tag in eine Datenbank schreiben und kann zum Beispiel durch SVGPlots seinen Ertrag visuell darstellen.

Achtung: Das oben beschriebene atDevice verwendet immer das Jahr 2017. Entweder ihr passt das Device im nächsten Jahr an oder ihr bastelt euch innerhalb des atDevice eine Abfrage.

Ich hoffe ich konnte euch verständlich erklären, wie man in FHEM eine CSV-Datei einliest und euch inspirieren dies selber auf eure Wünsche anzupassen und umzusetzen. Mit ein paar Anpassungen kann man natürlich relativ einfach die Routine nach seinen Wünschen anpassen. Zum Beispiel das Auslesen von mehreren Spalten oder das gleichzeitige Abspeichern des Datums.

5
Hinterlasse einen Kommentar

avatar
Fotos und Bilder
 
 
 
sonstiges Dateiformat
 
 
 
4 Comment threads
1 Thread replies
2 Followers
 
Most reacted comment
Hottest comment thread
3 Comment authors
DanielIngoNorman Recent comment authors
  Subscribe  
neuste älteste beste Bewertung
Benachrichtige mich zu:
Norman
Gast
Norman

Hi, Bei mir wird aller 30sec ein eintrag in eine Tageslog CSV geschrieben. wie kann ich denn alle Einträge der Datei mit dem namen des aktuellen Datums mit einmal einlesen?

Ingo
Gast
Ingo

Hi Daniel,

super Beitrag. Leider klappt es aber nicht mit dem Abruf der csv, da Du wohl mit einer lokalen csv getestet hast, vom Server wird aber der Pfad nicht gefunden. Wie bereits per Mail diskutiert, hast Du dafür bisher leider auch keine Lösung. Wäre schon wenn du dies hier auch schreiben würdest, damit nicht alle in die falsche Richtung laufen und sich wundern.

Ingo
Gast
Ingo

Hi Daniel, seit kurzem scheint die Methode mit slurp und der Routine nicht mehr zu gehen. Habe am Code nichts geändert. Hast Du eine Idee? 2018.01.05 13:51:31 1: reload: Error:Modul 99_readCSVUtils deactivated: Can’t locate IO/Scalar.pm in @INC (you may need to install the IO::Scalar module) (@INC contains: . /etc/perl /usr/local/lib/arm-linux-gnueabihf/perl/5.20.2 /usr/local/share/perl/5.20.2 /usr/lib/arm-linux-gnueabihf/perl5/5.20 /usr/share/perl5 /usr/lib/arm-linux-gnueabihf/perl/5.20 /usr/share/perl/5.20 /usr/local/lib/site_perl ./FHEM) at /usr/local/share/perl/5.20.2/Text/CSV/Slurp.pm line 8. BEGIN failed–compilation aborted at /usr/local/share/perl/5.20.2/Text/CSV/Slurp.pm line 8. Compilation failed in require at ./FHEM/99_readCSVUtils.pm line 13. BEGIN failed–compilation aborted at ./FHEM/99_readCSVUtils.pm line 13. 2018.01.05 13:51:31 1: Including fhem.cfg 2018.01.05 13:51:31 1: reload: Error:Modul 99_readCSVUtils deactivated: Attempt to reload Text/CSV/Slurp.pm aborted.… weiterlesen »

Ingo
Gast

Hallo Daniel, habe eine Lösung ohne Routine mit wget gefunden: http://www.buerfeind.de/fhem-csv-datei-als-reading-einlesen/