regel nagative werte

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Taifun2300
Beiträge: 19
Registriert: 27. Dez 2022 09:19
Answers: 0

Re: regel nagative werte

Beitrag von Taifun2300 »

Nochmals vielen lieben Dank für die ausführliche Erklärung und vor allem für die Beispiele!

Für meinen konkreten Anwendungsfall habe ich die notwendigen Abfragen alle auf Event gesteuert umgestellt, und es funktioniert jetzt perfekt. Da es in der Darmstädter Gegen die letzten Tage viel geregnet hatte, konnte ich die dynamische Anpassung der Steuerung auch ausgiebig testen :D
Bzgl. der Menge der MQTT Daten habe ich den FHEM Sever meiner Solarsteuerung einen kleinen "Maulkorb" verpasst. Jetzt kommen die Daten 5 minütlich, oder bei starken Änderungen (jeweils festgelegt).

LG
openHAB 4.0.3 im Docker auf Debian 11, Anbindung an Raspmatic, Hue, FHEM, Fritzbox, Buderus KM200, Worx, Bilnk, Alexa

Benutzeravatar
udo1toni
Beiträge: 15247
Registriert: 11. Apr 2018 18:05
Answers: 242
Wohnort: Darmstadt

Re: regel nagative werte

Beitrag von udo1toni »

:)
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

steinadler
Beiträge: 69
Registriert: 29. Apr 2020 19:15
Answers: 0

Re: regel nagative werte

Beitrag von steinadler »

entschuldigung, wenn ich nochmal störe, und das alte thema neu aufwirbel
ich komme irgendwie nicht weiter
mein problem ist, das die regel ab und an wieder die olle 0 einwirft
mirkommt esso for, das das beim wechsel eines wwertes passiert
nach der null liesst die regel den wert vom zähler ein, ohne den wert neu zu bearbeiten(gibt dann auch negativen wert an), aber nuir einmal, dann läuft die regel wieder normal, bis ja bis irgendwann die null kommt
stell ich die regel auf manuell, funktioniert alles einwandfrei
automatik das problem mit der null
MQTTfx zeigt mir die null nicht an, da das zu schnell geht(der wechsel)
die null seh ich nur in arduino in der konsole(esp8266--wemosD1)
kann mir einer bitte einen tipp geben, was ich noch probieren kann ?

Code: Alles auswählen

rule "virtual item VerbrauchTest"
  when
    Item Verbrauch changed 
      then
        VerbrauchTest.postUpdate  (Verbrauch.state.toString)
      end  
/*rule "virtual Extra"
  when
    Text Extra changed
      then
       VerbrauchTest.postUpdate  (Verbrauch.state.toString)
      end  
*/
rule "Uhrschalter setzen"    
when
   Item VerbrauchTest changed
    //Time cron "0 0 * * * ?"   // Regel stündlich ausführen
then
    var soll = ON                               // Default Sollwert ON
    if(now.getHour > 16 && now.getHour < 17)     // falls aktuelle Zeit 09:00:00 Uhr bis 18:59:59 Uhr
        soll = OFF                              // Ändere Sollwert auf OFF

    if(Uhrschalter.state != soll)               // falls Uhrschalter Status von soll abweicht
        Uhrschalter.postUpdate(soll.toString)   // Setze Uhrschalter auf Sollwert
end
   

rule "Wechselrichter Soyosorce"
when
    Item VerbrauchTest changed 
then
    if(Schalter.state == ON)
        return;  

    if(Uhrschalter.state != ON)                               // Rule nicht aktiv?
        return;                                               // dann raus!

    if(!(newState instanceof Number))                         // keine Zahl?
        return;                                               // dann raus!
    
     //if(Math.abs((oldState as Number).floatValue - (newState as Number).floatValue) >= 20)
       //var zahl = (newState as Number).floatValue
        var zahl = (newState as Number).floatValue                // weise zu
     if(Math.abs((zahl as Number).floatValue - (newState as Number).floatValue) >= 20)
     
     
    //if(zahl < 1)                                              // Wert kleiner 1?
       //zahl = 10                                              // dann setze Wert 10
    if(zahl > 550)                                            // Wert größer 550?
       zahl = 500                                             // dann setze Wert 500

    val mqttActions = getActions("mqtt","mqtt:broker:neuer")
        mqttActions.publishMQTT("Leistung", zahl.toString)        // schreibe in Leistung
end  
  

rule "zuschalten"
 
   when 
    
     Item Verbrauch changed
      then
        if(Schalter.state == OFF){
            
         var zahl2 = 0    
              val mqttActions = getActions("mqtt","mqtt:broker:neuer")
                  mqttActions.publishMQTT("Leistung", zahl2.toString)
        }
     else {
        var  zahl2 = Extra.state as Number
       
        val mqttActions = getActions("mqtt","mqtt:broker:neuer")
            mqttActions.publishMQTT("Leistung", zahl2.toString) 
     }
end      

Code: Alles auswählen

//Stromzähler
   Number Gesamtverbrauch  "Gesamtverbrauch  [%.1f K_Watt]" <returnpipe>  (Strom)  { channel="mqtt:topic:neuer:Stromzaehler:Gesamtverbrauch"}
   Number Eingespeist     "Eingespeist     [%.1f K_Watt]"   <flowpipe>    (Strom)  { channel="mqtt:topic:neuer:Stromzaehler:Eingespeist"}
   Number Verbrauch        "Verbrauch       [%.1f Watt]"    < line>       (Strom)  { channel="mqtt:topic:neuer:Stromzaehler:Verbrauch"}
   Number VerbrauchTest  "VerbrauchTest     [%.1f Watt]"     < line>       (Strom) // { channel="mqtt:topic:neuer:Stromzaehler:Verbrauch"} // [profile="transform:JS", function="negativNULL.js"] }
kopie aus arduinokonsole
16:52:29.938 -> $V!
16:52:29.938 -> ��
16:52:30.962 -> 10
16:52:30.962 -> 10
16:52:30.962 -> $V!
16:52:30.962 -> ��
16:52:31.955 -> 10
16:52:31.955 -> 10
16:52:31.955 -> $V!
16:52:31.955 -> ��

16:52:32.962 -> 0
16:52:32.962 -> 10
16:52:32.962 -> $V!
16:52:32.962 -> ��
16:52:33.964 -> -195
16:52:33.964 -> 10

16:52:33.964 -> $V!
16:52:33.964 -> ��
16:52:34.965 -> 10
16:52:34.965 -> 10
16:52:34.965 -> $V!
vielleicht noch mein sketch für den esp(inc++)

Code: Alles auswählen

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
   Serial.println(item);
   /*
   if (item >= 550) {
      item = 500;
     } else if (item <= 0) {
      item = 10;
     }
     
    if (first_run) { // wenn es der erste durchlauf ist, setze old_item auf 100
       old_item = 100;
       first_run = false; // setze die Variable auf false, damit sie nicht mehr ausgeführt wird
}
else { 
   if (item <= 5) {
      item = 10;
   }
   
    if (abs(item - old_item) >= 20) {
      if (old_item < item) {
        item += 10;
      }
      else if (old_item > item) {
        item -= 10;
      }
    }
  old_item = (item +1);
  if (item >= 550) {
      item = 500;  
}
*/
//Serial.println(item);
if (item >= 550) {
item = 500;
} else if (item <= 0) {
item = 10;
} //else if (item <= 5) {
//item = 10;
//} 
else if (abs(item - old_item) >= 20) {
if (old_item < item) {
item += 10;
} else if (old_item > item) {
item -= 10;
}
}
old_item = item + 1;
if (item >= 550) {
item = 500;
}
 
 
    
    
    
    Serial.println(item);
    int c = 0x24;
    int d = 0x56;
    int h = 0x00;  
    int e = 0x21;
    int i = (item >> 8);                                      // int i = 0x00; //Leistung
    int k = (item & 0xFF);                                    // int k = 0x3E; //leistung
    int f = 0x80;
    int g = (264 - i - k);                                    //int g = 0xCA; //CRC Prüfung
    
    

    String data = String(c, HEX) + 
                  String(d, HEX) +
                      (h < 0x10 ? "0" : "") +  
                  String(h, HEX) + 
                  String(e, HEX) + 
                      (i < 0x10 ? "0" : "") + 
                  String(i, HEX) + 
                      (k < 0x10 ? "0" : "") + 
                  String(k, HEX) + 
                  String(f, HEX) + 
                  String(g, HEX);

    data.replace(" ", "");
    for (int i = 0; i < data.length(); i += 2) {
        byte b = (byte) strtol(data.substring(i, i + 2).c_str(), NULL, 16);
        Serial.write(b);
    }
     //Serial.println(topic);
     Serial.println();
     delay(1000);
     //item = 0;


}
  
  //Serial.print("Value: ");
  //Serial.println(value);
}
ich habe überall das was ich probiert habe mal drin gelassen, damit man sieht, was ich schon probiert habe
ist alles nach handbuch erarbeitet, könnte mir vorstellen, das es besser geht, aber ersteinmal das wichtigste, die olle null ...

so, ist nun bischen viel geworden, danke, wenn einer mal darüber weg fliegt und mir einen tip geben kann wo ich(wegen der null) weiter machen müsste(bin kein profi, also nicht so viel schimpfen)
danke im vorraus...

Benutzeravatar
udo1toni
Beiträge: 15247
Registriert: 11. Apr 2018 18:05
Answers: 242
Wohnort: Darmstadt

Re: regel nagative werte

Beitrag von udo1toni »

Du hast vor allem mal komplettes Chaos in Deinen Rules veranstaltet.
Du musst schon verstehen, was die einzelnen Befehle bewirken, um zum Ziel zu kommen, Raten ist hier keine Option.

Die Frage wäre also zunächst: WAS willst Du eigentlich erreichen?

Zu den ganzen Fehlern in den gezeigten Rules:

Erst mal formal: Einrückungen dienen der Lesbarkeit für den Anwender, dem Parser (der die Rule liest) sind sie egal.
Der Parser nimmt die Datei und sucht zunächst Kommentarblöcke (alles zwischen den beiden Zeichenfolgen /* und */, incl.) und entfernt diese Blöcke.
Anschließend sucht er zeilenweise nach // und entfernt alles dahinter (wieder incl. //).
Damit sind nun keinerlei kommentare mehr vorhanden.
Nun werden alle Zeilenumbrüche durch ein einzelnes Leerzeichen ersetzt, ebenso werden alle Tabulatoren durch ein einzelnes Leerzeichen ersetzt, dann werden alle zusammenhängenden Leerzeichen durch ein einzelnes Leerzeichen ersetzt.
Die erste Rule

Code: Alles auswählen

rule "virtual item VerbrauchTest"
  when
    Item Verbrauch changed 
      then
        VerbrauchTest.postUpdate  (Verbrauch.state.toString)
      end  
sieht dann so aus:

Code: Alles auswählen

rule "virtual item VerbrauchTest" when Item Verbrauch changed then VerbrauchTest.postUpdate (Verbrauch.state.toString) end
Erst dann fängt der Parser an, die Rule zu analysieren.

Es geht bei den Einrückungen also ausschließlich um Lesbarkeit und Nachvollziehbarkeit, nicht um Hierarchien.
Im Umkehrschluss sollte man also Einrückungen so setzen, dass zusammenhängende Codeblöcke auf gleicher Ebene abgebildet sind. Beispiel erste Rule:

Code: Alles auswählen

rule "virtual item VerbrauchTest"
when
    Item Verbrauch changed
then
    VerbrauchTest.postUpdate(Verbrauch.state.toString)
end
Die Schlüsselworte rule, when, then und end sind Teil des Rahmens, der die Rule bildet. Hinter rule steht der Name der Rule, nach when folgen alle Trigger, nach then der auszuführende Code,
end kennzeichnet das Ende einer Rule.

Schlüsselworte hinter when:
Item bezeichnet ein itembasiertes Ereignis.
Text (die ausgeklammerte Rule) gibt es an dieser Stelle nicht. Bitte nicht raten oder rumprobieren, die Schlüsselworte sind bestens dokumentiert.
Time bezeichnet ein zeitliches Event. Ist hier völlig fehl am Platze, aber sei's drum...

Du definierst in der Rule "Uhrschalter setzen" einen Itemzustand, abhängig von now.getHour.
.getHour ist eine Funktion, die den Stundenanteil einer Uhrzeit (bzw. eines vollständigen Datums mit Uhrzeit) liefert. Der Stundenanteil ist das, was auf einer Digitalanzeige links vom linken Doppelpunkt steht, das heißt, um 16:00:00 Uhr liefert .getHour 16, um 16:59:59 Uhr liefert getHour ebenfalls 16, um 17:00:00 Uhr liefert .getHour dann 17.
.getHour ist per Definition eine Ganzzahl (oder auf englisch Integer), der Wertebereich ist 0 bis 23, es gibt also keine 24 Uhr, sondern nur 0 Uhr.
Entsprechend wird die Formel

Code: Alles auswählen

if(now.getHour > 16 && now.getHour < 17)
auch niemals wahr, somit wird auch Uhrschalter niemals einen anderen Zustand annehmen als ON. Wenn Du den Zeitraum von 9 Uhr bis 19 Uhr haben willst, wäre der korrekte Ausdruck

Code: Alles auswählen

if(now.getHour > 8 && now.getHour < 19)
, denn um 08:59:59 liefert .getHour immer noch den Wert 8, was nicht größer als 8 ist, um 19 Uhr liefert .getHour dann zum ersten Mal 19, was nicht kleiner als 19 ist.

Besser wären hier zwei Rules:

Code: Alles auswählen

rule "Uhrschalter ON"
when
    Time cron "0 0 9 * * ?"     // Regel um 9 Uhr ausführen
then
    Uhrschalter.postUpdate(ON)  // Setze Uhrschalter ON
end

rule "Uhrschalter OFF"
when
    Time cron "0 0 19 * * ?"    // Regel um 19 Uhr ausführen
then
    Uhrschalter.postUpdate(OFF) // Setze Uhrschalter OFF
end
Durch Deine Nichteinhaltung der Einrückungen ist vollkommen unklar, was Du wo zuzuweisen versuchst. Wichtig ist aber: Du musst (!) vor dem Casten eines Wertes (das heißt, einen bestimmten Datentyp erzwingen) prüfen, ob der Wert überhaupt in dem gewünschten Format dargestellt werden kann.

Ein Number Item kann neben beliebigen Zahlenformaten immer auch die Werte NULL und UNDEF liefern. Diese beiden Werte müssen unter allen Umständen vermieden werden, deshalb muss vor dem Zugriff auf den Wert geprüft werden, ob er NULL oder UNDEF ist.
ODER man prüft, ob es sich bei einem Wert um eine Instanz des Typs Number handelt.
Bei jedem "ersten" Zugriff, das heißt, innerhalb jeder Rule müssen alle verwendeten Itemstatus geprüft werden. newState ist ein Itemstaus, genau wie previousState.

oldState gibt es übrigens nicht...

Dann hast Du dieses Konstrukt:

Code: Alles auswählen

var zahl = (newState as Number).floatValue
if(Math.abs((zahl as Number).floatValue - (newState as Number).floatValue) >= 20)
Mal abgesehen davon, dass zahl bereits vom Typ Number ist, das Casting hier also komplett sinnlos ist, glaubst Du tatsächlich, dass ein ein Wert, von sich selbst abgezogen eine andere Zahl als 0 ergibt?

Schließlich in der letzten Rule...

Wo kommt denn nun Extra plötzlich her? Und warum schreibst Du Code doppelt? Wenn es darum geht, entweder 0 oder Extra auszugeben, wäre der korrekte Code hierfür dieser:

Code: Alles auswählen

rule "zuschalten"
when 
    Item Verbrauch changed
then
    val mqttActions = getActions("mqtt","mqtt:broker:neuer")
    var zahl2 = 0.0

    if(Schalter.state != OFF && Extra.state instanceof Number)
        zahl2 = (Extra.state as Number).floatValue

     mqttActions.publishMQTT("Leistung", zahl2.toString) 
end
Die lokale Variable zahl2 wird mit dem Wert 0.0 vordefiniert. 0.0 bewirkt, dass hier Double als Genauigkeit verwendet wird.
Wenn der Schalter nicht OFF ist (das ist die gleiche Bedingung, wie sie für Deinen else-Teil gilt) UND Extra eine gültige Zahl liefert (wir wollen ja keine NullPointer Exception), wird der lokalen Variablen zahl2 der Wert aus Extra zugewisen, gecastet nach Number und als Float Wert interpretiert.
Anschließend wird zahl2 ausgegeben, so oder so.

Allerdings ist es mehr als fragwürdig, was das Ganze bringen soll.

Noch so eine Unsitte: Warum nutzt Du hier überhaupt die Action publishMQTT? Definiere lieber einen String Channel (oder vielleicht sogar einen Number Channel...), in dessen commandTopic Du das passende Topic einträgst (also in diesem Fall "Leistung", was allerdings auch keine sonderlich gute Idee ist. MQTT ist eigentlich hierarchisch aufgebaut, oder sollte es zumindest sein.)
Mit dem passenden Item sähe die Rule dann so aus:

Code: Alles auswählen

rule "zuschalten"
when 
    Item Verbrauch changed
then
    var zahl2 = 0.0

    if(Schalter.state != OFF && Extra.state instanceof Number)
        zahl2 = (Extra.state as Number).floatValue

     Leistung.sendCommand(zahl2)
end
Aber wie gesagt, das Ganze schreit danach, dass hier eine Menge Dinge gemacht werden, für nichts und wieder nichts.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Benutzeravatar
udo1toni
Beiträge: 15247
Registriert: 11. Apr 2018 18:05
Answers: 242
Wohnort: Darmstadt

Re: regel nagative werte

Beitrag von udo1toni »

Mein Tipp (aufgrund des oben geschriebenen... aber auch weil ich mir jetzt noch den Sketch angetan habe...)

Arbeite strukturiert.
Wenn Du Code auskommentierst, erstelle eine Kopie ohne die Kommentare.
Achte auf Einrückungen.
Denke über die Formulierungen nach, ob diese überhaupt Sinn ergeben können.

Niemals verschiedene Rules verwenden, um auf das selbe Ziel schreibend zuzugreifen, Du weißt im Zweifel nicht, woher ein falscher Wert kommt (hier zwei Rules, die beide in das Topic "Leistung" schreiben)
Versuche nicht, Code auf verschiedene Systeme aufzuteilen. ENTWEDER openHAB kümmert sich um positive und negative Werte, ODER der Arduino.
Nullwerte vermeidest Du, indem Du vor dem Schreiben des Wertes auf NULLwerte prüfst, und zwar auf die einzig korrekte Art.

Code: Alles auswählen

if(Item.state instanceof Number)
    // verwende den Wert als Zahl
oder alternativ

Code: Alles auswählen

if(!(Item.state instanceof Number))
    // keine gültige Zahl, also z.B. Abbruch oder Fehlermeldung
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

steinadler
Beiträge: 69
Registriert: 29. Apr 2020 19:15
Answers: 0

Re: regel nagative werte

Beitrag von steinadler »

danke deiner ausführungen erst einmal
mir kommt es nur so for, wenn die regel neu anläuft, wird null, dann der originalwert vom zähler gesendet
dann, wenn die regel läuft ist alles gut, die werte stimmen (auch auskommandierte werte werden nicht gesendet) bis...
die regel läuft wieder neu an, selbe spiel -null-der negative wert (obwohl gesperrt)
das passiert zyklisch, scheinbar immer im selben abstand
naja, muss ich noch ein bissel lesen und rumexperimentieren...
danke dennoch...

Benutzeravatar
udo1toni
Beiträge: 15247
Registriert: 11. Apr 2018 18:05
Answers: 242
Wohnort: Darmstadt

Re: regel nagative werte

Beitrag von udo1toni »

Ja, sicher, weil die Rule halt kompletter Bullshit ist.
Noch mal: Was willst Du tatsächlich erreichen? Du hast da diverse Befehle aneinander gereiht, die nichts Sinnvolles tun.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Antworten