sub AMAD_Parse($$) {
my($name,$valuestring) = @_;
my @array=split('@@',$valuestring);
foreach (@array){fhem("setreading $name $_\n");}
}
Wie kann ich hier ein readingsupdate mit dem empfohlenen readingsBeginUpdate, readingsBulkUpdate, readingsEndUpdate machen.
Leider weiß ich nicht wie viele Readings in der Tat reinkommen, daher die foreach Schleife.
Grüße
Leon
Hallo Leon,
wenn du in einem Modul bist, das seine eigenen Readings ändert, solltest du generell statt
{fhem("setreading $name $_\n");}
besser
readingsSingleUpdate($hash, $readingName, $readingValue, 1);
verwenden.
Dann ist auch der Umbau nicht mehr schwer. Zunächst solltest du den split so machen, dass du readingName und readingValue getrennt bekommst, indem du sie in einer Hash-Variablen pufferst. Anschließend kannst du folgendes machen:
readingsBeginUpdate($hash);
while (($t, $v) = each %buffer) {
readingsBulkUpdate($hash, $t, $v) if (defined($v));
}
readingsEndUpdate($hash, 1);
Hast du den Modul-Hash nicht, aber bist zumindest in FHEM, kannst du ihn dir im Normalfall so holen:
my $hash = $defs{$name};
wobei $name der Modul-Instanzname ist.
LG, Jens
Hallo Jens,
Vielen Dank für Deine Antwort.
Ja ich bin in einem Modul welches seine eigenen Readings ändert. Es ist ein Modul was ich selber schreibe. Eigentlich habe ich keine Ahnung von FHEM Development und nur bedingt von Perl. Aber pah hat mal zu mir gesagt "keine Ahnung hatten wir alle mal, das ist keine Ausrede". Tja und nun sitze ich hier und pauke. Das besondere an dem Modul ist, so denke ich, das es seine Readings nicht holt sonder ungefragt zugesendet bekommt. Per http request mittels ?cmd=.
Das mit dem buffer hatte ich auch schon gelesen und auch probiert. Leider hatte ich Fehler bekommen. ein readingsSingleUpdate wäre nicht gut, da ja die Menge der zu aktualisierenden Readings unbekannt ist. Auf jeden Fall immer mehr wie eines, min 2.
Hier mal mein Modul, bitte nicht so genau auf die Funktionen achten, einige liegen nur brach da für später.
##############################################
# $Id: 98_AMAD.pm 8809 2015-07-21 11:09:00Z leongaultier $
package main;
use strict;
use warnings;
sub
AMAD_Initialize($)
{
my ($hash) = @_;
$hash->{DefFn} = "AMAD_Define";
$hash->{UndefFn} = "AMAD_Undef";
$hash->{AttrFn} = "AMAD_Attr";
$hash->{ParseFn} = "AMAD_Parse";
$hash->{AttrList} = "readingList setList interval ". $readingFnAttributes;
}
###############################################################################
sub
AMAD_Define($$)
{
my ($hash, $def) = @_;
my $name = $hash->{NAME};
my @a = split("[ \t][ \t]*", $def);
return "Wrong syntax: use define <name> AMAD <IP>" if(int(@a) < 3);
$hash->{".host"} = $a[2];
return undef;
}
################################################################################
sub AMAD_Undef($$)
{
my ($hash, $arg) = @_;
RemoveInternalTimer($hash);
if(defined($hash->{helper}{RUNNING_PID}))
{
BlockingKill($hash->{helper}{RUNNING_PID});
}
return undef;
}
################################################################################
sub AMAD_Attr($$)
{
my ($cmd,$name, $attrName,$attrVal) = @_;
my $hash = $defs{$name};
if ($cmd eq "set") {
if ($attrName eq "interval")
{
if (int($attrVal) < 2) {$attrVal="5";}
$hash->{".interval"} = $attrVal;
$attr{$name}{interval} = $attrVal;
}
}
return undef;
}
###############################################################################
sub AMAD_Parse($$) {
my($name,$valuestring) = @_;
my @array=split('@@',$valuestring);
foreach (@array){fhem("setreading $name $_\n");}
}
################################################################################
# Funktion welche von Automagic über http request aufgerufen wird und Infos überträgt
sub pushAutomagicInfo($$) {
my($name,$valuestring) = @_;
AMAD_Parse($name,$valuestring);
}
################################################################################
1;
Also das eigentliche Programm auf dem Handy oder Tablet heißt Automagic. Diverse Trigger stoßen unterschiedliche Flows an, welche Daten einsammeln und diese dann in Form von
http://fhem.local/fhem?cmd={pushAutomagicInfo('Device,readingName1 $reading1@@readingName2 $reading2....')}
sendet.
Die Funktion pushAutomagicInfo nimmt nur entgegen und gibt die Werte sofort weiter an die Funktion AMAD_Parse, welche dann entsprechend die Readings setzen soll.
So nun werde ich mal versuchen Deine Tips zu verinnerlichen und meine Funktion entsprechend an zu passen.
Kann ich mich wieder melden wenn ich nicht weiter komme? Also falls Du Lust und Zeit hast und ich tausend Fragen. Ich will das wirklich lernen.
Grüße
Hallo Leon,
du kannst gerne weiter Fragen stellen, ich werde Antworten, so gut ich kann. Habe mich selbst mit Trial and Error an die Sache heran getastet und inzwischen schon einen kleinen Überblick über die Möglichkeiten.
Die _Parse-Funktion ist normalerweise eine spezielle Funktion mit vordefinierter Parameterliste, da sie von anderen Modulen aufgerufen werden kann (z.B. vom Telnet-Server, wenn er Daten empfängt). Da du sie nur intern mit eigener Parameterliste verwendest, solltest du sie nicht in der _Initialize-Funktion als ParseFn registrieren. Funktionieren wird das aber auch ohne die Änderung.
LG, Jens
Hallo,
Ich hatte das ganze vorher ohne Pars. Wusste nicht was das genau soll. Klang nur gut für mich als ich das gelesen hatte. Bleiben wir beim kleinsten gemeinsamen.
Och habe ein Modul was ich definieren und un-definieren kann. Ausserdem kann ich Attribute vergeben. Das mache ich mit den entsprechenden dafür vorgesehenen FHEM eigenen Funktionen.
Ich habe eine eigene Funktion, welche so aus schaut
sub pushAutomagicInfo($$) {
my ($name, $pushstring) = @_;
my $hash = $defs($name);
my ($t,$v) = split('@@','@@'$pushstring);
readingsBeginUpdate($hash);
while (($t, $v) = each %buffer) {
readingsBulkUpdate($hash, $t, $v) if (defined($v));
}
readingsEndUpdate($hash, 1);
}
Diese wird von extern aufgerufen. Mehr will ich erstmal nicht. Die Feinheiten kommen später. Die Funktion wird aufgerufen und Werte werden übergeben. Die Funktion verarbeitet die Werte und soll dann entsprechend der Werte die Readings setzen. Das alles soll erstmal die eine Funktion machen.
Ich habe noch Probleme mit dem Code. Ein Reload bringt folgende Fehlermeldung
Global symbol "$defs" requires explicit package name at ./FHEM/98_AMAD.pm line 74.
syntax error at ./FHEM/98_AMAD.pm line 74, near "$defs("
syntax error at ./FHEM/98_AMAD.pm line 75, near "'@@'$pushstring"
Global symbol "$hash" requires explicit package name at ./FHEM/98_AMAD.pm line 77.
Global symbol "%buffer" requires explicit package name at ./FHEM/98_AMAD.pm line 78.
Wo und wie definiere ich $defs ?
Sind bestimmt voll die Basics :-[
Hallo Leon,
da sieht für mich aus wie 2 Tippfehler:
Z74: my $hash = $defs{$name};
Z75: my ($t,$v) = split('@@', $pushstring);
$defs wird von FHEM global definiert, deshalb kannst du einfach darauf zugreifen.
LG, Jens
Ah ok das habe ich verstanden. Ich danke Dir
Aber wieso eigentlich nur
split('@@', $pushstring);
@@ soll mein Trenner sein und keine Variable. das sieht so aus
('$device',readingname1 reading1@@readingname2 reading2@@...')
Wie kann ich jetzt mein $t und mein $v da rausbekommen?
Und ich habe noch ein
Global symbol "%buffer" requires explicit package name at ./FHEM/98_AMAD.pm line 78.
Hi Leon,
mein letzter Vorschlag behebt nur den Syntax-Error, aber er löst noch nicht die Aufgabe. Wollte dir noch etwas Arbeit lassen. :D
Das ganze wird so nicht gehen, aber vielleicht etwa so:
my @pairs = split('@@', $pushstring);
my %buffer;
foreach (@pairs ) {
my @pair = split(' ', $_);
$buffer{$pair[0]} = $pair[1];
}
Damit hast du die Readings im %buffer und kannst weitermachen.
LG, Jens
supi damit komme ich weiter. aber ich denke ich werde statt einem leerzeichen einen selbst definierten 2. Trenner nehmen. Denn es kann auch mal vor kommen das ein Readingwert ein Leerzeichen hat. Da würde er ja dann falsch splitten oder?
PS: Mega DANK für Deine Geduld ;D
Kein Thema, freut mich dass es geholfen hat.
Wenn du ein Leerzeichen in den Nutzdaten haben kannst, dann nimm einen anderen Trenner (z.B. "=").
Willst du aber beliebige Nutzdaten transportieren, muss du schon beim Eintüten ein zusätzliches Escapezeichen wählen (z.B. "\") und es in den Nutzdaten vor jeden Trenner schreiben. Dann kannst du den Trenner "=" und einen Trenner in den Nutzdaten "\=" unterscheiden. Hast du ein Escapezeichen in den Nutzdaten, muss auch das gedoppelt werden. Das macht das Parsen hinterher natürlich nicht leichter, aber zumindest eindeutig.
LG, Jens
Guten Morgen,
Ich musste gestern abbrechen, Kopfaua ;D
Ich habe jetzt mal versucht unsere Ausarbeitungen zusammen zu bringen. Und zwar eins zu eins so wie Du es geschrieben hast. Ich denk mal beim verstehen und zusammen setzten habe ich bestimmt murx gemacht.
Das ist jetzt meine Funktion
sub pushAutomagicInfo($$) {
my ($name, $pushstring) = @_;
my $hash = $defs{$name};
my @pairs = split('@@', $pushstring);
my %buffer;
foreach (@pairs) {
my @pair = split(' ', $_);
$buffer{$pair[0]} = $pair[1];
}
readingsBeginUpdate($hash);
my $t;
my $v;
while (($t, $v) = each %buffer) {
readingsBulkUpdate($hash, $t, $v) if (defined($v));
}
readingsEndUpdate($hash, 1);
}
Und das kommt als Fehler
Not enough arguments for main::pushAutomagicInfo at (eval 67330) line 1, near "'automagicNexus5Marko,powerLevel 65@@powerPlugged 1')"
Es fehlt der Zusammenhang von
$buffer{$pair[0]} = $pair[1];
und $t $v, sehe ich das Richtig.
Hi Leon,
ZitatNot enough arguments for main::pushAutomagicInfo
bedeutet, dass du diese Funktion mit keinem oder nur einem Argument aufgerufen hast, aber sie erwartet ja nun mal zwei, wegen des
($$).
LG, jensb
Juhu,
Ich werde irre das funktioniert. Hammer es geht. Frreuuuuuuu. Luftsprung
Melde mich wenn ich verstanden habe wieso das geht. lach
LG
Ok soweit blicke ich da durch. Muss unbedingt viel mehr Perl lesen.
Aber eines verstehe ich noch nicht
$buffer{$readings[0]} = $readings[1];
dem Skalar buffer wird das erste Element von readings zugewiesen aber was bedeutet = $readings[1] und wieso die geschweiften klammern {$readings[0]}
%buffer ist eine Hash-Variable
mit $buffer{key} kann man auf einen gehashten Wert zugreifen (mit key = String), die {} sind die Zufgriffsoperatoren für Hashes
@readings ist eine Array-Variable
mit $readings[n] kann man auf die Werte zugreifen (mit n ab 0), die [] sind die Zugriffsoperatoren für Arrayelemente
LG, Jens
Hallo Jens,
Ich danke Dir für Deine Erklärungen. Das wird ne lange Busheimfahrt mit viel Buch lesen ;D
Die nächsten Tage schaue ich dann mal wie ich mein Modul erweitern kann. Als nächstes kommen SET Funktionen. Ich will Automagic mittels http request (HttpUtils) einen String zur Verarbeitung senden.
Mal schauen wie weit ich da komme.
LG
Leon