Ankündigung

Einklappen
Keine Ankündigung bisher.

Fragen zur LBS Erstellung

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    Fragen zur LBS Erstellung

    Bei der Entwicklung meines ersten LBS habe ich folgende Problemstellung:

    Mein LBS soll eine IP Steckdose mfi mPower schalten und überwachen. Der EXEC Teil als Daemon überwacht den Status der IP Steckdose (z.B. wenn jemand die Steckdose per mPower Webinterface geschaltet hat.) Die Kommunikation funktioniert per ssh. Die Erweiterung des php um die ssh2 libs war noch recht einfach und fiunktioniert auch.

    Im EXEC Bereich wird eine ssh Verbindung zur IP Steckdose aufgebaut und bleibt ja auch bestehen, was die Performance erheblich verbessert, da beim Polling nicht jedes Mal der Verbindungsaufbau gemacht werden muss. Nur bei fehlerhaftem Polling, wird die SSH Verbindung neu aufgebaut.

    Gleiches wollte ich nun im LBS Teil auch machen, um die Steckdose Ereignis-getriggert (Änderung eines Eingangs) zu schalten. Funktionierte zunächst auch über eine statische Variable, die dann die SSH connectioin enthält. Beim Einfügen einer zweiten Steckdose in meine Logikseiten geht das natürlich unweigerlich schief, da für den LBS Teil ja keine neue Instanz angelegt wird, sondern derselbe Programmcode verwendet wird, nur mit anderen Eingangsparametern. Damit überlebt also nur die SSH Verbindung, die beim Aktivieren von edomi zuletzt initialisiert wird, da diese Verbindung in meiner statischen Variable $connection steht.

    Ich habe es nun zunächst so gelöst, dass meine statische Variable $connection ein Array von SSH connections enthält, das mit der IP Adresse der Steckdose indiziert ist, so dass für jeden LBS dieses Typs eine eigene statische Variable angelegt wird. Das funktioniert soweit auch.

    Meine Fragen sind:

    1. Gibt es einen eleganteren Weg?
    2. Sollte das Schalten der IP Steckdose per SSH nicht ohnehin in einen EXEC Bereich ausgelagert werden?
    3. Wie kann ich Signale vom LBS Bereich in den EXEC Bereich senden, wenn dieser schon als Daemon läuft? Muss ich das selbst machen. z.B. mit einer MessageQueue?
    4. Sollte ich ggf. Schalten und Pollen in zwei LBS zerlegen, dann könnte das Schalten im EXEC Bereich des Schalten-LBS gemacht werden.

    Ich hoffe das in etwa klar geworden ist, was ich meine.

    Ich warte auf eure Anregungen?
    VG
    André

    #2
    Zitat von jonofe Beitrag anzeigen
    1. Gibt es einen eleganteren Weg?
    Ich bin verwirrt Meinst du jetzt mit "Steckdose" eine "Dose in der Leiste" oder eine "Steckdosenleiste"? Anders: eine ssh Connection oder mehrere benoetigt? Wenn nur eine, sehe ich grad das Problem nicht... Vielleicht aber auch, weil gar keins da ist

    Zitat von jonofe Beitrag anzeigen
    2. Sollte das Schalten der IP Steckdose per SSH nicht ohnehin in einen EXEC Bereich ausgelagert werden?
    Ich schreibe ungern in fett, aber: auf jeden Fall!

    Zitat von jonofe Beitrag anzeigen
    3. Wie kann ich Signale vom LBS Bereich in den EXEC Bereich senden, wenn dieser schon als Daemon läuft? Muss ich das selbst machen. z.B. mit einer MessageQueue?
    Am einfachsten ueber interne Variablen. Also diese [v#1=2] Konstrukte, ist vermutlich in der Doku naeher erlaeutert.

    Zitat von jonofe Beitrag anzeigen
    4. Sollte ich ggf. Schalten und Pollen in zwei LBS zerlegen, dann könnte das Schalten im EXEC Bereich des Schalten-LBS gemacht werden.
    Das hat den Vorteil, dass der Daemon die Verbidung aufrecht erhaelt und im Hintergrund vor sich hinduempelt... Du haettest dann fuer jede "Leiste" einen Daemon (und natuerlich sowieso einen Baustein). Kommunikation zwischen EXEC und LBS Teil ueber Variablen machen...

    gruesse :: Michael

    Kommentar


      #3
      Zitat von wintermute Beitrag anzeigen
      Anders: eine ssh Connection oder mehrere benoetigt? Wenn nur eine, sehe ich grad das Problem nicht... Vielleicht aber auch, weil gar keins da ist
      Eine SSH connection für eine Leiste. Ich habe aber zwei Leisten im Einsatz. D.h. zweimail den Baustein in meiner Logikseite aber mit unterschiedlichen IP Adressen konfiguriert.

      Zitat von wintermute Beitrag anzeigen
      Ich schreibe ungern in fett, aber: auf jeden Fall!
      Okay. Spricht dann eher für einen Split in zwei Bausteine, oder ich muss das Schaltsignal vom LBS and den EXEC Daemon übergeben.

      Zitat von wintermute Beitrag anzeigen
      Am einfachsten ueber interne Variablen. Also diese [v#1=2] Konstrukte, ist vermutlich in der Doku naeher erlaeutert.
      Ist es richtig, dass in diesen Variablen (#v) nur Strings übertragen werden können? Der Versuch der Speicherung eines Objects (SSH Connection Ressource) ist bei mir zumindest fehlgeschlagen.

      Zitat von wintermute Beitrag anzeigen
      Das hat den Vorteil, dass der Daemon die Verbidung aufrecht erhaelt und im Hintergrund vor sich hinduempelt... Du haettest dann fuer jede "Leiste" einen Daemon (und natuerlich sowieso einen Baustein). Kommunikation zwischen EXEC und LBS Teil ueber Variablen machen...
      Wenn ich es mir jetzt recht überlege, bräuchte ich das Triggern eines Eingangs (Schaltsignal) ja gar nicht im LBS Teil zu behandeln, sondern könnte es direkt in meiner EXEC Schleife machen. Denn dort könnte ich doch auch bei jedem Durchlauf die LBS-Eingänge prüfen und den Kanal entprechend schalten, oder? Bleibt nur die Frage, wie die Performance aussieht, wenn ich 1x pro Sekunde im EXEC Daemon eine $E=getLogicEingangDataAll($id); mache. Hmmmm...

      Kommentar


        #4
        Mir fällt noch was ein ...

        Wäre es möglich über eine #v Variable den EXEC Bereich in zwei Bereiche zu unterscheiden, d.h.

        v=0 => EXEC wird als DAEMON aufgerufen: while (1) { <mein Code> }
        v=1 => EXEC wird als TRIGGER aufgerufen, um einen Schaltkanal zu schalten

        Im LBS Baustein wird dann sichergestellt, dass der Daemon nur einmal je LBS Instanz gestartet wird.
        Bei einem Input Trigger wird dann jeweil die EXEC Routine mit v=1 aufgerufen und würde sich nach dem Schalten beenden.
        Vermutlich würde es ein Performance Problem (im Hinblick auf die Schaltdauer, nicht auf die EDOMI Logik Engine) geben, da bei einem Schaltsignal immer eine neue SSH Verbindung aufgebaut werden muss, denn ich kann ja keine statische Variable verwenden, da der php EXEC Prozess ja nach der Ausführung endet. Richtig?

        Wichtig wäre mir, dass ich die einmal aufgebaute SSH Verbindung weiterverwenden kann, da sonst die Schaltvorgängen teilweise 1-3 Sekunden dauern. Bei Wiederverwendung der SSH Verbindung i.d.R. <1 Sekunde.

        Kommentar


          #5
          Das mit den Variablen und den Strings ist mir aufgefallen... brauchst Du ja aber garnicht.
          Im EXEC ziehst du die ssh Connection hoch und gut ist. Fuer die zweite Connection brauchst du ja einen zweiten LBS bzw Daemon und der laeuft dann komplett getrennt vom anderen. Triggern wuerde ich dann ueber die Variablen, ich mach gern:
          -im LBS auf "refresh" ueberprufen
          -Variable auf "value" setzen
          -im loop im EXEC Teil gucken ob die Variable gesetzt ist, dann
          -Aktion ausfuehren
          -Variable loeschen

          1s sleep im loop ist gut und stresst das system quasi garnicht, brauchste dir also keine Sorgen zu machen

          Ich poste hier mal (ausnahmsweise) einen Code der im Prinzip dasselbe macht, also einen EXEC Teil als Daemon, der auf Veraenderungen im LBS Teil reagiert. Wenn Du noch etwas Geduld hast: ich gedenke in Baelde die erste Squeeze-Server Version ins Portal zu stellen. Das macht im Prinzip dasselbe wie Dein Steckdosen-LBS (abstrakt gesprochen):

          PHP-Code:
          ###[LBS]###
          <?
          function LB_LBSID($id) {
              if ($E=getLogicEingangDataAll($id)) {
                  if ($E[1]['refresh']) {
                      if ($E[1]['value']==0) {
                          # setze Variable zum Beenden des EXEC-Teils
                          setLogicElementVar($id,1,0);
                      } else {
                          if (getLogicElementVar($id,1)!=1) {
                              setLogicElementVar($id,1,1);
                              callLogicFunctionExec(LBSID,$id);
                          }
                      }
                  }
              }
          }

          ?>
          ###[/LBS]###


          ###[EXEC]###
          <?
          require(dirname(__FILE__)."/../../../../main/include/php/incl_lbsexec.php");
          set_time_limit(0);
          sql_connect();
          if ($E=getLogicEingangDataAll($id)) {
              $hd=abs($E[2]['value'])/1000;
              $ld=abs($E[3]['value'])/1000;
              $ht=0;
              $lt=0;
              $z=$E[4]['value'];
              $zd=0;
              $delay=$E[5]['value']*1000;
              if (!$delay) { $delay=1000; }
              writeToTraceLog(0,true,"LBSLBS_ID: Oscillator daemon starting, times ".($hd*1000)."/".($ld*1000)."ms, delay ".($delay/1000)."ms, cycles $z");
              $v=false;
              while (getSysInfo(1)>=1) {
                  $time=microtime(true);
                  if ($v && ($time-$ht>=$hd)) {
                      setLogicLinkAusgang($id,1,0);
                      if ($z) { $zd++; }
                      $lt=$time;
                      $v=false;
                  } else if (!$v && ($time-$lt>=$ld)) {
                      if (!$z || ($zd<$z)) {
                          setLogicLinkAusgang($id,1,1);
                          $ht=$time;
                          $v=true;
                      } else {
                          finish();
                      }
                  }
                  if (getLogicElementVar($id,1)==0) { finish(); }
                  usleep($delay);
              }
          }

          finish();

          function finish() {
                  global $id;
                  writeToTraceLog(0,true,"LBSLBS_ID: Oscillator daemon terminating");
                  setLogicLinkAusgang($id,1,0);
                  setLogicElementVar($id,1,0);
                  sql_disconnect();
                  exit();
          }

          ?>
          ###[/EXEC]###

          Kommentar


            #6
            Super, danke für das Feedback. Klingt gut. Werde ich so mal umsetzen.
            Allerdings noch eine Frage dazu:
            Darf die Variable #v ein Array sein? Ansonsten befürchte ich, dass Trigger verloren gehen könnten, wenn nämlich die Variable #v in LBS Teil schneller geändert wird, als sie im EXEC Teil ausgelesen wird. Mit einem Array könnte man quasi eine FIFO Queue realisieren. EXEC nimmt vorne raus und LBS schreibt hinten ins array rein. Würde das funktionieren? Wie sind denn die #v Variablen in php realisiert? Shared Memory?
            Wird sicher gestellt, dass EXEC und LBS nicht gleichzeitig ändern?

            Kommentar


              #7
              Weiss ich alles nicht, ich stell auch keine Mutmassungen (mehr) zu an
              Christian kann da sicher mehr zu sagen.

              Aber wenn du "irgendeine" Variablenart da ablegen willst, dann benutze am besten (un)serialize, das sollte funktionieren (nach meinen Erfahrungen duerfen da naemlich nur Strings drinstehen, eventuell gibts sogar noch ne Groessenbeschraenkung!). Ich wuerde mich aber erstmal nicht damit befassen im LBS alle Eventualitaeten abzufangen, im Zweifelsfall einfach beim "Hersteller" beschweren
              Denn wenn da wirklich was verloren gehen sollte, dann ist das kein LBS-Problem, sondern eher ein generelles. Anders: die queue sollte schon von seiten Edomi realisiert sein... ich mach mir normalerweise auch keine Gedanken darueber wie eine Programmiersprache zB mit meinen Variablen umgeht, wenn die dabei Bloedsinn baut, nehm ich einfach ne andere

              gruesse :: Michael

              BTW: wieso muessen eigentlich alle zum "Ausprobieren" erstmal das schwierigste was grad zu finden ist ausprobieren?

              Kommentar


                #8
                Zitat von wintermute Beitrag anzeigen

                BTW: wieso muessen eigentlich alle zum "Ausprobieren" erstmal das schwierigste was grad zu finden ist ausprobieren?
                Ganz einfach: Wenn DAS funktioniert, dann weiss ich, dass ich auch den Rest auf EDOMI portiert bekomme.
                Und das "einfach" funktioniert, das haben ja hier schon viele dokumentiert und das glaube ich auch.

                Das mit der gemeinsamen Nutzung von Variablen zwischen EXEC und LBS ist aus meiner Sicht eher eine Designfrage von EDOMI. Wenn Christian da was zu sagen könnte, wäre das natürlich super.
                Vielleicht helfen solche Diskussionen ja auch anderen EDOMI besser zu verstehen.

                Viele Grüße und danke für eure Geduld mit einem EDOMI Einsteiger

                André




                Kommentar


                  #9
                  Zitat von jonofe Beitrag anzeigen
                  Und das "einfach" funktioniert, das haben ja hier schon viele dokumentiert und das glaube ich auch.
                  Stümmt... und weil es den Burj Khalifa gibt, kann ich auch was hoeheres in meinem Garten bauen. Mit was anderem geb ich mich nicht garnicht erst ab

                  Nix fuer ungut, aber um rudimentaere Funktionsweisen zu verstehen mag es hilfreich sein, auch mal am Anfang und nicht direkt mit Steilvorlage quer einzusteigen. Dein Vorhaben ist weder komplex noch unmachbar, aber IMHO ist es sinnvoller unten auf der Leiter anzufangen und nicht oben. Fragen wie 2) von oben zB waeren dann garnicht erst aufgepoppt.

                  Nicht falsch verstehen, das ist nicht boese gemeint oder so: aber gleich mit der Enduebung (Daemon-LBS mit persisten ssh-Connections) anzufangen und dann Einsteigerfragen zu stellen bringt ja keinem wirklich was. Es ist halt nicht nur PHP, man muss auch verstehen wie Edomi grad tickt...

                  Ungeachtet all dessen helf ich trotzdem gern - soweit ich kann

                  gruesse :: Michael

                  Kommentar


                    #10
                    Zitat von jonofe Beitrag anzeigen
                    Das mit der gemeinsamen Nutzung von Variablen zwischen EXEC und LBS ist aus meiner Sicht eher eine Designfrage von EDOMI. Wenn Christian da was zu sagen könnte, wäre das natürlich super.
                    Kann ich

                    Ganz einfach: Das EXEC-Script läuft als vollkommen unabhängige PHP-Instanz - daher sind natürlich KEINERLEI PHP(!)-Variablen aus dem LBS-Abschnitt verfügbar. Die LBS-Variablen (v#1 etc.) sind letztlich Datenbank-Records - daher können in diesen "Variablen" auch nicht beliebige Werte transportiert werden. In der DB sind die Variablen vom Typ VARCHAR(10000), werden allerdings vor dem UPDATE/INSERT noch um diverse Sonderzeichen (überwiegend ASCII-Steuerzeichen) erleichtert. Erlaubt sind alle "normalen" Zeichen, sowie CR/LF/TAB/etc. - jedoch z.B. nicht chr(0) usw...

                    Wie wintermute schon schrieb: Das Beste Vorgehen bei "Rohdaten" (Bytewerte) ist sicherlich das Konvertieren in Base64 oder etwas vergleichbares. Dann ist man auf der sicheren Seite!

                    PS: Wer unbedingt mag, kann natürlich auch Shared-Memory-Segmente einrichten etc. - allerdings wird's dann langsam kritisch für die Gesamtstabilität Da muss man also sehr genau wissen, was man da macht...
                    EDOMI - Intelligente Steuerung und Visualisierung KNX-basierter Elektro-Installationen (http://www.edomi.de)

                    Kommentar


                      #11
                      Vielen Dank für die Klärung. So ungefähr hatte ich es vermutet. D.h. bedeutet aber grundsätzlich, das im EXEC Teil Statuswelchsel von Variablen "übersehen" werden können, wenn die Variable "zu schnell" geändert wird. (Bsp. in meinem konkreten Fall: ich schalte zweimal schnell hintereinander eine Steckdose in meiner Leiste. Wenn die Durchlaufzeit meiner while(1)-Schleife länger dauert als dieser Wechsel, dann sehe ich nur den letzten Schaltvorgang).

                      Daher habe ich es jetzt in meinem LBS mit einer Message-Queue realisiert. Läuft bislang stabil und auch die Schaltzeiten sind sehr performant. Die eindeutige MessageQueue-ID generiere ich beim ersten Aufruf im LBS und generiere dort auch die message queue per:

                      PHP-Code:
                          if ($E=getLogicEingangDataAll($id)) {
                                if (
                      getLogicElementVar($id,1)!=1) {
                                  
                      setLogicElementVar($id,1,1);                    
                                  
                      $uniqid hexdec(uniqid()); 
                                  
                      setLogicElementVar($id,3,$uniqid);                    
                                  
                      callLogicFunctionExec(LBSID,$id);               
                                 } else { 
                                  
                      $uniqid getLogicElementVar($id,3);                    
                                     
                      $msg_queue msg_get_queue $uniqid );
                                 ...
                                 } 
                      Im Exec connecte ich dann zur message queue und frage bei jedem Durchlauf die message queue aus. Wenn keine message da ist, mache ich mit dem normalen Poll des Status weiter:

                      PHP-Code:
                      $uniqid=getLogicElementVar($id,3);                    
                      $msg_queue msg_get_queue $uniqid );

                      while (
                      1)
                      {
                          if (
                      $connection)
                          {
                              
                      $result msg_receive($msg_queue,0,$msgtype4096$msgtrueMSG_IPC_NOWAIT$msg_error);
                           ...
                          } 
                      Shared Memory wäre natürlich auch eine Idee, da habe ich die Erfahrung gemacht, dass man den Zugriff am besten mit Semaphoren absichert. War mir zu kompliziert.

                      @Christian: Der Zusatzaufwand bzgl. Performance im LBS wären also die beiden Statements msg_get_queue() und msg_send(), welche bei jedem Wechsel eines Eingangs ausgeführt werden. Ist das vernachlässigbar?

                      Kommentar


                        #12
                        Aber macht der Aufwand denn auch Sinn? Die GUI wird doch ohnehin garnich so schnell aktualisiert... oder loggst Du die Werte irgendwo mit?
                        Und auch wenn ichs nicht machen wuerde, IMHO geht shared-Memory am einfachsten (und stabilsten) mit dem memcached.

                        gruesse :: Michael

                        Kommentar


                          #13
                          Die msg_queue erzeugt schon eine Menge Overhead - aber in Zahlen kann ich das nicht beschreiben. Sprich: Am Besten mal austesten und messen (microtime). Ansonsten wäre auch meine Empfehlung: Alles so "schlank" wie möglich und sinnvoll halten...
                          EDOMI - Intelligente Steuerung und Visualisierung KNX-basierter Elektro-Installationen (http://www.edomi.de)

                          Kommentar


                            #14
                            Es ging mir eigentlich vor allem darum, dass keine Signale (Schaltvorgänge) verloren gehen. Möchte ich z.B. um meine Kamera zu resetten, die Steckdose aus und wieder einschalten, dann kann es sein, dass das AUS Signal gar nicht ausgeführt wird, da beim nächsten Schleifendurchlauf der Wert schon wieder auf on steht. Ja, ich weiss, dass kann man natürlich berücksichtigen, indem man zuerst ausschaltet, 3 Sekunden Timer startet, und danach erst wieder einschaltet. Ich möchte aber solche Probleme, die später sehr schwer zufinden sind, einfach ausschließen, indem sichergestellt wird, das nichts verloren geht.

                            Ich habe memcached noch nicht verwendet. Gibt es dabei sowas wie ein queue oder müsste ich selbst sicherstellen, dass meine Ereignisse z.B. durch ein FIFO array in der richtigen Reihenfolge bleiben? Genau aus dem Grund habe ich eine msg-queue verwendet. Ich muss im LBS nur Elemente reinschreiben und im EXEC auslesen. Es sind sowohl im LBS und EXEC lediglich 3 Statements und ich verwende es seit Jahren zuverlässig in meiner KNX Logik.

                            Werde mir aber memcached mal ansehen. Den Vorteil den ich bei shared memory sehen ist die Performance. Da sich aber ein ssh-Befehl anschließt, ist diese Performancesteigerung vermutlich über den eigentlichen Schaltvorgang hinweg kaum messbar.

                            Kommentar


                              #15
                              Zitat von gaert Beitrag anzeigen
                              Die msg_queue erzeugt schon eine Menge Overhead - aber in Zahlen kann ich das nicht beschreiben. Sprich: Am Besten mal austesten und messen (microtime). Ansonsten wäre auch meine Empfehlung: Alles so "schlank" wie möglich und sinnvoll halten...

                              Okay, werde das mal messen.

                              Kommentar

                              Lädt...
                              X