PageRenderTime 65ms CodeModel.GetById 20ms 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

Large files files are truncated, but you can click here to view the full 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

Large files files are truncated, but you can click here to view the full file