SolarMax Datenlogger

Allgemein über Datenlogger, Kommunikation, DFÜ

Moderator: Mod-Team

 

3.83 (6 Bewertungen) | Zum Bewerten bitte anmelden

Re: SolarMax Datenlogger

Beitragvon zagibu » 12.08.2010, 09:05

Der Solarmax Wechselrichter scheint am Morgen, wenn er einschaltet, bereits Verbindungen anzunehmen, aber eine Weile noch keine Daten zu liefern. Das ist für den momentanen Logger noch problematisch, und ich muss die TCP-Geschichte umschreiben, um diesen Fakt zu adressieren.
zagibu
Vielschreiber
Vielschreiber
 
- Threadstarter -
 
Beiträge: 195
Registriert: 27.07.2010, 16:31
PV-Anlage [kWp]: 3
Info: Betreiber

Re: SolarMax Datenlogger

Beitragvon zagibu » 12.08.2010, 13:32

So, dies ist der Code, welcher non-blocking reads durchführt. Morgen werden wir sehen, ob's wirklich daran lag:

Code: Alles auswählen
/*
   Simple solarmax logger c program written by zagibu@gmx.ch in July 2010
   This program is licensed under WTFPL 2 http://sam.zoy.org/wtfpl/

   # ./logger hostname port loginterval

   Sources:
      - http://www.linuxhowtos.org/C_C++/socket.htm
      - http://wwwuser.gwdg.de/~kboehm/ebook/21_kap15_w6.html#49329
      - http://man.cx/setbuf%283%29
      - http://allfaq.org/forums/t/169895.aspx
      - http://dev.mysql.com/tech-resources/articles/mysql-capi-tutorial.html
*/

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <mysql/mysql.h>
#include <regex.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#define DEBUG 1

FILE* error_file = NULL;
char* error_file_name = "/var/log/solarmax-error.log";
char* error_mode = "w";
FILE* debug_file = NULL;
char* debug_file_name = "/var/log/solarmax-debug.log";
char* debug_mode = "w";

void error_exit(const char* msg) {
   perror(msg);
   if (error_file != NULL)
      fclose(error_file);
   if (debug_file != NULL)
      fclose(debug_file);
   exit(0);
}

void debug_entry(char* msg) {
   time_t timestamp = time(NULL);
   char debug_msg[512];
   char *time_now = ctime(&timestamp);
   time_now[strlen(time_now)-1]=0;
   if (debug_file == NULL)
      error_exit("ERROR writing to debug.log file");
   sprintf(debug_msg, "%s %s", time_now, msg);
   fprintf(debug_file, "%s\n", debug_msg);
}

void error_retry(char* msg) {
   time_t timestamp = time(NULL);
   char error_msg[512];
   char *time_now = ctime(&timestamp);
   time_now[strlen(time_now)-1]=0;
   if (error_file == NULL)
      error_exit("ERROR writing to error.log file");
   sprintf(error_msg, "%s %s", time_now, msg);
   fprintf(error_file, "%s\n", error_msg);
}

void set_nonblock(int sock)
{
   int flags;
   flags = fcntl(sock,F_GETFL,0);
   if (flags == -1)
      error_exit("ERROR no valid flags on socket");
   fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}

int main(int argc, char *argv[]) {
   int sockfd, portno, n, log_interval, result, counter;
   struct sockaddr_in serv_addr;
   struct hostent* server;
   char* dbhost = "localhost";
   char* dbname = "solarmax";
   char* dbuser = "user";
   char* dbpass = "password";
   char* message = "{FB;01;46|64:KDY;KMT;KYR;KT0;TNF;TKK;PAC;PRL;IL1;IDC;UL1;UDC;SYS|1199}";
   char* expression = "...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*)";
   int kdy, kmt, kyr, kt0, tnf, tkk, pac, prl, il1, idc, ul1, udc, sys;
   char buffer[512], buffer2[512];
   char query[512];
   char* temp;
   regex_t rx;
   regmatch_t* matches;
   MYSQL* connection = NULL;

   // Check commandline arguments
   if (argc < 4)
      error_exit("ERROR program needs hostname, port and loginterval (in seconds) as parameters");

   // Try to open error log file
   if ((error_file = fopen(error_file_name, error_mode)) == NULL)
      error_exit("ERROR opening error.log file");

   // Make file unbuffered
   setbuf(error_file, NULL);

   // Try to open debug log file, if necessary
   if(DEBUG) {
      if((debug_file = fopen(debug_file_name, debug_mode)) == NULL)
         error_exit("ERROR opening debug.log file");

      // Make file unbuffered
      setbuf(debug_file, NULL);
   }

   // Get log interval from command line argument
   log_interval = atoi(argv[3]);

   // Try to compile regular expression
   result = regcomp(&rx, expression, REG_EXTENDED);
   if (result != 0) {
      regerror(result, &rx, expression, sizeof(expression));
      regfree(&rx);
      sprintf(buffer, "ERROR invalid regular expression: %s", expression);
      error_exit(buffer);
   }

   // Try to reserve memory for matches
   matches = (regmatch_t *) malloc((rx.re_nsub + 1) * sizeof(regmatch_t));
   if (!matches)
      error_exit("Out of memory");

   // Connect to database
   connection = mysql_init(NULL);
   if (!mysql_real_connect(connection, dbhost, dbuser, dbpass, dbname, 0, NULL, 0))
      error_exit(mysql_error(connection));

   if (DEBUG) {
      sprintf(buffer, "Connected to database %s on host %s", dbname, dbhost);
      debug_entry(buffer);
   }

   while (1) {
      // Check if connection to db-server must be re-established
      if (mysql_ping(connection)) {
         // Connect to database
         if (!mysql_real_connect(connection, dbhost, dbuser, dbpass, dbname, 0, NULL, 0))
            error_exit(mysql_error(connection));

         if (DEBUG) {
            sprintf(buffer, "Connected to database %s on host %s", dbname, dbhost);
            debug_entry(buffer);
         }
      }

      // Try to open socket for communication with solarmax
      sockfd = socket(AF_INET, SOCK_STREAM, 0);
      if (sockfd < 0) {
         error_retry("Can't open any socket");
         sleep(60);
         continue;
      }

      // Try to resolve solarmax address/hostname
      server = gethostbyname(argv[1]);
      if (server == NULL) {
         sprintf(buffer, "Can't resolve \"%s\"", argv[1]);
         error_retry(buffer);
         sleep(60);
         continue;
      }

      // Try to establish a connection with solarmax
      portno = atoi(argv[2]);
      bzero((char *) &serv_addr, sizeof(serv_addr));
      serv_addr.sin_family = AF_INET;
      bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
      serv_addr.sin_port = htons(portno);
      if (connect(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) {
         sprintf(buffer, "%s: Can't connect to solarmax (%s) on port %d", strerror(errno), argv[1], portno);
         error_retry(buffer);
         sleep(60);
         continue;
      }

      // Make socket non-blocking
      set_nonblock(sockfd);

      if (DEBUG) {
         sprintf(buffer, "Connected to solarmax (%s) on port %d", argv[1], portno);
         debug_entry(buffer);
      }

      // Start sending the data requests and logging the answers
      while (1) {
         if (DEBUG) {
            sprintf(buffer, "Sending message: %s", message);
            debug_entry(buffer);
         }

         // Send message
         n = write(sockfd,message,strlen(message));
         if (n < 0) {
            error_retry("ERROR sending TCP packet");
            close(sockfd);
            break;
         }

         // Read answer
         bzero(buffer, 256);
         n = read(sockfd, buffer, 255);
         for (counter = 0; counter < 10 && n < 0 && errno == EAGAIN; counter++)
         {
            if (DEBUG)
               debug_entry("Socket contains no data, trying to read again later");
            sleep(1);
            n = read(sockfd, buffer, 255);
         }

         if (n < 0) {
            error_retry("ERROR receiving TCP packet");
            close(sockfd);
            break;
         }

         
         if (DEBUG) {
            sprintf(buffer2, "Received answer: %s", buffer);
            debug_entry(buffer2);
         }

         // Extract the data fields from answer
         result = regexec(&rx, buffer, rx.re_nsub + 1, matches, 0);
         if (result) {
            regerror(result, &rx, buffer, sizeof(buffer));
            error_exit("ERROR no regexp match");
         }

         // Convert the extracted data fields to integer values
         temp = strndup(buffer + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
         kdy = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so);
         kmt = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[3].rm_so, matches[3].rm_eo - matches[3].rm_so);
         kyr = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[4].rm_so, matches[4].rm_eo - matches[4].rm_so);
         kt0 = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[5].rm_so, matches[5].rm_eo - matches[5].rm_so);
         tnf = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[6].rm_so, matches[6].rm_eo - matches[6].rm_so);
         tkk = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[7].rm_so, matches[7].rm_eo - matches[7].rm_so);
         pac = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[8].rm_so, matches[8].rm_eo - matches[8].rm_so);
         prl = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[9].rm_so, matches[9].rm_eo - matches[9].rm_so);
         il1 = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[10].rm_so, matches[10].rm_eo - matches[10].rm_so);
         idc = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[11].rm_so, matches[11].rm_eo - matches[11].rm_so);
         ul1 = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[12].rm_so, matches[12].rm_eo - matches[12].rm_so);
         udc = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[13].rm_so, matches[13].rm_eo - matches[13].rm_so);
         sys = strtol(temp, NULL, 16);
         free(temp);

         // Construct the query
         sprintf(query, "INSERT INTO log (kdy, kmt, kyr, kt0, tnf, tkk, pac, prl, il1, idc, ul1, udc, sys) VALUES (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d);", kdy, kmt, kyr, kt0, tnf, tkk, pac, prl, il1, idc, ul1, udc, sys);

         if (DEBUG) {
            sprintf(buffer, "Executing query: %s", query);
            debug_entry(buffer);
         }

         // Execute the query to write the data into db
         mysql_query(connection, query);
         if (mysql_errno(connection))
            error_exit(mysql_error(connection));

         // Wait for the specified number of seconds
         sleep(log_interval);
      }
   }

   return 0;
}
zagibu
Vielschreiber
Vielschreiber
 
- Threadstarter -
 
Beiträge: 195
Registriert: 27.07.2010, 16:31
PV-Anlage [kWp]: 3
Info: Betreiber

Re: SolarMax Datenlogger

Beitragvon zagibu » 13.08.2010, 09:01

Das Problem ist behoben. Hier nun der vorerst finale Code. Ich habe noch die Debug- und wiederkehrenden Error-Messages ausgeschalten, damit die Log-Files sich nicht zur Unendlichkeit aufblähen. Wer den Logger sowieso am Abend killt und am Morgen neu startet, kann DEBUG wieder auf 1 setzen und die auskommentierten Zeilen wieder aktivieren, denn die Logs werden bei jedem Neustart des Loggers gespült:

Code: Alles auswählen
/*
   Simple solarmax logger c program written by zagibu@gmx.ch in July 2010
   This program is licensed under WTFPL 2 http://sam.zoy.org/wtfpl/

   # ./logger hostname port loginterval

   Sources:
      - http://www.linuxhowtos.org/C_C++/socket.htm
      - http://wwwuser.gwdg.de/~kboehm/ebook/21_kap15_w6.html#49329
      - http://man.cx/setbuf%283%29
      - http://allfaq.org/forums/t/169895.aspx
      - http://dev.mysql.com/tech-resources/articles/mysql-capi-tutorial.html
*/

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <mysql/mysql.h>
#include <regex.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#define DEBUG 0

FILE* error_file = NULL;
char* error_file_name = "/var/log/solarmax-error.log";
char* error_mode = "w";
FILE* debug_file = NULL;
char* debug_file_name = "/var/log/solarmax-debug.log";
char* debug_mode = "w";

void error_exit(const char* msg) {
   perror(msg);
   if (error_file != NULL)
      fclose(error_file);
   if (debug_file != NULL)
      fclose(debug_file);
   exit(0);
}

void debug_entry(char* msg) {
   time_t timestamp = time(NULL);
   char debug_msg[512];
   char *time_now = ctime(&timestamp);
   time_now[strlen(time_now)-1]=0;
   if (debug_file == NULL)
      error_exit("ERROR writing to debug.log file");
   sprintf(debug_msg, "%s %s", time_now, msg);
   fprintf(debug_file, "%s\n", debug_msg);
}

void error_retry(char* msg) {
   time_t timestamp = time(NULL);
   char error_msg[512];
   char *time_now = ctime(&timestamp);
   time_now[strlen(time_now)-1]=0;
   if (error_file == NULL)
      error_exit("ERROR writing to error.log file");
   sprintf(error_msg, "%s %s", time_now, msg);
   fprintf(error_file, "%s\n", error_msg);
}

void set_nonblock(int sock)
{
   int flags;
   flags = fcntl(sock,F_GETFL,0);
   if (flags == -1)
      error_exit("ERROR no valid flags on socket");
   fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}

int main(int argc, char *argv[]) {
   int sockfd, portno, n, log_interval, result, counter;
   struct sockaddr_in serv_addr;
   struct hostent* server;
   char* dbhost = "localhost";
   char* dbname = "solarmax";
   char* dbuser = "logger";
   char* dbpass = "m4xx3n";
   char* message = "{FB;01;46|64:KDY;KMT;KYR;KT0;TNF;TKK;PAC;PRL;IL1;IDC;UL1;UDC;SYS|1199}";
   char* expression = "...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*);...=([0-9A-F]*)";
   int kdy, kmt, kyr, kt0, tnf, tkk, pac, prl, il1, idc, ul1, udc, sys;
   char buffer[512], buffer2[512];
   char query[512];
   char* temp;
   regex_t rx;
   regmatch_t* matches;
   MYSQL* connection = NULL;

   // Check commandline arguments
   if (argc < 4)
      error_exit("ERROR program needs hostname, port and loginterval (in seconds) as parameters");

   // Try to open error log file
   if ((error_file = fopen(error_file_name, error_mode)) == NULL)
      error_exit("ERROR opening error.log file");

   // Make file unbuffered
   setbuf(error_file, NULL);

   // Try to open debug log file, if necessary
   if(DEBUG) {
      if((debug_file = fopen(debug_file_name, debug_mode)) == NULL)
         error_exit("ERROR opening debug.log file");

      // Make file unbuffered
      setbuf(debug_file, NULL);
   }

   // Get log interval from command line argument
   log_interval = atoi(argv[3]);

   // Try to compile regular expression
   result = regcomp(&rx, expression, REG_EXTENDED);
   if (result != 0) {
      regerror(result, &rx, expression, sizeof(expression));
      regfree(&rx);
      sprintf(buffer, "ERROR invalid regular expression: %s", expression);
      error_exit(buffer);
   }

   // Try to reserve memory for matches
   matches = (regmatch_t *) malloc((rx.re_nsub + 1) * sizeof(regmatch_t));
   if (!matches)
      error_exit("Out of memory");

   // Connect to database
   connection = mysql_init(NULL);
   if (!mysql_real_connect(connection, dbhost, dbuser, dbpass, dbname, 0, NULL, 0))
      error_exit(mysql_error(connection));

   if (DEBUG) {
      sprintf(buffer, "Connected to database %s on host %s", dbname, dbhost);
      debug_entry(buffer);
   }

   while (1) {
      // Check if connection to db-server must be re-established
      if (mysql_ping(connection)) {
         // Connect to database
         if (!mysql_real_connect(connection, dbhost, dbuser, dbpass, dbname, 0, NULL, 0))
            error_exit(mysql_error(connection));

         if (DEBUG) {
            sprintf(buffer, "Connected to database %s on host %s", dbname, dbhost);
            debug_entry(buffer);
         }
      }

      // Try to open socket for communication with solarmax
      sockfd = socket(AF_INET, SOCK_STREAM, 0);
      if (sockfd < 0) {
         //error_retry("Can't open any socket");
         sleep(60);
         continue;
      }

      // Try to resolve solarmax address/hostname
      server = gethostbyname(argv[1]);
      if (server == NULL) {
         //sprintf(buffer, "Can't resolve \"%s\"", argv[1]);
         //error_retry(buffer);
         sleep(60);
         continue;
      }

      // Try to establish a connection with solarmax
      portno = atoi(argv[2]);
      bzero((char *) &serv_addr, sizeof(serv_addr));
      serv_addr.sin_family = AF_INET;
      bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
      serv_addr.sin_port = htons(portno);
      if (connect(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) {
         //sprintf(buffer, "%s: Can't connect to solarmax (%s) on port %d", strerror(errno), argv[1], portno);
         //error_retry(buffer);
         sleep(60);
         continue;
      }

      // Make socket non-blocking
      set_nonblock(sockfd);

      if (DEBUG) {
         sprintf(buffer, "Connected to solarmax (%s) on port %d", argv[1], portno);
         debug_entry(buffer);
      }

      // Start sending the data requests and logging the answers
      while (1) {
         if (DEBUG) {
            sprintf(buffer, "Sending message: %s", message);
            debug_entry(buffer);
         }

         // Send message
         n = write(sockfd,message,strlen(message));
         if (n < 0) {
            //error_retry("ERROR sending TCP packet");
            close(sockfd);
            break;
         }

         // Read answer
         bzero(buffer, 256);
         n = read(sockfd, buffer, 255);
         for (counter = 0; counter < 10 && n < 0 && errno == EAGAIN; counter++)
         {
            if (DEBUG)
               debug_entry("Socket contains no data, trying to read again later");
            sleep(1);
            n = read(sockfd, buffer, 255);
         }

         if (n < 0) {
            //error_retry("ERROR receiving TCP packet");
            close(sockfd);
            break;
         }

         
         if (DEBUG) {
            sprintf(buffer2, "Received answer: %s", buffer);
            debug_entry(buffer2);
         }

         // Extract the data fields from answer
         result = regexec(&rx, buffer, rx.re_nsub + 1, matches, 0);
         if (result) {
            regerror(result, &rx, buffer, sizeof(buffer));
            error_exit("ERROR no regexp match");
         }

         // Convert the extracted data fields to integer values
         temp = strndup(buffer + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
         kdy = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so);
         kmt = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[3].rm_so, matches[3].rm_eo - matches[3].rm_so);
         kyr = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[4].rm_so, matches[4].rm_eo - matches[4].rm_so);
         kt0 = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[5].rm_so, matches[5].rm_eo - matches[5].rm_so);
         tnf = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[6].rm_so, matches[6].rm_eo - matches[6].rm_so);
         tkk = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[7].rm_so, matches[7].rm_eo - matches[7].rm_so);
         pac = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[8].rm_so, matches[8].rm_eo - matches[8].rm_so);
         prl = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[9].rm_so, matches[9].rm_eo - matches[9].rm_so);
         il1 = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[10].rm_so, matches[10].rm_eo - matches[10].rm_so);
         idc = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[11].rm_so, matches[11].rm_eo - matches[11].rm_so);
         ul1 = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[12].rm_so, matches[12].rm_eo - matches[12].rm_so);
         udc = strtol(temp, NULL, 16);
         free(temp);
         temp = strndup(buffer + matches[13].rm_so, matches[13].rm_eo - matches[13].rm_so);
         sys = strtol(temp, NULL, 16);
         free(temp);

         // Construct the query
         sprintf(query, "INSERT INTO log (kdy, kmt, kyr, kt0, tnf, tkk, pac, prl, il1, idc, ul1, udc, sys) VALUES (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d);", kdy, kmt, kyr, kt0, tnf, tkk, pac, prl, il1, idc, ul1, udc, sys);

         if (DEBUG) {
            sprintf(buffer, "Executing query: %s", query);
            debug_entry(buffer);
         }

         // Execute the query to write the data into db
         mysql_query(connection, query);
         if (mysql_errno(connection))
            error_exit(mysql_error(connection));

         // Wait for the specified number of seconds
         sleep(log_interval);
      }
   }

   return 0;
}


Ich werde nun also bis auf weiteres nicht daran weiterarbeiten, es sei denn, jemand stellt Fehler fest.
zagibu
Vielschreiber
Vielschreiber
 
- Threadstarter -
 
Beiträge: 195
Registriert: 27.07.2010, 16:31
PV-Anlage [kWp]: 3
Info: Betreiber

Re: SolarMax Datenlogger

Beitragvon zagibu » 14.08.2010, 12:44

Hier ist noch ein Link zum Visualizer, der meine Anlage anzeigt, falls jemand das Ganze in Aktion sehen will: http://node23.net/solarmax
Sind halt erst ein paar Tage geloggt, und teilweise noch mit Lücken, aber ich denke man sieht schon, wie es funktionieren sollte.
zagibu
Vielschreiber
Vielschreiber
 
- Threadstarter -
 
Beiträge: 195
Registriert: 27.07.2010, 16:31
PV-Anlage [kWp]: 3
Info: Betreiber

Re: SolarMax Datenlogger

Beitragvon lasser » 18.08.2010, 23:29

Jo, ich hab mal ein wenig weiter gebastelt.

So sieht's bei uns aus:

http://lassowski.dyndns.org/BierderLOG/solarertrag.php
lasser
Stammmitglied
Stammmitglied
 
Beiträge: 109
Registriert: 16.04.2010, 10:42
PV-Anlage [kWp]: 5,5
Info: Betreiber

Re: SolarMax Datenlogger

Beitragvon zagibu » 19.08.2010, 17:52

Nicht schlecht, Herr Specht. Ich schlage vor, dass du die Linien erst nach dem Gitter zeichnest, sonst löscht es diese stellenweise aus.

Weiterhin könntest du für die Linien den y-Wert des vorherigen Punktes "mitschleppen" und dann statt nem Punkt ne Linie von diesem vorherigen Wert zum neuen machen. Sollte dem Auge helfen, der Linie besser folgen zu können, besonders, wenn die Werte stark herumspringen in einem Abschnitt. Must halt diesen nachgeschleppten Wert vor der Schleife mit 0 initialisieren, und evtl. keine Linie zeichnen, solange der 0 ist.
zagibu
Vielschreiber
Vielschreiber
 
- Threadstarter -
 
Beiträge: 195
Registriert: 27.07.2010, 16:31
PV-Anlage [kWp]: 3
Info: Betreiber

Re: SolarMax Datenlogger

Beitragvon lasser » 19.08.2010, 22:18

Moin!
zagibu hat geschrieben:Nicht schlecht, Herr Specht.

Danke.
Ich schlage vor, dass du die Linien erst nach dem Gitter zeichnest, sonst löscht es diese stellenweise aus.

Ja, bin ich bloß noch nicht zu gekommen. Das wird etwas besser aussehen.
Weiterhin könntest du für die Linien den y-Wert des vorherigen Punktes "mitschleppen" und dann statt nem Punkt ne Linie von diesem vorherigen Wert zum neuen machen. Sollte dem Auge helfen, der Linie besser folgen zu können, besonders, wenn die Werte stark herumspringen in einem Abschnitt. Must halt diesen nachgeschleppten Wert vor der Schleife mit 0 initialisieren, und evtl. keine Linie zeichnen, solange der 0 ist.

Ja, auch das wäre viel besser als es jetzt ist. Krieg ich wohl hin. Dabei kommen aber vermutlich "eckige" Kurven bei raus. Noch schöner wäre weiche Kurven, aber da fehlt mir komplett der Überblick...
lasser
Stammmitglied
Stammmitglied
 
Beiträge: 109
Registriert: 16.04.2010, 10:42
PV-Anlage [kWp]: 5,5
Info: Betreiber

Re: SolarMax Datenlogger

Beitragvon lasser » 19.08.2010, 23:24

Sodele, udc und tkk werden jetzt als Treppenstufen dargestellt. Sieht nicht ganz perfekt aus, aber viel besser als vorher :-)

http://lassowski.dyndns.org/BierderLOG/solarertrag.php
lasser
Stammmitglied
Stammmitglied
 
Beiträge: 109
Registriert: 16.04.2010, 10:42
PV-Anlage [kWp]: 5,5
Info: Betreiber

Re: SolarMax Datenlogger

Beitragvon zagibu » 20.08.2010, 10:14

Sieht schon viel besser aus. Die Leistung hätte ich aber hinter dem Gitter gelassen, weil dieses sonst unter Umständen grossflächig verdeckt wird, und dann die Höhe der Kurven evtl. nicht mehr gut abgeschätzt werden kann.
zagibu
Vielschreiber
Vielschreiber
 
- Threadstarter -
 
Beiträge: 195
Registriert: 27.07.2010, 16:31
PV-Anlage [kWp]: 3
Info: Betreiber

Re: SolarMax Datenlogger

Beitragvon lasser » 20.08.2010, 14:21

Moin!
zagibu hat geschrieben:Sieht schon viel besser aus. Die Leistung hätte ich aber hinter dem Gitter gelassen, weil dieses sonst unter Umständen grossflächig verdeckt wird, und dann die Höhe der Kurven evtl. nicht mehr gut abgeschätzt werden kann.

Das habe ich nicht gemacht, weil dann 2 while-Schleifen nötig sind, um die Daten ins Bild zu setzen.
Aber ich hab's jetzt trotzdem mal versucht, wird den Rechner schon nicht einknicken lassen... Allerdings wird mit folgendem Code zwar schön das Gitter vor die Leistung gemalt, allerdings tauchen kdy, tkk und udc nicht mehr auf. Und ich find den Fehler nicht.

Hier mal der Code zu meiner function draw_day($start, $end), vielleicht siehst Du, woran es liegt (und nicht wundern, ist nicht mehr so schön strukturiert wie bei Dir und alles auf eine Bildbreite von 820 Pixeln ausgerichtet):
Code: Alles auswählen
       function draw_day($start, $end) {
          // Select data from given day
          //$result = @mysql_query("SELECT HOUR(created) AS hour, MINUTE(created) AS minute, pac FROM log WHERE created BETWEEN '$start' AND '$end'") or die(mysql_error());
          $result = @mysql_query("SELECT HOUR(created) AS hour, MINUTE(created) AS minute, pac, kdy, tkk, udc FROM log WHERE created BETWEEN '$start' AND '$end'") or die(mysql_error());
          if (mysql_num_rows($result) == 0)
          {
             // No data...create dummy image
             $image = imagecreatetruecolor(10, 10);
             $white = imagecolorallocate($image, 255, 255, 255);
             imagefill($image, 0, 0, $white);
             imagepng($image, 'img/data.png');
             imagedestroy($image);
         
             return 'Keine Daten f&uuml;r diese Periode.<br />';
          }

          // Initialize pac image
          // Sun rise and fall during longest day at your place, must be integer
          $rise = 6; $fall = 22;
          // Pixel per hour should be equal to log entries per hour (I log every minute)
          $px_per_hour = 42;
          // Width = hours * px per hour + gap
          //$width = ($fall - $rise) * $px_per_hour + 50;
          $width = ($fall - $rise) * $px_per_hour +148;
          $maxpac = 5200;
          $maxkdy = 40;
          $maxtkk = 60;
          $lasttkk = 0;
          $maxudc = 400;
          $lastudc = 0;
          // How many W per diagram line
          $step_w = 500;
          $step_kdy = 5;
          $step_tkk = 8;
          $step_udc = 40;
          // How many px per diagram line (W/px = $step_w / $vert_px)
          $vert_px = 30;
          // Height = number of lines * px per line + px per line (for 0-line) + gap
          $height = $maxpac / $step_w * $vert_px + 40;
          // Create image, prepare colors and set background to white
          $image = imagecreatetruecolor($width, $height);
          $white = imagecolorallocate($image, 255, 255, 255);
          $gray = imagecolorallocate($image, 128, 128, 128);
          $black = imagecolorallocate($image, 0, 0, 0);
          $green = imagecolorallocate($image, 0, 196, 64);
          $blue = imagecolorallocate($image, 0, 0, 255);
          $red = imagecolorallocate($image, 255, 0, 0);
          imagefill($image, 0, 0, $white);

          // Draw pac values
          while($row = mysql_fetch_assoc($result)) {
             // Determine x position
             $xpos = ($row['hour'] - $rise) * $px_per_hour + $row['minute'] / 60 * $px_per_hour + 25;
             // Calculate y position with logged pac
             $pac = $row['pac'] / $step_w * $vert_px;
             // Draw pac line
             imageline($image, $xpos, $height - 30, $xpos, $height - 30 - $pac, $green);
          }

          // Draw horizontal lines with some space above and below
          for ($i = 0; $i <= $maxpac / $step_w; $i++) {
             // Create horizontal grid line
             $ypos = $height - $i * $vert_px - 30;
             imageline($image, 12, $ypos, $width - 110, $ypos, $gray);
             // Draw the pac value at the end of the horizontal line
             $pac = $i * $step_w;
             $kdy = $i * $step_kdy;
             $tkk = $i * $step_tkk;
             $udc = $i * $step_udc;
             imagefttext($image, 7, 0, $width - 109, $ypos + 4, $black, '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf', $pac);
             imagefttext($image, 7, 0, $width - 74, $ypos + 4, $blue, '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf', $kdy);
             imagefttext($image, 7, 0, $width - 47, $ypos + 4, $black, '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf', $tkk);
             imagefttext($image, 7, 0, $width - 25, $ypos + 4, $red, '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf', $udc);             
          }

          // Draw vertical lines with some space at the left and right
          for ($i = 0; $i <= $fall - $rise; $i++) {
             // Create vertical grid line
             $xpos = $i * $px_per_hour + 25;
             imageline($image, $xpos, 5, $xpos, $height - 25, $gray);
             // Draw the hour value at the end of the vertical line
             $hour = ($i + $rise) % 24 . ':00';
             imagefttext($image, 8, 0, $xpos - 10, $height - 12, $black, '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf', $hour);
          }

          imagefttext($image, 7, 0, $width - 107, 10, $black, '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf', "(W)");
          imagefttext($image, 6, 0, $width - 84, 10, $blue, '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf', "(kW/h)");
          imagefttext($image, 6, 0, $width - 50, 10, $black, '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf', "(°C)");
          imagefttext($image, 7, 0, $width - 25, 10, $red, '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf', "(V)");
         
          // Draw other logged values: kdy, tkk, udc
          while($row = mysql_fetch_assoc($result)) {
             // Determine x position
             $xpos = ($row['hour'] - $rise) * $px_per_hour + $row['minute'] / 60 * $px_per_hour + 25;
             $lastxpos = $xpos;
             // Logged kdy is ten times as high as effective
             $kdy = $row['kdy'] / 10 / $step_kdy * $vert_px;
             // Draw kdy dot
             imagesetpixel($image, $xpos, $height - 30 - $kdy, $blue);
             // draw tkk as a stair-line
             $tkk = $row['tkk'] / $step_tkk * $vert_px;
                if ($lasttkk == 0) {
                imagesetpixel($image, $xpos, $height - 30 - $tkk, $black);
                } else {
                imageline($image, $lastxpos, $height - 30 - $lasttkk, $xpos, $height - 30 - $tkk, $black);
                }
             $lasttkk = $tkk;
             // Logged udc is ten times as high as effective
             $udc = $row['udc'] / 10 / $step_udc * $vert_px;
                if ($lastudc == 0) {
                imagesetpixel($image, $xpos, $height - 30 - $udc, $red);
                } else {
                imageline($image, $lastxpos, $height - 30 - $lastudc, $xpos, $height - 30 - $udc, $red);
                }
             $lastudc = $udc;
          }
         
          imagepng($image, 'img/data.png');
          imagedestroy($image);

          return '<p>Leistung in Watt im Verlauf des Tages, Tagesertrag, Temperatur WR, DC-Spannung</p>';
       }
lasser
Stammmitglied
Stammmitglied
 
Beiträge: 109
Registriert: 16.04.2010, 10:42
PV-Anlage [kWp]: 5,5
Info: Betreiber

VorherigeNächste

Zurück zu Datenlogger



Ähnliche Beiträge

Bedarf an weiterem Datenlogger? Sun-Watch    Forum: Sun-Watch    Antw.: 437
Datenlogger mit Vollausstattung    Forum: Datenlogger    Antw.: 16
Noch ein Datenlogger...    Forum: Datenlogger    Antw.: 1
Datenlogger für Steca Grid9000 mit GSM?    Forum: Datenlogger    Antw.: 14
Datenlogger    Forum: Inselanlagen    Antw.: 3

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste