PicoC Energiezähler auslesen

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

    PicoC Energiezähler auslesen

    ​Hallo zusammen!

    Ein Freund von mir bat mich vor einiger Zeit um Hilfe für die Einbindung eines Energiezählers über Lan.
    Die Einbindung musste über PicoC erfolgen, da es sich um eine bidirektionale TCP-Verbindung handelt.

    Das ganze hat auch eigentlich funktioniert, aber wenn das Skript, dass ich geschrieben habe, einige Stunden im Betrieb ist, hört die Abfrage einfach auf.
    Wenn der Fehler auftritt, scheint das Skript offenbar in Frührente zu gehen, da ich keine Abfrage an den Zähler über Wireshark erkennen kann und auch der Loxone Monitor auf Level 3 keine Spur mehr aufzeigt vom Skript, wenn ihm Daten gesendet werden.

    Weil ich noch nicht so viel Berufserfahrung habe in der IT und es vorher noch nie mit Loxone Servern zu tun hatte, hoffe ich, dass mir jemand hier vielleicht helfen kann.


    Hardware:

    Energiezähler: Elster AS3000 mit einer AM300 Ethernet Erweiterung.

    Loxone Miniserver 1 Gen.


    ​​
    Die Projektseite:​
    Klicke auf die Grafik für eine vergrößerte Ansicht

Name: Unbenannt.PNG
Ansichten: 698
Größe: 72,0 KB
ID: 296837


    Code:
    // /?20285298!\r\n (nummer ist nur ein Beispiel)
    #define RD_BLOCK_SIZE 1000
    
    char szBuffer[RD_BLOCK_SIZE];
    char ps[RD_BLOCK_SIZE];
    
    int nCnt;
    int iplength;
    int znumlength;
    int ifstate = 0;
    int j;
    
    float input;
    
    char* ip;
    char* znum;
    char* ascii = "\r\n";
    
    while(TRUE) {
    
    while(input == 0 || iplength == 0 || znumlength == 0) { //Prüft ob alle nötigen Daten empfangen wurden
    input = getinput(0);
    ip = getinputtext(0);
    znum = getinputtext(1);
    
    iplength = strlen(ip);
    znumlength = strlen(znum);
    
    
    sleeps(2);
    }
    
    strcat(znum,ascii);
    
    while(input > 0) {
    
    for(int i=0; i < 10; i++) {
    
    STREAM* pTcpStream = stream_create(ip,0,0); //Stream oeffnen
    char* pTcpCmd = znum;
    
    stream_write(pTcpStream,pTcpCmd,strlen(pTcpCmd));
    stream_flush(pTcpStream);
    nCnt = stream_readline(pTcpStream,szBuffer,RD_BLOCK_SIZE, 4000);
    
    
    if(2 > nCnt) {
    
    stream_close(pTcpStream);
    
    }
    
    if(2 < nCnt) {
    
    break;
    
    }
    
    sleeps(1);
    
    }
    
    if (nCnt == -1) {
    
    setoutput(0,1); // Sendet eine 1 wenn ein Fehler auftritt
    
    }
    
    if(pTcpStream != NULL) {
    
    while(1 != nCnt) { // Liest den Stream aus
    if(1 < nCnt) {
    sleep(200);
    }
    nCnt = stream_readline(pTcpStream,szBuffer,RD_BLOCK_SIZE, 4000);
    printf("%d", nCnt);
    
    
    if(nCnt > 0)
    {
    ps = szBuffer;
    setoutputtext(0,ps); // Ausgabe des Streaminhalts
    }
    j++;
    
    if(-1 == nCnt && j > 2) { // Beendet den Stream bei unerwarteter Unterbrechung
    
    break;
    
    }
    
    }
    }
    stream_close(pTcpStream);
    iplength = 0;
    znumlength = 0;
    input = 0;
    setoutput(0,0);
    j = 0;
    }
    }
  • romildo
    Lebende Foren Legende
    • 25.08.2015
    • 5126

    #2
    Ich habe mir das Programm jetzt nicht im Detail angesehen, vermute aber dass es daran liegen könnte:
    <Alle Funktionen, die einen Zeiger zurückgeben, müssen den Speicher mit free () neu zuordnen, es sei denn, der Zeiger wurde als Parameter übergeben>
    lg Romildo

    Kommentar

    • Gast

      #3
      Hi Romildo,

      Danke für den guten Hinweis .
      Ich hab den Code jetzt angepasst, aber leider beendet sich das Skript immer noch aus dem nichts.


      Code:
      // /?20285298!\r\n (nummer ist nur ein Beispiel)
      #define RD_BLOCK_SIZE 1000
      
      char szBuffer[RD_BLOCK_SIZE];
      char ps[RD_BLOCK_SIZE];
      
      int nCnt;
      int iplength;
      int znumlength;
      int ifstate = 0;
      int j;
      
      char ascii[4];
      strncpy(ascii,"\r\n",4);
      
      float input;
      
      
      while(TRUE) {
      
      char* ip = (char*) malloc(sizeof(char)*28); //Prüft ob alle nötigen Daten empfangen wurden
      char* znum = (char*) malloc(sizeof(char)*11);
      
      while(input == 0 || iplength == 0 || znumlength == 0) {
      input = getinput(0);
      ip = getinputtext(0);
      znum = getinputtext(1);
      
      iplength = strlen(ip);
      znumlength = strlen(znum);
      
      
      sleeps(2);
      }
      
      strcat(znum,ascii);
      
      while(input > 0) {
      
      for(int i=0; i < 10; i++) {
      
      STREAM* pTcpStream = stream_create(ip,0,0); //Stream oeffnen
      
      stream_write(pTcpStream,znum,strlen(znum));
      stream_flush(pTcpStream);
      nCnt = stream_readline(pTcpStream,szBuffer,RD_BLOCK_SIZE, 4000);
      
      if(2 > nCnt) {
      
      stream_close(pTcpStream);
      
      }
      
      if(2 < nCnt) {
      
      break;
      
      }
      
      sleeps(1);
      
      }
      
      if (nCnt == -1) {
      
      setoutput(0,1); // Sendet eine 1 wenn ein Fehler auftritt
      
      }
      
      free(ip);
      free(znum);
      
      if(pTcpStream != NULL) {
      
      while(1 != nCnt) { // Liest den Stream aus
      if(1 < nCnt) {
      sleep(200);
      }
      nCnt = stream_readline(pTcpStream,szBuffer,RD_BLOCK_SIZE, 4000);
      
      
      if(nCnt > 0)
      {
      ps = szBuffer;
      setoutputtext(0,ps); // Ausgabe des Streaminhalts
      }
      j++;
      
      if(-1 == nCnt && j > 2) { // Beendet den Stream bei unerwarteter Unterbrechung
      
      break;
      
      }
      
      }
      }
      stream_close(pTcpStream);
      input = 0;
      iplength = 0;
      znumlength = 0;
      setoutput(0,0);
      j = 0;
      }
      }

      Kommentar

      • Labmaster
        Lox Guru
        • 20.01.2017
        • 2517

        #4
        1. du solltest nicht unnötige Operationszeit dem gesamten Miniserver System entziehen
        Man sollte möglichst also nur auf Änderungen von externen Ereignissen etwas ausführen. Ereignisse sind in deinem Fall nur Zustandsänderungen von Inputs.
        Somit sollte man das auch sauber handhaben und wenn keine Ereignis stattfindet das Programm am Stück möglichst lange schlafen lassen (sleep). Siehe auch die

        while(true){

        nEvents = getinputevent();
        if (nEvents & 0x0B) // Inputtext(0)=0x01 + Inputtext(1)=0x02 + input(0)=0x08 // 0x01 + 0x02 + 0x08 = 0x0B
        {
        ...
        }
        sleep(100);

        }
        2. neben 'pTcpStream' den du wieder freigibst hast du ja auch noch Speicher welcher über 'malloc' belegt wurde, auch dieser ist natürlich wieder sauber freizugeben.
        Wenn du diesen dann auch noch bei jedem Schleifendurchlauf neu belegst, (was sehr unglücklich gemacht ist) dann solltest du diesen zumindest vor jedem Schleifenende wieder freigeben.
        siehe Doku zu C free();



        Oh, jetzt hab ich so lange getippt, dass romildo schneller war

        Edit: Gast
        Die free() sind dort wo sie sind, nicht gut aufgehoben.
        So lange z.B. 'input' = 0 ist wird bei jedem while(true) Durchlauf der Speicher belegt aber nicht wieder freigegeben.
        Probier mal wenigstens die beiden free() ganz unten vor der letzten Klammer zu platzieren und nicht mitten in irgendwelchen Bedingungen und Schleifen welche eben nur bedingt ausgeführt werden.

        also so:


        while(true){
        char* ip = (char*) malloc(sizeof(char)*28); //Prüft ob alle nötigen Daten empfangen wurden
        char* znum = (char*) malloc(sizeof(char)*11);
        ...
        ...
        ...

        free(ip);
        free(znum);
        }


        Insgesamt ist das ganze Programm Konstukt so wie es aktuell ist, sicher nicht optimal für den Miniserver.
        Zuletzt geändert von Labmaster; 20.03.2021, 17:11.

        Kommentar


        • romildo
          romildo kommentierte
          Kommentar bearbeiten
          ​Dann hast Du aber wirklich sehr lange getippt, mein letzter Beitrag in diesem Post war vor 23 Stunden

        • Labmaster
          Labmaster kommentierte
          Kommentar bearbeiten
          Ups, da war wohl die Seite von gestern (noch vor deinem Kommentar) noch offen.
      • Gast

        #5
        Vielen Dank euch beiden, das Skript läuft jetzt wunderbar.

        Kommentar


        • romildo
          romildo kommentierte
          Kommentar bearbeiten
          war das mit der Freigabe jetzt die Lösung, oder gab es da noch etwas was wir nicht wissen?

        • Gast
          Gast kommentierte
          Kommentar bearbeiten
          Ja, das Problem waren die Freigaben, offenbar hat es auch geholfen, dass ich den Speicher mit malloc reserviert habe und nicht einfach einen String Pointer erstellt habe.

        • Labmaster
          Labmaster kommentierte
          Kommentar bearbeiten
          Ich bin mir relativ sicher, dass es an den falsch platzierten free() 's lag.
          Bei jedem Schleifendurchlauf wurde mit malloc Speicher belegt aber nur in gewissen Fällen auch wieder freigegeben.
      Lädt...