Seite 2 von 2

Re: Temperatur Vergleich mit Nummer

Verfasst: 1. Okt 2022 14:18
von udo1toni
N1d45 hat geschrieben: 1. Okt 2022 13:30 Irgendwo hatte ich gelesen (oder gehört in einem Video). das die DSL Regeln langsam währen und man deshalb ECDA Code nehmen sollte.
Nun ja, kommt drauf an, was man als langsam bezeichnet.
Ich habe mal aus Versehen eine Rule gebaut, die sich selbst getriggert hat, in der Art Trigger ist Update von Item a und innerhalb der Rule (an irgendeiner Stelle) dann a.postUpdate(). Die Rule wurde dann etwa 60 Mal pro Sekunde getriggert und hat über den Tag für knapp zwei GByte logs gesorgt. Die Rule Engine war natürlich komplett dicht und dennoch ließen sich gewöhnliche Befehle (also direkte, ohne das eine Rule beteiligt war) ganz normal ausführen.
Die Rule mit dem Timer wird vermutlich etwa drei Millisekunden brauchen. Der Timer Code wird etwa die gleiche Zeit brauchen.
Ob eine Rule in JavaScript so viel schneller ist? Vermutlich. Andererseits: dann braucht sie halt nur eine Millisekunde, aber hat das sonst irgendwelche Auswirkungen? Die Rule wird einmalig ausgelöst, wenn das Fenster geöffnet oder geschlossen wird. Der Timer wird alle zehn Minuten ausgelöst, im Verhältnis also immer noch komplett zu vernachlässigen.
Und wenn es um Hausautomation geht, reden wir von eher gemächlichen Systemen. Die Reaktionszeiten kommen regelmäßig von externen Systemen (ich habe ein Demo Video von Matter gesehen... und das soll ein Fortschritt sein? Schalter an, Pause, Pause, Licht an? Also ich weiß nicht...
N1d45 hat geschrieben: 1. Okt 2022 13:30 Die geschweiften If-Klammern schaden aber auch nicht.
Nein, ich wollte nur darauf hinweisen, dass sie hier nicht notwendig sind. Der Code der DSL Rules wird compiliert, eine Formatierung des Codes spielt also keinerlei Rolle für die Ausführungsgeschwindigkeit. Die {} sind nur wichtig, um Code-Blöcke zu markieren, weil anders als in z.B. php oder Python die Einrückung des Codes keine Rolle spielt, die ist nur zur besseren Lesbarkeit des Quelltextes.

Re: Temperatur Vergleich mit Nummer

Verfasst: 1. Okt 2022 20:25
von N1d45
Wäre ich doch mal selber auf die Idee mit dem Log gekommen. Aber nach eurem Feeback war mir schon klar das der Fehler auf meiner Seite liegt. Es war der Falsche Trigger für die Regel gewählt. Muss ich beim rumprobieren falsch gewählt haben. Denn ohne Temperatur funktionierte es bereits. Im Log kam keinerlei Ausgabe. Die Regel wurde also gar nicht gestartet.

Das Problem ist, das ich ein Equipment erstellt habe, das Fensterkontakt_Wohnzimmer heißt. Darin ist das Item für den Fensterkontakt hinterlegt, namens FensterkontaktWohnzimmer_Wert1. Natürlich muss man dann als Trigger dieses Item nehmen für den Change. Das ärgert mich gerade Total :x

Selbst der Vergleich des getStateItems mit einem Text vom Wert "15" funktioniert.
FensterAlarm.png

Code: Alles auswählen

var scriptExecution = Java.type('org.openhab.core.model.script.actions.ScriptExecution');

var zdt = Java.type('java.time.ZonedDateTime');

if (typeof this.timers === 'undefined') {
  this.timers = [];
}


if (typeof this.timers['WohnzimmerFensterTimer'] === 'undefined' || this.timers['WohnzimmerFensterTimer'].hasTerminated()) {
  this.timers['WohnzimmerFensterTimer'] = scriptExecution.createTimer(zdt.now().plusSeconds(10), function () {
    if (itemRegistry.getItem('FensterkontaktWohnzimmer_Wert1').getState() == 'OPEN' && itemRegistry.getItem('SensEgg58_Temperatur').getState() < '15') {
      events.sendCommand('EchoWohnen_Sprich', 'Wohnzimmer Fenster schließen');
      if (typeof this.timers['WohnzimmerFensterTimer'] !== 'undefined') { this.timers['WohnzimmerFensterTimer'].reschedule(zdt.now().plusSeconds(10)); }
    }
    })
} else {
  this.timers['WohnzimmerFensterTimer'].reschedule(zdt.now().plusSeconds(10));
}
Ich habe jetzt auch noch einmal Versucht das gestrige Problem zu rekonstruieren, das es nur mit dem Fensterkontaktwert funktioniert und mit dem hinzufügen des Temperaturvergleiches dann nicht mehr, und mit dem Entfernen des Temperaturvergleiches funktionierte es wieder. Aber ich bekomme es nicht rekonstruiert. Keine Ahnung was ich da gestern angestellt hatte.

Ich entschuldige mich für die Verwirrung.

Danke für eure Hilfe!

Re: Temperatur Vergleich mit Nummer

Verfasst: 2. Okt 2022 13:02
von Mclupo
Ich habe mal meine DSL Rule zum Üben in ECMA 21 umgeschrieben.
Dieses ist die Fensterüberwachungs Rule, die beim Öffnen und Schliessen des Fensters triggert
Die Öffnungszeit und die Anzahl der Fensteröffnungen sind nur Spielerei

Code: Alles auswählen

function pushMessage(message) {
  var message_item   = items.getItem('ProxyMessage');
  var volume_item    = items.getItem('SI01_Soundvolume');
  var sound_item     = items.getItem('SI01_Soundtonetoplay');
  
  message_item.postUpdate(message[0]);       //Pushnachricht setzen
    
  if ((typeof  message[1]) === 'number'){    //siren6 ansteuern falls gewünscht
  volume_item.sendCommand(message[1]);
  sound_item.sendCommand(message[2]) ; 
  }
}

//Hauptprogramm
// falls Fenster geöffnet wurde
if (event.itemState.toString() == 'OPEN' ){
  var counter_item   = items.getItem('FS01_WindowCounter');
  var time_item       = items.getItem('FS01_Timestamp');
  var temperature    = parseFloat(items.getItem('LS01_Sensortemperature').state);
  var wert                = +counter_item.state || 0   // Counter = null , dann auf 0 setzen
  
  var message_1      = ['0Toilettenfenster zu lange offen',20,4];
  var message_2      = ['0Toilettenfenster nicht vergessen']; 
  
  counter_item.postUpdate(++wert);   // Counter um einen Zähler erhöhen
  time_item.postUpdate(Date.now());  // Datum in Timestamp speichern

  if (temperature <= 13 ){            // falls zu kalt, 10 Minuten warten
                                                //dann Nachricht senden und Sirene läuten
    var timer = setTimeout(function() {pushMessage(message_1)},600000); 
  }
  else{                                      // sonst Nachricht senden und ans Fenster erinnern
    var timer = setTimeout(function() {pushMessage(message_2)},600000);   
  }
}

//falls Fenster geschlossen wurde -> Timer löschen
else{
  if (!timer.hasTerminated()){
  clearTimeout (timer);
  }
}
Die Pushnachricht triggert beim Update des "ProxyMessage" items

Code: Alles auswählen

var message = actions.Things.getActions("pushover", "pushover:pushover-account:30711927e8");
var item = items.getItem('ProxyMessage');
var index = parseInt(item.state)  ;    
var text = item.state.substring(1)
var NachrichtAktiv = items.getItem('NachrichtAktiv'.state); //falls ich keine Nachrichten möchte

switch (index){
  case 0 :{                          // normale Nachricht
    if (NachrichtAktiv == 'ON'){
      message.sendMessage(text, 'OpenHAB'); 
    }
  };
  case 1 :{
    if (NachrichtAktiv == 'ON'){    
      message.sendMessage(text, 'OpenHAB'); 
    }
  };    
  case 2 :{                        // Nachricht mit hoher Priorität
    message.sendPriorityMessage(text, 'OpenHAB',index);  
         };
}

Re: Temperatur Vergleich mit Nummer

Verfasst: 2. Okt 2022 13:31
von Mclupo
Einen Punkt habe ich noch ( falls nicht noch mehr gefunden werden).
Wenn der Timer abgelaufen ist (Message gesendet wurde) und dann das Toiletten Fenster geschlossen wird, kommt der Fehler

Code: Alles auswählen

 2022-10-02 13:21:20.559 [ERROR] [b.automation.script.javascript.stack] - Failed to execute script:
org.graalvm.polyglot.PolyglotException: TypeError: undefined has no such function "hasTerminated"

Code: Alles auswählen

 if (!timer.hasTerminated()){
  clearTimeout (timer);

Re: Temperatur Vergleich mit Nummer

Verfasst: 2. Okt 2022 13:58
von Mclupo
Ich habe es jetzt mal so gelöst, ist das i.O??

Code: Alles auswählen

else{
  if (!(timer === 'undefined')){
    if (!timer.hasTerminated())  clearTimeout (timer);     
  }
}/code]

Re: Temperatur Vergleich mit Nummer

Verfasst: 2. Okt 2022 15:09
von N1d45
Mclupo hat geschrieben: 2. Okt 2022 13:58 Ich habe es jetzt mal so gelöst, ist das i.O??
Das weiß ich nicht.
Ich habe das meiste in Blockly zusammengeschoben und mir dann den Code angeschaut. Am Ende habe ich mir den Code ohne Blockly zusammengestellt.

Code: Alles auswählen

var scriptExecution = Java.type('org.openhab.core.model.script.actions.ScriptExecution');
var zdt = Java.type('java.time.ZonedDateTime');
var text = '';                                // Text den Alexa ausgibt
var temperatur = 15;                          // Außentemperatur, die unterschritten sein muss, um das Skript auszuführen
var timerZeitMinuten = 10;                    // Zeit in Minuten, die der Timer laufen soll

if (typeof this.timers === 'undefined') {                                     
  this.timers = [];
} 

function fTimerCode() {         // Code nach ablauf des Timers
  if (itemRegistry.getItem('OpenWindows').getState() > 0                                                   // Wenn Fenster noch offen
      && itemRegistry.getItem('SensEgg58_Temperatur').getState() < temperatur) {                           // UND wenn Temperatur noch unterschritten
    text = '';
    if (zdt.now().getHour() >= 19 || zdt.now().getHour() <= 6) text = text + '<amazon:effect name="whispered"> ';
    if (itemRegistry.getItem('FensterkontaktBadezimmer_Wert1').getState() == 'OPEN') text = text + 'Bad <break time =\"200ms\"/>';
    if (itemRegistry.getItem('FensterkontaktBalkon_Wert1').getState() == 'OPEN') text = text + 'Balkon <break time =\"200ms\"/>';
    if (itemRegistry.getItem('FensterkontaktSchlafzimmer_Wert1').getState() == 'OPEN') text = text + 'Schlafzimmer <break time =\"200ms\"/>';
    if (itemRegistry.getItem('FensterkontaktBuro_Wert1').getState() == 'OPEN') text = text + 'Niki <break time =\"200ms\"/>';
    if (itemRegistry.getItem('FensterkontaktKinderzimmer_Wert1').getState() == 'OPEN') text = text + 'Kinder <break time =\"200ms\"/>';
    if (itemRegistry.getItem('FensterkontaktWohnzimmer_Wert1').getState() == 'OPEN') text = text + 'Wohnen <break time =\"200ms\"/>';
    if (itemRegistry.getItem('FensterkontaktKuche_Wert1').getState() == 'OPEN') text = text + 'Küche <break time =\"200ms\"/>';
    text = text + 'Fenster schließen';
    if (zdt.now().getHour() >= 19 || zdt.now().getHour() <= 6) text = text + '</amazon:effect>';
    if (zdt.now().getHour() <= 21 && zdt.now().getHour() >= 8) {                                           // Wenn im Zeitfenster
      events.sendCommand('EchoNici_Sprich', text);                                                         // Ausgabe Echo Nici
    }
    events.sendCommand('EchoWohnen_Sprich', text);                                                         // Ausgabe Echo Wohnen
    events.sendCommand('EchoKuche_Sprich', text);                                                          // Ausgabe Echo Küche
    events.sendCommand('EchoBad_Sprich', text);                                                            // Ausgabe Echo Bad
    if (typeof this.timers['FensterTimer'] !== 'undefined') {                                              // Wenn Timer nicht das gleiche wie undefinierd
      this.timers['FensterTimer'].reschedule(zdt.now().plusMinutes(timerZeitMinuten));                     // Starte Timer neu 
    }
  }
}

if (itemRegistry.getItem('SensEgg58_Temperatur').getState() < temperatur) {                                        // Nur ausführen, wenn Außentemperatur unter (Damit nicht Timer unnötig erstellt werden)
  if (typeof this.timers['FensterTimer'] === 'undefined' || this.timers['FensterTimer'].hasTerminated()) {         // Wenn der Timer nicht definiert oder abgelaufen
    this.timers['FensterTimer'] = scriptExecution.createTimer(zdt.now().plusMinutes(timerZeitMinuten), fTimerCode) // Erstelle einen Timer und führe Funktion aus
  } 
  else {
    this.timers['FensterTimer'].reschedule(zdt.now().plusMinutes(timerZeitMinuten));                               // Setzt den Timer neu, wenn der Rule Trigger erneut auslöst und Bedingung (Temperatur) oben erfüllt ist
  }
}
Fehler wirft der Code keinen aus. Nur wird der String text exzessiv gekürzt bzw. verlängert. Bei kleinen Microkontrollern ist das eigentlich ein NoGo, da dadurch ein RAM stark fragmentiert, da immer ein neuer passender Platz gesucht wird, und irgendwann kein zusammenhängender Platz mehr im RAM vorhanden ist. Wie sich das auf dem Raspberry sich verhält, und ob das vernachlässigbar ist, weiß ich natürlich nicht.