PageRenderTime 63ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/smatool.c

https://code.google.com/p/sma-bluetooth/
C | 2422 lines | 2082 code | 167 blank | 173 comment | 595 complexity | d6a1a42880b0df3e51abf2a544dd3211 MD5 | raw file
  1. /* tool to read power production data for SMA solar power convertors
  2. Copyright Wim Hofman 2010
  3. Copyright Stephen Collier 2010,2011
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  14. /* compile gcc -lbluetooth -lcurl -lmysqlclient -g -o smatool smatool.c */
  15. #define _XOPEN_SOURCE /* glibc needs this */
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <unistd.h>
  19. #include <sys/socket.h>
  20. #include <bluetooth/bluetooth.h>
  21. #include <bluetooth/rfcomm.h>
  22. #include <string.h>
  23. #include <math.h>
  24. #include <time.h>
  25. #include <assert.h>
  26. #include <sys/types.h>
  27. #include <curl/curl.h>
  28. #include "repost.h"
  29. #include "sma_mysql.h"
  30. /*
  31. * u16 represents an unsigned 16-bit number. Adjust the typedef for
  32. * your hardware.
  33. */
  34. typedef u_int16_t u16;
  35. #define PPPINITFCS16 0xffff /* Initial FCS value */
  36. #define PPPGOODFCS16 0xf0b8 /* Good final FCS value */
  37. #define ASSERT(x) assert(x)
  38. #define SCHEMA "3" /* Current database schema */
  39. #define _XOPEN_SOURCE /* glibc2 needs this */
  40. typedef struct{
  41. unsigned int key1;
  42. unsigned int key2;
  43. char description[20];
  44. char units[20];
  45. float divisor;
  46. } ReturnType;
  47. char *accepted_strings[] = {
  48. "$END",
  49. "$ADDR",
  50. "$TIME",
  51. "$SER",
  52. "$CRC",
  53. "$POW",
  54. "$DTOT",
  55. "$ADD2",
  56. "$CHAN",
  57. "$ITIME",
  58. "$TMMI",
  59. "$TMPL",
  60. "$TIMESTRING",
  61. "$TIMEFROM1",
  62. "$TIMETO1",
  63. "$TIMEFROM2",
  64. "$TIMETO2",
  65. "$TESTDATA",
  66. "$ARCHIVEDATA1",
  67. "$PASSWORD",
  68. "$SIGNAL",
  69. "$UNKNOWN",
  70. "$INVCODE",
  71. "$ARCHCODE",
  72. "$INVERTERDATA",
  73. "$CNT", /*Counter of sent packets*/
  74. "$TIMEZONE", /*Timezone seconds +1 from GMT*/
  75. "$TIMESET" /*Unknown string involved in time setting*/
  76. };
  77. extern void live_mysql( ConfType *, int, int, int, int, int, int, char *, long long, char *, float, char *, int );
  78. int cc,debug = 0,verbose=0;
  79. unsigned char fl[1024] = { 0 };
  80. static u16 fcstab[256] = {
  81. 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
  82. 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
  83. 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
  84. 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
  85. 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
  86. 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
  87. 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
  88. 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
  89. 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
  90. 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
  91. 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
  92. 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
  93. 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
  94. 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
  95. 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
  96. 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
  97. 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
  98. 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
  99. 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
  100. 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
  101. 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
  102. 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
  103. 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
  104. 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
  105. 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
  106. 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
  107. 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
  108. 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
  109. 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
  110. 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
  111. 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
  112. 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
  113. };
  114. /*
  115. * Calculate a new fcs given the current fcs and the new data.
  116. */
  117. u16 pppfcs16(u16 fcs, void *_cp, int len)
  118. {
  119. register unsigned char *cp = (unsigned char *)_cp;
  120. /* don't worry about the efficiency of these asserts here. gcc will
  121. * recognise that the asserted expressions are constant and remove them.
  122. * Whether they are usefull is another question.
  123. */
  124. ASSERT(sizeof (u16) == 2);
  125. ASSERT(((u16) -1) > 0);
  126. while (len--)
  127. fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff];
  128. return (fcs);
  129. }
  130. /*
  131. * Strip escapes (7D) as they aren't includes in fcs
  132. */
  133. void
  134. strip_escapes(unsigned char *cp, int *len)
  135. {
  136. int i,j;
  137. for( i=0; i<(*len); i++ ) {
  138. if( cp[i] == 0x7d ) { /*Found escape character. Need to convert*/
  139. cp[i] = cp[i+1]^0x20;
  140. for( j=i+1; j<(*len)-1; j++ ) cp[j] = cp[j+1];
  141. (*len)--;
  142. }
  143. }
  144. }
  145. /*
  146. * Add escapes (7D) as they are required
  147. */
  148. void
  149. add_escapes(unsigned char *cp, int *len)
  150. {
  151. int i,j;
  152. for( i=19; i<(*len); i++ ) {
  153. switch( cp[i] ) {
  154. case 0x7d :
  155. case 0x7e :
  156. case 0x11 :
  157. case 0x12 :
  158. case 0x13 :
  159. for( j=(*len); j>i; j-- ) cp[j] = cp[j-1];
  160. cp[i+1] = cp[i]^0x20;
  161. cp[i]=0x7d;
  162. (*len)++;
  163. }
  164. }
  165. }
  166. /*
  167. * Recalculate and update length to correct for escapes
  168. */
  169. void
  170. fix_length_send(unsigned char *cp, int *len)
  171. {
  172. int delta=0;
  173. if( debug == 1 )
  174. printf( "sum=%x\n", cp[1]+cp[3] );
  175. if(( cp[1] != (*len)+1 ))
  176. {
  177. delta = (*len)+1 - cp[1];
  178. if( debug == 1 ) {
  179. printf( " length change from %x to %x diff=%x \n", cp[1],(*len)+1,cp[1]+cp[3] );
  180. }
  181. cp[3] = (cp[1]+cp[3])-((*len)+1);
  182. cp[1] =(*len)+1;
  183. switch( cp[1] ) {
  184. case 0x3a: cp[3]=0x44; break;
  185. case 0x3b: cp[3]=0x43; break;
  186. case 0x3c: cp[3]=0x42; break;
  187. case 0x3d: cp[3]=0x41; break;
  188. case 0x3e: cp[3]=0x40; break;
  189. case 0x3f: cp[3]=0x41; break;
  190. case 0x40: cp[3]=0x3e; break;
  191. case 0x41: cp[3]=0x3f; break;
  192. case 0x42: cp[3]=0x3c; break;
  193. case 0x52: cp[3]=0x2c; break;
  194. case 0x53: cp[3]=0x2b; break;
  195. case 0x54: cp[3]=0x2a; break;
  196. case 0x55: cp[3]=0x29; break;
  197. case 0x56: cp[3]=0x28; break;
  198. case 0x57: cp[3]=0x27; break;
  199. case 0x58: cp[3]=0x26; break;
  200. case 0x59: cp[3]=0x25; break;
  201. case 0x5a: cp[3]=0x24; break;
  202. case 0x5b: cp[3]=0x23; break;
  203. case 0x5c: cp[3]=0x22; break;
  204. case 0x5d: cp[3]=0x23; break;
  205. case 0x5e: cp[3]=0x20; break;
  206. case 0x5f: cp[3]=0x21; break;
  207. case 0x60: cp[3]=0x1e; break;
  208. case 0x61: cp[3]=0x1f; break;
  209. case 0x62: cp[3]=0x1e; break;
  210. default: printf( "NO CONVERSION!" );getchar();break;
  211. }
  212. if( debug == 1 )
  213. printf( "new sum=%x\n", cp[1]+cp[3] );
  214. }
  215. }
  216. /*
  217. * Recalculate and update length to correct for escapes
  218. */
  219. void
  220. fix_length_received(unsigned char *received, int *len)
  221. {
  222. int delta=0;
  223. int sum;
  224. if( received[1] != (*len) )
  225. {
  226. sum = received[1]+received[3];
  227. if (debug == 1) printf( "sum=%x", sum );
  228. delta = (*len) - received[1];
  229. if (debug == 1) printf( "length change from %x to %x\n", received[1], (*len) );
  230. if(( received[3] != 0x13 )&&( received[3] != 0x14 )) {
  231. received[1] = (*len);
  232. switch( received[1] ) {
  233. case 0x52: received[3]=0x2c; break;
  234. case 0x5a: received[3]=0x24; break;
  235. case 0x66: received[3]=0x1a; break;
  236. case 0x6a: received[3]=0x14; break;
  237. default: received[3]=sum-received[1]; break;
  238. }
  239. }
  240. }
  241. }
  242. /*
  243. * How to use the fcs
  244. */
  245. void
  246. tryfcs16(unsigned char *cp, int len)
  247. {
  248. u16 trialfcs;
  249. unsigned
  250. int i;
  251. unsigned char stripped[1024] = { 0 };
  252. memcpy( stripped, cp, len );
  253. /* add on output */
  254. if (debug ==2){
  255. printf("String to calculate FCS\n");
  256. for (i=0;i<len;i++) printf("%02x ",cp[i]);
  257. printf("\n\n");
  258. }
  259. trialfcs = pppfcs16( PPPINITFCS16, stripped, len );
  260. trialfcs ^= 0xffff; /* complement */
  261. fl[cc] = (trialfcs & 0x00ff); /* least significant byte first */
  262. fl[cc+1] = ((trialfcs >> 8) & 0x00ff);
  263. cc+=2;
  264. if (debug == 2 ){
  265. printf("FCS = %x%x %x\n",(trialfcs & 0x00ff),((trialfcs >> 8) & 0x00ff), trialfcs);
  266. }
  267. }
  268. unsigned char conv(char *nn)
  269. {
  270. unsigned char tt=0,res=0;
  271. int i;
  272. for(i=0;i<2;i++){
  273. switch(nn[i]){
  274. case 65: /*A*/
  275. case 97: /*a*/
  276. tt = 10;
  277. break;
  278. case 66: /*B*/
  279. case 98: /*b*/
  280. tt = 11;
  281. break;
  282. case 67: /*C*/
  283. case 99: /*c*/
  284. tt = 12;
  285. break;
  286. case 68: /*D*/
  287. case 100: /*d*/
  288. tt = 13;
  289. break;
  290. case 69: /*E*/
  291. case 101: /*e*/
  292. tt = 14;
  293. break;
  294. case 70: /*F*/
  295. case 102: /*f*/
  296. tt = 15;
  297. break;
  298. default:
  299. tt = nn[i] - 48;
  300. }
  301. res = res + (tt * pow(16,1-i));
  302. }
  303. return res;
  304. }
  305. int
  306. check_send_error( ConfType * conf, int *s, int *rr, unsigned char *received, int cc, unsigned char *last_sent, int *terminated, int *already_read )
  307. {
  308. int bytes_read,i,j;
  309. unsigned char buf[1024]; /*read buffer*/
  310. unsigned char header[3]; /*read buffer*/
  311. struct timeval tv;
  312. fd_set readfds;
  313. tv.tv_sec = 0; // set timeout of reading
  314. tv.tv_usec = 5000;
  315. memset(buf,0,1024);
  316. FD_ZERO(&readfds);
  317. FD_SET((*s), &readfds);
  318. select((*s)+1, &readfds, NULL, NULL, &tv);
  319. (*terminated) = 0; // Tag to tell if string has 7e termination
  320. // first read the header to get the record length
  321. if (FD_ISSET((*s), &readfds)){ // did we receive anything within 5 seconds
  322. bytes_read = recv((*s), header, sizeof(header), 0); //Get length of string
  323. (*rr) = 0;
  324. for( i=0; i<sizeof(header); i++ ) {
  325. received[(*rr)] = header[i];
  326. if (debug == 1) printf("%02x ", received[(*rr)]);
  327. (*rr)++;
  328. }
  329. }
  330. else
  331. {
  332. if( verbose==1) printf("Timeout reading bluetooth socket\n");
  333. (*rr) = 0;
  334. memset(received,0,1024);
  335. return -1;
  336. }
  337. if (FD_ISSET((*s), &readfds)){ // did we receive anything within 5 seconds
  338. bytes_read = recv((*s), buf, header[1]-3, 0); //Read the length specified by header
  339. }
  340. else
  341. {
  342. if( verbose==1) printf("Timeout reading bluetooth socket\n");
  343. (*rr) = 0;
  344. memset(received,0,1024);
  345. return -1;
  346. }
  347. if ( bytes_read > 0){
  348. if (debug == 1) printf("\nReceiving\n");
  349. if (debug == 1){
  350. printf( " %08x: .. .. .. .. .. .. .. .. .. .. .. .. ", 0 );
  351. j=12;
  352. for( i=0; i<sizeof(header); i++ ) {
  353. if( j%16== 0 )
  354. printf( "\n %08x: ",j);
  355. printf("%02x ",header[i]);
  356. j++;
  357. }
  358. for (i=0;i<bytes_read;i++) {
  359. if( j%16== 0 )
  360. printf( "\n %08x: ",j);
  361. printf("%02x ",buf[i]);
  362. j++;
  363. }
  364. printf(" rr=%d",(bytes_read+(*rr)));
  365. printf("\n\n");
  366. }
  367. if ((cc==bytes_read)&&(memcmp(received,last_sent,cc) == 0)){
  368. printf( "ERROR received what we sent!" ); getchar();
  369. //Need to do something
  370. }
  371. if( buf[ bytes_read-1 ] == 0x7e )
  372. (*terminated) = 1;
  373. else
  374. (*terminated) = 0;
  375. for (i=0;i<bytes_read;i++){ //start copy the rec buffer in to received
  376. if (buf[i] == 0x7d){ //did we receive the escape char
  377. switch (buf[i+1]){ // act depending on the char after the escape char
  378. case 0x5e :
  379. received[(*rr)] = 0x7e;
  380. break;
  381. case 0x5d :
  382. received[(*rr)] = 0x7d;
  383. break;
  384. default :
  385. received[(*rr)] = buf[i+1] ^ 0x20;
  386. break;
  387. }
  388. i++;
  389. }
  390. else {
  391. received[(*rr)] = buf[i];
  392. }
  393. if (debug == 1) printf("%02x ", received[(*rr)]);
  394. (*rr)++;
  395. }
  396. fix_length_received( received, rr );
  397. if (debug == 1) {
  398. printf("\n");
  399. for( i=0;i<(*rr); i++ ) printf("%02x ", received[(i)]);
  400. }
  401. if (debug == 1) printf("\n\n");
  402. (*already_read)=1;
  403. }
  404. return 0;
  405. }
  406. int
  407. read_bluetooth( ConfType * conf, int *s, int *rr, unsigned char *received, int cc, unsigned char *last_sent, int *terminated )
  408. {
  409. int bytes_read,i,j;
  410. unsigned char buf[1024]; /*read buffer*/
  411. unsigned char header[3]; /*read buffer*/
  412. struct timeval tv;
  413. fd_set readfds;
  414. tv.tv_sec = conf->bt_timeout; // set timeout of reading
  415. tv.tv_usec = 0;
  416. memset(buf,0,1024);
  417. FD_ZERO(&readfds);
  418. FD_SET((*s), &readfds);
  419. select((*s)+1, &readfds, NULL, NULL, &tv);
  420. (*terminated) = 0; // Tag to tell if string has 7e termination
  421. // first read the header to get the record length
  422. if (FD_ISSET((*s), &readfds)){ // did we receive anything within 5 seconds
  423. bytes_read = recv((*s), header, sizeof(header), 0); //Get length of string
  424. (*rr) = 0;
  425. for( i=0; i<sizeof(header); i++ ) {
  426. received[(*rr)] = header[i];
  427. if (debug == 2) printf("%02x ", received[i]);
  428. (*rr)++;
  429. }
  430. }
  431. else
  432. {
  433. if( verbose==1) printf("Timeout reading bluetooth socket\n");
  434. (*rr) = 0;
  435. memset(received,0,1024);
  436. return -1;
  437. }
  438. if (FD_ISSET((*s), &readfds)){ // did we receive anything within 5 seconds
  439. bytes_read = recv((*s), buf, header[1]-3, 0); //Read the length specified by header
  440. }
  441. else
  442. {
  443. if( verbose==1) printf("Timeout reading bluetooth socket\n");
  444. (*rr) = 0;
  445. memset(received,0,1024);
  446. return -1;
  447. }
  448. if ( bytes_read > 0){
  449. if (debug == 1) printf("\nReceiving\n");
  450. if (debug == 1){
  451. printf( " %08x: .. .. .. .. .. .. .. .. .. .. .. .. ", 0 );
  452. j=12;
  453. for( i=0; i<sizeof(header); i++ ) {
  454. if( j%16== 0 )
  455. printf( "\n %08x: ",j);
  456. printf("%02x ",header[i]);
  457. j++;
  458. }
  459. for (i=0;i<bytes_read;i++) {
  460. if( j%16== 0 )
  461. printf( "\n %08x: ",j);
  462. printf("%02x ",buf[i]);
  463. j++;
  464. }
  465. printf(" rr=%d",(bytes_read+(*rr)));
  466. printf("\n\n");
  467. }
  468. if ((cc==bytes_read)&&(memcmp(received,last_sent,cc) == 0)){
  469. printf( "ERROR received what we sent!" ); getchar();
  470. //Need to do something
  471. }
  472. if( buf[ bytes_read-1 ] == 0x7e )
  473. (*terminated) = 1;
  474. else
  475. (*terminated) = 0;
  476. for (i=0;i<bytes_read;i++){ //start copy the rec buffer in to received
  477. if (buf[i] == 0x7d){ //did we receive the escape char
  478. switch (buf[i+1]){ // act depending on the char after the escape char
  479. case 0x5e :
  480. received[(*rr)] = 0x7e;
  481. break;
  482. case 0x5d :
  483. received[(*rr)] = 0x7d;
  484. break;
  485. default :
  486. received[(*rr)] = buf[i+1] ^ 0x20;
  487. break;
  488. }
  489. i++;
  490. }
  491. else {
  492. received[(*rr)] = buf[i];
  493. }
  494. if (debug == 2) printf("%02x ", received[(*rr)]);
  495. (*rr)++;
  496. }
  497. fix_length_received( received, rr );
  498. if (debug == 2) {
  499. printf("\n");
  500. for( i=0;i<(*rr); i++ ) printf("%02x ", received[(i)]);
  501. }
  502. if (debug == 1) printf("\n\n");
  503. }
  504. return 0;
  505. }
  506. int select_str(char *s)
  507. {
  508. int i;
  509. for (i=0; i < sizeof(accepted_strings)/sizeof(*accepted_strings);i++)
  510. {
  511. //printf( "\ni=%d accepted=%s string=%s", i, accepted_strings[i], s );
  512. if (!strcmp(s, accepted_strings[i])) return i;
  513. }
  514. return -1;
  515. }
  516. unsigned char * get_timezone_in_seconds( unsigned char *tzhex )
  517. {
  518. time_t curtime;
  519. struct tm *loctime;
  520. struct tm *utctime;
  521. int day,month,year,hour,minute,isdst;
  522. char *returntime;
  523. float localOffset;
  524. int tzsecs;
  525. returntime = (char *)malloc(6*sizeof(char));
  526. curtime = time(NULL); //get time in seconds since epoch (1/1/1970)
  527. loctime = localtime(&curtime);
  528. day = loctime->tm_mday;
  529. month = loctime->tm_mon +1;
  530. year = loctime->tm_year + 1900;
  531. hour = loctime->tm_hour;
  532. minute = loctime->tm_min;
  533. isdst = loctime->tm_isdst;
  534. utctime = gmtime(&curtime);
  535. if( debug == 1 ) printf( "utc=%04d-%02d-%02d %02d:%02d local=%04d-%02d-%02d %02d:%02d diff %d hours\n", utctime->tm_year+1900, utctime->tm_mon+1,utctime->tm_mday,utctime->tm_hour,utctime->tm_min, year, month, day, hour, minute, hour-utctime->tm_hour );
  536. localOffset=(hour-utctime->tm_hour)+(minute-utctime->tm_min)/60;
  537. if( debug == 1 ) printf( "localOffset=%f\n", localOffset );
  538. if(( year > utctime->tm_year+1900 )||( month > utctime->tm_mon+1 )||( day > utctime->tm_mday ))
  539. localOffset+=24;
  540. if(( year < utctime->tm_year+1900 )||( month < utctime->tm_mon+1 )||( day < utctime->tm_mday ))
  541. localOffset-=24;
  542. if( debug == 1 ) printf( "localOffset=%f isdst=%d\n", localOffset, isdst );
  543. if( isdst > 0 )
  544. localOffset=localOffset-1;
  545. tzsecs = (localOffset) * 3600 + 1;
  546. if( tzsecs < 0 )
  547. tzsecs=65536+tzsecs;
  548. if( debug == 1 ) printf( "tzsecs=%x %d\n", tzsecs, tzsecs );
  549. tzhex[1] = tzsecs/256;
  550. tzhex[0] = tzsecs -(tzsecs/256)*256;
  551. if( debug == 1 ) printf( "tzsecs=%02x %02x\n", tzhex[1], tzhex[0] );
  552. return tzhex;
  553. }
  554. int auto_set_dates( ConfType * conf, int * daterange, int mysql, char * datefrom, char * dateto )
  555. /* If there are no dates set - get last updated date and go from there to NOW */
  556. {
  557. MYSQL_ROW row;
  558. char SQLQUERY[200];
  559. time_t curtime;
  560. int day,month,year,hour,minute,second;
  561. struct tm *loctime;
  562. if( mysql == 1 )
  563. {
  564. OpenMySqlDatabase( conf->MySqlHost, conf->MySqlUser, conf->MySqlPwd, conf->MySqlDatabase);
  565. //Get last updated value
  566. sprintf(SQLQUERY,"SELECT DATE_FORMAT( DateTime, \"%%Y-%%m-%%d %%H:%%i:%%S\" ) FROM DayData ORDER BY DateTime DESC LIMIT 1" );
  567. if (debug == 1) printf("%s\n",SQLQUERY);
  568. DoQuery(SQLQUERY);
  569. if ((row = mysql_fetch_row(res))) //if there is a result, update the row
  570. {
  571. strcpy( datefrom, row[0] );
  572. }
  573. mysql_free_result( res );
  574. mysql_close(conn);
  575. }
  576. if( strlen( datefrom ) == 0 )
  577. strcpy( datefrom, "2000-01-01 00:00:00" );
  578. curtime = time(NULL); //get time in seconds since epoch (1/1/1970)
  579. loctime = localtime(&curtime);
  580. day = loctime->tm_mday;
  581. month = loctime->tm_mon +1;
  582. year = loctime->tm_year + 1900;
  583. hour = loctime->tm_hour;
  584. minute = loctime->tm_min;
  585. second = loctime->tm_sec;
  586. sprintf( dateto, "%04d-%02d-%02d %02d:%02d:00", year, month, day, hour, minute );
  587. (*daterange)=1;
  588. if( verbose == 1 ) printf( "Auto set dates from %s to %s\n", datefrom, dateto );
  589. return 1;
  590. }
  591. int is_light( ConfType * conf )
  592. /* Check if all data done and past sunset or before sunrise */
  593. {
  594. int light=1;
  595. MYSQL_ROW row;
  596. char SQLQUERY[200];
  597. OpenMySqlDatabase( conf->MySqlHost, conf->MySqlUser, conf->MySqlPwd, conf->MySqlDatabase);
  598. //Get Start of day value
  599. sprintf(SQLQUERY,"SELECT if(sunrise < NOW(),1,0) FROM Almanac WHERE date= DATE_FORMAT( NOW(), \"%%Y-%%m-%%d\" ) " );
  600. if (debug == 1) printf("%s\n",SQLQUERY);
  601. DoQuery(SQLQUERY);
  602. if ((row = mysql_fetch_row(res))) //if there is a result, update the row
  603. {
  604. if( atoi( (char *)row[0] ) == 0 ) light=0;
  605. }
  606. if( light ) {
  607. sprintf(SQLQUERY,"SELECT if( dd.datetime > al.sunset,1,0) FROM DayData as dd left join Almanac as al on al.date=DATE(dd.datetime) and al.date=DATE(NOW()) WHERE 1 ORDER BY dd.datetime DESC LIMIT 1" );
  608. if (debug == 1) printf("%s\n",SQLQUERY);
  609. DoQuery(SQLQUERY);
  610. if ((row = mysql_fetch_row(res))) //if there is a result, update the row
  611. {
  612. if( atoi( (char *)row[0] ) == 1 ) light=0;
  613. }
  614. }
  615. if (debug == 1) printf("Before close\n",SQLQUERY);
  616. mysql_close(conn);
  617. return light;
  618. }
  619. //Set a value depending on inverter
  620. void SetInverterType( ConfType * conf )
  621. {
  622. if( strcmp(conf->Inverter, "1700TL") == 0 ) {
  623. conf->InverterCode[0] = 0x12;
  624. conf->InverterCode[1] = 0x1a;
  625. conf->InverterCode[2] = 0xd9;
  626. conf->InverterCode[3] = 0x38;
  627. conf->ArchiveCode = 0x63;
  628. }
  629. if( strcmp(conf->Inverter, "2100TL") == 0 ) {
  630. conf->InverterCode[0] = 0x17;
  631. conf->InverterCode[1] = 0x97;
  632. conf->InverterCode[2] = 0x51;
  633. conf->InverterCode[3] = 0x38;
  634. conf->ArchiveCode = 0x63;
  635. }
  636. if( strcmp(conf->Inverter, "3000TL") == 0 ) {
  637. conf->InverterCode[0] = 0x12;
  638. conf->InverterCode[1] = 0x1a;
  639. conf->InverterCode[2] = 0xd9;
  640. conf->InverterCode[3] = 0x38;
  641. conf->InverterCode[0] = 0x32;
  642. conf->InverterCode[1] = 0x42;
  643. conf->InverterCode[2] = 0x85;
  644. conf->InverterCode[3] = 0x38;
  645. conf->ArchiveCode = 0x71;
  646. }
  647. if( strcmp(conf->Inverter, "3000TLHF") == 0 ) {
  648. conf->InverterCode[0] = 0x1b;
  649. conf->InverterCode[1] = 0xb1;
  650. conf->InverterCode[2] = 0xa6;
  651. conf->InverterCode[3] = 0x38;
  652. conf->ArchiveCode = 0x83;
  653. }
  654. if( strcmp(conf->Inverter, "4000TL") == 0 ) {
  655. conf->InverterCode[0] = 0x78;
  656. conf->InverterCode[1] = 0x21;
  657. conf->InverterCode[2] = 0xbf;
  658. conf->InverterCode[3] = 0x3a;
  659. conf->ArchiveCode = 0x4e;
  660. }
  661. if( strcmp(conf->Inverter, "5000TL") == 0 ) {
  662. conf->InverterCode[0] = 0x3f;
  663. conf->InverterCode[1] = 0x10;
  664. conf->InverterCode[2] = 0xfb;
  665. conf->InverterCode[3] = 0x39;
  666. conf->ArchiveCode = 0x4e;
  667. }
  668. if( strcmp(conf->Inverter, "7000") == 0 ) {
  669. conf->InverterCode[0] = 0xcf;
  670. conf->InverterCode[1] = 0x84;
  671. conf->InverterCode[2] = 0x84;
  672. conf->InverterCode[3] = 0x3a;
  673. conf->ArchiveCode = 0x63;
  674. }
  675. if( strcmp(conf->Inverter, "10000TL") == 0 ) {
  676. conf->InverterCode[0] = 0x69;
  677. conf->InverterCode[1] = 0x45;
  678. conf->InverterCode[2] = 0x32;
  679. conf->InverterCode[3] = 0x39;
  680. conf->ArchiveCode = 0x80;
  681. }
  682. if( strcmp(conf->Inverter, "XXXXTL") == 0 ) {
  683. conf->InverterCode[0] = 0x99;
  684. conf->InverterCode[1] = 0x35;
  685. conf->InverterCode[2] = 0x40;
  686. conf->InverterCode[3] = 0x36;
  687. conf->ArchiveCode = 0x4e;
  688. }
  689. }
  690. //Convert a recieved string to a value
  691. long ConvertStreamtoLong( unsigned char * stream, int length, long unsigned int * value )
  692. {
  693. int i, nullvalue;
  694. (*value) = 0;
  695. nullvalue = 1;
  696. for( i=0; i < length; i++ )
  697. {
  698. if( stream[i] != 0xff ) //check if all ffs which is a null value
  699. nullvalue = 0;
  700. (*value) = (*value) + stream[i]*pow(256,i);
  701. }
  702. if( nullvalue == 1 )
  703. (*value) = 0; //Asigning null to 0 at this stage unless it breaks something
  704. return (*value);
  705. }
  706. //Convert a recieved string to a value
  707. float ConvertStreamtoFloat( unsigned char * stream, int length, float * value )
  708. {
  709. int i, nullvalue;
  710. (*value) = 0;
  711. nullvalue = 1;
  712. for( i=0; i < length; i++ )
  713. {
  714. if( stream[i] != 0xff ) //check if all ffs which is a null value
  715. nullvalue = 0;
  716. (*value) = (*value) + stream[i]*pow(256,i);
  717. }
  718. if( nullvalue == 1 )
  719. (*value) = 0; //Asigning null to 0 at this stage unless it breaks something
  720. return (*value);
  721. }
  722. //read return value data from init file
  723. ReturnType *
  724. InitReturnKeys( ConfType * conf, ReturnType * returnkeylist, int * num_return_keys )
  725. {
  726. FILE *fp;
  727. char line[400];
  728. ReturnType tmp;
  729. int i, j, reading, data_follows;
  730. data_follows = 0;
  731. fp=fopen(conf->File,"r");
  732. while (!feof(fp)){
  733. if (fgets(line,400,fp) != NULL){ //read line from smatool.conf
  734. if( line[0] != '#' )
  735. {
  736. if( strncmp( line, ":unit conversions", 17 ) == 0 )
  737. data_follows = 1;
  738. if( strncmp( line, ":end unit conversions", 21 ) == 0 )
  739. data_follows = 0;
  740. if( data_follows == 1 ) {
  741. tmp.key1=0x0;
  742. tmp.key2=0x0;
  743. strcpy( tmp.description, "" ); //Null out value
  744. strcpy( tmp.units, "" ); //Null out value
  745. tmp.divisor=0;
  746. reading=0;
  747. if( sscanf( line, "%x %x", &tmp.key1, &tmp.key2 ) == 2 ) {
  748. j=0;
  749. for( i=6; line[i]!='\0'; i++ ) {
  750. if(( line[i] == '"' )&&(reading==1)) {
  751. tmp.description[j]='\0';
  752. break;
  753. }
  754. if( reading == 1 )
  755. {
  756. tmp.description[j] = line[i];
  757. j++;
  758. }
  759. if(( line[i] == '"' )&&(reading==0))
  760. reading = 1;
  761. }
  762. if( sscanf( line+i+1, "%s %f", tmp.units, &tmp.divisor ) == 2 ) {
  763. if( (*num_return_keys) == 0 )
  764. returnkeylist=(ReturnType *)malloc(sizeof(ReturnType));
  765. else
  766. returnkeylist=(ReturnType *)realloc(returnkeylist,sizeof(ReturnType)*((*num_return_keys)+1));
  767. (returnkeylist+(*num_return_keys))->key1=tmp.key1;
  768. (returnkeylist+(*num_return_keys))->key2=tmp.key2;
  769. strcpy( (returnkeylist+(*num_return_keys))->description, tmp.description );
  770. strcpy( (returnkeylist+(*num_return_keys))->units, tmp.units );
  771. (returnkeylist+(*num_return_keys))->divisor = tmp.divisor;
  772. (*num_return_keys)++;
  773. }
  774. }
  775. }
  776. }
  777. }
  778. }
  779. fclose(fp);
  780. return returnkeylist;
  781. }
  782. //Convert a recieved string to a value
  783. int ConvertStreamtoInt( unsigned char * stream, int length, int * value )
  784. {
  785. int i, nullvalue;
  786. (*value) = 0;
  787. nullvalue = 1;
  788. for( i=0; i < length; i++ )
  789. {
  790. if( stream[i] != 0xff ) //check if all ffs which is a null value
  791. nullvalue = 0;
  792. (*value) = (*value) + stream[i]*pow(256,i);
  793. }
  794. if( nullvalue == 1 )
  795. (*value) = 0; //Asigning null to 0 at this stage unless it breaks something
  796. return (*value);
  797. }
  798. //Convert a recieved string to a value
  799. time_t ConvertStreamtoTime( unsigned char * stream, int length, time_t * value )
  800. {
  801. int i, nullvalue;
  802. (*value) = 0;
  803. nullvalue = 1;
  804. for( i=0; i < length; i++ )
  805. {
  806. if( stream[i] != 0xff ) //check if all ffs which is a null value
  807. nullvalue = 0;
  808. (*value) = (*value) + stream[i]*pow(256,i);
  809. }
  810. if( nullvalue == 1 )
  811. (*value) = 0; //Asigning null to 0 at this stage unless it breaks something
  812. return (*value);
  813. }
  814. // Set switches to save lots of strcmps
  815. void SetSwitches( ConfType *conf, char * datefrom, char * dateto, int *location, int *mysql, int *post, int *file, int *daterange, int *test )
  816. {
  817. //Check if all location variables are set
  818. if(( conf->latitude_f <= 180 )&&( conf->longitude_f <= 180 ))
  819. (*location)=1;
  820. else
  821. (*location)=0;
  822. //Check if all Mysql variables are set
  823. if(( strlen(conf->MySqlUser) > 0 )
  824. &&( strlen(conf->MySqlPwd) > 0 )
  825. &&( strlen(conf->MySqlHost) > 0 )
  826. &&( strlen(conf->MySqlDatabase) > 0 )
  827. &&( (*test)==0 ))
  828. (*mysql)=1;
  829. else
  830. (*mysql)=0;
  831. //Check if all File variables are set
  832. if( strlen(conf->File) > 0 )
  833. (*file)=1;
  834. else
  835. (*file)=0;
  836. //Check if all PVOutput variables are set
  837. if(( strlen(conf->PVOutputURL) > 0 )
  838. &&( strlen(conf->PVOutputKey) > 0 )
  839. &&( strlen(conf->PVOutputSid) > 0 ))
  840. (*post)=1;
  841. else
  842. (*post)=0;
  843. if(( strlen(datefrom) > 0 )
  844. &&( strlen(dateto) > 0 ))
  845. (*daterange)=1;
  846. else
  847. (*daterange)=0;
  848. }
  849. unsigned char *
  850. ReadStream( ConfType * conf, int * s, unsigned char * stream, int * streamlen, unsigned char * datalist, int * datalen, unsigned char * last_sent, int cc, int * terminated, int * togo )
  851. {
  852. int finished;
  853. int finished_record;
  854. int i, j=0;
  855. (*togo)=ConvertStreamtoInt( stream+43, 2, togo );
  856. if( debug==1 ) printf( "togo=%d\n", (*togo) );
  857. i=59; //Initial position of data stream
  858. (*datalen)=0;
  859. datalist=(unsigned char *)malloc(sizeof(char));
  860. finished=0;
  861. finished_record=0;
  862. while( finished != 1 ) {
  863. datalist=(unsigned char *)realloc(datalist,sizeof(char)*((*datalen)+(*streamlen)-i));
  864. while( finished_record != 1 ) {
  865. if( i> 500 ) break; //Somthing has gone wrong
  866. if(( i < (*streamlen) )&&(( (*terminated) != 1)||(i+3 < (*streamlen) )))
  867. {
  868. datalist[j]=stream[i];
  869. j++;
  870. (*datalen)=j;
  871. i++;
  872. }
  873. else
  874. finished_record = 1;
  875. }
  876. finished_record = 0;
  877. if( (*terminated) == 0 )
  878. {
  879. read_bluetooth( conf, s, streamlen, stream, cc, last_sent, terminated );
  880. i=18;
  881. }
  882. else
  883. finished = 1;
  884. }
  885. if( debug== 1 ) {
  886. printf( "len=%d data=", (*datalen) );
  887. for( i=0; i< (*datalen); i++ )
  888. printf( "%02x ", datalist[i] );
  889. printf( "\n" );
  890. }
  891. return datalist;
  892. }
  893. /* Init Config to default values */
  894. void InitConfig( ConfType *conf, char * datefrom, char * dateto )
  895. {
  896. strcpy( conf->Config,"./smatool.conf");
  897. strcpy( conf->Setting,"./invcode.in");
  898. strcpy( conf->Inverter, "" );
  899. strcpy( conf->BTAddress, "" );
  900. conf->bt_timeout = 30;
  901. strcpy( conf->Password, "0000" );
  902. strcpy( conf->File, "sma.in.new" );
  903. conf->latitude_f = 999 ;
  904. conf->longitude_f = 999 ;
  905. strcpy( conf->MySqlHost, "localhost" );
  906. strcpy( conf->MySqlDatabase, "smatool" );
  907. strcpy( conf->MySqlUser, "" );
  908. strcpy( conf->MySqlPwd, "" );
  909. strcpy( conf->PVOutputURL, "http://pvoutput.org/service/r2/addstatus.jsp" );
  910. strcpy( conf->PVOutputKey, "" );
  911. strcpy( conf->PVOutputSid, "" );
  912. conf->InverterCode[0]=0;
  913. conf->InverterCode[1]=0;
  914. conf->InverterCode[2]=0;
  915. conf->InverterCode[3]=0;
  916. conf->ArchiveCode=0;
  917. strcpy( datefrom, "" );
  918. strcpy( dateto, "" );
  919. }
  920. /* read Config from file */
  921. int GetConfig( ConfType *conf )
  922. {
  923. FILE *fp;
  924. char line[400];
  925. char variable[400];
  926. char value[400];
  927. if (strlen(conf->Config) > 0 )
  928. {
  929. if(( fp=fopen(conf->Config,"r")) == (FILE *)NULL )
  930. {
  931. printf( "Error! Could not open file %s\n", conf->Config );
  932. return( -1 ); //Could not open file
  933. }
  934. }
  935. else
  936. {
  937. if(( fp=fopen("./smatool.conf","r")) == (FILE *)NULL )
  938. {
  939. printf( "Error! Could not open file ./smatool.conf\n" );
  940. return( -1 ); //Could not open file
  941. }
  942. }
  943. while (!feof(fp)){
  944. if (fgets(line,400,fp) != NULL){ //read line from smatool.conf
  945. if( line[0] != '#' )
  946. {
  947. strcpy( value, "" ); //Null out value
  948. sscanf( line, "%s %s", variable, value );
  949. if( debug == 1 ) printf( "variable=%s value=%s\n", variable, value );
  950. if( value[0] != '\0' )
  951. {
  952. if( strcmp( variable, "Inverter" ) == 0 )
  953. strcpy( conf->Inverter, value );
  954. if( strcmp( variable, "BTAddress" ) == 0 )
  955. strcpy( conf->BTAddress, value );
  956. if( strcmp( variable, "BTTimeout" ) == 0 )
  957. conf->bt_timeout = atoi(value);
  958. if( strcmp( variable, "Password" ) == 0 )
  959. strcpy( conf->Password, value );
  960. if( strcmp( variable, "File" ) == 0 )
  961. strcpy( conf->File, value );
  962. if( strcmp( variable, "Latitude" ) == 0 )
  963. conf->latitude_f = atof(value) ;
  964. if( strcmp( variable, "Longitude" ) == 0 )
  965. conf->longitude_f = atof(value) ;
  966. if( strcmp( variable, "MySqlHost" ) == 0 )
  967. strcpy( conf->MySqlHost, value );
  968. if( strcmp( variable, "MySqlDatabase" ) == 0 )
  969. strcpy( conf->MySqlDatabase, value );
  970. if( strcmp( variable, "MySqlUser" ) == 0 )
  971. strcpy( conf->MySqlUser, value );
  972. if( strcmp( variable, "MySqlPwd" ) == 0 )
  973. strcpy( conf->MySqlPwd, value );
  974. if( strcmp( variable, "PVOutputURL" ) == 0 )
  975. strcpy( conf->PVOutputURL, value );
  976. if( strcmp( variable, "PVOutputKey" ) == 0 )
  977. strcpy( conf->PVOutputKey, value );
  978. if( strcmp( variable, "PVOutputSid" ) == 0 )
  979. strcpy( conf->PVOutputSid, value );
  980. }
  981. }
  982. }
  983. }
  984. fclose( fp );
  985. return( 0 );
  986. }
  987. /* read Inverter Settings from file */
  988. int GetInverterSetting( ConfType *conf )
  989. {
  990. FILE *fp;
  991. char line[400];
  992. char variable[400];
  993. char value[400];
  994. int found_inverter=0;
  995. if (strlen(conf->Setting) > 0 )
  996. {
  997. if(( fp=fopen(conf->Setting,"r")) == (FILE *)NULL )
  998. {
  999. printf( "Error! Could not open file %s\n", conf->Setting );
  1000. return( -1 ); //Could not open file
  1001. }
  1002. }
  1003. else
  1004. {
  1005. if(( fp=fopen("./invcode.in","r")) == (FILE *)NULL )
  1006. {
  1007. printf( "Error! Could not open file ./invcode.in\n" );
  1008. return( -1 ); //Could not open file
  1009. }
  1010. }
  1011. while (!feof(fp)){
  1012. if (fgets(line,400,fp) != NULL){ //read line from smatool.conf
  1013. if( line[0] != '#' )
  1014. {
  1015. strcpy( value, "" ); //Null out value
  1016. sscanf( line, "%s %s", variable, value );
  1017. if( debug == 1 ) printf( "variable=%s value=%s\n", variable, value );
  1018. if( value[0] != '\0' )
  1019. {
  1020. if( strcmp( variable, "Inverter" ) == 0 )
  1021. {
  1022. if( strcmp( value, conf->Inverter ) == 0 )
  1023. found_inverter = 1;
  1024. else
  1025. found_inverter = 0;
  1026. }
  1027. if(( strcmp( variable, "Code1" ) == 0 )&& found_inverter )
  1028. {
  1029. sscanf( value, "%X", &conf->InverterCode[0] );
  1030. }
  1031. if(( strcmp( variable, "Code2" ) == 0 )&& found_inverter )
  1032. sscanf( value, "%X", &conf->InverterCode[1] );
  1033. if(( strcmp( variable, "Code3" ) == 0 )&& found_inverter )
  1034. sscanf( value, "%X", &conf->InverterCode[2] );
  1035. if(( strcmp( variable, "Code4" ) == 0 )&& found_inverter )
  1036. sscanf( value, "%X", &conf->InverterCode[3] );
  1037. if(( strcmp( variable, "InvCode" ) == 0 )&& found_inverter )
  1038. sscanf( value, "%X", &conf->ArchiveCode );
  1039. }
  1040. }
  1041. }
  1042. }
  1043. fclose( fp );
  1044. if(( conf->InverterCode[0] == 0 ) ||
  1045. ( conf->InverterCode[1] == 0 ) ||
  1046. ( conf->InverterCode[2] == 0 ) ||
  1047. ( conf->InverterCode[3] == 0 ) ||
  1048. ( conf->ArchiveCode == 0 ))
  1049. {
  1050. printf( "\n Error ! not all codes set\n" );
  1051. fclose( fp );
  1052. return( -1 );
  1053. }
  1054. return( 0 );
  1055. }
  1056. /* Print a help message */
  1057. void PrintHelp()
  1058. {
  1059. printf( "Usage: smatool [OPTION]\n" );
  1060. printf( " -v, --verbose Give more verbose output\n" );
  1061. printf( " -d, --debug Show debug\n" );
  1062. printf( " -c, --config CONFIGFILE Set config file default smatool.conf\n" );
  1063. printf( " --test Run in test mode - don't update data\n" );
  1064. printf( "\n" );
  1065. printf( "Dates are no longer required - defaults to last update if using mysql\n" );
  1066. printf( "or 2000 to now if not using mysql\n" );
  1067. printf( " -from --datefrom YYYY-DD-MM HH:MM:00 Date range from date\n" );
  1068. printf( " -to --dateto YYYY-DD-MM HH:MM:00 Date range to date\n" );
  1069. printf( "\n" );
  1070. printf( "The following options are in config file but may be overridden\n" );
  1071. printf( " -i, --inverter INVERTER_MODEL inverter model\n" );
  1072. printf( " -a, --address INVERTER_ADDRESS inverter BT address\n" );
  1073. printf( " -t, --timeout TIMEOUT bluetooth timeout (secs) default 5\n" );
  1074. printf( " -p, --password PASSWORD inverter user password default 0000\n" );
  1075. printf( " -f, --file FILENAME command file default sma.in.new\n" );
  1076. printf( "Location Information to calculate sunset and sunrise so inverter is not\n" );
  1077. printf( "queried in the dark\n" );
  1078. printf( " -lat, --latitude LATITUDE location latitude -180 to 180 deg\n" );
  1079. printf( " -lon, --longitude LONGITUDE location longitude -90 to 90 deg\n" );
  1080. printf( "Mysql database information\n" );
  1081. printf( " -H, --mysqlhost MYSQLHOST mysql host default localhost\n");
  1082. printf( " -D, --mysqldb MYSQLDATBASE mysql database default smatool\n");
  1083. printf( " -U, --mysqluser MYSQLUSER mysql user\n");
  1084. printf( " -P, --mysqlpwd MYSQLPASSWORD mysql password\n");
  1085. printf( "Mysql tables can be installed using INSTALL you may have to use a higher \n" );
  1086. printf( "privelege user to allow the creation of databases and tables, use command line \n" );
  1087. printf( " --INSTALL install mysql data tables\n");
  1088. printf( " --UPDATE update mysql data tables\n");
  1089. printf( "PVOutput.org (A free solar information system) Configs\n" );
  1090. printf( " -url, --pvouturl PVOUTURL pvoutput.org live url\n");
  1091. printf( " -key, --pvoutkey PVOUTKEY pvoutput.org key\n");
  1092. printf( " -sid, --pvoutsid PVOUTSID pvoutput.org sid\n");
  1093. printf( " -repost verify and repost data if different\n");
  1094. printf( "\n\n" );
  1095. }
  1096. /* Init Config to default values */
  1097. int ReadCommandConfig( ConfType *conf, int argc, char **argv, char * datefrom, char * dateto, int * verbose, int * debug, int * repost, int * test, int * install, int * update )
  1098. {
  1099. int i;
  1100. // these need validation checking at some stage TODO
  1101. for (i=1;i<argc;i++) //Read through passed arguments
  1102. {
  1103. if ((strcmp(argv[i],"-v")==0)||(strcmp(argv[i],"--verbose")==0)) (*verbose) = 1;
  1104. else if ((strcmp(argv[i],"-d")==0)||(strcmp(argv[i],"--debug")==0)) (*debug) = 1;
  1105. else if ((strcmp(argv[i],"-c")==0)||(strcmp(argv[i],"--config")==0)){
  1106. i++;
  1107. if(i<argc){
  1108. strcpy(conf->Config,argv[i]);
  1109. }
  1110. }
  1111. else if (strcmp(argv[i],"--test")==0) (*test)=1;
  1112. else if ((strcmp(argv[i],"-from")==0)||(strcmp(argv[i],"--datefrom")==0)){
  1113. i++;
  1114. if(i<argc){
  1115. strcpy(datefrom,argv[i]);
  1116. }
  1117. }
  1118. else if ((strcmp(argv[i],"-to")==0)||(strcmp(argv[i],"--dateto")==0)){
  1119. i++;
  1120. if(i<argc){
  1121. strcpy(dateto,argv[i]);
  1122. }
  1123. }
  1124. else if (strcmp(argv[i],"-repost")==0){
  1125. i++;
  1126. (*repost)=1;
  1127. }
  1128. else if ((strcmp(argv[i],"-i")==0)||(strcmp(argv[i],"--inverter")==0)){
  1129. i++;
  1130. if (i<argc){
  1131. strcpy(conf->Inverter,argv[i]);
  1132. }
  1133. }
  1134. else if ((strcmp(argv[i],"-a")==0)||(strcmp(argv[i],"--address")==0)){
  1135. i++;
  1136. if (i<argc){
  1137. strcpy(conf->BTAddress,argv[i]);
  1138. }
  1139. }
  1140. else if ((strcmp(argv[i],"-t")==0)||(strcmp(argv[i],"--timeout")==0)){
  1141. i++;
  1142. if (i<argc){
  1143. conf->bt_timeout = atoi(argv[i]);
  1144. }
  1145. }
  1146. else if ((strcmp(argv[i],"-p")==0)||(strcmp(argv[i],"--password")==0)){
  1147. i++;
  1148. if (i<argc){
  1149. strcpy(conf->Password,argv[i]);
  1150. }
  1151. }
  1152. else if ((strcmp(argv[i],"-f")==0)||(strcmp(argv[i],"--file")==0)){
  1153. i++;
  1154. if (i<argc){
  1155. strcpy(conf->File,argv[i]);
  1156. }
  1157. }
  1158. else if ((strcmp(argv[i],"-lat")==0)||(strcmp(argv[i],"--latitude")==0)){
  1159. i++;
  1160. if(i<argc){
  1161. conf->latitude_f=atof(argv[i]);
  1162. }
  1163. }
  1164. else if ((strcmp(argv[i],"-long")==0)||(strcmp(argv[i],"--longitude")==0)){
  1165. i++;
  1166. if(i<argc){
  1167. conf->longitude_f=atof(argv[i]);
  1168. }
  1169. }
  1170. else if ((strcmp(argv[i],"-H")==0)||(strcmp(argv[i],"--mysqlhost")==0)){
  1171. i++;
  1172. if (i<argc){
  1173. strcpy(conf->MySqlHost,argv[i]);
  1174. }
  1175. }
  1176. else if ((strcmp(argv[i],"-D")==0)||(strcmp(argv[i],"--mysqlcwdb")==0)){
  1177. i++;
  1178. if (i<argc){
  1179. strcpy(conf->MySqlDatabase,argv[i]);
  1180. }
  1181. }
  1182. else if ((strcmp(argv[i],"-U")==0)||(strcmp(argv[i],"--mysqluser")==0)){
  1183. i++;
  1184. if (i<argc){
  1185. strcpy(conf->MySqlUser,argv[i]);
  1186. }
  1187. }
  1188. else if ((strcmp(argv[i],"-P")==0)||(strcmp(argv[i],"--mysqlpwd")==0)){
  1189. i++;
  1190. if (i<argc){
  1191. strcpy(conf->MySqlPwd,argv[i]);
  1192. }
  1193. }
  1194. else if ((strcmp(argv[i],"-url")==0)||(strcmp(argv[i],"--pvouturl")==0)){
  1195. i++;
  1196. if(i<argc){
  1197. strcpy(conf->PVOutputURL,argv[i]);
  1198. }
  1199. }
  1200. else if ((strcmp(argv[i],"-key")==0)||(strcmp(argv[i],"--pvoutkey")==0)){
  1201. i++;
  1202. if(i<argc){
  1203. strcpy(conf->PVOutputKey,argv[i]);
  1204. }
  1205. }
  1206. else if ((strcmp(argv[i],"-sid")==0)||(strcmp(argv[i],"--pvoutsid")==0)){
  1207. i++;
  1208. if(i<argc){
  1209. strcpy(conf->PVOutputSid,argv[i]);
  1210. }
  1211. }
  1212. else if ((strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help") == 0 ))
  1213. {
  1214. PrintHelp();
  1215. return( -1 );
  1216. }
  1217. else if (strcmp(argv[i],"--INSTALL")==0) (*install)=1;
  1218. else if (strcmp(argv[i],"--UPDATE")==0) (*update)=1;
  1219. else
  1220. {
  1221. printf("Bad Syntax\n\n" );
  1222. for( i=0; i< argc; i++ )
  1223. printf( "%s ", argv[i] );
  1224. printf( "\n\n" );
  1225. PrintHelp();
  1226. return( -1 );
  1227. }
  1228. }
  1229. return( 0 );
  1230. }
  1231. char * debugdate()
  1232. {
  1233. time_t curtime;
  1234. struct tm *tm;
  1235. static char result[20];
  1236. curtime = time(NULL); //get time in seconds since epoch (1/1/1970)
  1237. tm = localtime(&curtime);
  1238. sprintf( result, "%4d-%02d-%02d %02d:%02d:%02d",
  1239. 1900+tm->tm_year,
  1240. 1+tm->tm_mon,
  1241. tm->tm_mday,
  1242. tm->tm_hour,
  1243. tm->tm_min,
  1244. tm->tm_sec );
  1245. return result;
  1246. }
  1247. int main(int argc, char **argv)
  1248. {
  1249. FILE *fp;
  1250. unsigned char * last_sent;
  1251. ConfType conf;
  1252. ReturnType *returnkeylist;
  1253. int num_return_keys=0;
  1254. struct sockaddr_rc addr = { 0 };
  1255. unsigned char received[1024];
  1256. unsigned char datarecord[1024];
  1257. unsigned char * data;
  1258. unsigned char send_count = 0x0;
  1259. long long inverter_serial;
  1260. int return_key;
  1261. int gap=1;
  1262. int datalen = 0;
  1263. int archdatalen=0;
  1264. int failedbluetooth=0;
  1265. int terminated=0;
  1266. int s,i,j,status,mysql=0,post=0,repost=0,test=0,file=0,daterange=0;
  1267. int install=0, update=0, already_read=0;
  1268. int location=0, error=0;
  1269. int ret,found,crc_at_end, finished=0;
  1270. int togo=0;
  1271. int initstarted=0,setupstarted=0,rangedatastarted=0;
  1272. long returnpos;
  1273. int returnline;
  1274. int max_output;
  1275. char compurl[400]; //seg error on curl fix 2012.01.14
  1276. char datefrom[100];
  1277. char dateto[100];
  1278. int pass_i;
  1279. char line[400];
  1280. unsigned char address[6] = { 0 };
  1281. unsigned char address2[6] = { 0 };
  1282. unsigned char timestr[25] = { 0 };
  1283. unsigned char serial[4] = { 0 };
  1284. unsigned char tzhex[2] = { 0 };
  1285. unsigned char timeset[4] = { 0x30,0xfe,0x7e,0x00 };
  1286. int invcode;
  1287. char *lineread;
  1288. time_t curtime;
  1289. time_t reporttime;
  1290. time_t fromtime;
  1291. time_t totime;
  1292. time_t idate;
  1293. time_t prev_idate;
  1294. struct tm *loctime;
  1295. struct tm tm;
  1296. int day,month,year,hour,minute,second,datapoint;
  1297. char tt[10] = {48,48,48,48,48,48,48,48,48,48};
  1298. char ti[3];
  1299. char chan[1];
  1300. float currentpower_total;
  1301. int rr;
  1302. int linenum = 0;
  1303. float dtotal;
  1304. float gtotal;
  1305. float ptotal;
  1306. float strength;
  1307. MYSQL_ROW row, row1;
  1308. char SQLQUERY[200];
  1309. struct archdata_type
  1310. {
  1311. time_t date;
  1312. char inverter[20];
  1313. long unsigned int serial;
  1314. float accum_value;
  1315. float current_value;
  1316. } *archdatalist;
  1317. char sunrise_time[6],sunset_time[6];
  1318. CURL *curl;
  1319. CURLcode result;
  1320. memset(received,0,1024);
  1321. last_sent = (unsigned char *)malloc( sizeof( unsigned char ));
  1322. /* get the report time - used in various places */
  1323. reporttime = time(NULL); //get time in seconds since epoch (1/1/1970)
  1324. // set config to defaults
  1325. InitConfig( &conf, datefrom, dateto );
  1326. // read command arguments needed so can get config
  1327. if( ReadCommandConfig( &conf, argc, argv, datefrom, dateto, &verbose, &debug, &repost, &test, &install, &update ) < 0 )
  1328. exit(0);
  1329. // read Config file
  1330. if( GetConfig( &conf ) < 0 )
  1331. exit(-1);
  1332. // read command arguments again - they overide config
  1333. if( ReadCommandConfig( &conf, argc, argv, datefrom, dateto, &verbose, &debug, &repost, &test, &install, &update ) < 0 )
  1334. exit(0);
  1335. // read Inverter Setting file
  1336. if( GetInverterSetting( &conf ) < 0 )
  1337. exit(-1);
  1338. // set switches used through the program
  1339. SetSwitches( &conf, datefrom, dateto, &location, &mysql, &post, &file, &daterange, &test );
  1340. if(( install==1 )&&( mysql==1 ))
  1341. {
  1342. install_mysql_tables( &conf, SCHEMA, debug );
  1343. exit(0);
  1344. }
  1345. if(( update==1 )&&( mysql==1 ))
  1346. {
  1347. update_mysql_tables( &conf, debug );
  1348. exit(0);
  1349. }
  1350. // Set value for inverter type
  1351. //SetInverterType( &conf );
  1352. // Get Return Value lookup from file
  1353. returnkeylist = InitReturnKeys( &conf, returnkeylist, &num_return_keys );
  1354. // Get Local Timezone offset in seconds
  1355. get_timezone_in_seconds( tzhex );
  1356. // Location based information to avoid quering Inverter in the dark
  1357. if((location==1)&&(mysql==1)) {
  1358. if( debug == 1 ) printf( "Before todays Almanac\n" );
  1359. if( ! todays_almanac( &conf, debug ) ) {
  1360. sprintf( sunrise_time, "%s", sunrise(&conf, debug ));
  1361. sprintf( sunset_time, "%s", sunset(&conf, debug ));
  1362. if( verbose==1) printf( "sunrise=%s sunset=%s\n", sunrise_time, sunset_time );
  1363. update_almanac( &conf, sunrise_time, sunset_time );
  1364. }
  1365. }
  1366. if( mysql==1 )
  1367. if( debug == 1 ) printf( "Before Check Schema\n" );
  1368. if( check_schema( &conf, SCHEMA, debug ) != 1 )
  1369. exit(-1);
  1370. if(daterange==0 ) { //auto set the dates
  1371. if( debug == 1 ) printf( "auto_set_dates\n" );
  1372. auto_set_dates( &conf, &daterange, mysql, datefrom, dateto );
  1373. }
  1374. else
  1375. if( verbose == 1 ) printf( "QUERY RANGE from %s to %s\n", datefrom, dateto );
  1376. if(( daterange==1 )&&((location=0)||(mysql==0)||is_light( &conf )))
  1377. {
  1378. if (debug ==1) printf("Address %s\n",conf.BTAddress);
  1379. if (file ==1)
  1380. fp=fopen(conf.File,"r");
  1381. else
  1382. fp=fopen("/etc/sma.in","r");
  1383. for( i=1; i<20; i++ ){
  1384. // allocate a socket
  1385. s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
  1386. // set the connection parameters (who to connect to)
  1387. addr.rc_family = AF_BLUETOOTH;
  1388. addr.rc_channel = (uint8_t) 1;
  1389. str2ba( conf.BTAddress, &addr.rc_bdaddr );
  1390. // connect to server
  1391. if( debug==1 ) { printf( "datefrom=%s dateto=%s\n", datefrom, dateto ); }
  1392. status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
  1393. if (status <0){
  1394. printf("Error connecting to %s\n",conf.BTAddress);
  1395. close( s );
  1396. }
  1397. else
  1398. break;
  1399. }
  1400. if (status < 0 )
  1401. {
  1402. printf("Bad Status\n");
  1403. return( -1 );
  1404. }
  1405. // convert address
  1406. address[5] = conv(strtok(conf.BTAddress,":"));
  1407. address[4] = conv(strtok(NULL,":"));
  1408. address[3] = conv(strtok(NULL,":"));
  1409. address[2] = conv(strtok(NULL,":"));
  1410. address[1] = conv(strtok(NULL,":"));
  1411. address[0] = conv(strtok(NULL,":"));
  1412. while (!feof(fp)){
  1413. start:
  1414. if (fgets(line,400,fp) != NULL){ //read line from sma.in
  1415. linenum++;
  1416. lineread = strtok(line," ;");
  1417. if(!strcmp(lineread,"R")){ //See if line is something we need to receive
  1418. if (debug == 1) printf("[%d] %s Waiting for string\n",linenum, debugdate() );
  1419. cc = 0;
  1420. do{
  1421. lineread = strtok(NULL," ;");
  1422. switch(select_str(lineread)) {
  1423. case 0: // $END
  1424. //do nothing
  1425. break;
  1426. case 1: // $ADDR
  1427. for (i=0;i<6;i++){
  1428. fl[cc] = address[i];
  1429. cc++;
  1430. }
  1431. break;
  1432. case 3: // $SER
  1433. for (i=0;i<4;i++){
  1434. fl[cc] = serial[i];
  1435. cc++;
  1436. }
  1437. break;
  1438. case 7: // $ADD2
  1439. for (i=0;i<6;i++){
  1440. fl[cc] = address2[i];
  1441. cc++;
  1442. }
  1443. break;
  1444. case 8: // $CHAN
  1445. fl[cc] = chan[0];
  1446. cc++;
  1447. break;
  1448. default :
  1449. fl[cc] = conv(lineread);
  1450. cc++;
  1451. }
  1452. }
  1453. while (strcmp(lineread,"$END"));
  1454. if (debug == 1){
  1455. printf("[%d] %s waiting for: ", linenum, debugdate() );
  1456. for (i=0;i<cc;i++) printf("%02x ",fl[i]);
  1457. printf("\n\n");
  1458. }
  1459. if (debug == 1) printf("[%d] %s Waiting for data on rfcomm\n", linenum, debugdate());
  1460. found = 0;
  1461. do {
  1462. if( already_read == 0 )
  1463. rr=0;
  1464. if(( already_read == 0 )&&( read_bluetooth( &conf, &s, &rr, received, cc, last_sent, &terminated ) != 0 ))
  1465. {
  1466. already_read=0;
  1467. fseek( fp, returnpos, 0 );
  1468. linenum = returnline;
  1469. found=0;
  1470. if( archdatalen > 0 )
  1471. free( archdatalist );
  1472. archdatalen=0;
  1473. strcpy( lineread, "" );
  1474. sleep(10);
  1475. failedbluetooth++;
  1476. if( failedbluetooth > 3 )
  1477. exit(-1);
  1478. goto start;
  1479. }
  1480. else {
  1481. already_read=0;
  1482. if (debug == 1){
  1483. printf( "[%d] %s looking for: ",linenum, debugdate());
  1484. for (i=0;i<cc;i++) printf("%02x ",fl[i]);
  1485. printf( "\n" );
  1486. printf( "[%d] %s received: ",linenum, debugdate());
  1487. for (i=0;i<rr;i++) printf("%02x ",received[i]);
  1488. printf("\n\n");
  1489. }
  1490. if (memcmp(fl+4,received+4,cc-4) == 0){
  1491. found = 1;
  1492. if (debug == 1) printf("[%d] %s Found string we are waiting for\n",linenum, debugdate());
  1493. } else {
  1494. if (debug == 1) printf("[%d] %s Did not find string\n", linenum,debugdate());
  1495. }
  1496. }
  1497. } while (found == 0);
  1498. if (debug == 2){
  1499. for (i=0;i<cc;i++) printf("%02x ",fl[i]);
  1500. printf("\n\n");
  1501. }
  1502. }
  1503. if(!strcmp(lineread,"S")){ //See if line is something we need to send
  1504. if (debug == 1) printf("[%d] %s Sending\n", linenum,debugdate());
  1505. cc = 0;
  1506. do{
  1507. lineread = strtok(NULL," ;");
  1508. switch(select_str(lineread)) {
  1509. case 0: // $END
  1510. //do nothing
  1511. break;
  1512. case 1: // $ADDR
  1513. for (i=0;i<6;i++){
  1514. fl[cc] = address[i];
  1515. cc++;
  1516. }
  1517. break;
  1518. case 3: // $SER
  1519. for (i=0;i<4;i++){
  1520. fl[cc] = serial[i];
  1521. cc++;
  1522. }
  1523. break;
  1524. case 7: // $ADD2
  1525. for (i=0;i<6;i++){
  1526. fl[cc] = address2[i];
  1527. cc++;
  1528. }
  1529. break;
  1530. case 2: // $TIME
  1531. // get report time and convert
  1532. sprintf(tt,"%x",(int)reporttime); //convert to a hex in a string
  1533. for (i=7;i>0;i=i-2){ //change order and convert to integer
  1534. ti[1] = tt[i];
  1535. ti[0] = tt[i-1];
  1536. ti[2] = '\0';
  1537. fl[cc] = conv(ti);
  1538. cc++;
  1539. }
  1540. break;
  1541. case 11: // $TMPLUS
  1542. // get report time and convert
  1543. sprintf(tt,"%x",(int)reporttime+1); //convert to a hex in a string
  1544. for (i=7;i>0;i=i-2){ //change order and convert to integer
  1545. ti[1] = tt[i];
  1546. ti[0] = tt[i-1];
  1547. ti[2] = '\0';
  1548. fl[cc] = conv(ti);
  1549. cc++;
  1550. }
  1551. break;
  1552. case 10: // $TMMINUS
  1553. // get report time and convert
  1554. sprintf(tt,"%x",(int)reporttime-1); //convert to a hex in a string
  1555. for (i=7;i>0;i=i-2){ //change order and convert to integer
  1556. ti[1] = tt[i];
  1557. ti[0] = tt[i-1];
  1558. ti[2] = '\0';
  1559. fl[cc] = conv(ti);
  1560. cc++;
  1561. }
  1562. break;
  1563. case 4: //$crc
  1564. tryfcs16(fl+19, cc -19);
  1565. add_escapes(fl,&cc);
  1566. fix_length_send(fl,&cc);
  1567. break;
  1568. case 8: // $CHAN
  1569. fl[cc] = chan[0];
  1570. cc++;
  1571. break;
  1572. case 12: // $TIMESTRING
  1573. for (i=0;i<25;i++){
  1574. fl[cc] = timestr[i];
  1575. cc++;
  1576. }
  1577. break;
  1578. case 13: // $TIMEFROM1
  1579. // get report time and convert
  1580. if( daterange == 1 ) {
  1581. if( strptime( datefrom, "%Y-%m-%d %H:%M:%S", &tm) == 0 )
  1582. {
  1583. if( debug==1 ) printf( "datefrom %s\n", datefrom );
  1584. printf( "Time Coversion Error\n" );
  1585. error=1;
  1586. exit(-1);
  1587. }
  1588. tm.tm_isdst=-1;
  1589. fromtime=mktime(&tm);
  1590. if( fromtime == -1 ) {
  1591. // Error we need to do something about it
  1592. printf( "%03x",(int)fromtime ); getchar();
  1593. printf( "\n%03x", (int)fromtime ); getchar();
  1594. fromtime=0;
  1595. printf( "bad from" ); getchar();
  1596. }
  1597. }
  1598. else
  1599. {
  1600. printf( "no from" ); getchar();
  1601. fromtime=0;
  1602. }
  1603. sprintf(tt,"%03x",(int)fromtime-300); //convert to a hex in a string and start 5 mins before for dummy read.
  1604. for (i=7;i>0;i=i-2){ //change order and convert to integer
  1605. ti[1] = tt[i];
  1606. ti[0] = tt[i-1];
  1607. ti[2] = '\0';
  1608. fl[cc] = conv(ti);
  1609. cc++;
  1610. }
  1611. break;
  1612. case 14: // $TIMETO1
  1613. if( daterange == 1 ) {
  1614. if( strptime( dateto, "%Y-%m-%d %H:%M:%S", &tm) == 0 )
  1615. {
  1616. if( debug==1 ) printf( "dateto %s\n", dateto );
  1617. printf( "Time Coversion Error\n" );
  1618. error=1;
  1619. exit(-1);
  1620. }
  1621. tm.tm_isdst=-1;
  1622. totime=mktime(&tm);
  1623. if( totime == -1 ) {
  1624. // Error we need to do something about it
  1625. printf( "%03x",(int)totime ); getchar();
  1626. printf( "\n%03x", (int)totime ); getchar();
  1627. totime=0;
  1628. printf( "bad to" ); getchar();
  1629. }
  1630. }
  1631. else
  1632. totime=0;
  1633. sprintf(tt,"%03x",(int)totime); //convert to a hex in a string
  1634. // get report time and convert
  1635. for (i=7;i>0;i=i-2){ //change order and convert to integer
  1636. ti[1] = tt[i];
  1637. ti[0] = tt[i-1];
  1638. ti[2] = '\0';
  1639. fl[cc] = conv(ti);
  1640. cc++;
  1641. }
  1642. break;
  1643. case 15: // $TIMEFROM2
  1644. if( daterange == 1 ) {
  1645. strptime( datefrom, "%Y-%m-%d %H:%M:%S", &tm);
  1646. tm.tm_isdst=-1;
  1647. fromtime=mktime(&tm)-86400;
  1648. if( fromtime == -1 ) {
  1649. // Error we need to do something about it
  1650. printf( "%03x",(int)fromtime ); getchar();
  1651. printf( "\n%03x", (int)fromtime ); getchar();
  1652. fromtime=0;
  1653. printf( "bad from" ); getchar();
  1654. }
  1655. }
  1656. else
  1657. {
  1658. printf( "no from" ); getchar();
  1659. fromtime=0;
  1660. }
  1661. sprintf(tt,"%03x",(int)fromtime); //convert to a hex in a string
  1662. for (i=7;i>0;i=i-2){ //change order and convert to integer
  1663. ti[1] = tt[i];
  1664. ti[0] = tt[i-1];
  1665. ti[2] = '\0';
  1666. fl[cc] = conv(ti);
  1667. cc++;
  1668. }
  1669. break;
  1670. case 16: // $TIMETO2
  1671. if( daterange == 1 ) {
  1672. strptime( dateto, "%Y-%m-%d %H:%M:%S", &tm);
  1673. tm.tm_isdst=-1;
  1674. totime=mktime(&tm)-86400;
  1675. if( totime == -1 ) {
  1676. // Error we need to do something about it
  1677. printf( "%03x",(int)totime ); getchar();
  1678. printf( "\n%03x", (int)totime ); getchar();
  1679. fromtime=0;
  1680. printf( "bad from" ); getchar();
  1681. }
  1682. }
  1683. else
  1684. totime=0;
  1685. sprintf(tt,"%03x",(int)totime); //convert to a hex in a string
  1686. for (i=7;i>0;i=i-2){ //change order and convert to integer
  1687. ti[1] = tt[i];
  1688. ti[0] = tt[i-1];
  1689. ti[2] = '\0';
  1690. fl[cc] = conv(ti);
  1691. cc++;
  1692. }
  1693. break;
  1694. case 19: // $PASSWORD
  1695. j=0;
  1696. for(i=0;i<12;i++){
  1697. if( conf.Password[j] == '\0' )
  1698. fl[cc] = 0x88;
  1699. else {
  1700. pass_i = conf.Password[j];
  1701. fl[cc] = (( pass_i+0x88 )%0xff);
  1702. j++;
  1703. }
  1704. cc++;
  1705. }
  1706. break;
  1707. case 21: // $UNKNOWN
  1708. for (i=0;i<4;i++){
  1709. fl[cc] = conf.InverterCode[i];
  1710. cc++;
  1711. }
  1712. break;
  1713. case 22: // $INVCODE
  1714. fl[cc] = invcode;
  1715. cc++;
  1716. break;
  1717. case 23: // $ARCHCODE
  1718. fl[cc] = conf.ArchiveCode;
  1719. cc++;
  1720. break;
  1721. case 25: // $CNT send counter
  1722. send_count++;
  1723. fl[cc] = send_count;
  1724. cc++;
  1725. break;
  1726. case 26: // $TIMEZONE timezone in seconds, reverse endian
  1727. fl[cc] = tzhex[0];
  1728. fl[cc+1] = tzhex[1];
  1729. cc+=2;
  1730. break;
  1731. case 27: // $TIMESET unknown setting
  1732. for( i=0; i<4; i++ ) {
  1733. fl[cc] = timeset[i];
  1734. cc++;
  1735. }
  1736. break;
  1737. default :
  1738. fl[cc] = conv(lineread);
  1739. cc++;
  1740. }
  1741. } while (strcmp(lineread,"$END"));
  1742. if (debug == 1){
  1743. printf( "[%d] %s sending:\n",linenum, debugdate());
  1744. printf( " %08x: .. .. .. .. .. .. .. .. .. .. .. .. ", 0 );
  1745. j=12;
  1746. for (i=0;i<cc;i++) {
  1747. if( j%16== 0 )
  1748. printf( "\n %08x: ",j);
  1749. printf("%02x ",fl[i]);
  1750. j++;
  1751. }
  1752. printf(" cc=%d",cc);
  1753. printf("\n\n");
  1754. }
  1755. last_sent = (unsigned char *)realloc( last_sent, sizeof( unsigned char )*(cc));
  1756. memcpy(last_sent,fl,cc);
  1757. write(s,fl,cc);
  1758. already_read=0;
  1759. //check_send_error( &conf, &s, &rr, received, cc, last_sent, &terminated, &already_read );
  1760. }
  1761. if(!strcmp(lineread,"E")){ //See if line is something we need to extract
  1762. if (debug == 1) printf("[%d] %s Extracting\n", linenum, debugdate());
  1763. cc = 0;
  1764. do{
  1765. lineread = strtok(NULL," ;");
  1766. //printf( "\nselect=%d", select_str(lineread));
  1767. switch(select_str(lineread)) {
  1768. case 3: // Extract Serial of Inverter
  1769. data = ReadStream( &conf, &s, received, &rr, data, &datalen, last_sent, cc, &terminated, &togo );
  1770. /*
  1771. printf( "1.len=%d data=", datalen );
  1772. for( i=0; i< datalen; i++ )
  1773. printf( "%02x ", data[i] );
  1774. printf( "\n" );
  1775. */
  1776. serial[3]=data[19];
  1777. serial[2]=data[18];
  1778. serial[1]=data[17];
  1779. serial[0]=data[16];
  1780. if (verbose == 1) printf( "serial=%02x:%02x:%02x:%02x\n",serial[3]&0xff,serial[2]&0xff,serial[1]&0xff,serial[0]&0xff );
  1781. free( data );
  1782. break;
  1783. case 9: // extract Time from Inverter
  1784. idate = (received[66] * 16777216 ) + (received[65] *65536 )+ (received[64] * 256) + received[63];
  1785. loctime = localtime(&idate);
  1786. day = loctime->tm_mday;
  1787. month = loctime->tm_mon +1;
  1788. year = loctime->tm_year + 1900;
  1789. hour = loctime->tm_hour;
  1790. minute = loctime->tm_min;
  1791. second = loctime->tm_sec;
  1792. printf("Date power = %d/%d/%4d %02d:%02d:%02d\n",day, month, year, hour, minute,second);
  1793. //currentpower = (received[72] * 256) + received[71];
  1794. //printf("Current power = %i Watt\n",currentpower);
  1795. break;
  1796. case 5: // extract current power $POW
  1797. data = ReadStream( &conf, &s, received, &rr, data, &datalen, last_sent, cc, &terminated, &togo );
  1798. if( (data+3)[0] == 0x08 )
  1799. gap = 40;
  1800. if( (data+3)[0] == 0x10 )
  1801. gap = 40;
  1802. if( (data+3)[0] == 0x40 )
  1803. gap = 28;
  1804. if( (data+3)[0] == 0x00 )
  1805. gap = 28;
  1806. for ( i = 0; i<datalen; i+=gap )
  1807. {
  1808. idate=ConvertStreamtoTime( data+i+4, 4, &idate );
  1809. loctime = localtime(&idate);
  1810. day = loctime->tm_mday;
  1811. month = loctime->tm_mon +1;
  1812. year = loctime->tm_year + 1900;
  1813. hour = loctime->tm_hour;
  1814. minute = loctime->tm_min;
  1815. second = loctime->tm_sec;
  1816. ConvertStreamtoFloat( data+i+8, 3, &currentpower_total );
  1817. return_key=-1;
  1818. for( j=0; j<num_return_keys; j++ )
  1819. {
  1820. if(( (data+i+1)[0] == returnkeylist[j].key1 )&&((data+i+2)[0] == returnkeylist[j].key2)) {
  1821. return_key=j;
  1822. break;
  1823. }
  1824. }
  1825. if( return_key >= 0 )
  1826. {
  1827. printf("%d-%02d-%02d %02d:%02d:%02d %-20s = %.0f %-20s\n", year, month, day, hour, minute, second, returnkeylist[return_key].description, currentpower_total/returnkeylist[return_key].divisor, returnkeylist[return_key].units );
  1828. inverter_serial=serial[3]*16777216+serial[2]*65536+serial[1]*256+serial[0];
  1829. live_mysql( &conf, year, month, day, hour, minute, second, conf.Inverter, inverter_serial, returnkeylist[return_key].description, currentpower_total/returnkeylist[return_key].divisor, returnkeylist[return_key].units, debug );
  1830. }
  1831. else
  1832. printf("%d-%02d-%02d %02d:%02d:%02d NO DATA for %02x %02x = %.0f NO UNITS\n", year, month, day, hour, minute, second, (data+i+1)[0], (data+i+1)[1], currentpower_total );
  1833. }
  1834. free( data );
  1835. break;
  1836. case 6: // extract total energy collected today
  1837. gtotal = (received[69] * 65536) + (received[68] * 256) + received[67];
  1838. gtotal = gtotal / 1000;
  1839. printf("G total so far = %.2f Kwh\n",gtotal);
  1840. dtotal = (received[84] * 256) + received[83];
  1841. dtotal = dtotal / 1000;
  1842. printf("E total today = %.2f Kwh\n",dtotal);
  1843. break;
  1844. case 7: // extract 2nd address
  1845. memcpy(address2,received+26,6);
  1846. if (debug == 1) printf("address 2 \n");
  1847. break;
  1848. case 8: // extract bluetooth channel
  1849. memcpy(chan,received+22,1);
  1850. if (debug == 1) printf("Bluetooth channel = %i\n",chan[0]);
  1851. break;
  1852. case 12: // extract time strings $TIMESTRING
  1853. if(( received[60] == 0x6d )&&( received[61] == 0x23 ))
  1854. {
  1855. memcpy(timestr,received+63,24);
  1856. if (debug == 1) printf("extracting timestring\n");
  1857. memcpy(timeset,received+79,4);
  1858. idate=ConvertStreamtoTime( received+63,4, &idate );
  1859. /* Allow delay for inverter to be slow */
  1860. if( reporttime > idate ) {
  1861. if( debug == 1 )
  1862. printf( "delay=%d\n", (int)(reporttime-idate) );
  1863. //sleep( reporttime - idate );
  1864. sleep(5); //was sleeping for > 1min excessive
  1865. }
  1866. }
  1867. else
  1868. {
  1869. memcpy(timestr,received+63,24);
  1870. if (debug == 1) printf("bad extracting timestring\n");
  1871. already_read=0;
  1872. fseek( fp, returnpos, 0 );
  1873. linenum = returnline;
  1874. found=0;
  1875. if( archdatalen > 0 )
  1876. free( archdatalist );
  1877. archdatalen=0;
  1878. strcpy( lineread, "" );
  1879. failedbluetooth++;
  1880. if( failedbluetooth > 60 )
  1881. exit(-1);
  1882. goto start;
  1883. //exit(-1);
  1884. }
  1885. break;
  1886. case 17: // Test data
  1887. data = ReadStream( &conf, &s, received, &rr, data, &datalen, last_sent, cc, &terminated, &togo );
  1888. printf( "\n" );
  1889. free( data );
  1890. break;
  1891. case 18: // $ARCHIVEDATA1
  1892. finished=0;
  1893. ptotal=0;
  1894. idate=0;
  1895. printf( "\n" );
  1896. while( finished != 1 ) {
  1897. data = ReadStream( &conf, &s, received, &rr, data, &datalen, last_sent, cc, &terminated, &togo );
  1898. j=0;
  1899. for( i=0; i<datalen; i++ )
  1900. {
  1901. datarecord[j]=data[i];
  1902. j++;
  1903. if( j > 11 ) {
  1904. if( idate > 0 ) prev_idate=idate;
  1905. else prev_idate=0;
  1906. idate=ConvertStreamtoTime( datarecord, 4, &idate );
  1907. if( prev_idate == 0 )
  1908. prev_idate = idate-300;
  1909. loctime = localtime(&idate);
  1910. day = loctime->tm_mday;
  1911. month = loctime->tm_mon +1;
  1912. year = loctime->tm_year + 1900;
  1913. hour = loctime->tm_hour;
  1914. minute = loctime->tm_min;
  1915. second = loctime->tm_sec;
  1916. ConvertStreamtoFloat( datarecord+4, 8, &gtotal );
  1917. if(archdatalen == 0 )
  1918. ptotal = gtotal;
  1919. printf("\n%d/%d/%4d %02d:%02d:%02d total=%.3f Kwh current=%.0f Watts togo=%d i=%d crc=%d", day, month, year, hour, minute,second, gtotal/1000, (gtotal-ptotal)*12, togo, i, crc_at_end);
  1920. if( idate != prev_idate+300 ) {
  1921. printf( "Date Error! prev=%d current=%d\n", (int)prev_idate, (int)idate );
  1922. error=1;
  1923. break;
  1924. }
  1925. if( archdatalen == 0 )
  1926. archdatalist = (struct archdata_type *)malloc( sizeof( struct archdata_type ) );
  1927. else
  1928. archdatalist = (struct archdata_type *)realloc( archdatalist, sizeof( struct archdata_type )*(archdatalen+1));
  1929. (archdatalist+archdatalen)->date=idate;
  1930. strcpy((archdatalist+archdatalen)->inverter,conf.Inverter);
  1931. ConvertStreamtoLong( serial, 4, &(archdatalist+archdatalen)->serial);
  1932. ; (archdatalist+archdatalen)->accum_value=gtotal/1000;
  1933. (archdatalist+archdatalen)->current_value=(gtotal-ptotal)*12;
  1934. archdatalen++;
  1935. ptotal=gtotal;
  1936. j=0; //get ready for another record
  1937. }
  1938. }
  1939. if( togo == 0 )
  1940. finished=1;
  1941. else
  1942. if( read_bluetooth( &conf, &s, &rr, received, cc, last_sent, &terminated ) != 0 )
  1943. {
  1944. fseek( fp, returnpos, 0 );
  1945. linenum = returnline;
  1946. found=0;
  1947. if( archdatalen > 0 )
  1948. free( archdatalist );
  1949. archdatalen=0;
  1950. strcpy( lineread, "" );
  1951. sleep(10);
  1952. failedbluetooth++;
  1953. if( failedbluetooth > 3 )
  1954. exit(-1);
  1955. goto start;
  1956. }
  1957. }
  1958. free( data );
  1959. printf( "\n" );
  1960. break;
  1961. case 20: // SIGNAL signal strength
  1962. strength = (received[22] * 100.0)/0xff;
  1963. if (verbose == 1) {
  1964. printf("bluetooth signal = %.0f%%\n",strength);
  1965. }
  1966. break;
  1967. case 22: // extract time strings $INVCODE
  1968. invcode=received[22];
  1969. if (debug == 1) printf("extracting invcode=%02x\n", invcode);
  1970. break;
  1971. case 24: // Inverter data $INVERTERDATA
  1972. data = ReadStream( &conf, &s, received, &rr, data, &datalen, last_sent, cc, &terminated, &togo );
  1973. if( debug==1 ) printf( "data=%02x\n",(data+3)[0] );
  1974. if( (data+3)[0] == 0x08 )
  1975. gap = 40;
  1976. if( (data+3)[0] == 0x10 )
  1977. gap = 40;
  1978. if( (data+3)[0] == 0x40 )
  1979. gap = 28;
  1980. if( (data+3)[0] == 0x00 )
  1981. gap = 28;
  1982. for ( i = 0; i<datalen; i+=gap )
  1983. {
  1984. idate=ConvertStreamtoTime( data+i+4, 4, &idate );
  1985. loctime = localtime(&idate);
  1986. day = loctime->tm_mday;
  1987. month = loctime->tm_mon +1;
  1988. year = loctime->tm_year + 1900;
  1989. hour = loctime->tm_hour;
  1990. minute = loctime->tm_min;
  1991. second = loctime->tm_sec;
  1992. ConvertStreamtoFloat( data+i+8, 3, &currentpower_total );
  1993. return_key=-1;
  1994. for( j=0; j<num_return_keys; j++ )
  1995. {
  1996. if(( (data+i+1)[0] == returnkeylist[j].key1 )&&((data+i+2)[0] == returnkeylist[j].key2)) {
  1997. return_key=j;
  1998. break;
  1999. }
  2000. }
  2001. if( return_key >= 0 ) {
  2002. if( i==0 )
  2003. printf("%d-%02d-%02d %02d:%02d:%02d %s\n", year, month, day, hour, minute, second, (data+i+8) );
  2004. printf("%d-%02d-%02d %02d:%02d:%02d %-20s = %.0f %-20s\n", year, month, day, hour, minute, second, returnkeylist[return_key].description, currentpower_total/returnkeylist[return_key].divisor, returnkeylist[return_key].units );
  2005. }
  2006. else
  2007. printf("%d-%02d-%02d %02d:%02d:%02d NO DATA for %02x %02x = %.0f NO UNITS \n", year, month, day, hour, minute, second, (data+i+1)[0], (data+i+1)[0], currentpower_total );
  2008. }
  2009. free( data );
  2010. break;
  2011. }
  2012. }
  2013. while (strcmp(lineread,"$END"));
  2014. }
  2015. if(!strcmp(lineread,":init")){ //See if line is something we need to extract
  2016. initstarted=1;
  2017. returnpos=ftell(fp);
  2018. returnline = linenum;
  2019. }
  2020. if(!strcmp(lineread,":setup")){ //See if line is something we need to extract
  2021. setupstarted=1;
  2022. returnpos=ftell(fp);
  2023. returnline = linenum;
  2024. }
  2025. if(!strcmp(lineread,":startsetup")){ //See if line is something we need to extract
  2026. sleep(1);
  2027. }
  2028. if(!strcmp(lineread,":setinverter1")){ //See if line is something we need to extract
  2029. setupstarted=1;
  2030. returnpos=ftell(fp);
  2031. returnline = linenum;
  2032. }
  2033. if(!strcmp(lineread,":getrangedata")){ //See if line is something we need to extract
  2034. rangedatastarted=1;
  2035. returnpos=ftell(fp);
  2036. returnline = linenum;
  2037. }
  2038. }
  2039. }
  2040. if ((mysql ==1)&&(error==0)){
  2041. /* Connect to database */
  2042. OpenMySqlDatabase( conf.MySqlHost, conf.MySqlUser, conf.MySqlPwd, conf.MySqlDatabase );
  2043. for( i=1; i<archdatalen; i++ ) //Start at 1 as the first record is a dummy
  2044. {
  2045. sprintf(SQLQUERY,"INSERT INTO DayData ( DateTime, Inverter, Serial, CurrentPower, EtotalToday ) VALUES ( FROM_UNIXTIME(%ld),\'%s\',%ld,%0.f, %.3f ) ON DUPLICATE KEY UPDATE DateTime=Datetime, Inverter=VALUES(Inverter), Serial=VALUES(Serial), CurrentPower=VALUES(CurrentPower), EtotalToday=VALUES(EtotalToday)",(archdatalist+i)->date, (archdatalist+i)->inverter, (archdatalist+i)->serial, (archdatalist+i)->current_value, (archdatalist+i)->accum_value );
  2046. if (debug == 1) printf("%s\n",SQLQUERY);
  2047. DoQuery(SQLQUERY);
  2048. getchar();
  2049. }
  2050. mysql_close(conn);
  2051. }
  2052. curtime = time(NULL); //get time in seconds since epoch (1/1/1970)
  2053. loctime = localtime(&curtime);
  2054. day = loctime->tm_mday;
  2055. month = loctime->tm_mon +1;
  2056. year = loctime->tm_year + 1900;
  2057. hour = loctime->tm_hour;
  2058. minute = loctime->tm_min;
  2059. datapoint = (int)(((hour * 60) + minute)) / 5;
  2060. if ((post ==1)&&(mysql==1)&&(error==0)){
  2061. char batch_string[400];
  2062. int batch_count = 0;
  2063. /* Connect to database */
  2064. OpenMySqlDatabase( conf.MySqlHost, conf.MySqlUser, conf.MySqlPwd, conf.MySqlDatabase );
  2065. /*
  2066. //Get Start of day value
  2067. sprintf(SQLQUERY,"SELECT EtotalToday FROM DayData WHERE DateTime=DATE_FORMAT( NOW(), \"%%Y%%m%%d000000\" ) " );
  2068. if (debug == 1) printf("%s\n",SQLQUERY);
  2069. DoQuery(SQLQUERY);
  2070. if (row = mysql_fetch_row(res)) //if there is a result, update the row
  2071. {
  2072. starttotal = atof( (char *)row[0] );
  2073. /* if( archdatalen < 3 ) //Use Batch mode if greater
  2074. if ( 1 = 2 ) //Always use batch mode, r2 api is better and r1 may go away one day
  2075. {
  2076. for( i=1; i<archdatalen; i++ ) { //Start at 1 as the first record is a dummy
  2077. if((archdatalist+i)->current_value > 0 )
  2078. {
  2079. dtotal = (archdatalist+i)->accum_value*1000 - (starttotal*1000);
  2080. idate = (archdatalist+i)->date;
  2081. loctime = localtime(&(archdatalist+i)->date);
  2082. day = loctime->tm_mday;
  2083. month = loctime->tm_mon +1;
  2084. year = loctime->tm_year + 1900;
  2085. hour = loctime->tm_hour;
  2086. minute = loctime->tm_min;
  2087. second = loctime->tm_sec;
  2088. ret=sprintf(compurl,"%s?d=%04i%02i%02i&t=%02i:%02i&v1=%f&v2=%f&key=%s&sid=%s",conf.PVOutputURL,year,month,day,hour,minute,dtotal,(archdatalist+i)->current_value,conf.PVOutputKey,conf.PVOutputSid);
  2089. sprintf(SQLQUERY,"SELECT PVOutput FROM DayData WHERE DateTime=\"%i%02i%02i%02i%02i%02i\" and PVOutput IS NOT NULL", year, month, day, hour, minute, second );
  2090. if (debug == 1) printf("%s\n",SQLQUERY);
  2091. DoQuery(SQLQUERY);
  2092. if (debug == 1) printf("url = %s\n",compurl);
  2093. if (row = mysql_fetch_row(res)) //if there is a result, already done
  2094. {
  2095. if (verbose == 1) printf("Already Updated\n");
  2096. }
  2097. else
  2098. {
  2099. curl = curl_easy_init();
  2100. if (curl){
  2101. curl_easy_setopt(curl, CURLOPT_URL, compurl);
  2102. curl_easy_setopt(curl, CURLOPT_FAILONERROR, compurl);
  2103. result = curl_easy_perform(curl);
  2104. if (debug == 1) printf("result = %d\n",result);
  2105. curl_easy_cleanup(curl);
  2106. if( result==0 )
  2107. {
  2108. sprintf(SQLQUERY,"UPDATE DayData set PVOutput=NOW() WHERE DateTime=\"%i%02i%02i%02i%02i%02i\" ", year, month, day, hour, minute, second );
  2109. if (debug == 1) printf("%s\n",SQLQUERY);
  2110. DoQuery(SQLQUERY);
  2111. }
  2112. else
  2113. break;
  2114. }
  2115. }
  2116. }
  2117. }
  2118. }
  2119. else //Use batch mode 30 values at a time!
  2120. */
  2121. /* Connect to database */
  2122. OpenMySqlDatabase( conf.MySqlHost, conf.MySqlUser, conf.MySqlPwd, conf.MySqlDatabase );
  2123. sprintf(SQLQUERY,"SELECT Value FROM LiveData WHERE Inverter = \'%s\' and Serial=\'%d\' and Description=\'Max Phase 1\' ORDER BY DateTime DESC LIMIT 1", conf.Inverter, inverter_serial );
  2124. if (debug == 1) printf("%s\n",SQLQUERY); getchar();
  2125. DoQuery(SQLQUERY);
  2126. if( mysql_num_rows(res) == 1 )
  2127. {
  2128. if ((row = mysql_fetch_row(res)))
  2129. {
  2130. max_output = atoi(row[0]) * 1.2;
  2131. }
  2132. mysql_free_result( res );
  2133. }
  2134. sprintf(SQLQUERY,"SELECT DATE_FORMAT(dd1.DateTime,\'%%Y%%m%%d\'), DATE_FORMAT(dd1.DateTime,\'%%H:%%i\'), ROUND((dd1.ETotalToday-dd2.EtotalToday)*1000), if( dd1.CurrentPower < %d ,dd1.CurrentPower, %d ), dd1.DateTime FROM DayData as dd1 join DayData as dd2 on dd2.DateTime=DATE_FORMAT(dd1.DateTime,\'%%Y-%%m-%%d 00:00:00\') WHERE dd1.DateTime>=Date_Sub(CURDATE(),INTERVAL 13 DAY) and dd1.PVOutput IS NULL and dd1.CurrentPower>0 ORDER BY dd1.DateTime ASC", max_output, max_output );
  2135. if (debug == 1) printf("%s\n",SQLQUERY);
  2136. DoQuery(SQLQUERY);
  2137. batch_count=0;
  2138. if( mysql_num_rows(res) == 1 )
  2139. {
  2140. if ((row = mysql_fetch_row(res))) //Need to update these
  2141. {
  2142. sprintf(compurl,"%s?d=%s&t=%s&v1=%s&v2=%s&key=%s&sid=%s",conf.PVOutputURL,row[0],row[1],row[2],row[3],conf.PVOutputKey,conf.PVOutputSid);
  2143. if (debug == 1) printf("url = %s\n",compurl);
  2144. {
  2145. curl = curl_easy_init();
  2146. if (curl){
  2147. curl_easy_setopt(curl, CURLOPT_URL, compurl);
  2148. curl_easy_setopt(curl, CURLOPT_FAILONERROR, compurl);
  2149. result = curl_easy_perform(curl);
  2150. if (debug == 1) printf("result = %d\n",result);
  2151. curl_easy_cleanup(curl);
  2152. if( result==0 )
  2153. {
  2154. sprintf(SQLQUERY,"UPDATE DayData set PVOutput=NOW() WHERE DateTime=\"%s\" ", row[4] );
  2155. if (debug == 1) printf("%s\n",SQLQUERY);
  2156. DoQuery(SQLQUERY);
  2157. }
  2158. }
  2159. }
  2160. }
  2161. }
  2162. else
  2163. {
  2164. while ((row = mysql_fetch_row(res))) //Need to update these
  2165. {
  2166. sleep(2);
  2167. if( batch_count > 0 )
  2168. sprintf( batch_string,"%s;%s,%s,%s,%s", batch_string, row[0], row[1], row[2], row[3] );
  2169. else
  2170. sprintf( batch_string,"%s,%s,%s,%s", row[0], row[1], row[2], row[3] );
  2171. batch_count++;
  2172. if( batch_count == 30 )
  2173. {
  2174. curl = curl_easy_init();
  2175. if (curl){
  2176. sprintf(compurl,"http://pvoutput.org/service/r2/addbatchstatus.jsp?data=%s&key=%s&sid=%s",batch_string,conf.PVOutputKey,conf.PVOutputSid);
  2177. if (debug == 1) printf("url = %s\n",compurl);
  2178. curl_easy_setopt(curl, CURLOPT_URL, compurl);
  2179. curl_easy_setopt(curl, CURLOPT_FAILONERROR, compurl);
  2180. result = curl_easy_perform(curl);
  2181. sleep(1);
  2182. if (debug == 1) printf("result = %d\n",result);
  2183. curl_easy_cleanup(curl);
  2184. if( result==0 )
  2185. {
  2186. sprintf(SQLQUERY,"SELECT DATE_FORMAT(dd1.DateTime,\'%%Y%%m%%d\'), DATE_FORMAT(dd1.DateTime,\'%%H:%%i\'), ROUND((dd1.ETotalToday-dd2.EtotalToday)*1000), dd1.CurrentPower, dd1.DateTime FROM DayData as dd1 join DayData as dd2 on dd2.DateTime=DATE_FORMAT(dd1.DateTime,\'%%Y-%%m-%%d 00:00:00\') WHERE dd1.DateTime>=Date_Sub(CURDATE(),INTERVAL 13 DAY) and dd1.PVOutput IS NULL and dd1.CurrentPower>0 ORDER BY dd1.DateTime ASC limit %d", batch_count );
  2187. if (debug == 1) printf("%s\n",SQLQUERY);
  2188. DoQuery1(SQLQUERY);
  2189. while ((row1 = mysql_fetch_row(res1))) //Need to update these
  2190. {
  2191. sprintf(SQLQUERY,"UPDATE DayData set PVOutput=NOW() WHERE DateTime=\"%s\" ", row1[4] );
  2192. if (debug == 1) printf("%s\n",SQLQUERY);
  2193. DoQuery2(SQLQUERY);
  2194. }
  2195. mysql_free_result( res1 );
  2196. }
  2197. else
  2198. break;
  2199. }
  2200. batch_count = 0;
  2201. strcpy( batch_string, "" ); //NULL the string
  2202. }
  2203. }
  2204. if( batch_count > 0 )
  2205. {
  2206. curl = curl_easy_init();
  2207. if (curl){
  2208. sprintf(compurl,"http://pvoutput.org/service/r2/addbatchstatus.jsp?data=%s&key=%s&sid=%s",batch_string,conf.PVOutputKey,conf.PVOutputSid);
  2209. if (debug == 1) printf("url = %s\n",compurl);
  2210. curl_easy_setopt(curl, CURLOPT_URL, compurl);
  2211. curl_easy_setopt(curl, CURLOPT_FAILONERROR, compurl);
  2212. result = curl_easy_perform(curl);
  2213. sleep(1);
  2214. if (debug == 1) printf("result = %d\n",result);
  2215. curl_easy_cleanup(curl);
  2216. if( result==0 )
  2217. {
  2218. sprintf(SQLQUERY,"SELECT DATE_FORMAT(dd1.DateTime,\'%%Y%%m%%d\'), DATE_FORMAT(dd1.DateTime,\'%%H:%%i\'), ROUND((dd1.ETotalToday-dd2.EtotalToday)*1000), dd1.CurrentPower, dd1.DateTime FROM DayData as dd1 join DayData as dd2 on dd2.DateTime=DATE_FORMAT(dd1.DateTime,\'%%Y-%%m-%%d 00:00:00\') WHERE dd1.DateTime>=Date_Sub(CURDATE(),INTERVAL 1 DAY) and dd1.PVOutput IS NULL and dd1.CurrentPower>0 ORDER BY dd1.DateTime ASC limit %d", batch_count );
  2219. if (debug == 1) printf("%s\n",SQLQUERY);
  2220. DoQuery1(SQLQUERY);
  2221. while ((row1 = mysql_fetch_row(res1))) //Need to update these
  2222. {
  2223. sprintf(SQLQUERY,"UPDATE DayData set PVOutput=NOW() WHERE DateTime=\"%s\" ", row1[4] );
  2224. if (debug == 1) printf("%s\n",SQLQUERY);
  2225. DoQuery2(SQLQUERY);
  2226. }
  2227. mysql_free_result( res1 );
  2228. }
  2229. }
  2230. batch_count = 0;
  2231. }
  2232. }
  2233. mysql_free_result( res );
  2234. mysql_close(conn);
  2235. }
  2236. close(s);
  2237. if( archdatalen > 0 )
  2238. free( archdatalist );
  2239. archdatalen=0;
  2240. free(last_sent);
  2241. }
  2242. if ((repost ==1)&&(error==0)){
  2243. printf( "\nrepost\n" ); getchar();
  2244. sma_repost( &conf, debug, verbose );
  2245. }
  2246. return 0;
  2247. }