Fragen zu lambda-script

Begonnen von dieter56, 12 Juni 2019, 11:56:58

Vorheriges Thema - Nächstes Thema

dieter56

Zitat

Die Nachricht, die an dich gesendet wurde:

Hallo Dieter,

das mit dem setReading habe ich gefunden: habe leichtsinnigerweise ein Test-Lambda-Script 'setReading' genannt: das hat lambda-script dann als fhem-device eingelesen ...

den Rest probier ich jetzt erst mal aus.

Soll ich den Schriftwechsel lieber im Forum führen, kenne mich leider mit den Gepflogenheiten überhaupt nicht aus.

Freundliche Grüße !
Reiner

Hallo Reiner,

Danke für deine Rückmeldung.
Das Kommando setReading funktioniert auch dann, wenn ein Device setReading existiert. Du musst nur vor setReading ein Hochkomma setzen.

'setReading temperature 12 door "closed";

Dadurch wird die Auswertung des Symbols verhindert.
Ich habe noch einen entsprechenden Hinweis in die Sprachbeschreibung eingefügt.
http://lambda-script.org/handbuch.php#3.1

Gruß
Dieter

rhabarber

#1
Hallo Dieter,

schon wieder eine Frage:

warum funktioniert:   x := x + 1;    problemlos,

aber nicht:

x := 0;

always {
x := x + 1;
setReading xzahl x;
wait 0,10;
};

Fehlermeldung: Funktion nicht definiert: x + 'number';



noch ein Problem, ich kopiere das script:

   
__________________________
always {
   wait 00:01;     #zum Testen :)
   case [08:00 12:00] {
      faktor := 0.5 + [ProplaWetter fc0_cloud09]'toNumber / 100};
   case [12:00 15:00] {
      faktor := 0.5 + [ProplaWetter fc0_cloud12]'toNumber / 100};
   case [15:00 18:00] {
      faktor := 0.5 + [ProplaWetter fc0_cloud15]'toNumber / 100};
   case [18:00 20:00] {
      faktor := 0.5 + [ProplaWetter fc0_cloud18]'toNumber / 100};
   setReading akt faktor;
};
_________________________

Fehlermeldung: Funktion nicht definiert: setReading akt faktor;


was muss ich tun, damit das geht ?

Danke und Grüße ! Reiner

rhabarber

habe es jetzt doch noch rausgefunden, wer lesen kann ist klar im Vorteil:

es benötigt für jede Art von Rechnung oder Zuweisung eine Art Schablone (Funktion):

die Schablone kann auch so was einfaches sein wie x := 1  ...  oder ich muss die vorher auf diese Art definierte Variable mit in die Schleif reingeben:  always x {
...
setReading dingsda x;
}

damit funktioniert es jetzt jedenfall :)

dieter56

Zitatwarum funktioniert:   x := x + 1;    problemlos,

aber nicht:

x := 0;

always {
x := x + 1;
setReading xzahl x;
wait 0,10;
};

Richtig ist:

x := 0;

always [b]x[/b] {
  x := x + 1;
   setReading xzahl x;
   wait 0,10;
}

oder wenn kein weiter Code folgt geht auch:

x := 0;
repeat  {
  x := x + 1;
   setReading xzahl x;
   wait 0,10;
}

dieter56

Zitatnoch ein Problem, ich kopiere das script:

   
__________________________
always {
   wait 00:01;     #zum Testen :)
   case [08:00 12:00] {
      faktor := 0.5 + [ProplaWetter fc0_cloud09]'toNumber / 100};
   case [12:00 15:00] {
      faktor := 0.5 + [ProplaWetter fc0_cloud12]'toNumber / 100};
   case [15:00 18:00] {
      faktor := 0.5 + [ProplaWetter fc0_cloud15]'toNumber / 100};
   case [18:00 20:00] {
      faktor := 0.5 + [ProplaWetter fc0_cloud18]'toNumber / 100};
   setReading akt faktor;
};
_________________________

Fehlermeldung: Funktion nicht definiert: setReading akt faktor;

faktor ist nur innerhalb der Blöcke {...} definiert. So müßte es gehen:

faktor := 0;
always faktor {
   wait 00:01;
   case [08:00 12:00] {
      faktor := 0.5 + [ProplaWetter fc0_cloud09]'toNumber / 100};
   case [12:00 15:00] {
      faktor := 0.5 + [ProplaWetter fc0_cloud12]'toNumber / 100};
   case [15:00 18:00] {
      faktor := 0.5 + [ProplaWetter fc0_cloud15]'toNumber / 100};
   case [18:00 20:00] {
      faktor := 0.5 + [ProplaWetter fc0_cloud18]'toNumber / 100};
   setReading akt faktor;
};

rhabarber

#5
danke !

was ich noch nicht verstehe: anscheinend kann ich ja Funktionsdefinitionen irgendwo hinschreiben und ggf. in einen Block oder eine Subfunktion übergeben;

an welcher Stelle geht das _nicht _? Sonst wäre ja die Fehlermeldung: Funktion nicht definiert nicht möglich. Also, mir ist nicht klar, an welcher Stelle ich Funktionen definieren 'darf' und wo nicht.

Sind case-Blocks auch eigene Gültigkeitsbereiche ? Wie übergebe ich Variablen an case-Blocks ?

kann man > 1 Variable an einen Block geben ? space, komma, semicolon ?

dieter56

#6
Hallo,

Ich bin begeistert davon, wie du dich reinhängst.

Funktionen müssen vor ihrer Verwendung definiert werden.
Beispiel: Ein Funktion summiert die Quadrate der beiden Parameter (number). Der Aufruf soll so sein:
z := qrt 2 5;
z soll dann den Wert 2 *2 + 5*5 = 29 haben.

'(qrt number'a number'b) {a a + b b};

z := qrt 2 5;
log z;

siehe auch hier: http://lambda-script.org/handbuch.php#6.2


Funktionen, Variable und Klassen gelten in dem Block in dem sie definiert sind und allen Blöcken die in diesem enthalten sind.
D.h.: Eine Variable, die außerhalb des case-Kommandos definiert wurde gilt auch in den Blöcken die Bestandteil des Kommandos case sind.

Eine Außnahme bilden threads. (always erzeugt einen Thread)
Innerhalb eines Threads kann nur auf externe Variable zugegriffen werden, wenn diese explizit übergeben wurden.
Vorher definierte Klassen und Funktionen sind immer (auch in threads) erreichbar.

siehe auch hier: http://lambda-script.org/handbuch.php#5.4

Ich hoffe, ich konnte ein wenig helfen.
Gruß
Dieter

rhabarber

ja danke, das hilft schon mal weiter. Bin erst mal dazu übergegangen, Dinge in einzelne threads zu schreiben, da braucht man dann eher nicht so viele Variable ...

was neues:
Beim Überprüfen eines Zeitwechsels, zB Monats- oder Jahresende:

funktioniert:

uhrzeit := 22:11;
setReading richtig (uhrzeit = 22:11);


die beiden funktionieren nicht:

uhrzeit := 22:22;
setReading richtig (uhrzeit > 11:11);

oder:

z := now - year;
#setReading zeit z;
setReading richtig (z > 164/0);

Funktion nicht definiert

gleich funktioniert, die anderen nicht. Was ist zu tun ?

dieter56

Hallo,

22:22 und 11:11 etc. sind ein Werte vom Datentyp timespan. Diese Datentypen lassen sich nicht miteinander vergleichen(siehe dazu: http://lambda-script.org/handbuch.php#6.3.4)

Um zu testen, ob die aktuelle Uhrzeit in einem bestimmten Intervall liegt kannst du z.B. [6:00 13:00] oder so ähnlich beutzen (siehe http://lambda-script.org/handbuch.php#6.3.5)

Oder willst du etwas anderes Vergleichen? Dann beschreib mal dein Problem genau.

Gruß
Dieter

rhabarber

Hallo Dieter,
das hat auch schon mal weiter geholfen. Kann jetzt so ziemlich schreiben was ich will, auch wenn vielleicht ein großer Teil der Möglichkeiten bisher ungenutzt bleibt.

Weil mir bestimmte Dinge zunächst Probleme gemacht und die einfache Nutzung der script-Sprache erschwert haben, hier folgende Fragen:

sind 2 Typen string erforderlich ?
sind 2 Typen Zeit erforderlich, wäre es nicht möglich, moment als timespan mit Dauer eine Sekunde zu definieren ?
könnte man dem Compiler beibringen, die runden Klammern bis zu den jeweiligen Grundfunktionen 'selbst' zu setzen ?

Grüße, Reiner.

dieter56

#10
Hallo,

Zitatsind 2 Typen string erforderlich ?
Es gibt nur einen Typ string. Der steht für jede beliebige Zeichenkette. Diese Zeichenketten können jedes Zeichen (auch Leerzeichen, Zeilenumbrüche, usw. - auch ganze Texte) enthalten.
Manchmal, z.B. bei Indizes einer collection sind nur Zeichenketten die keine Leerzeichen enthalten zulässig. (z.B. Namen von readings oder Namen von Devices). Deshalb wurde eine Unterklasse word eingeführt. Jeder Wert von Typ word ist auch ein string. Man kann einer Variablen von Typ string auch einen Wert von Typ word zuweisen. Der wird automatisch konvertiert. (siehe http://lambda-script.org/handbuch.php#4.2) Eigentlich dürften so beim praktische Programmieren kaum Probleme auftreten. Wenn doch, kannst du mir mal ein konkretes Beispiel schicken.

Zitatsind 2 Typen Zeit erforderlich, wäre es nicht möglich, moment als timespan mit Dauer eine Sekunde zu definieren ?
moment und timespan sind völlig verschiedene Dinge:

moment: Die Klasse moment repräsentiert Objekte, die einen bestimmten Zeitpunkt definieren. (siehe http://lambda-script.org/handbuch.php#4.1.6) Konkrete Zeitpunkte sind: Der Beginn und das Ende eines Fußballspiels, oder der Moment in dem der erste Mensch den Mond betreten hat.

timespan: Die Klasse timespan repräsentiert Objekte, die eine bestimmte Zeitspanne beschreiben. Eine Zeitspanne ist die Differenz zwischen zwei Objekten von Typ moment. So ist die aktuelle Uhrzeit ein timespan und genau die Zeitspanne vom Beginn des heutigen Tages bis jetzt. (siehe auch: http://lambda-script.org/handbuch.php#4.1.7) Konkrete Zeitspannen sind: 90 Minuten Spieldauer, oder die Zeit die man braucht, um von der Erde bis zum Mond zu fliegen.

Zitatkönnte man dem Compiler beibringen, die runden Klammern bis zu den jeweiligen Grundfunktionen 'selbst' zu setzen ?
Hier weiß ich nicht genau was du meinst.
Der zentrale Begriff bei der Programmierung in lambda-script ist "Kommando". Ein Kommando ist eine Folge von Symbolen und Werten und eventuell Blöcken. Es beginnt mit dem ersten Zeichen und endet mit einem Semikolon.
Manchmal ist ein Wert auch wieder ein berechneter Ausdruck. Dann wird das Kommando, das diese Berechnung ausführt, in runde Klammern eingeschlossen an die Stelle des Wertes geschrieben. (siehe http://lambda-script.org/handbuch.php#3.6) Diese Klammern muss man schon selbst setzten. Auch der Rechner weiß nicht, was du berechnen möchtest.
1 + (3 + 3) * 7; ist etwas anderes als 1 + (3 + 3 * 7);
Ich gebe dir Recht, wenn du beklagst, das der Editor der in FHEM eingebaut ist, keine IDE für lambda-script darstellt. So etwas wie Typkontrolle während des Schreibens und Autovervollständigung wären schon praktisch. Auch ein Debugger wäre toll. Das ist das Nächste was ich, wenn lambda-script 1.1 fertig ist, angehe.

Gruß
Dieter

rhabarber

#11
danke !!

dann hier meine (vorerst) letzte Frage:
könntest Du einrichten, dass die device-Liste bei Änderung von vorhanden devices neu eingelesen wird ? Es dauert bei mir immer mal ne Weile, bis ich merke, das lambda-script zB neu hinzugefügte devices noch nicht kennt.

Jedenfalls verstehe ich mehr, wenn ich meine Fragen stellen kann und Du die so geduldig beantwortest :)

... und das mit der IDE wäre natürlich genial

dieter56

Hallo,

das automatische Einlesen von neuen Devices steht schon auf meiner ToDo-Liste. Wenn ich es fertig habe schreibe ich es hier.

Ich freue mich über Fragen. Dann weiß ich wenigstens was ich im Handbuch noch besser erklären muss.

Gruß
Dieter

rhabarber

#13
:) dann hier gleich die nächsten:

wie überprüfe ich auf Monatswechsel, also 1. eines jeden Monats um 0:10 - 0:23,
habe (wahrscheinlich fast) jede Kombination von x/x/x:yy,zz durch,

außer bei: setReading richtig [xx:zz  yy:zz]        mit true wenn now dazwischen liegt

kommt bei:  setReading richtig [x/x/x:xx,zz  x/x/x:yy,zz]      in jeder Kombination false raus.

Beispiel tasmota-Verbrauchszähler:
always {
   setReading Gerade [WZ  ENERGY_CURRENT];
   setReading Heute [WZ  ENERGY_Today];
   setReading Gestern [WZ  ENERGY_Yesterday];
   case [0:0 0:20] {
      setReading MonatkWh ([StromkostenWZ  MonatkWh]'toNumber + [StromkostenWZ  Gestern]'toNumber);
      setReading Monat€ (([StromkostenWZ  MonatkWh]'toNumber + [StromkostenWZ  Gestern]'toNumber) * [EurkWh]);
      setReading JahrkWh ([StromkostenWZ  JahrkWh]'toNumber + [StromkostenWZ  Gestern]'toNumber);
      setReading Jahr€ (([StromkostenWZ  JahrkWh]'toNumber + [StromkostenWZ  Gestern]'toNumber) * [EurkWh]);
      };
   setReading Insgesamt [WZ  ENERGY_Total];
   >>>>>>>>>case [1/0:00 1/0:20] {setReading Monat " "};
   >>>>>>>>>case [1/1/0:00 1/1/0:20] {setReading Jahr " "};
   wait 0:15;
};
an der markierten Stelle hätte ich gerne dass der jeweilige Zähler zurückgesetzt wird. Wenn ich das entsprechend mit der aktuellen Zeit versuche, funktioniert das nicht.



apropos Handbuch: jedes weitere Beispiel ist eine echte zusätzliche Hilfe !


und:


gibt es eine Möglichkeit, bei einer Funktion mit mehr als 1 Parameter einen Rückgabewert, zB string, zu bekommen ?

Danke und Gruß !

dieter56

Hallo,

Zitatalways {
   setReading Gerade [WZ  ENERGY_CURRENT];
   setReading Heute [WZ  ENERGY_Today];
   setReading Gestern [WZ  ENERGY_Yesterday];
   case [0:0 0:20] {
      setReading MonatkWh ([StromkostenWZ  MonatkWh]'toNumber + [StromkostenWZ  Gestern]'toNumber);
      setReading Monat€ (([StromkostenWZ  MonatkWh]'toNumber + [StromkostenWZ  Gestern]'toNumber) * [EurkWh]);
      setReading JahrkWh ([StromkostenWZ  JahrkWh]'toNumber + [StromkostenWZ  Gestern]'toNumber);
      setReading Jahr€ (([StromkostenWZ  JahrkWh]'toNumber + [StromkostenWZ  Gestern]'toNumber) * [EurkWh]);
      };
   setReading Insgesamt [WZ  ENERGY_Total];
   >>>>>>>>>case [1/0:00 1/0:20] {setReading Monat " "};
   >>>>>>>>>case [1/1/0:00 1/1/0:20] {setReading Jahr " "};
   wait 0:15;
}

Ich verstehe die Problematik so: Du hast Reading, die periodisch aktualisiert werden soll. - manche all 15 Minuten (kleinstes Intervall), manche mit dem Start eines neuen Tages und andere mit Beginn eines neuen Monats ...
Ich würde das so lösen:


always {
   # Aktualisierung der 15Min Readings
   setReading
      r1 wert1
      r2 wert2
      ....
   ;
   wait 15,0;
};

# Starten eines weiteren Threads der die tägliche Arbeit verrichtet, Wartet bis 0:00 Uhr des nächsten Tages
always {
   wait tomorrow;
   setReading
      r1 wert1
      r2 wert2
      ....
   ;
   ....
}

# Starten eines weiteren Threads der die monatliche Arbeit verrichtet, Wartet bis 0:00 Uhr des nächsten Montasersten
always {
   wait (month + 1/0/0);
   setReading
      r1 wert1
      r2 wert2
      ....
   ;
   ...
}


Zitatkommt bei:  setReading richtig [x/x/x:xx,zz  x/x/x:yy,zz]      in jeder Kombination false raus.
Das Kommand [xx:yy xx:yy] funktioniert nur mit Uhrzeiten. Das ist so gewollt. Ich werde im Handbuch noch einen Hinweis aufnehmen.

Zitatgibt es eine Möglichkeit, bei einer Funktion mit mehr als 1 Parameter einen Rückgabewert, zB string, zu bekommen ?
Selbstverständlich geht das. Schildere dein Problem genauer und ich helfe gern.

Gruß
Dieter