Allgemein über Datenlogger, Kommunikation, DFÜ
Moderator: Mod-Team
von zagibu » 27.07.2010, 16:41
Ich habe hier ein extrem simples C-Programm erstellt, welches ich benutze, um die Daten meines SolarMax Wechselrichters zu loggen. Der Mäxe ist per Ethernet an mein LAN angeschlossen, und das Programm läuft auf einer Linux-Maschine. Die Auswertung fehlt leider noch. Ich dachte mir, ich poste das mal, damit vielleicht der eine oder andere, der im Gegensatz zu mir wirklich C programmieren kann, einen Open-Source SolarMax Logger starten kann. Oder halt auch für den Eigengebrauch. Verbesserungsvorschläge sind herzlich willkommen. - 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 logfile 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://www.hinz.fdns.net/timestamp-in-c-and-python.html */
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <time.h>
void error(char *msg) { perror(msg); exit(0); }
int main(int argc, char *argv[]) { int sockfd, portno, n, log_interval; struct sockaddr_in serv_addr; struct hostent *server; char *message1 = "{FB;01;3A|64:KDY;KMT;KYR;KT0;TNF;TKK;PAC;PRL;SYS;SAL|0E8E}"; char *message2 = "{FB;01;3E|64:IL1;IDC;UL1;UDC;PAC;PRL;KDY;KYR;KT0;SYS;SAL|0F53}"; char buffer[256]; FILE *file; char *file_name; char *mode = "a"; time_t *timestamp;
// Check commandline arguments if (argc < 5) error("ERROR program needs hostname, port, logfile and loginterval (in seconds) as parameters");
// Get log file path from command line argument file_name = argv[3];
// Get log interval from command line argument log_interval = atoi(argv[4]);
// Try to open socket portno = atoi(argv[2]); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket");
// Try to resolve host server = gethostbyname(argv[1]); if (server == NULL) error("ERROR resolving host");
// Try to establish a connection 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,&serv_addr,sizeof(serv_addr)) < 0) error("ERROR connecting");
// Try to open log file if ((file = fopen(file_name, mode)) == NULL) error("ERROR opening log file");
// Make file unbuffered setbuf(file, NULL);
// Start sending the data requests and logging the answers while (1) { // Send message 1 n = write(sockfd,message1,strlen(message1)); if (n < 0) error("ERROR writing to socket");
// Read answer bzero(buffer, 256); n = read(sockfd, buffer, 255); if (n < 0) error("ERROR reading from socket");
// Write the current timestamp to file timestamp = time(NULL); fprintf(file, "NOW=%d;", (int) timestamp);
// Write the answer data to file fprintf(file, "%s;", buffer + 13);
// Send message 2 n = write(sockfd,message2,strlen(message2)); if (n < 0) error("ERROR writing to socket");
// Read answer bzero(buffer, 256); n = read(sockfd, buffer, 255); if (n < 0) error("ERROR reading from socket");
// Write the answer data to file fprintf(file, "%s;\n", buffer + 13);
// Wait for the specified number of seconds sleep(log_interval); }
return 0; }
Falls es schon ein anderes Open-Source Programm mit dem gleichen Zweck geben sollte, wäre ich für einen Link darauf dankbar.
-
zagibu
- Vielschreiber

-
- - Threadstarter -
-
- Beiträge: 195
- Registriert: 27.07.2010, 16:31
- PV-Anlage [kWp]: 3
- Info: Betreiber
von zagibu » 28.07.2010, 11:17
Ich hab das Programm noch ein wenig abgeändert, so dass es nur bei kritischen Fehlern beendet, und z.B. bei Verbindungsabbruch weiterläuft und versucht, die Verbindung wieder aufzubauen: - 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 logfile 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://www.hinz.fdns.net/timestamp-in-c-and-python.html */
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <time.h>
void error(char *msg) { perror(msg); exit(0); }
int main(int argc, char *argv[]) { int sockfd, portno, n, log_interval; struct sockaddr_in serv_addr; struct hostent *server; char *message1 = "{FB;01;3A|64:KDY;KMT;KYR;KT0;TNF;TKK;PAC;PRL;SYS;SAL|0E8E}"; char *message2 = "{FB;01;3E|64:IL1;IDC;UL1;UDC;PAC;PRL;KDY;KYR;KT0;SYS;SAL|0F53}"; char buffer[256]; FILE *file; char *file_name; char *mode = "a"; time_t *timestamp;
// Check commandline arguments if (argc < 5) error("ERROR program needs hostname, port, logfile and loginterval (in seconds) as parameters");
// Get log file path from command line argument file_name = argv[3];
// Get log interval from command line argument log_interval = atoi(argv[4]);
// Try to open log file if ((file = fopen(file_name, mode)) == NULL) error("ERROR opening log file");
// Make file unbuffered setbuf(file, NULL);
while (1) { // Try to open socket portno = atoi(argv[2]); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { sleep(60); continue; }
// Try to resolve host server = gethostbyname(argv[1]); if (server == NULL) { sleep(60); continue; }
// Try to establish a connection 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,&serv_addr,sizeof(serv_addr)) < 0) { sleep(60); continue; }
// Start sending the data requests and logging the answers while (1) { // Send message 1 n = write(sockfd,message1,strlen(message1)); if (n < 0) break;
// Read answer bzero(buffer, 256); n = read(sockfd, buffer, 255); if (n < 0) break;
// Write the current timestamp to file timestamp = time(NULL); fprintf(file, "NOW=%d;", (int) timestamp);
// Write the answer data to file fprintf(file, "%s;", buffer + 13);
// Send message 2 n = write(sockfd,message2,strlen(message2)); if (n < 0) break;
// Read answer bzero(buffer, 256); n = read(sockfd, buffer, 255); if (n < 0) break;
// Write the answer data to file fprintf(file, "%s;\n", buffer + 13);
// Wait for the specified number of seconds sleep(log_interval); } }
return 0; }
-
zagibu
- Vielschreiber

-
- - Threadstarter -
-
- Beiträge: 195
- Registriert: 27.07.2010, 16:31
- PV-Anlage [kWp]: 3
- Info: Betreiber
von borsti87 » 01.08.2010, 14:20
Hallo,
da ich selber gerade versuche ein Progamm zu schreiben mit dem ich meine Wechselrichter abfrage und ich bei der suche nach hilfreichen Informationen auf diesen Beitrag gestoßen bin hab ich mal eine kurze frage. Was wird mit TNF, SYS und SAL abgefragt? Dazu finde ich nichts in der Protokoldokumentation. By the way, vieleicht kann mir ja auch wer sagen was folgende Keys abfragen: KLD, SE1, SE2, SPR, SCD (Gefunden bei SolarView)
Danke und Gruß borsti87
-
borsti87
- Neu hier

-
- Beiträge: 6
- Registriert: 09.04.2010, 12:53
- Info: Interessent
von zagibu » 01.08.2010, 16:15
TNF ist die Netzfrequenz, SYS ist vermutlich "system state" und ist bei mir entweder 4E24,0 oder 4E28,0, was MaxTalk als 20004,0 (Betrieb auf MPP) und 20008,0 (Netzbetrieb) anzeigt. KLD ist Energie gestern (kWh last day). SAL könnte die "Anlagennummer" des Verbundes sein, also 0 für die erste, 1 für die zweite, etc. Ist bei mir jedenfalls immer 0. Die anderen Werte kenne ich leider auch nicht. Dein Post hat mich übrigens noch hier rauf geführt: http://blog.dest-unreach.be/2009/04/15/ ... engineeredIch denke, mit dieser Information kann ich mein Programm noch einiges verbessern. Hätte auch Zeit sparen können, statt das ganze mit Wireshark selbst auszulesen.
-
zagibu
- Vielschreiber

-
- - Threadstarter -
-
- Beiträge: 195
- Registriert: 27.07.2010, 16:31
- PV-Anlage [kWp]: 3
- Info: Betreiber
von zagibu » 04.08.2010, 16:42
Ich hab mal den Code noch etwas optimiert, so dass unter anderem nur noch eine Anfrage an den Mäxe mit allen interessanten Werten drin geschickt wird. Als nächsten Schritt werde ich versuchen statt einem Textfile als Log in eine MySQL DB zu schreiben, damit das Zeug dann per PHP + GD oder so ausgewertet werden kann. Übrigens, die Checksum, wie im Link in obigem Post beschrieben, ist keine übliche CRC-16 oder so was, sondern einfach alle Bytes aufsummiert und modulo 2^16 genommen. Musste ich mühsam aus seinem Perl Code herauslesen  . Beim Erstellen von eigenen Messages auch das Anpassen des Messagelänge-Feldes nicht vergessen, sonst antwortet der Mäxe nicht. Hat mich einige Zeit gekostet... - Code: Alles auswählen
/* Simple solarmax logger c program written by zagibu@gmx.ch in August 2010 This program is licensed under WTFPL 2 http://sam.zoy.org/wtfpl/
# ./logger hostname port logfile 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://www.hinz.fdns.net/timestamp-in-c-and-python.html */
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <time.h>
void error(char *msg) { perror(msg); exit(0); }
int main(int argc, char *argv[]) { int sockfd, portno, n, log_interval; struct sockaddr_in serv_addr; struct hostent* server; char* message = "{FB;01;46|64:KDY;KMT;KYR;KT0;TNF;TKK;PAC;PRL;IL1;IDC;UL1;UDC;SYS|1199}"; char buffer[256]; FILE* file; char* file_name; char* mode = "a"; time_t* timestamp;
// Check commandline arguments if (argc < 5) error("ERROR program needs hostname, port, logfile and loginterval (in seconds) as parameters");
// Get log file path from command line argument file_name = argv[3];
// Get log interval from command line argument log_interval = atoi(argv[4]);
// Try to open log file if ((file = fopen(file_name, mode)) == NULL) error("ERROR opening log file");
// Make file unbuffered setbuf(file, NULL);
while (1) { // Try to open socket portno = atoi(argv[2]); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { sleep(60); continue; }
// Try to resolve host server = gethostbyname(argv[1]); if (server == NULL) { sleep(60); continue; }
// Try to establish a connection 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,&serv_addr,sizeof(serv_addr)) < 0) { sleep(60); continue; }
// Start sending the data requests and logging the answers while (1) { printf("sending message: %s\n", message); // Send message 1 n = write(sockfd,message,strlen(message)); if (n < 0) break;
// Read answer bzero(buffer, 256); n = read(sockfd, buffer, 255); if (n < 0) break; printf("received answer: %s\n", buffer);
// Write the current timestamp to file timestamp = time(NULL); fprintf(file, "NOW=%d;", (int) timestamp);
// Write the answer data to file fprintf(file, "%s;", buffer + 13);
// Wait for the specified number of seconds sleep(log_interval); } }
return 0; }
-
zagibu
- Vielschreiber

-
- - Threadstarter -
-
- Beiträge: 195
- Registriert: 27.07.2010, 16:31
- PV-Anlage [kWp]: 3
- Info: Betreiber
von lasser » 05.08.2010, 19:30
Moin! zagibu hat geschrieben:Ich hab mal den Code noch etwas optimiert, so dass unter anderem nur noch eine Anfrage an den Mäxe mit allen interessanten Werten drin geschickt wird. Als nächsten Schritt werde ich versuchen statt einem Textfile als Log in eine MySQL DB zu schreiben, damit das Zeug dann per PHP + GD oder so ausgewertet werden kann.
Hm, funktioniert hier auch gut, unsere Anlage ist seit heut in Betrieb. Bei den evtl. anfallenden Datenmengen ist es sicher sinnvoll eine Datenbank zu verwenden. Muss ich mich dann wohl auch mal mit auseinandersetzen  Eines ist mir an der Antwort des WR aufgefallen: Der HEX-Wert von P ac ist viel zu hoch, ca. das doppelte des auf dem Display angezeigten Wertes. Stellst Du das bei Dir auch fest? Muss da vllt. eine Konstante abgezogen werden?
-
lasser
- Stammmitglied

-
- Beiträge: 109
- Registriert: 16.04.2010, 10:42
- PV-Anlage [kWp]: 5,5
- Info: Betreiber
von zagibu » 05.08.2010, 21:20
Bei mir ist es genau doppelt so hoch wie es im MaxTalk angezeigt wird. Warum weiss ich nicht. Ich hab den Logger mit DB-Anbindung fertig, aber leider konnte ich ihn noch nicht vollständig testen, weil mittlerweile mein Max ausgeschaltet hat  . Hier ist er trotzdem mal: - 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 */
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <mysql/mysql.h> #include <regex.h>
void error(char *msg) { perror(msg); exit(0); }
int main(int argc, char *argv[]) { int i = 0; int sockfd, portno, n, log_interval, result; struct sockaddr_in serv_addr; struct hostent* server; 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]*)"; int kdy, kmt, kyr, kt0, tnf, tkk, pac, prl, il1, idc, ul1, udc, sys; char buffer[512]; char query[512]; char value[32]; regex_t rx; regmatch_t* matches; MYSQL* connection = NULL;
// Check commandline arguments if (argc < 4) error("ERROR program needs hostname, port and loginterval (in seconds) as parameters");
// Get log interval from command line argument log_interval = strtol(argv[3]);
// Try to compile regular expression result = regcomp(&rx, expression, REG_EXTENDED); if (result != 0) { regerror(result, &rx, expression, sizeof(expression)); //fprintf(stderr, "Invalid regular expression: %s\n", expression); regfree(&rx); }
// Try to reserve memory for matches matches = (regmatch_t *) malloc((rx.re_nsub + 1) * sizeof(regmatch_t)); if (!matches) error("Out of memory.");
while (1) { // Try to establish connection to db server if (!connection) connection = mysql_init(NULL);
// Connect to database if (!mysql_real_connect(connection, "localhost", "root", "password", "solarmax", 0, NULL, 0)) error(mysql_error(connection));
// Try to open socket for communication with solarmax portno = strtol(argv[2]); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { sleep(60); continue; }
// Try to resolve solarmax address/hostname server = gethostbyname(argv[1]); if (server == NULL) { sleep(60); continue; }
// Try to establish a connection with solarmax 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,&serv_addr,sizeof(serv_addr)) < 0) { sleep(60); continue; }
// Start sending the data requests and logging the answers while (1) { printf("sending message: %s\n", message); // Send message n = write(sockfd,message,strlen(message)); if (n < 0) break;
// Read answer bzero(buffer, 256); n = read(sockfd, buffer, 255); if (n < 0) break; printf("received answer: %s\n", buffer);
// 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("ERROR no regexp match"); }
// Convert the extracted data fields to integer values kdy = strtol(strndup(buffer + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so), NULL, 16); kmt = strtol(strndup(buffer + matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so), NULL, 16); kyr = strtol(strndup(buffer + matches[3].rm_so, matches[3].rm_eo - matches[3].rm_so), NULL, 16); kt0 = strtol(strndup(buffer + matches[4].rm_so, matches[4].rm_eo - matches[4].rm_so), NULL, 16); tnf = strtol(strndup(buffer + matches[5].rm_so, matches[5].rm_eo - matches[5].rm_so), NULL, 16); tkk = strtol(strndup(buffer + matches[6].rm_so, matches[6].rm_eo - matches[6].rm_so), NULL, 16); pac = strtol(strndup(buffer + matches[7].rm_so, matches[7].rm_eo - matches[7].rm_so), NULL, 16); prl = strtol(strndup(buffer + matches[8].rm_so, matches[8].rm_eo - matches[8].rm_so), NULL, 16); il1 = strtol(strndup(buffer + matches[9].rm_so, matches[9].rm_eo - matches[9].rm_so), NULL, 16); idc = strtol(strndup(buffer + matches[10].rm_so, matches[10].rm_eo - matches[10].rm_so), NULL, 16); ul1 = strtol(strndup(buffer + matches[11].rm_so, matches[11].rm_eo - matches[11].rm_so), NULL, 16); udc = strtol(strndup(buffer + matches[12].rm_so, matches[12].rm_eo - matches[12].rm_so), NULL, 16); sys = strtol(strndup(buffer + matches[13].rm_so, matches[13].rm_eo - matches[13].rm_so), NULL, 16);
// 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);
// Execute the query to write the data into db mysql_query(connection, query); if (mysql_errno(connection)) error(mysql_error(connection));
// Wait for the specified number of seconds sleep(log_interval); } }
return 0; }
Zum Kompilieren braucht man die libmysqlclient und libmysqlclient-dev (heisst evtl. leicht anders je nach Distro) und muss den Schalter -lmysqlclient an den gcc Aufruf anhängen. Die DB-Verbindung ist halt noch hardcodiert. Bei mir sieht die DB so aus: - Code: Alles auswählen
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | solarmax | +--------------------+ 3 rows in set (0.00 sec)
mysql> use solarmax; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A
Database changed mysql> show tables; +--------------------+ | Tables_in_solarmax | +--------------------+ | log | +--------------------+ 1 row in set (0.00 sec)
mysql> show columns from log; +---------+-----------+------+-----+-------------------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+-----------+------+-----+-------------------+-------+ | created | timestamp | NO | PRI | CURRENT_TIMESTAMP | | | kdy | int(11) | NO | | NULL | | | kmt | int(11) | NO | | NULL | | | kyr | int(11) | NO | | NULL | | | kt0 | int(11) | NO | | NULL | | | tnf | int(11) | NO | | NULL | | | tkk | int(11) | NO | | NULL | | | pac | int(11) | NO | | NULL | | | prl | int(11) | NO | | NULL | | | il1 | int(11) | NO | | NULL | | | idc | int(11) | NO | | NULL | | | ul1 | int(11) | NO | | NULL | | | udc | int(11) | NO | | NULL | | | sys | int(11) | NO | | NULL | | +---------+-----------+------+-----+-------------------+-------+ 14 rows in set (0.00 sec)
Die Werte werden bereits im Logger zu Dezimalzahlen konvertiert. Evtl. muss man das noch anpassen, wenn man den Logger auf nem Mikrocontroller oder so laufen lassen will, bin nämlich nicht sicher ob das Regexp-Zeug dort auch so problemlos funktioniert. Vermutlich werde ich den Logger in einen Client und einen Server aufteilen, so dass der Client dann auf nem Mikro im LAN laufen kann, und nur die Daten vom Solarmax holt und an den Serverteil weiterschickt, welcher dann die Werte extrahiert, umwandelt und in der DB speichert. Aber das kommt wohl noch später als der Visualisierer, wenn überhaupt.
-
zagibu
- Vielschreiber

-
- - Threadstarter -
-
- Beiträge: 195
- Registriert: 27.07.2010, 16:31
- PV-Anlage [kWp]: 3
- Info: Betreiber
von zagibu » 06.08.2010, 11:54
Hier ist eine getestete Version, die zusammen mit der oben geposteten DB funktioniert (braucht natürlich immer noch libmysqlclient, libmysqlclient-dev und den gcc-Schalter -lmysqlclient am Ende): - 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 */
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <mysql/mysql.h> #include <regex.h>
#define DEBUG 0
void error(char *msg) { perror(msg); exit(0); }
int main(int argc, char *argv[]) { int i = 0; int sockfd, portno, n, log_interval, result; struct sockaddr_in serv_addr; struct hostent* server; 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]; char query[512]; char value[32]; regex_t rx; regmatch_t* matches; MYSQL* connection = NULL;
// Check commandline arguments if (argc < 4) error("ERROR program needs hostname, port and loginterval (in seconds) as parameters");
// 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)); //fprintf(stderr, "Invalid regular expression: %s\n", expression); regfree(&rx); }
// Try to reserve memory for matches matches = (regmatch_t *) malloc((rx.re_nsub + 1) * sizeof(regmatch_t)); if (!matches) error("Out of memory.");
while (1) { // Try to establish connection to db server if (!connection) connection = mysql_init(NULL);
// Connect to database if (!mysql_real_connect(connection, "localhost", "root", "password", "solarmax", 0, NULL, 0)) error(mysql_error(connection));
// Try to open socket for communication with solarmax portno = atoi(argv[2]); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { sleep(60); continue; }
// Try to resolve solarmax address/hostname server = gethostbyname(argv[1]); if (server == NULL) { sleep(60); continue; }
// Try to establish a connection with solarmax 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,&serv_addr,sizeof(serv_addr)) < 0) { sleep(60); continue; }
// Start sending the data requests and logging the answers while (1) { if (DEBUG) printf("sending message: %s\n", message);
// Send message n = write(sockfd,message,strlen(message)); if (n < 0) break;
// Read answer bzero(buffer, 256); n = read(sockfd, buffer, 255); if (n < 0) break; if (DEBUG) printf("received answer: %s\n", buffer);
// 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("ERROR no regexp match"); }
// Convert the extracted data fields to integer values kdy = strtol(strndup(buffer + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so), NULL, 16); kmt = strtol(strndup(buffer + matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so), NULL, 16); kyr = strtol(strndup(buffer + matches[3].rm_so, matches[3].rm_eo - matches[3].rm_so), NULL, 16); kt0 = strtol(strndup(buffer + matches[4].rm_so, matches[4].rm_eo - matches[4].rm_so), NULL, 16); tnf = strtol(strndup(buffer + matches[5].rm_so, matches[5].rm_eo - matches[5].rm_so), NULL, 16); tkk = strtol(strndup(buffer + matches[6].rm_so, matches[6].rm_eo - matches[6].rm_so), NULL, 16); pac = strtol(strndup(buffer + matches[7].rm_so, matches[7].rm_eo - matches[7].rm_so), NULL, 16); prl = strtol(strndup(buffer + matches[8].rm_so, matches[8].rm_eo - matches[8].rm_so), NULL, 16); il1 = strtol(strndup(buffer + matches[9].rm_so, matches[9].rm_eo - matches[9].rm_so), NULL, 16); idc = strtol(strndup(buffer + matches[10].rm_so, matches[10].rm_eo - matches[10].rm_so), NULL, 16); ul1 = strtol(strndup(buffer + matches[11].rm_so, matches[11].rm_eo - matches[11].rm_so), NULL, 16); udc = strtol(strndup(buffer + matches[12].rm_so, matches[12].rm_eo - matches[12].rm_so), NULL, 16); sys = strtol(strndup(buffer + matches[13].rm_so, matches[13].rm_eo - matches[13].rm_so), NULL, 16);
// 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);
// Execute the query to write the data into db mysql_query(connection, query); if (mysql_errno(connection)) error(mysql_error(connection));
// Wait for the specified number of seconds sleep(log_interval); } }
return 0; }
-
zagibu
- Vielschreiber

-
- - Threadstarter -
-
- Beiträge: 195
- Registriert: 27.07.2010, 16:31
- PV-Anlage [kWp]: 3
- Info: Betreiber
von lasser » 06.08.2010, 12:30
Moin! zagibu hat geschrieben:Hier ist eine getestete Version, die zusammen mit der oben geposteten DB funktioniert (braucht natürlich immer noch libmysqlclient, libmysqlclient-dev und den gcc-Schalter -lmysqlclient am Ende)...
So, ich denke ich bin raus. Bei mir wird der logger zwar kompiliert - mit warnings: - Code: Alles auswählen
user@rechner:~/test$ gcc -o logger logger.c -lmysqlclient logger.c: In function ‘error’: logger.c:28: warning: incompatible implicit declaration of built-in function ‘exit’ logger.c: In function ‘main’: logger.c:63: warning: incompatible implicit declaration of built-in function ‘malloc’ logger.c:75: warning: passing argument 1 of ‘error’ discards qualifiers from pointer target type logger.c:93: warning: incompatible implicit declaration of built-in function ‘bzero’ logger.c:95: warning: incompatible implicit declaration of built-in function ‘bcopy’ logger.c:99: warning: passing argument 2 of ‘connect’ from incompatible pointer type logger.c:110: warning: incompatible implicit declaration of built-in function ‘strlen’ logger.c:131: warning: incompatible implicit declaration of built-in function ‘strndup’ logger.c:154: warning: passing argument 1 of ‘error’ discards qualifiers from pointer target type
- aber es scheint mir nicht so, dass in die Datenbank, die bei mir so aussieht: - Code: Alles auswählen
mysql> show columns from log; +---------+-----------+------+-----+-------------------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+-----------+------+-----+-------------------+-------+ | created | timestamp | NO | PRI | CURRENT_TIMESTAMP | | | kdy | int(11) | NO | | 0 | | | kmt | int(11) | NO | | 0 | | | kyr | int(11) | NO | | 0 | | | kt0 | int(11) | NO | | 0 | | | tnf | int(11) | NO | | 0 | | | tkk | int(11) | NO | | 0 | | | pac | int(11) | NO | | 0 | | | prl | int(11) | NO | | 0 | | | il1 | int(11) | NO | | 0 | | | idc | int(11) | NO | | 0 | | | ul1 | int(11) | NO | | 0 | | | udc | int(11) | NO | | 0 | | | sys | int(11) | NO | | 0 | | +---------+-----------+------+-----+-------------------+-------+ 14 rows in set (0.08 sec)
irgendetwas hineingeschrieben wird. Ich weiß nicht, wo ich nachschauen soll, logs gibt's auch keine. Im Feld "Default" steht bei Dir allerdings "Null", bei mir die Ziffer 0. Macht das einen Unterschied? Wenn ja, wie erstelle ich die Tabelle denn? Wenn ich beim erstellen der Tabelle "NULL" angebe, erhalte ich die Meldung, dass das ein falscher Default-Wert wäre, bei der Ziffer 0 läuft alles durch. Wenn der logger läuft gibt es allerdings auch keine Fehlermeldungen... Ich wäre um Hilfestellung dankbar, auch wenn es dann OT wird und Du mich vielleicht zu irgendeiner manpage oder zu einem Forum jagst 
-
lasser
- Stammmitglied

-
- Beiträge: 109
- Registriert: 16.04.2010, 10:42
- PV-Anlage [kWp]: 5,5
- Info: Betreiber
von RasGer » 06.08.2010, 14:33
zagibu hat geschrieben:Die Auswertung fehlt leider noch.
Hi @all, falls ihr Euch bald auf ein Datenformat einigt und es mir bekannt gebt, könntet ihr (solange ihr noch nichts eigenes gebastelt habt  ) mein Tool für die Visualisierung der Daten benutzen. Ich würde dann einen Importfilter für Eure Daten schreiben. Details gerne per PN. Viele Grüße, Stephan
-
RasGer
- Forumsinventar

-
- Beiträge: 1532
- Registriert: 21.11.2007, 16:29
- Info: Betreiber
Zurück zu Datenlogger
Ähnliche Beiträge
Wer ist online?
Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast
|