Hauptmenü

Array

Begonnen von MisterEltako, 14 Februar 2013, 23:23:15

Vorheriges Thema - Nächstes Thema

MisterEltako

Hi!

Ich bastle gerade etwas mir Array's herum, um auszuprobieren, wie man sie besser einsetzen kann.
Dabei bin ich aufolgendes Problem gestoßen:

Wie kann man in Perl oder Fhem abfragen, ob ein Array angelegt wurde???
Und wenn nicht, möchte ich es anlegen.


mit:
if ( not defined @@Array) {\
   my @@Array=("");;\
}


erhalte ich bei meinen Versuchen bisher immer:
defined(@array) is deprecated at (eval 1785) line 1.
   (Maybe you should just omit the defined()?)
2013.02.14 23:37:22 3: Speicher return value: Global symbol "@Array" requires explicit package name at (eval 1785) line 1.
Missing right curly or square bracket at (eval 1785) line 2, at end of line
syntax error at (eval 1785) line 2, at EOF


MfG, MisterEltako.
HMLAN-Konfigurations-Adapter, HM-Funkjalousieaktor/HM-Dimmaktor/HM-Schaltaktor f. Markenschalter, Jalousie-/Schaltaktor von Eltako, FT4 v. Eltako, TCM310

Reinerlein

Hi MisterEltako,

also die Meldung mit dem Deprecated sorgt zumindest nicht für den Abbruch. Das ist nur ein Hinweis.

Aber das folgende dahinter ist wichtig.
Das Array muss erst mittels "my" angelegt werden:

my @@Array;\
# Array füllen oder belegen...\
if (!defined(@@Array)) {\
    @@Array=("");;\
}

Wenn das Array einmal angelegt wurde, kannst du es nicht nochmal mittels my anlegen. Das hat aber nichts mit einem etwaigen Verwenden zu tun...

Unter http://www.tizag.com/perlT/perlarrays.php z.B. findest du ein paar Hinweise zur Verwendung von Arrays.

Allgemein würde ich dir empfehlen, der besseren Lesbarkeit wegen, die Verwendung von Perl-Code in ein 99er-Modul auszulagern.

Grüße Reinerlein

MisterEltako

Danke für die Hinweise!

Testvorhaben:

ich will 3 letzte Temperaturwerte eines Sensors in ein Array speichern.
Das habe ich auch hinbekommen, aber wenn das Array in der Abfragefunktion immer mit "my @@Array" angelegt wird kann ich ja keine Elemente mit "push" zu bestehenden hinzufügen, sondern fange wieder mit leerem Array an.

Also will ich abfragen ob:

Array da ist -  dann "push Element.."
Array noch nicht da - dann "my @Array ..."

MfG, MisterEltako.
HMLAN-Konfigurations-Adapter, HM-Funkjalousieaktor/HM-Dimmaktor/HM-Schaltaktor f. Markenschalter, Jalousie-/Schaltaktor von Eltako, FT4 v. Eltako, TCM310

Reinerlein

Hi MrEltako,

und genau das geht nicht ohne den Code auszulagern...

ein Notify in FHEM wird, grob gesagt, in einem eval-Kontext ausgeführt, und du brauchst etwas "übergeordnetes", um deine Variable zum nächsten Aufruf rüberzuretten.

Ein 99er Modul wird einmal zu Anfang geladen. Dabei kannst du dein Array anlegen lassen, sozusagen als "Modul-globale" Variable.
Bei jedem Notify rufst du eine Sub-Prozedur auf, die in dem Modul von dir definiert wurde. Dort hast du dann Zugriff auf diese Variable, und kannst sie verändern und verwenden...

z.B.:

.
.
my @oldTempValues;

sub notifyProcedure($) {
  my ($value) = @_;

  push @oldTempValues, $value;

  foreach $tempElem (@oldTempValues) {
    # Do Something interesting here...
  }
}
.
.


Der Code soll dir natürlich nur einen Anhaltspunkt liefern...

Grüße Reinerlein

MisterEltako

Hi Reinerlein!

Danke, das war das was ich suchte!!!

Ich habe es jetzt so gelöst:

in Fhem.cfg:
define 3_LetzteTemperatur dummy
attr 3_LetzteTemperatur room Array
define 2_VorletzteTemperatur dummy
attr 2_VorletzteTemperatur room Array
define 1_DrittletzteTemperatur dummy
attr 1_DrittletzteTemperatur room Array

define Temp dummy
attr Temp room Array

define Speicher notify Temp:.* {\
my $PP = Value("Temp");;\
Tempspeicher($PP);;\
}


in 99_myUtils:
my @Speicher=("na","na","na");

sub Tempspeicher($){
my ($P)=@_;
my $delTemp=shift(@Speicher);
push (@Speicher,$P);
Log 1, "@Speicher";
my $Temp3=@Speicher[-1];
my $Temp2=@Speicher[-2];
my $Temp1=@Speicher[-3];
Log 1, "Letzte:$Temp3,Vorletzte: $Temp2,Drittletzte: $Temp1";
fhem("set 3_LetzteTemperatur $Temp3");
fhem("set 2_VorletzteTemperatur $Temp2");
fhem("set 1_DrittletzteTemperatur $Temp1");
}


Vielen Dank an dich!

MfG, MisterEltako.
HMLAN-Konfigurations-Adapter, HM-Funkjalousieaktor/HM-Dimmaktor/HM-Schaltaktor f. Markenschalter, Jalousie-/Schaltaktor von Eltako, FT4 v. Eltako, TCM310

Reinerlein

Hi MrEltakto,

schön, das es geholfen hat... allerdings:
Wenn du bereits drei Dummies dafür definiert hast, kannst du dir das Array wiederum sparen, da diese Dummies bereits sozusagen deine "globalen Variablen" darstellen.

Du kannst also auch folgendes tun:
define 3_LetzteTemperatur dummy
attr 3_LetzteTemperatur room Array
define 2_VorletzteTemperatur dummy
attr 2_VorletzteTemperatur room Array
define 1_DrittletzteTemperatur dummy
attr 1_DrittletzteTemperatur room Array

define Temp dummy
attr Temp room Array

define Speicher notify Temp:.* {\
fhem("set 1_DrittletzteTemperatur ".Value("2_VorletzteTemperatur"));\
fhem("set 2_VorletzteTemperatur ".Value("3_LetzteTemperatur"));\
fhem("set 3_LetzteTemperatur ".Value("Temp"));\
}

Damit hast du zunächst das gleiche erreicht wie mit der anderen Variante, nur dass du die Werte nicht doppelt ablegst (also im Array und und einem Dummy).

Aber was machst du danach mit den Werten? Die Beachtung dieser Werte erfolgt dann woanders? Bedenke, dass beim Setzen eines Wertes ein Event ausgelöst wird. In diesem (und deinem) Fall also drei Stück.
Wenn du diese Events nicht brauchst, kannst du anstatt "set" auch "setState" verwenden. Da wird dann nix getriggert...

Die Array-Variante (dann allerdings ohne irgendwelche Dummies) würde den Vorteil bringen, dass du eben keine Dummy-Devices anlegst, die ja auch von FHEM verwaltet werden müssen, und damit Ressourcen auffressen.
Das würde bedeuten, dass du die Verarbeitung der Werte bereits in der Sub-Prozedure erledigst, was ja u.U. bei deiner dir gestellten Aufgabe nicht geht...

Grüße Reinerlein

MisterEltako

Hi!

Ja stimmt das ist tatsächlich doppelt. Ursprünglich hatte ich es nur mit dem Array angedacht, aber nach Änderungen von anderen Codezeilen in der 99_myUtils.pm und speichern, waren die Werte des Array's wieder weg. So dachte ich sie in den Dummy's "längerfristiger" speichern zu können.

Das ganze Projekt soll als Lösung für die Anfrage vom Benutzer My-FHEM in dem Thead: "Zugriff auf Sensordaten" dienen.

Über die Auslastung der Ressourcen hatte ich mir noch keine Gedanken gemacht, aber jetzt schon ;o).

MfG, MisterEltako.
HMLAN-Konfigurations-Adapter, HM-Funkjalousieaktor/HM-Dimmaktor/HM-Schaltaktor f. Markenschalter, Jalousie-/Schaltaktor von Eltako, FT4 v. Eltako, TCM310

Reinerlein

Hi MisterEltako,

das ist natürlich ein Vorteil der Dummies. Der Zustand wird beim Speichern weggesichert, und beim Starten wieder hergestellt...
Das passiert bei den Variablen nicht...

Dazu könntest du dir aber auch alles beim Dummy "Temp" in diversen Readings ablegen. Dann wäre es nur ein Device, und irgendwie "zusammen, wo es hingehört" :-)

Grüße Reinerlein

My-FHEM

Hi Reinerlein, MisterEltako,

ich sehe gerade diese Diskussion, vielen Dank für eure
Mühe meine Frage zu beantworten.

Hierzu einige Ergänzungen meinerseits. Ich benötige die historischen
Sensordaten um für meine Verwendung PID für Fussbodenheizung
den D-Anteil des Reglers über mehrere Abtastzeitpunkte auszurechnen.

Die Temperatur wird typischer Weise alle 5 Min abgetastet. Damit wird
das MODUL PID.pm ebenfalls alle 5 min aktualiesiert. der D-Anteil existiert  
somit nur für 1 Abtastperiode, da danach meistens derselbe Temp Wert
gelesen wird und somit D=0.

Der Zugriff auf historische Werte der Zeitreihe ermöglicht also eine
langsame Berechnung von delta-Temp/ delta-Zeit.

Wenn der Zugriff sinnvoller Weise in ein Perl modul ausgelagert
wird wäre vielleicht für diese Anwendung ein modifizertes 99_PID_slow_cycle.pm
mit variabler Rückschau der Abtastzeitpunkte sinnvoll.

Leider sind meine Perl Fähigkeiten nahezu null. So das hier eure Hilfe
wunderbar wäre.

Grüße

MisterEltako

@Reinerlein

Das mit dem Dummy und den Readings habe ich auch schon irgendwo gelesen.
Leider habe ich das nicht verstanden, wie ich dem Dummy Readings einfüge.
Doch nicht etwa mit "attr Dummy setList ...."????

MfG, MisterEltako.
HMLAN-Konfigurations-Adapter, HM-Funkjalousieaktor/HM-Dimmaktor/HM-Schaltaktor f. Markenschalter, Jalousie-/Schaltaktor von Eltako, FT4 v. Eltako, TCM310

Reinerlein

Hi MisterEltako,

du kannst zum Setzen von Readings einfach folgenden Perl-Code verwenden:
readingsSingleUpdate($main::defs{DeviceName}, 'ReadingsName', 'ReadingsValue', 0);

Leider gibt es meines Wissens nach keine Funktion in fhem.pl, die den DeviceHash zurückgibt, wenn man den Devicenamen hat. Deswegen der etwas kryptische Code im ersten Parameter. Damit wird nur der DeviceHash eingesetzt.
Die '0' beim letzten Parameter bedeutet, dass hier keine Events getriggert werden sollen. Wenn du dort eine '1' hinschreibst, wird ein normales Event mit dem Wert des Readings ausgelöst.

Bedenke, dass beim DeviceName in den geschweiften Klammern wirklich keine Anführungszeichen stehen dürfen. Das ist eine Hashwert-Auflösung, kein Parameter...

Bei deinem Temp-Beispiel wäre das z.B. wie folgt:
define Speicher notify Temp:.* {\
  readingsSingleUpdate($main::defs{Temp}, '1_DrittletzteTemperatur', ReadingsVal('Temp', '2_VorletzteTemperatur', ''), 0);\
  readingsSingleUpdate($main::defs{Temp}, '2_VorletzteTemperatur', ReadingsVal('Temp', '3_LetzteTemperatur', ''), 0);\
  readingsSingleUpdate($main::defs{Temp}, '3_LetzteTemperatur', Value("Temp"), 0);\
}
Die Umbrüche sind hier etwas unglücklich... Bitte korrigieren :-)

Grüße Reinerlein

MisterEltako

Hi!

define Speicher notify Temp:.* {\
  readingsSingleUpdate($main::defs{Temp},'1_DrittletzteTemperatur', ReadingsVal('Temp','2_VorletzteTemperatur', ''), 0);;\
  readingsSingleUpdate($main::defs{Temp},'2_VorletzteTemperatur', ReadingsVal('Temp','3_LetzteTemperatur', ''), 0);;\
  readingsSingleUpdate($main::defs{Temp},'3_LetzteTemperatur', Value("Temp"), 0);;\
}


führt zu Absturz von Fhem!!!!

Ist da was falsch? ;o)

MfG, MisterEltako
HMLAN-Konfigurations-Adapter, HM-Funkjalousieaktor/HM-Dimmaktor/HM-Schaltaktor f. Markenschalter, Jalousie-/Schaltaktor von Eltako, FT4 v. Eltako, TCM310

Reinerlein

Hi MisterEltako,

manchmal sollte man Dinge testen, bevor man sie postet...
Die Prozedur scheint er nicht aufrufen zu wollen, obwohl ich sie in meinen Modulen massiv verwende...

Alternativ kannst du auch "setReadingsVal" verwenden (in einem kurzen Test bei mir hat es mit den grundsätzlichen Funktionen zumindest über das kleine Kommandofeld oben geklappt :-)
define Speicher notify Temp:.* {\
  setReadingsVal($main::defs{Temp}, '1_DrittletzteTemperatur', ReadingsVal('Temp', '2_VorletzteTemperatur', ''), TimeNow());;\
  setReadingsVal($main::defs{Temp}, '2_VorletzteTemperatur', ReadingsVal('Temp', '3_LetzteTemperatur', ''), TimeNow());;\
  setReadingsVal($main::defs{Temp}, '3_LetzteTemperatur', Value("Temp"), TimeNow());;\
}

Versuch doch bitte das nochmal...

Grüße Reinerlein

MisterEltako

Prima! Diese Variante klappt!!!!
Das ist echt toll das man sowas machen kann. Das eröffnet wieder neue Möglichkeiten....


Vielen Dank!

MfG, MisterEltako.
HMLAN-Konfigurations-Adapter, HM-Funkjalousieaktor/HM-Dimmaktor/HM-Schaltaktor f. Markenschalter, Jalousie-/Schaltaktor von Eltako, FT4 v. Eltako, TCM310

MisterEltako

Noch eine Frage dazu:

Das im vorigen Post beschriebene Event setzen mit 1 oder 0 geht hierbei aber nicht oder?

MfG, MisterEltako.
HMLAN-Konfigurations-Adapter, HM-Funkjalousieaktor/HM-Dimmaktor/HM-Schaltaktor f. Markenschalter, Jalousie-/Schaltaktor von Eltako, FT4 v. Eltako, TCM310