./PaxHeaders.21049/aurora-1.8.80000644000000000000000000000013212461572417012646 xustar0030 mtime=1422325007.509465064 30 atime=1353288463.717557954 30 ctime=1422325007.509465064 aurora-1.8.8/0000775000000000001440000000000012461572417013221 5ustar00rootusers00000000000000aurora-1.8.8/PaxHeaders.21049/comm.c0000644000000000000000000000013212461565740013666 xustar0030 mtime=1422322656.045825153 30 atime=1411060395.658158985 30 ctime=1422322656.058826064 aurora-1.8.8/comm.c0000775000000000001440000026204012461565740014330 0ustar00rootusers00000000000000/* * aurora - Communications with Magnetek Aurora Inverter * * Copyright (C) 2006-2015 Curtis J. Blank curt@curtronics.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program may be used and hosted free of charge by anyone for * personal purposes as long as this and all included copyright * notice(s) remain intact. * * Obtain permission before selling the code for this program or * hosting this software on a commercial website, excluding if it is * solely hosted for distribution, that is allowable . In all cases * copyright must remain intact. * * This work based on Magnetek's 'Aurora PV Inverter - Communications * Protocol -' document, Rel. 1.8 09/05/2005 * Staring with v1.5-0 this work based on Power One's 'Aurora Inverter * Series - Communication Protocol -' document, Rel. 4.6 25/02/09 * * Special thanks to Tron Melzl at Magnetek for all his help including, but * by no means limited to, supplying the Communications Protocol document * And another thanks to Jonathan Duddington on the other side of the pond * for his contribution of items he gathered while reverse engineering the * inverters communication some of which were incorporated beginning with * verison 1.7.8 * * modified 17-jul-2006 cjb 1. Last 7 Days production value has been dropped in the v2.3 Communications Protocol doc * modified 13-oct-2006 cjb 1. correct possible divide by zero when calculating inverter efficiency * modified 25-apr-2007 cjb 1. update set time warning * 2. take into account Daylight Savings Time when setting the Aurora's time * modified 29-dec-2008 cjb 1. correct an error in strftime that only may show up in the first or last * week of the year (%G vs %Y) * modified 19-aug-2009 cjb 1. szSerBuffer needs to be [11] if ending with "\0" * modified 18-sep-2009 cjb 1. add cCommandEnd = '\0' * modified 12-oct-2009 cjb 1. add -o option to output data to a file * modified 30-oct-2009 cjb 1. added errno for read problems * modified 07-mar-2010 cjb 1. fix sizeof pointer passing in memset * 2. use -Y option in Communicate function * 3. in ReadNextChar restore serial port settings and clear lock if exiting * modified 13-mar-2010 cjb 1. if yReadPause is set use it * modified 28-mar-2010 cjb 1. working on adding more DSP information * modified 27-jul-2010 cjb 1. added -P option to throttle commands sent to the inverter * modified 21-sep-2010 cjb 1. fix using wrong param when displaying TransState message * 2. pass TransState the command description so if it gets a non-zero status it can * report for what command it got it * 3. added reporting for "Last four alarms" * modified 30-jul-2011 cjb 1. fixed joule conversion error * modified 06-aug-2011 cjb 1. fixed a integer conversion issue for -k due to some architectures * 2. fixed bizarreness with -bt * 3. adjust TimeBase to true UTC-0000 and take into account timezone in GetTime (-t) * SetTime (-S) functions * modified 22-aug-2011 cjb 1. in SetTime check scanf return value rc * modified 05-nov-2011 cjb 1. added function for -q --energy-sent option * modified 09-nov-2011 cjb 1. added function for -L --reconcile-time option * modified 13-nov-2011 cjb 1. added handling for -W option swap endian * modified 22-nov-2011 cjb 1. fixed -k, -n, & -p strings output that were overflowing on occasion * modified 21-dec-2011 cjb 1. fixed some bad trailing characters showing up in date strings on MIPS platforms * modified 31-dec-2011 cjb 1. --energy-sent values are W not kW Doh! * 2. Grid Current & Grid Power can now return negative values * modified 02-jan-2012 cjb 1. add bad return code tracking * modified 03-jan-2012 cjb 1. fix W not kW in all spots for --energy-sent. My bad. * modified 07-jan-2012 cjb 1. timing issues again setting the inverter time waiting for inverter response * modified 15-jan-2012 cjb 1. --daily-kwh date started tomorrow instead of today, adjusted timebase * 2. dynamically adjust timebase for --daily-kwh if it looks to be off * 3. watch for out of order or duplicate dates in --daily-kwh * modified 30-jan-2012 cjb 1. be more aggressive and at the same time patient trying to read characters from * slow to respond inverters (READ! the README for the impacts this has) * 2. added -M option maximum amount of time in seconds that aurora * will run * modified 16-feb-2012 cjb 1. use multiplier for --energy-sent if known for inverter model * 2. revamp --daily-kwh after discovering data may not always be contiguous * modified 24-feb-2012 cjb 1. modify -i, --get-count option to use a bitmask indictating what to do * modified 28-feb-2012 cjb 1. initialize some variables so as to avoid compiler warnings * 2. check validity of value returned by GetInvTime to be sure inverter responded * modified 29-feb-2012 cjb 1. allow display of out of order dates for -k (--daily-kwh) if they appear to be * valid this may then require the output be sorted * modified 05-mar.2012 cjb 1. handle out of order dates for -k (--daily-kwh) by sorting them and suppressing * duplicate entries for a date * modified 18-mar-2013 cjb 1. add -Q option and only use qMultiplier for -q, --energy-sent if -Q is used * 2. add -K option and use value supplied for -k, --daily-kwh value multiplier * modified 16-nov-2013 cjb 1. handle missing tm_gmtoff in tm structure * modified 05-dec-2013 cjb 1. temperatures can be below zero i.e. negative (inverters installed outdoors) * modified 11-apr-2014 cjb 1. correct reporting wrong model when -Q is not used * */ char VersionC[7] = "1.8.8"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "include/main.h" #include "include/comm.h" #include "include/names.h" #include "include/states.h" char VersionSHc[6] = VersionSH; int invOp; int invFunc; static char szSerBuffer[_szSerBufferLen]; /* serial read/write buffer */ static WORD crcValue; static int ModelID; static float qMultiplier = -1.0; static char ModelName[_ModelNameLen]; static int star[5] = { '|','/','-','\\','*' }; static BOOL CmdNotImp = FALSE; /* local functions */ static long int getGMToffset(time_t seconds); static int TransState(int TransCode, char Desription[], BOOL FailIf); static int PrintModel(void); static long GetCEdata(int fdser, int yAddress, int opcode, int param, char description[]); static float GetCECdata(int fdser, int yAddress, int opcode, int param, char description[], int yGetEnergyCen); static float GetDSPdata(int fdser, int yAddress, int opcode, int param, char description[], BOOL TScheck); static time_t GetInvTime(int fdser, int yAddress); static int GetCountersData(int fdser, int yAddress, int param, char *uptime); static BOOL exceededRT(); static int Communicate(int fdser, int yAddress); static int ReadNextChar(int nfd, char *pChar, int timeout); static int ReadToBuffer(int nfd, char *pszBuffer, int nBufSize); static WORD crc16(char *data_p, unsigned short length); static char* FindString(WORD wRule, char *ptr); static float *szCvrtFloat(char *Buffer); static unsigned short szCvrtShort(char *Buffer); static unsigned long szCvrtLong(char *Buffer); static unsigned long cvrtLong(char *Buffer); /*-------------------------------------------------------------------------- TransState ----------------------------------------------------------------------------*/ int TransState(int TransCode, char Desription[], BOOL FailIf) { if (bVerbose) fprintf(stderr, "Transmission State Check: %i\n",TransCode); CmdNotImp = FALSE; if (TransCode == 0) return(1); if (TransCode == 51 || TransCode == 52) { CmdNotImp = TRUE; if (! FailIf) return(1); } fprintf(outfp, "\nTransmission State: %2i Command: \"%s\" %s\n\n",TransCode,Desription,FindString(TransCode, szTransStates)); return(0); } /*-------------------------------------------------------------------------- CommCheck ----------------------------------------------------------------------------*/ int CommCheck(int fdser, int yAddress) { int nCnt; int pos = 0; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = opGetVer; szSerBuffer[cCommandEnd] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0 && TransState((int)szSerBuffer[aState],_opGetVer,TRUE)) { ModelID = szSerBuffer[aPar1]; while (ModelID != model_names[pos].ID && model_names[pos].ID >= 0) pos++; if (bUseMultiplierQ) qMultiplier = model_names[pos].multipler; strcpy(ModelName,model_names[pos].name); if (bVerbose) { fprintf(stderr, "Model ID \"%c\" qMultiplier %.7f ",ModelID,qMultiplier); PrintModel(); } return(0); } invOp = 0; invFunc = -1; return(-1); } /*-------------------------------------------------------------------------- getGMToffset ----------------------------------------------------------------------------*/ long int getGMToffset(time_t seconds) { long int gmtoff = 0; struct tm local; #ifdef NO_TM_GMTOFF struct tm gmt; int day = 0; int hour = 0; int min = 0; #endif local = *localtime(&seconds); #ifndef NO_TM_GMTOFF gmtoff = local.tm_gmtoff; #else gmt = *gmtime(&seconds); day = local.tm_yday - gmt.tm_yday; hour = ((day < -1 ? 24 : 1 < day ? -24 : day * 24) + local.tm_hour - gmt.tm_hour); min = hour * 60 + local.tm_min - gmt.tm_min; gmtoff = min * 60; #endif if (bVerbose) fprintf(stderr, "gmtoff %li\n", gmtoff); return(gmtoff); } /*-------------------------------------------------------------------------- GetState ----------------------------------------------------------------------------*/ int GetState(int fdser, int yAddress) { int nCnt; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opGetState; szSerBuffer[cCommandEnd] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0 && TransState((int)szSerBuffer[aState],_opGetState,TRUE)) { fprintf(outfp, "\nGlobal State: %s\n",FindString((int)szSerBuffer[aMState], szGlobalStates)); fprintf(outfp, "Inverter State: %s\n",FindString((int)szSerBuffer[aParam1], szInverterState)); fprintf(outfp, "Channel 1 Dc/Dc State: %s\n",FindString((int)szSerBuffer[aParam2], szDcDcStatus)); fprintf(outfp, "Channel 2 Dc/Dc State: %s\n",FindString((int)szSerBuffer[aParam3], szDcDcStatus)); fprintf(outfp, "Alarm State: %s\n",FindString((int)szSerBuffer[aParam4], szAlarmState)); return(0); } return(-1); } /*-------------------------------------------------------------------------- GetLastAlarms ----------------------------------------------------------------------------*/ int GetLastAlarms(int fdser, int yAddress) { int nCnt; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /*clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /*set inverter address */ szSerBuffer[cCommand] = invOp = opGetLastAlarms; szSerBuffer[cCommandEnd] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0 && TransState((int)szSerBuffer[aState],_opGetLastAlarms,TRUE)) { fprintf(outfp, "\nAlarm 1: %s\n",FindString((int)szSerBuffer[aParam1], szAlarmState)); fprintf(outfp, "Alarm 2: %s\n",FindString((int)szSerBuffer[aParam2], szAlarmState)); fprintf(outfp, "Alarm 3: %s\n",FindString((int)szSerBuffer[aParam3], szAlarmState)); fprintf(outfp, "Alarm 4: %s\n",FindString((int)szSerBuffer[aParam4], szAlarmState)); return(0); } return(-1); } /*-------------------------------------------------------------------------- GetPN CMD 52 ----------------------------------------------------------------------------*/ int GetPN(int fdser, int yAddress) { int nCnt; char PartNumber[7]; PartNumber[0] = '\0'; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opGetPN; szSerBuffer[cCommandEnd] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0) { strncpy(PartNumber, szSerBuffer, 6); PartNumber[6] = '\0'; fprintf(outfp, "\nPart Number: %s\n",PartNumber); return(0); } return(-1); } /*-------------------------------------------------------------------------- GetPNC CMD 105 ----------------------------------------------------------------------------*/ int GetPNC(int fdser, int yAddress) { int nCnt; char PartNumber[7]; if (ModelID != 'C' && ModelID != 'M' && ModelID != 'L' && ModelID != 'B' && ModelID != 'A') { fprintf(outfp, "\nCannot query for Part Number, doea not appear to be a Central inverter (%c)\n\n", ModelID); return(-1); } PartNumber[0] = '\0'; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opGetPNC; szSerBuffer[cCommandEnd] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0) { strncpy(PartNumber, szSerBuffer, 6); PartNumber[6] = '\0'; fprintf(outfp, "\nPart Number (Central): %s\n",PartNumber); return(0); } return(-1); } /*-------------------------------------------------------------------------- PrintModel ----------------------------------------------------------------------------*/ int PrintModel(void) { if (outfp != stderr) fprintf(outfp, "\nInverter Version: "); fprintf(outfp, "-- %s --\n",ModelName); return(0); } /*-------------------------------------------------------------------------- GetVer ----------------------------------------------------------------------------*/ int GetVer(int fdser, int yAddress) { int nCnt; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opGetVer; szSerBuffer[cCommandEnd] = '\0'; szSerBuffer[cParam1] = '.'; nCnt = Communicate(fdser, yAddress); crcValue = crc16(szSerBuffer, 8); if (nCnt > 0 && TransState((int)szSerBuffer[aState],_opGetVer,TRUE)) { if (bVerbose) fprintf(stderr, "aPar2 %c aPar3 %c aPar4 %c\naPar2 %2x aPar3 %2x aPar4 %2x\n", szSerBuffer[aPar2], szSerBuffer[aPar3], szSerBuffer[aPar4], szSerBuffer[aPar2], szSerBuffer[aPar3], szSerBuffer[aPar4]); PrintModel(); switch (szSerBuffer[aPar2]) { case 'A': fprintf(outfp, "%s -- ",aPar2A); break; case 'E': fprintf(outfp, "%s -- ",aPar2E); break; case 'S': fprintf(outfp, "%s -- ",aPar2S); break; case 'I': fprintf(outfp, "%s -- ",aPar2I); break; case 'U': fprintf(outfp, "%s -- ",aPar2U); break; case 'K': fprintf(outfp, "%s -- ",aPar2K); break; case 'F': fprintf(outfp, "%s -- ",aPar2F); break; case 'R': fprintf(outfp, "%s -- ",aPar2R); break; case 'B': fprintf(outfp, "%s -- ",aPar2B); break; case 'O': fprintf(outfp, "%s -- ",aPar2O); break; case 'G': fprintf(outfp, "%s -- ",aPar2G); break; case 'T': fprintf(outfp, "%s -- ",aPar2T); break; case 'C': fprintf(outfp, "%s -- ",aPar2C); break; case 'Q': fprintf(outfp, "%s -- ",aPar2Q); break; case 'a': fprintf(outfp, "%s -- ",aPar2a); break; case 'b': fprintf(outfp, "%s -- ",aPar2b); break; case 'c': fprintf(outfp, "%s -- ",aPar2c); break; case 'X': fprintf(outfp, "%s -- ",aPar2X); break; case 'x': fprintf(outfp, "%s -- ",aPar2x); break; case 'u': fprintf(outfp, "%s -- ",aPar2u); break; case 'k': fprintf(outfp, "%s -- ",aPar2k); break; case 'W': fprintf(outfp, "%s -- ",aPar2W); break; case 'H': fprintf(outfp, "%s -- ",aPar2H); break; case 'o': fprintf(outfp, "%s -- ",aPar2o); break; case 'P': fprintf(outfp, "%s -- ",aPar2P); break; case 'e': fprintf(outfp, "%s -- ",aPar2e); break; } switch (szSerBuffer[aPar3]) { case 'T': fprintf(outfp, "%s -- ",aPar3T); break; case 'N': fprintf(outfp, "%s -- ",aPar3N); break; case 't': fprintf(outfp, "%s -- ",aPar3t); break; case 'X': fprintf(outfp, "%s -- ",aPar3X); break; default: fprintf(outfp, "%s -- ","unknown"); break; } switch (szSerBuffer[aPar4]) { case 'W': fprintf(outfp, "%s -- ",aPar4W); break; case 'N': fprintf(outfp, "%s -- ",aPar4N); break; case 'X': fprintf(outfp, "%s -- ",aPar4X); break; default: fprintf(outfp, "%s -- ","unknown"); break; } fprintf(outfp, "\n"); return(0); } return(-1); } /*-------------------------------------------------------------------------- GetConf ----------------------------------------------------------------------------*/ int GetConf(int fdser, int yAddress) { int nCnt; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opGetConfig; szSerBuffer[cCommandEnd] = '\0'; nCnt = Communicate(fdser, yAddress); crcValue = crc16(szSerBuffer, 8); if (nCnt > 0 && TransState((int)szSerBuffer[aState],_opGetConfig,TRUE)) { switch (szSerBuffer[aConfCode]) { case ConfCode0: fprintf(outfp, "\n%s\n",_ConfCode0); break; case ConfCode1: fprintf(outfp, "\n%s\n",_ConfCode1); break; case ConfCode2: fprintf(outfp, "\n%s\n",_ConfCode2); break; default: break; } return(0); } return(-1); } /*-------------------------------------------------------------------------- GetSN ----------------------------------------------------------------------------*/ int GetSN(int fdser, int yAddress) { int nCnt; char SerialNumber[7]; SerialNumber[0] = '\0'; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opGetSN; szSerBuffer[cCommandEnd] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0) { strncpy(SerialNumber, szSerBuffer, 6); SerialNumber[6] = '\0'; fprintf(outfp, "\nSerial Number: %s\n",SerialNumber); return(0); } return(-1); } /*-------------------------------------------------------------------------- GetVerFW ----------------------------------------------------------------------------*/ int GetVerFW(int fdser, int yAddress) { int nCnt; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opGetVerFW; szSerBuffer[cCommandEnd] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0 && TransState((int)szSerBuffer[aState],_opGetVerFW,TRUE)) { fprintf(outfp, "\nFirmware: %c.%c.%c.%c\n",szSerBuffer[aRel3],szSerBuffer[aRel2],szSerBuffer[aRel1],szSerBuffer[aRel0]); return(0); } return(-1); } /*-------------------------------------------------------------------------- GetMfgDate ----------------------------------------------------------------------------*/ int GetMfgDate(int fdser, int yAddress) { int nCnt; char MfgWeek[3] = " \0"; char MfgYear[3] = " \0"; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opGetMfg; szSerBuffer[cCommandEnd] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0 && TransState((int)szSerBuffer[aState],_opGetMfg,TRUE)) { MfgWeek[0] = szSerBuffer[aWeekH]; MfgWeek[1] = szSerBuffer[aWeekL]; MfgYear[0] = szSerBuffer[aYearH]; MfgYear[1] = szSerBuffer[aYearL]; fprintf(outfp, "\nManufacturing Date: Year %s Week %s\n",MfgYear,MfgWeek); return(0); } return(-1); } /*-------------------------------------------------------------------------- GetCESent ** Experimental ** ----------------------------------------------------------------------------*/ int GetCESent(int fdser, int yAddress, int yGetEnergySent) { int nCnt = 0; time_t timeValLong = 0; time_t timeValLongLast = 0; long int gmtoff = 0; long int gmtoffTS = 0; long int gmtoffTSnext = 0; struct tm TS, TSnext; char DT[18] = " "; int addC = 0; int addS = 0; BOOL loop = TRUE; BOOL beg = FALSE; BOOL tsync = FALSE; BOOL cr = FALSE; BOOL odd = FALSE; int value1 = 0; int value2 = 0; static char tBuf[4]; int ffff = 0; int cnt = 0; int i = 0; if (bVerbose)fprintf(stderr, "TimeBase %lu timeValLong %lu\n",(long)TimeBase,timeValLong); if ((timeValLong = GetInvTime(fdser, yAddress)) < 0) return(-1); TS = *(localtime(&timeValLong)); gmtoff = getGMToffset(timeValLong); if (bVerbose) { strftime(DT,sizeof(DT),"%Y%m%d-%H:%M:%S",&TS); DT[sizeof(DT)-1] = '\0'; fprintf(stderr, "Inverter Time: %17s\t0.0 timeValLong %lu gmtoff %li TimeBase %lu\n",DT,timeValLong,gmtoff,(long)TimeBase); } invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /*clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /*set inverter address */ szSerBuffer[cCommand] = invOp = HIBYTE(opGetCESent); szSerBuffer[cParam1] = invFunc = LOBYTE(opGetCESent); szSerBuffer[cParam1End] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0 && TransState((int)szSerBuffer[aState],_opGetCESent,TRUE)) { addS = szCvrtShort(szSerBuffer); if (bVerbose) { fprintf(stderr, "\nszSerBuffer addS: "); for (i = 0; i < cSIZE; i++) { fprintf(stderr, "%02x ",(unsigned char)szSerBuffer[i]); } fprintf(stderr, "\naddS 0x%04x %i\n",addS,addS); } addC = addS; if (addC == aCESMemAdd) beg = TRUE; invFunc = -1; while (loop && nCnt > 0) { memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); szSerBuffer[cAddress] = yAddress; /*set inverter address */ szSerBuffer[cCommand] = invOp = opGetCEValue; szSerBuffer[cCEDailyAddH] = HIBYTE(addC); szSerBuffer[cCEDailyAddL] = LOBYTE(addC); szSerBuffer[cCEDailyEnd] = '\0'; nCnt = Communicate(fdser, yAddress); cnt++; if (bVerbose) { fprintf(stderr, "%i 0x%02x%02x szSerBuffer addS: ",cnt,HIBYTE(addC),LOBYTE(addC)); for (i = 0; i < cSIZE; i++) { fprintf(stderr, "%02x ",(unsigned char)szSerBuffer[i]); } fprintf(stderr, "\n"); } if (nCnt > 0 && TransState((int)szSerBuffer[aState],_opGetCESent,TRUE)) { if (bVerbose) { fprintf(stderr, "addr 0x%02x%02x ",HIBYTE(addC),LOBYTE(addC)); } value1 = szCvrtShort(szSerBuffer); if (bVerbose) { fprintf(stderr, "addr 0x%02x%02x ",HIBYTE(addC+2),LOBYTE(addC+2)); } value2 = szCvrtShort(szSerBuffer+2); if (addC <= ((aCESMemAdd+(aCESMaxCnt*4))-4)) { if (value1 == 0xffff) { ffff = value1; tBuf[0] = HIBYTE(value2); tBuf[1] = LOBYTE(value2); value2 = 0xffff; } else if (value2 == 0xffff) { ffff = value2; } else if (ffff != 0) { if (cvrtLong(tBuf) == 0) { tBuf[0] = HIBYTE(value1); tBuf[1] = LOBYTE(value1); tBuf[2] = HIBYTE(value2); tBuf[3] = LOBYTE(value2); value1 = value2 = 0xffff; } else { tBuf[2] = HIBYTE(value1); tBuf[3] = LOBYTE(value1); value1 = 0xffff; } timeValLong = cvrtLong(tBuf) + TimeBase; TS = *(localtime(&timeValLong)); gmtoff = getGMToffset(timeValLong); timeValLong -= gmtoff; tBuf[0] = tBuf[1] = tBuf[2] = tBuf[3] = '\0'; ffff = 0; if (bVerbose) { fprintf(stderr, "time change old: timeValLong %lu ",timeValLongLast); fprintf(stderr, "new: timeValLong %lu gmtoff %li\n",timeValLong,gmtoff); TS = *(localtime(&timeValLongLast)); strftime(DT,sizeof(DT),"%Y%m%d-%H:%M:%S",&TS); DT[sizeof(DT)-1] = '\0'; fprintf(stderr, "old: %17s",DT); TS = *(localtime(&timeValLong)); strftime(DT,sizeof(DT),"%Y%m%d-%H:%M:%S",&TS); DT[sizeof(DT)-1] = '\0'; fprintf(stderr, " new: %17s\n",DT); } if (! tsync) { TSnext = *(localtime(&timeValLong)); gmtoffTSnext = getGMToffset(timeValLong); timeValLongLast = timeValLong; TS = *(localtime(&timeValLongLast)); TS.tm_sec = TS.tm_min = TS.tm_hour = 0; timeValLongLast = mktime(&TS); TS = *(localtime(&timeValLongLast)); gmtoffTS = getGMToffset(timeValLongLast); timeValLongLast += (gmtoffTS - gmtoffTSnext); TS = *(localtime(&timeValLongLast)); if (TSnext.tm_year == TS.tm_year && TSnext.tm_mon == TS.tm_mon && TSnext.tm_mday == TS.tm_mday) tsync =TRUE; } if (tsync) { while (timeValLongLast < timeValLong) { TS = *(localtime(&timeValLongLast)); strftime(DT,sizeof(DT),"%Y%m%d-%H:%M:%S",&TS); DT[sizeof(DT)-1] = '\0'; fprintf(outfp, "\n%17s %9.1f W",DT,0.0); timeValLongLast += 10; } if (bVerbose && ! cr) { fprintf(outfp, "\n"); } } else tsync = TRUE; } } if (bVerbose && addC == aCESMemAdd) { fprintf(stderr, "addC %04x cnt = %i szSerBuffer addC: ",addC,cnt); for (i = 0; i < cSIZE; i++) { fprintf(stderr, "%02x ",(unsigned char)szSerBuffer[i]); } fprintf(stderr, "\n"); } if (addC != aCESMemAdd && addC <= ((aCESMemAdd+(aCESMaxCnt*4))-4) && value1 != 0xffff) { if (cr) fprintf(outfp, "\n"); TS = *(localtime(&timeValLong)); gmtoff = getGMToffset(timeValLong); if (tsync) { strftime(DT,sizeof(DT),"%Y%m%d-%H:%M:%S",&TS); DT[sizeof(DT)-1] = '\0'; if (qMultiplier <= 0) fprintf(outfp, "%17s %9.1f W",DT,(float)value1/10); else fprintf(outfp, "%17s %9.1f W",DT,(float)value1*qMultiplier); } else { if (qMultiplier <= 0) fprintf(outfp, "YYYYMMDD-%04i %9.1f W",((cnt-1)*2)+1,(float)value1/10); else fprintf(outfp, "YYYYMMDD-%04i %9.1f W",((cnt-1)*2)+1,(float)value1*qMultiplier); } if (bVerbose) fprintf(outfp, "\t0x%04x",value1); if (tsync) { timeValLong += 10; timeValLongLast = timeValLong; } cr = TRUE; } if ((addC+2) <= ((aCESMemAdd+(aCESMaxCnt*4))-2) && value2 != 0xffff && ! (cnt == aCESMaxCnt && odd)) { if (cr) fprintf(outfp, "\n"); TS = *(localtime(&timeValLong)); gmtoff = getGMToffset(timeValLong); if (tsync) { strftime(DT,sizeof(DT),"%Y%m%d-%H:%M:%S",&TS); DT[sizeof(DT)-1] = '\0'; if (qMultiplier <= 0) fprintf(outfp, "%17s %9.1f W",DT,(float)value2/10); else fprintf(outfp, "%17s %9.1f W",DT,(float)value2*qMultiplier); } else { if (qMultiplier <= 0) fprintf(outfp, "YYYYMMDD-%04i %9.1f W",((cnt-1)*2)+2,(float)value2/10); else fprintf(outfp, "YYYYMMDD-%04i %9.1f W",((cnt-1)*2)+2,(float)value2*qMultiplier); } if (bVerbose) fprintf(outfp, "\t0x%04x",value2); if (tsync) { timeValLong += 10; timeValLongLast = timeValLong; } cr = TRUE; } addC += 4; if (cnt >= aCESMaxCnt || cnt >= yGetEnergySent || (beg && addC >= addS)) loop = FALSE; else { if (addC > ((aCESMemAdd+(aCESMaxCnt*4))-2)) { /* -2 in case start align was +1 */ if (beg) loop = FALSE; else { if (bVerbose) { fprintf(stderr, "%i wrapping addC cur 0x%02x%02x ",cnt,HIBYTE(addC),LOBYTE(addC)); } if (addC > ((aCESMaxCnt*4)+aCESMemAdd)) odd = TRUE; addC = aCESMemAdd; if (bVerbose) { fprintf(stderr, "new 0x%02x%02x %s\n",HIBYTE(addC),LOBYTE(addC),odd ? "odd" : "even"); } beg = TRUE; } } } } else { return(-1); } } } else return(-1); return(0); } /*-------------------------------------------------------------------------- GetCEDaily ** Experimental ** ----------------------------------------------------------------------------*/ int GetCEDaily(int fdser, int yAddress, int yGetEnergyDaily) { int nCnt; int addC = 0; int loop = 1; int pCnt = 0; int i = 0, j = 0; time_t timeValLongBase = 0, timeValLongToday = 0, tVal = 0; long int gmtoff = 0; struct tm TS; char DT[18] = ""; char YMD[9] = ""; char DCEL[95] = ""; unsigned long days = 0, lastDays = 0, begDay = 0, kwh = 0; BOOL looped = FALSE; int data[366][2]; DT[0] = '\0'; if (bVerbose)fprintf(stderr, "TimeBase %lu timeValLong %lu\n",(long)TimeBase,timeValLongBase); if ((timeValLongBase = GetInvTime(fdser, yAddress)) < 0) return(-1); TS = *(localtime(&timeValLongBase)); gmtoff = getGMToffset(timeValLongBase); if (bVerbose) { strftime(DT,sizeof(DT),"%Y%m%d-%H:%M:%S",&TS); DT[sizeof(DT)-1] = '\0'; fprintf(stderr, "\nInverter Time: %17s timeValLong %12lu gmtoff %7li TimeBase %12lu\n",DT,timeValLongBase,gmtoff,(long)TimeBase); } TS.tm_sec = TS.tm_min = TS.tm_hour = TS.tm_isdst = 0; timeValLongToday = mktime(&TS); timeValLongBase = time(NULL); TS = *(localtime(&timeValLongBase)); TS.tm_sec = TS.tm_min = TS.tm_hour = TS.tm_mon = TS.tm_isdst = 0; TS.tm_sec = TS.tm_min = TS.tm_hour = TS.tm_isdst = 0; TS.tm_mday = 1; TS.tm_year = 100; timeValLongBase = mktime(&TS); timeValLongBase -= 86400; TS = *(localtime(&timeValLongBase)); gmtoff = getGMToffset(timeValLongBase); DT[sizeof(DT)-1] = '\0'; if (bVerbose) { strftime(DT,sizeof(DT),"%Y%m%d-%H:%M:%S",&TS); DT[sizeof(DT)-1] = '\0'; fprintf(stderr, "Timebase: %17s 0.0 timeValLong %12lu gmtoff %7li TimeBase %12lu\n",DT,timeValLongBase,gmtoff,(long)TimeBase); } if (bVerbose) { TS = *(localtime(&timeValLongToday)); strftime(DT,sizeof(DT),"%Y%m%d-%H:%M:%S",&TS); DT[sizeof(DT)-1] = '\0'; fprintf(stderr, "Todays Base: %17s timeValLong %12lu gmtoff %7li TimeBase %12lu\n",DT,timeValLongToday,gmtoff,(long)TimeBase); } if (bVerbose) { fprintf(stderr, "Multiplier: %f\n", yMultiplierK); } YMD[0] = '\0'; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /*set inverter address */ szSerBuffer[cCommand] = invOp = HIBYTE(opGetCEAdd); szSerBuffer[cParam1] = invFunc = LOBYTE(opGetCEAdd); szSerBuffer[cParam1End] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0 && TransState((int)szSerBuffer[aState],_opGetCEAdd,TRUE)) { addC = szCvrtShort(szSerBuffer); if (bVerbose) fprintf(stderr, "\nDCE Epoch: Address: 0x%04x\n",(WORD)addC); else fprintf(outfp, "\n"); invFunc = -1; while (loop && nCnt > 0) { if (!bVerbose) fprintf(stderr, "%c%c", star[(loop-1)%5], 0x0d); memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); szSerBuffer[cAddress] = yAddress; /*set inverter address */ szSerBuffer[cCommand] = invOp = opGetCEValue; szSerBuffer[cCEDailyAddH] = HIBYTE(addC); szSerBuffer[cCEDailyAddL] = LOBYTE(addC); szSerBuffer[cCEDailyEnd] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0 && TransState((int)szSerBuffer[aState],_opGetCEAdd,TRUE)) { days = szCvrtShort(szSerBuffer); kwh = szCvrtShort(szSerBuffer+2); if (bVerbose) sprintf(DCEL, "DCE Loop: %3d Address: 0x%04x Day: %3d Days: 0x%02x%02x Value: 0x%02x%02x %5li = ",loop,addC,pCnt+1,(BYTE)szSerBuffer[aCEDailyDaysH],(BYTE)szSerBuffer[aCEDailyDaysL],(BYTE)szSerBuffer[aCEDailyValH],(BYTE)szSerBuffer[aCEDailyValL],days); if (kwh != 0xffff) { tVal = timeValLongBase + ((days-1)*86400); if (loop == 1) { begDay = days; if (tVal != timeValLongToday) { if (bVerbose) { TS = *(localtime(&timeValLongBase)); strftime(DT,sizeof(DT),"%Y%m%d-%H:%M:%S",&TS); DT[sizeof(DT)-1] = '\0'; fprintf(stderr, "\nAdjusting timebase by %li\nwas %12li %s\n",timeValLongToday-tVal,timeValLongBase,DT); } timeValLongBase = timeValLongToday - ((days-1)*86400); if (bVerbose) { TS = *(localtime(&timeValLongBase)); strftime(DT,sizeof(DT),"%Y%m%d-%H:%M:%S",&TS); DT[sizeof(DT)-1] = '\0'; fprintf(stderr, "is %12li %s\n\n",timeValLongBase,DT); } tVal = timeValLongBase + ((days-1)*86400); } } if (bVerbose) { TS = *(localtime(&tVal)); strftime(YMD,sizeof(YMD),"%Y%m%d",&TS); YMD[sizeof(YMD)-1] = '\0'; fprintf(stderr, "%s%s %6.3f kWh",DCEL,YMD,(float)kwh/(1000.0/yMultiplierK)); } if (days != lastDays && (days < begDay || lastDays == 0)) { data[pCnt][0] = days; data[pCnt][1] = kwh; lastDays = days; pCnt++; } else if (bVerbose) fprintf(stderr, " out of order or duplicate\n"); } else if (bVerbose) fprintf(stderr, "%s???????? %6.3f kWh invalid",DCEL,(float)kwh/(1000.0/yMultiplierK)); if (! looped && addC <= 0x4388) { addC += (366*4); looped = TRUE; if (bVerbose) fprintf(stderr, " Move to end 0x%04x",addC); } else addC -= 4; if (bVerbose) fprintf(stderr, "\n"); if (pCnt >= yGetEnergyDaily) loop = 0; else loop++; } else return(-1); if (loop > 367) loop = 0; } for (i = 0; i < pCnt; i++) { for (j = i; j < pCnt; j++) { if (data[i][0] < data[j][0] || (data[i][0] == data[j][0] && data[i][1] < data[j][1])) { data[i][0] += data[j][0]; data[j][0] = data[i][0] - data[j][0]; data[i][0] -= data[j][0]; data[i][1] += data[j][1]; data[j][1] = data[i][1] - data[j][1]; data[i][1] -= data[j][1]; } } } lastDays = -1; for (i = 0; i < pCnt; i++) { if (data[i][0] != lastDays) { tVal = timeValLongBase + ((data[i][0]-1)*86400); TS = *(localtime(&tVal)); strftime(YMD,sizeof(YMD),"%Y%m%d",&TS); YMD[sizeof(YMD)-1] = '\0'; fprintf(outfp, "%s %9.3f kWh\n",YMD,(float)data[i][1]/(1000.0/yMultiplierK)); lastDays = data[i][0]; } } return(0); } else if (bVerbose) fprintf(stderr, "\nDCE Address retreival problem\n"); return(-1); } /*-------------------------------------------------------------------------- GetCEC CMD 68 ----------------------------------------------------------------------------*/ int GetCEC(int fdser, int yAddress, int yGetEnergyCen) { float DAILY = 0.0, WEEKLY = 0.0, MONTHLY = 0.0, YEARLY = 0.0, NDAYS = 0.0, TOTAL = 0.0, PARTIAL = 0.0; int yTimeoutOrg; char Days[16]; if ((DAILY = GetCECdata(fdser,yAddress,opGetCEC,CECpar1,_opGetCEC,-1)) == _ERROR_) return(-1); if ((WEEKLY = GetCECdata(fdser,yAddress,opGetCEC,CECpar2,_opGetCEC,-1)) == _ERROR_) return(-1); if ((MONTHLY = GetCECdata(fdser,yAddress,opGetCEC,CECpar3,_opGetCEC,-1)) == _ERROR_) return(-1); if ((YEARLY = GetCECdata(fdser,yAddress,opGetCEC,CECpar4,_opGetCEC,-1)) == _ERROR_) return(-1); yTimeoutOrg = yTimeout; yTimeout = 2000; if ((NDAYS = GetCECdata(fdser,yAddress,opGetCEC,CECpar5,_opGetCEC,yGetEnergyCen)) == _ERROR_) return(-1); yTimeout = yTimeoutOrg; if ((TOTAL = GetCECdata(fdser,yAddress,opGetCEC,CECpar6,_opGetCEC,-1)) == _ERROR_) return(-1); if ((PARTIAL = GetCECdata(fdser,yAddress,opGetCEC,CECpar7,_opGetCEC,-1)) == _ERROR_) return(-1); sprintf(Days,"%d %s",yGetEnergyCen,_CECpar5); if (bColumns) { fprintf(outfp, "%12.3f %12.3f %12.3f %12.3f %12.3f %12.3f %12.3f ",DAILY/1000.0,WEEKLY/1000.0,MONTHLY/1000.0,YEARLY/1000.0,NDAYS/1000.0,TOTAL/1000.0,PARTIAL/1000.0); bColOutput = TRUE; } else { fprintf(outfp, "\n%-26s = %12.3f kWh",_CECpar1,DAILY/1000.0); if (yCost > 0) fprintf(outfp, "\t(%s %11.3f)",sCostType,(DAILY/1000.0)*yCost); fprintf(outfp, "\n%-26s = %12.3f kWh",_CECpar2,WEEKLY/1000.0); if (yCost > 0) fprintf(outfp, "\t(%s %11.3f)",sCostType,(WEEKLY/1000.0)*yCost); fprintf(outfp, "\n%-26s = %12.3f kWh",_CECpar3,MONTHLY/1000.0); if (yCost > 0) fprintf(outfp, "\t(%s %11.3f)",sCostType,(MONTHLY/1000.0)*yCost); fprintf(outfp, "\n%-26s = %12.3f kWh",_CECpar4,YEARLY/1000.0); if (yCost > 0) fprintf(outfp, "\t(%s %11.3f)",sCostType,(YEARLY/1000.0)*yCost); // fprintf(outfp, "\n%3d %-22s = %12.3f kWh",yGetEnergyCen,_CECpar5,NDAYS/1000.0); fprintf(outfp, "\n%-26s = %12.3f kWh",Days,NDAYS/1000.0); if (yCost > 0) fprintf(outfp, "\t(%s %11.3f)",sCostType,(NDAYS/1000.0)*yCost); fprintf(outfp, "\n%-26s = %12.3f kWh",_CECpar6,TOTAL/1000.0); if (yCost > 0) fprintf(outfp, "\t(%s %11.3f)",sCostType,(TOTAL/1000.0)*yCost); fprintf(outfp, "\n%-26s = %12.3f kWh",_CECpar7,PARTIAL/1000.0); if (yCost > 0) fprintf(outfp, "\t(%s %11.3f)",sCostType,(PARTIAL/1000.0)*yCost); fprintf(outfp, "\n"); } return(0); } /*-------------------------------------------------------------------------- GetCECdata ----------------------------------------------------------------------------*/ float GetCECdata(int fdser, int yAddress, int opcode, int param, char description[], int yGetEnergyCen) { int nCnt; float paramValFloat; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opcode; /* set Measure request to the Energy opcode */ szSerBuffer[cParam1] = invFunc = param; if (yGetEnergyCen > 0) { szSerBuffer[cParam2] = HIBYTE((WORD)yGetEnergyCen); szSerBuffer[cParam3] = LOBYTE((WORD)yGetEnergyCen); } else { szSerBuffer[cParam2] = szSerBuffer[cParam3] = 0; } szSerBuffer[cParam4] = 0; szSerBuffer[cParam4End] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0 && TransState((int)szSerBuffer[aState],description,TRUE)) { paramValFloat = *szCvrtFloat(szSerBuffer); if (bVerbose) fprintf(stderr, "value %12.6f\n",paramValFloat); return(paramValFloat); } return(_ERROR_); } /*-------------------------------------------------------------------------- GetCE CMD 78 ----------------------------------------------------------------------------*/ int GetCE(int fdser, int yAddress) { long DAILY, WEEKLY, LAST7DAYS, MONTHLY, YEARLY, TOTAL, PARTIAL; if (bVerbose) fprintf(stderr, "\nAttempting to get Partial Energy value "); if ((PARTIAL = GetCEdata(fdser,yAddress,opGetCE,CEpar6,_opGetCE)) < 0) return(-1); if ((DAILY = GetCEdata(fdser,yAddress,opGetCE,CEpar0,_opGetCE)) < 0) return(-1); if ((WEEKLY = GetCEdata(fdser,yAddress,opGetCE,CEpar1,_opGetCE)) < 0) return(-1); LAST7DAYS = 0.0; /* do this for now since this has been dropped in the v2.3 Communications Protocol doc */ /* placeholder for the -c option (colums)for now */ if ((MONTHLY = GetCEdata(fdser,yAddress,opGetCE,CEpar3,_opGetCE)) < 0) return(-1); if ((YEARLY = GetCEdata(fdser,yAddress,opGetCE,CEpar4,_opGetCE)) < 0) return(-1); if ((TOTAL = GetCEdata(fdser,yAddress,opGetCE,CEpar5,_opGetCE)) < 0) return(-1); if (bColumns) { /* must continue to output LAST7DAYS as a placeholder even though the inverter(s) may no longer report it */ fprintf(outfp, "%11.3f %11.3f %11.3f %11.3f %11.3f %11.3f %11.3f ",DAILY/1000.0,WEEKLY/1000.0,LAST7DAYS/1000.0,MONTHLY/1000.0,YEARLY/1000.0,TOTAL/1000.0,PARTIAL/1000.0); bColOutput = TRUE; } else { fprintf(outfp, "\n%-26s = %11.3f kWh",_CEpar0,DAILY/1000.0); if (yCost > 0) fprintf(outfp, "\t(%s %10.3f)",sCostType,(DAILY/1000.0)*yCost); fprintf(outfp, "\n%-26s = %11.3f kWh",_CEpar1,WEEKLY/1000.0); if (yCost > 0) fprintf(outfp, "\t(%s %10.3f)",sCostType,(WEEKLY/1000.0)*yCost); fprintf(outfp, "\n%-26s = %11.3f kWh",_CEpar3,MONTHLY/1000.0); if (yCost > 0) fprintf(outfp, "\t(%s %10.3f)",sCostType,(MONTHLY/1000.0)*yCost); fprintf(outfp, "\n%-26s = %11.3f kWh",_CEpar4,YEARLY/1000.0); if (yCost > 0) fprintf(outfp, "\t(%s %10.3f)",sCostType,(YEARLY/1000.0)*yCost); fprintf(outfp, "\n%-26s = %11.3f kWh",_CEpar5,TOTAL/1000.0); if (yCost > 0) fprintf(outfp, "\t(%s %10.3f)",sCostType,(TOTAL/1000.0)*yCost); fprintf(outfp, "\n%-26s = %11.3f kWh",_CEpar6,PARTIAL/1000.0); if (yCost > 0) fprintf(outfp, "\t(%s %10.3f)",sCostType,(PARTIAL/1000.0)*yCost); fprintf(outfp, "\n"); } return(0); } /*-------------------------------------------------------------------------- GetCEdata ----------------------------------------------------------------------------*/ long GetCEdata(int fdser, int yAddress, int opcode, int param, char description[]) { int nCnt; unsigned long paramValLong; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opcode; /* set Measure request to the Energy opcode */ szSerBuffer[cParam1] = invFunc = param; if (yCentral < 0) szSerBuffer[cParam1End] = '\0'; else { szSerBuffer[cParam1] = yCentral; szSerBuffer[cParam2End] = '\0'; } nCnt = Communicate(fdser, yAddress); if (nCnt > 0 && TransState((int)szSerBuffer[aState],description,TRUE)) { paramValLong = szCvrtLong(szSerBuffer); if (bVerbose) fprintf(stderr, "value %12lu\n",(unsigned long)paramValLong); return((int)paramValLong); } return(-1); } /*-------------------------------------------------------------------------- GetDSP CMD 59 ----------------------------------------------------------------------------*/ int GetDSP(int fdser, int yAddress) { float GVR=0.0, GCR=0.0, GPR=0.0, GPRC=0.0, FRQ=0.0, INVeff=0.0, INVeffC=0.0, INVtemp=0.0, ENVtemp=0.0, PVpwr = 0.0; float STR1V=0.0, STR1C=0.0, STR2V=0.0, STR2C=0.0; STR1V = STR1C = STR2V = STR2C = -1.0; if ((FRQ = GetDSPdata(fdser,yAddress,opGetDSP,ToM4,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((GVR = GetDSPdata(fdser,yAddress,opGetDSP,ToM1,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((GCR = GetDSPdata(fdser,yAddress,opGetDSP,ToM2,_opGetDSP,TRUE)) < -1000000.0) return(-1); if ((GPR = GetDSPdata(fdser,yAddress,opGetDSP,ToM3,_opGetDSP,TRUE)) < -1000000.0) return(-1); if (yGetDSP == 0 || yGetDSP == 1) { if ((STR1V = GetDSPdata(fdser,yAddress,opGetDSP,ToM23,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((STR1C = GetDSPdata(fdser,yAddress,opGetDSP,ToM25,_opGetDSP,TRUE)) == _ERROR_) return(-1); } if (yCentral < 0 && (yGetDSP == 0 || yGetDSP == 2)) { if ((STR2V = GetDSPdata(fdser,yAddress,opGetDSP,ToM26,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((STR2C = GetDSPdata(fdser,yAddress,opGetDSP,ToM27,_opGetDSP,TRUE)) == _ERROR_) return(-1); } if (yCentral < 0) { if ((INVtemp = GetDSPdata(fdser,yAddress,opGetDSP,ToM21,_opGetDSP,TRUE)) < -100) return(-1); if ((ENVtemp = GetDSPdata(fdser,yAddress,opGetDSP,ToM22,_opGetDSP,TRUE)) < -100) return(-1); } if (bCalcGridPwr) GPRC = GVR * GCR; if (STR1V >= 0.0 && STR1C >= 0.0) PVpwr = STR1V*STR1C; if (STR2V >= 0.0 && STR2C >= 0.0) PVpwr += STR2V*STR2C; if (PVpwr > 0) { INVeff = (GPR/PVpwr)*100; INVeffC = (GPRC/PVpwr)*100; } if (bColumns) { if (yGetDSP == 0 || yGetDSP == 1) fprintf(outfp, "%13.6f %13.6f %13.6f ",STR1V,STR1C,STR1V*STR1C); else fprintf(outfp, "%11s %11s %11s ","n/a","n/a","n/a"); if (yGetDSP == 0 || yGetDSP == 2) fprintf(outfp, "%13.6f %13.6f %13.6f ",STR2V,STR2C,STR2V*STR2C); else fprintf(outfp, "%11s %11s %11s ","n/a","n/a","n/a"); fprintf(outfp, "%13.6f %13.6f %13.6f %13.6f ",GVR,GCR,GPR,FRQ); if (yGetDSP == 0 || INVeff < 101.0) if (INVeff >= 0.0) fprintf(outfp, "%13.6f ",INVeff); else fprintf(outfp, "%13.6f ",0.0); else fprintf(outfp, "%11s ","OverRange"); fprintf(outfp, "%13.6f %13.6f ",INVtemp,ENVtemp); bColOutput = TRUE; } else { if (yGetDSP == 0 || yGetDSP == 1) { fprintf(outfp, "\n%-27s = %13.6f V\n",_ToM23,STR1V); fprintf(outfp, "%-27s = %13.6f A\n",_ToM25,STR1C); fprintf(outfp, "%-27s = %13.6f W\n",_Str1P,STR1V*STR1C); } else { fprintf(outfp, "\n%-27s = %11s V\n",_ToM23,"n/a"); fprintf(outfp, "%-27s = %11s A\n",_ToM25,"n/a"); fprintf(outfp, "%-27s = %11s W\n",_Str1P,"n/a"); } if (yCentral < 0) { if (yGetDSP == 0 || yGetDSP == 2) { fprintf(outfp, "\n%-27s = %13.6f V\n",_ToM26,STR2V); fprintf(outfp, "%-27s = %13.6f A\n",_ToM27,STR2C); fprintf(outfp, "%-27s = %13.6f W\n",_Str2P,STR2V*STR2C); } else { fprintf(outfp, "\n%-27s = %11s V\n",_ToM26,"n/a"); fprintf(outfp, "%-27s = %11s A\n",_ToM27,"n/a"); fprintf(outfp, "%-27s = %11s W\n",_Str2P,"n/a"); } } fprintf(outfp, "\n%-27s = %13.6f V\n",_ToM1,GVR); fprintf(outfp, "%-27s = %13.6f A\n",_ToM2,GCR); fprintf(outfp, "%-27s = %13.6f W\n",_ToM3,GPR); if (bCalcGridPwr) fprintf(outfp, "%-27s = %13.6f W\n",_ToM3C,GPRC); fprintf(outfp, "%-27s = %13.6f Hz.\n",_ToM4,FRQ); if (yGetDSP == 0 || INVeff < 101.0) if (INVeff >= 0.0) fprintf(outfp, "\n%-27s = %13.1f %s",_DcAcEff,INVeff,"%"); else fprintf(outfp, "\n%-27s = %13.1f %s",_DcAcEff,0.0,"%"); else fprintf(outfp, "\n%-27s = %13s ",_DcAcEff,"over range"); if (bCalcGridPwr) { if (yGetDSP == 0 || INVeffC < 101.0) fprintf(outfp, " (Using Grid Power Reading)\n%-27s = %13.1f %s (Using Grid Power Calculated)",_DcAcEff,INVeffC,"%"); else fprintf(outfp, " (Using Grid Power Reading)\n%-27s = %13s (Using Grid Power Calculated)",_DcAcEff,"over range"); } fprintf(outfp, "\n%-27s = %13.6f C\n",_ToM21,INVtemp); fprintf(outfp, "%-27s = %13.6f C\n",_ToM22,ENVtemp); } return(0); } void PrintBuffer() { int i; for (i = 0; i < cSIZE; i++) { fprintf(stderr, "%02x ",(unsigned char)szSerBuffer[i]); } fprintf(stderr, "\n"); } /*-------------------------------------------------------------------------- GetDSPExtended ----------------------------------------------------------------------------*/ int GetDSPExtended(int fdser, int yAddress) { float VB,ILD,ILI,P1,P2,GV,GF,IR,VBD,AGV,VBM,PP,PPT,GVn,WGF,VBp,VBm,ST,AT,HT,T1,T2,T3,F1,F2,F3,F4,F5,PSL,RRB,VPm; char note[3]; VB = ILD = ILI = P1 = P2 = GV = GF = IR = VBD = AGV = VBM = PP = PPT = GVn = WGF = 0.0; VBp = VBm = ST = AT = HT = T1 = T2 = T3 = F1 = F2 = F3 = F4 = F5 = PSL = RRB = VPm = 0.0; if ((VB = GetDSPdata(fdser,yAddress,opGetDSP,ToM5,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((IR = GetDSPdata(fdser,yAddress,opGetDSP,ToM30,_opGetDSP,FALSE)) == _ERROR_) return(-1); if ((P1 = GetDSPdata(fdser,yAddress,opGetDSP,ToM8,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((PPT = GetDSPdata(fdser,yAddress,opGetDSP,ToM35,_opGetDSP,TRUE)) == _ERROR_) return(-1); if (yCentral < 0) { if ((ILD = GetDSPdata(fdser,yAddress,opGetDSP,ToM6,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((ILI = GetDSPdata(fdser,yAddress,opGetDSP,ToM7,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((P2 = GetDSPdata(fdser,yAddress,opGetDSP,ToM9,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((GV = GetDSPdata(fdser,yAddress,opGetDSP,ToM28,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((GF = GetDSPdata(fdser,yAddress,opGetDSP,ToM29,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((VBD = GetDSPdata(fdser,yAddress,opGetDSP,ToM31,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((AGV = GetDSPdata(fdser,yAddress,opGetDSP,ToM32,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((VBM = GetDSPdata(fdser,yAddress,opGetDSP,ToM33,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((PP = GetDSPdata(fdser,yAddress,opGetDSP,ToM34,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((GVn = GetDSPdata(fdser,yAddress,opGetDSP,ToM36,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((WGF = GetDSPdata(fdser,yAddress,opGetDSP,ToM37,_opGetDSP,TRUE)) == _ERROR_) return(-1); } else { if ((VBp = GetDSPdata(fdser,yAddress,opGetDSP,ToM45,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((VBm = GetDSPdata(fdser,yAddress,opGetDSP,ToM46,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((ST = GetDSPdata(fdser,yAddress,opGetDSP,ToM47,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((AT = GetDSPdata(fdser,yAddress,opGetDSP,ToM48,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((HT = GetDSPdata(fdser,yAddress,opGetDSP,ToM49,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((T1 = GetDSPdata(fdser,yAddress,opGetDSP,ToM50,_opGetDSP,FALSE)) == _ERROR_) return(-1); if ((T2 = GetDSPdata(fdser,yAddress,opGetDSP,ToM51,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((T3 = GetDSPdata(fdser,yAddress,opGetDSP,ToM52,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((F1 = GetDSPdata(fdser,yAddress,opGetDSP,ToM53,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((F2 = GetDSPdata(fdser,yAddress,opGetDSP,ToM54,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((F3 = GetDSPdata(fdser,yAddress,opGetDSP,ToM55,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((F4 = GetDSPdata(fdser,yAddress,opGetDSP,ToM56,_opGetDSP,FALSE)) == _ERROR_) return(-1); if ((F5 = GetDSPdata(fdser,yAddress,opGetDSP,ToM57,_opGetDSP,FALSE)) == _ERROR_) return(-1); if ((PSL = GetDSPdata(fdser,yAddress,opGetDSP,ToM58,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((RRB = GetDSPdata(fdser,yAddress,opGetDSP,ToM59,_opGetDSP,TRUE)) == _ERROR_) return(-1); if ((VPm = GetDSPdata(fdser,yAddress,opGetDSP,ToM60,_opGetDSP,TRUE)) == _ERROR_) return(-1); } note[0] = '\0'; if (bColumns) { // if (AGV == VBD) strcpy(note,"*\0"); fprintf(outfp, "%11.6f %11.6f%s %11.6f%s %11.6f%s %11.6f %11.6f %11.6f %11.6f %11.6f %11.6f%s %11.6f%s %11.6f %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f %11.6f %11.6f%s %11.6f%s %11.6f%s %11.6f%s ",VB,VBM,note,VBp,note,VBm,note,VBD,ILD,ILI,IR,GV,AGV,note,GVn,note,GF,PP,note,PPT,note,ST,note,AT,note,HT,note,T1,note,T2,note,T3,note,F1,note,F2,note,F3,note,F4,note,F5,note,P1,P2,PSL,note,RRB,note,VPm,note,WGF,note); bColOutput = TRUE; } else { fprintf(outfp, "\nExtended DSP Reporting\n"); fprintf(outfp, "%-31s = %11.6f V\n",_ToM5,VB); fprintf(outfp, "%-31s = %11.6f Mohm\n",_ToM30,IR); fprintf(outfp, "%-31s = %11.6f W %s\n",_ToM35,PPT,note); fprintf(outfp, "%-31s = %11.6f W\n",_ToM8,P1); if (yCentral < 0) { if (AGV == VBD) strcpy(note,"*\0"); fprintf(outfp, "%-31s = %11.6f W\n",_ToM9,P2); fprintf(outfp, "\n%-31s = %11.6f V %s\n",_ToM33,VBM,note); fprintf(outfp, "%-31s = %11.6f V\n",_ToM31,VBD); fprintf(outfp, "\n%-31s = %11.6f A\n",_ToM6,ILD); fprintf(outfp, "%-31s = %11.6f A\n",_ToM7,ILI); fprintf(outfp, "\n%-31s = %11.6f V\n",_ToM28,GV); fprintf(outfp, "%-31s = %11.6f V %s\n",_ToM32,AGV,note); fprintf(outfp, "%-31s = %11.6f V %s\n",_ToM36,GVn,note); fprintf(outfp, "%-31s = %11.6f Hz\n",_ToM29,GF); fprintf(outfp, "\n%-31s = %11.6f W %s\n",_ToM34,PP,note); fprintf(outfp, "%-31s = %11.6f Hz %s\n",_ToM37,WGF,note); if (AGV == VBD) fprintf(outfp, "(Note: * = May not be in this Inverter's firmware)\n"); } else { fprintf(outfp, "\n%-31s = %11.6f V %s\n",_ToM45,VBp,note); fprintf(outfp, "%-31s = %11.6f V %s\n",_ToM46,VBm,note); fprintf(outfp, "\n%-31s = %11.6f C %s\n",_ToM47,ST,note); fprintf(outfp, "%-31s = %11.6f C %s\n",_ToM48,AT,note); fprintf(outfp, "%-31s = %11.6f C %s\n",_ToM49,HT,note); fprintf(outfp, "%-31s = %11.6f C %s\n",_ToM50,T1,note); fprintf(outfp, "%-31s = %11.6f C %s\n",_ToM51,T2,note); fprintf(outfp, "%-31s = %11.6f C %s\n",_ToM52,T3,note); fprintf(outfp, "\n%-31s = %11.6f RPM%s\n",_ToM53,F1,note); fprintf(outfp, "%-31s = %11.6f RPM%s\n",_ToM54,F2,note); fprintf(outfp, "%-31s = %11.6f RPM%s\n",_ToM55,F3,note); fprintf(outfp, "%-31s = %11.6f RPM%s\n",_ToM56,F4,note); fprintf(outfp, "%-31s = %11.6f RPM%s\n",_ToM57,F5,note); fprintf(outfp, "\n%-31s = %11.6f W %s\n",_ToM58,PSL,note); fprintf(outfp, "%-31s = %11.6f V %s\n",_ToM59,RRB,note); fprintf(outfp, "%-31s = %11.6f V %s\n",_ToM60,VPm,note); } } return(0); } /*-------------------------------------------------------------------------- GetDSP3Phase ----------------------------------------------------------------------------*/ int GetDSP3Phase(int fdser, int yAddress) { float VBD,GVPn,GVPr,GVPs,GVPt,GCPr,GCPs,GCPt,FRQPr,FRQPs,FRQPt; BOOL GVPnImp = TRUE; char note[3]; VBD = GVPn = GVPr = GVPs = GVPt = GCPr = GCPs = GCPt = FRQPr = FRQPs = FRQPt = 0.0; if (yCentral < 0) { if ((VBD = GetDSPdata(fdser,yAddress,opGetDSP,ToM31,_opGetDSP,TRUE)) < 0) return(-1); } if ((GVPn = GetDSPdata(fdser,yAddress,opGetDSP,ToM38,_opGetDSP,FALSE)) < 0) return(-1); GVPnImp = ! CmdNotImp; if ((GVPr = GetDSPdata(fdser,yAddress,opGetDSP,ToM61,_opGetDSP,TRUE)) < 0) return(-1); if ((GVPs = GetDSPdata(fdser,yAddress,opGetDSP,ToM62,_opGetDSP,TRUE)) < 0) return(-1); if ((GVPt = GetDSPdata(fdser,yAddress,opGetDSP,ToM63,_opGetDSP,TRUE)) < 0) return(-1); if ((GCPr = GetDSPdata(fdser,yAddress,opGetDSP,ToM39,_opGetDSP,TRUE)) < 0) return(-1); if ((GCPs = GetDSPdata(fdser,yAddress,opGetDSP,ToM40,_opGetDSP,TRUE)) < 0) return(-1); if ((GCPt = GetDSPdata(fdser,yAddress,opGetDSP,ToM41,_opGetDSP,TRUE)) < 0) return(-1); if ((FRQPr = GetDSPdata(fdser,yAddress,opGetDSP,ToM42,_opGetDSP,TRUE)) < 0) return(-1); if ((FRQPs = GetDSPdata(fdser,yAddress,opGetDSP,ToM43,_opGetDSP,TRUE)) < 0) return(-1); if ((FRQPt = GetDSPdata(fdser,yAddress,opGetDSP,ToM44,_opGetDSP,TRUE)) < 0) return(-1); note[0] = '\0'; if (bColumns) { if (yCentral < 0 && GVPn == VBD) strcpy(note,"*\0"); fprintf(outfp, "%11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s %11.6f%s ",GVPn,note,GVPr,note,GVPs,note,GVPt,note,GCPr,note,GCPs,note,GCPt,note,FRQPr,note,FRQPs,note,FRQPt,note); bColOutput = TRUE; } else { if (yCentral < 0 && GVPn == VBD) strcpy(note," *\0"); fprintf(outfp, "\n3-Phase DSP Reporting\n"); if (GVPnImp) fprintf(outfp, "%-26s = %11.6f V %s\n",_ToM38,GVPn,note); fprintf(outfp, "%-26s = %11.6f V %s\n",_ToM61,GVPr,note); fprintf(outfp, "%-26s = %11.6f V %s\n",_ToM62,GVPs,note); fprintf(outfp, "%-26s = %11.6f V %s\n",_ToM63,GVPt,note); fprintf(outfp, "\n%-26s = %11.6f A %s\n",_ToM39,GCPr,note); fprintf(outfp, "%-26s = %11.6f A %s\n",_ToM40,GCPs,note); fprintf(outfp, "%-26s = %11.6f A %s\n",_ToM41,GCPt,note); fprintf(outfp, "\n%-26s = %11.6f Hz%s\n",_ToM42,FRQPr,note); fprintf(outfp, "%-26s = %11.6f Hz%s\n",_ToM43,FRQPs,note); fprintf(outfp, "%-26s = %11.6f Hz%s\n",_ToM44,FRQPt,note); if (yCentral < 0 && GVPn == VBD) fprintf(outfp, "(Note: * = May not be in this Inverter's firmware)\n"); } return(0); } /*-------------------------------------------------------------------------- GetDSPdata ----------------------------------------------------------------------------*/ float GetDSPdata(int fdser, int yAddress, int opcode, int param, char description[], BOOL TScheck) { int nCnt; float paramValFloat = 0.0; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opcode; /* set Measure request to the DSP opcode */ szSerBuffer[cParam1] = invFunc = param; szSerBuffer[cParam1End] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0 && (! TScheck || TransState((int)szSerBuffer[aState],description,TScheck))) { if (! CmdNotImp) paramValFloat = *szCvrtFloat(szSerBuffer); if (bVerbose) fprintf(stderr, "value %12.6f\n",paramValFloat); return(paramValFloat); } return(_ERROR_); } /*-------------------------------------------------------------------------- GetJoules ----------------------------------------------------------------------------*/ int GetJoules(int fdser, int yAddress) { int nCnt; unsigned long Joules; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opGetEnergy10Sec; szSerBuffer[cCommandEnd] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0 && TransState((int)szSerBuffer[aState],_opGetEnergy10Sec,TRUE)) { Joules = szCvrtShort(szSerBuffer); if (bVerbose) fprintf(stderr, "Joules %12lu\n",(unsigned long)Joules); fprintf(outfp, "\nEnergy in the last 10 seconds (Joules) : %lu\n",(unsigned long)Joules); return(0); } return(-1); } /*-------------------------------------------------------------------------- GetInvTime ----------------------------------------------------------------------------*/ time_t GetInvTime(int fdser, int yAddress) { int nCnt = 0; time_t timeValLong = 0; long int gmtoff = 0; long int gmtoffTB = 0; struct tm tim; char curTime[24]; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /*clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /*set inverter address */ szSerBuffer[cCommand] = invOp = opGetTime; szSerBuffer[cCommandEnd] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0) { if (! TransState((int)szSerBuffer[aState],_opGetTime,TRUE)) return(-1); timeValLong = time(NULL); tim = *(localtime(&timeValLong)); gmtoff = getGMToffset(timeValLong); timeValLong = (time_t)TimeBase; tim = *(localtime(&timeValLong)); gmtoffTB = getGMToffset(timeValLong); if (bVerbose) { timeValLong = (time_t)TimeBase - gmtoffTB; fprintf(stderr, "\nTimeBase %12lu\n",(time_t)TimeBase); fprintf(stderr, "gmtoffTB %12li\n",gmtoffTB); tim = *(localtime(&timeValLong)); strftime(curTime,sizeof(curTime),"%d-%b-%Y %H:%M:%S",&tim); curTime[sizeof(curTime)-1] = '\0'; fprintf(stderr, "Base Inverter date/time: %s\n",curTime); } timeValLong = (time_t)szCvrtLong(szSerBuffer) & 0xffffffff; if (bVerbose) { fprintf(stderr, "timeValLong %12lu\n",(time_t)timeValLong); fprintf(stderr, "gmtoff %12li\n",gmtoff); } timeValLong += (time_t)TimeBase; timeValLong -= gmtoff; if (bVerbose) fprintf(stderr, "timeValLong %12lu\n",(time_t)timeValLong); } else { if (bVerbose) fprintf(stderr, "GetInvTime no response nCnt %i\n",nCnt); return(-1); } return(timeValLong); } /*-------------------------------------------------------------------------- GetTime ----------------------------------------------------------------------------*/ int GetTime(int fdser, int yAddress) { time_t timeValLong; struct tm tim; char curTime[24]; char fromInv[10] = "Inverter \0"; if (bGetInvTime) { if ((timeValLong = GetInvTime(fdser, yAddress)) < 0) return(-1); if (bVerbose) fprintf(stderr, "GetTime: timeValLong %12lu\n",(time_t)timeValLong); } if (bGetLocTime) { timeValLong = time(NULL); fromInv[0] = '\0'; } if (timeValLong != 0 || bGetLocTime) { tim = *(localtime(&timeValLong)); if (!bColumns || (yGetDSP < 0 && !bGetEnergy)) { fprintf(outfp, "Current %sdate/time: ",fromInv); strftime(curTime,sizeof(curTime),"%d-%b-%Y %H:%M:%S",&tim); if (bVerbose && !bGetLocTime) fprintf(stderr, "\n"); } else { strftime(curTime,sizeof(curTime),"%Y%m%d-%H:%M:%S",&tim); bColOutput = TRUE; } curTime[sizeof(curTime)-1] = '\0'; fprintf(outfp, "%s",curTime); return(0); } return(-1); } /*-------------------------------------------------------------------------- CheckSetTime Check if the time on the inverter differs fro the computers time and modify it as requested ----------------------------------------------------------------------------*/ int CheckSetTime(int fdser, int yAddress) { time_t timeValLongInv; time_t timeValLongCur; time_t timeValLongMN; struct tm TS; long int gmtoffCur = 0; long int gmtoffInv = 0; long int gmtoffMN = 0; char DateTime[24]; BOOL ChangeTime = FALSE; int rc = 0; if ((timeValLongInv = GetInvTime(fdser, yAddress)) < 0) return(-1); timeValLongCur = timeValLongMN = time(NULL); TS = *(localtime(&timeValLongCur)); gmtoffCur = getGMToffset(timeValLongCur); if (bVerbose) { fprintf(stderr, "\ntimeValLongCur %lu timeValLongInv %li diff %li\n",timeValLongCur,timeValLongInv,timeValLongInv-timeValLongCur); strftime(DateTime,sizeof(DateTime),"%d-%b-%Y %H:%M:%S",&TS); DateTime[sizeof(DateTime)-1] = '\0'; fprintf(stderr, "Current Time: %s gmtoff: %li\n",DateTime,gmtoffCur); TS = *(localtime(&timeValLongInv)); gmtoffInv = getGMToffset(timeValLongInv); strftime(DateTime,sizeof(DateTime),"%d-%b-%Y %H:%M:%S",&TS); fprintf(stderr, "Inverter Time: %s gmtoff: %li",DateTime,gmtoffInv); DateTime[sizeof(DateTime)-1] = '\0'; } if (yCheckSetTime == 0) { TS = *(localtime(&timeValLongMN)); TS.tm_sec = TS.tm_min = TS.tm_hour = 0; timeValLongMN = mktime(&TS); TS = *(localtime(&timeValLongMN)); gmtoffMN = getGMToffset(timeValLongMN); timeValLongMN += (gmtoffCur - gmtoffMN); TS = *(localtime(&timeValLongMN)); gmtoffMN = getGMToffset(timeValLongMN); if (gmtoffCur != gmtoffMN && abs(timeValLongCur-timeValLongInv) >= 900) ChangeTime = TRUE; if (bVerbose) { strftime(DateTime,sizeof(DateTime),"%d-%b-%Y %H:%M:%S",&TS); DateTime[sizeof(DateTime)-1] = '\0'; fprintf(stderr, "\nYesterday: %s gmtoff: %li",DateTime,gmtoffMN); } } else if (abs(timeValLongInv-timeValLongCur) >= yCheckSetTime) ChangeTime = TRUE; if (bVerbose) fprintf(stderr, " ChangeTime: %s\n",ChangeTime ? "TRUE" : "FALSE"); if (ChangeTime) rc = SetTime(fdser,yAddress,TRUE); return(rc); } /*-------------------------------------------------------------------------- SetTime ----------------------------------------------------------------------------*/ int SetTime(int fdser, int yAddress, BOOL force) { int nCnt = 0; int rc; int yTimeoutOrg; time_t timeValLong, timeValLongInv; struct tm tim; long int gmtoff = 0; char strTime[24]; char answer; if (bVerbose && force) fprintf(stderr, "Force setting time\n"); if (! force) { printf("\n**** WARNING ***** ***** WARNING ***** ***** WARNING ****\n"); printf("Setting the Date and Time has been known to clear all History\n"); printf(" Except \"Total Energy\" but no guarantees that it won't\n"); printf(" (May not be enabled on all models)\n"); printf("\nAre you sure your want to proceed? y/[n] : "); rc = scanf("%c", &answer); if (rc == EOF || (answer != 'y' && answer != 'Y')) return(1); } timeValLong = time(NULL); tim = *(localtime(&timeValLong)); gmtoff = getGMToffset(timeValLong); if (bVerbose) { fprintf(stderr, "\ntimeValLong %12lu\n",(time_t)timeValLong); strftime(strTime,sizeof(strTime),"%d-%b-%Y %H:%M:%S",&tim); strTime[sizeof(strTime)-1] = '\0'; fprintf(stderr, "setting time to %s DST %i\n",strTime,tim.tm_isdst); } /* adjust time to Aurora's time base */ timeValLong -= (long)TimeBase; timeValLong += gmtoff; /* adjust by 1 due to latency in setting the time */ timeValLong++; if (bVerbose) fprintf(stderr, "timeValLong %12lu\n",(time_t)timeValLong); invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opSetTime; szSerBuffer[cParam1] = (timeValLong >> 24) & 0xff; szSerBuffer[cParam2] = (timeValLong >> 16) & 0xff; szSerBuffer[cParam3] = (timeValLong >> 8) & 0xff; szSerBuffer[cParam4] = timeValLong & 0xff; szSerBuffer[cCommandEnd+4] = '\0'; yTimeoutOrg = yTimeout; if (yTimeout == 0) yTimeout = 1000; nCnt = Communicate(fdser, yAddress); yTimeout = yTimeoutOrg; if (nCnt > 0 && ! TransState((int)szSerBuffer[aState],_opSetTime,TRUE)) return(-1); if (nCnt <= 0 || bVerbose) { timeValLong = time(NULL); if ((timeValLongInv = GetInvTime(fdser, yAddress)) < 0) return(-1); tim = *(localtime(&timeValLong)); gmtoff = getGMToffset(timeValLong); if (bVerbose) { tim = *(localtime(&timeValLong)); strftime(strTime,sizeof(strTime),"%d-%b-%Y %H:%M:%S",&tim); strTime[sizeof(strTime)-1] = '\0'; fprintf(stderr, "\ntimeValLong %12lu\t%s\n",(time_t)timeValLong,strTime); tim = *(localtime(&timeValLongInv)); strftime(strTime,sizeof(strTime),"%d-%b-%Y %H:%M:%S",&tim); strTime[sizeof(strTime)-1] = '\0'; fprintf(stderr, "timeValLongInv %12lu\t%s\n",(time_t)timeValLongInv,strTime); } } if (nCnt > 0) { fprintf(stderr, "\nInverter date/time set (successful)\n"); return(0); } else { if (bVerbose) fprintf(stderr, "no response, comparing time\n"); if (abs(timeValLong - timeValLongInv) <= 2) { fprintf(stderr, "\nInverter date/time set (checked)\n"); return(0); } } return(-1); } /*-------------------------------------------------------------------------- GetCounters ----------------------------------------------------------------------------*/ int GetCounters(int fdser, int yAddress) { char TRT[18], PRT[18], TGC[18], RPC[18]; if ((yGetCount & 0x01) && GetCountersData(fdser, yAddress, cTotalRun, TRT) < 0) return(-1); if ((yGetCount & 0x02) && GetCountersData(fdser, yAddress, cPartialRun, PRT) < 0) return(-1); if ((yGetCount & 0x04) && GetCountersData(fdser, yAddress, cTotalGrid, TGC) < 0) return(-1); if ((yGetCount & 0x08) && GetCountersData(fdser, yAddress, cResetPartial, RPC) < 0) return(-1); fprintf(outfp, "\n%-34s %18s\n","","yyy ddd hh:mm:ss"); if (yGetCount & 0x01) fprintf(outfp, "%-34s : %18s\n",_cTotalRun,TRT); if (yGetCount & 0x02) fprintf(outfp, "%-34s : %18s\n",_cPartialRun,PRT); if (yGetCount & 0x04) fprintf(outfp, "%-34s : %18s\n",_cTotalGrid,TGC); if (yGetCount & 0x08) fprintf(outfp, "%-34s : %18s\n",_cResetPartial,RPC); return(0); } /*-------------------------------------------------------------------------- GetCountersData ----------------------------------------------------------------------------*/ int GetCountersData(int fdser, int yAddress, int param, char *uptime) { int nCnt; unsigned long paramValPtr, paramValLong; int years, days, hours, minutes, seconds; invFunc = -1; memcpy(szSerBuffer,_clearCMD,sizeof(szSerBuffer)); /* clear Aurora cmd string */ szSerBuffer[cAddress] = yAddress; /* set inverter address */ szSerBuffer[cCommand] = invOp = opGetCounters; /* set Measure request to the DSP opcode */ szSerBuffer[cParam1] = invFunc = param; szSerBuffer[cParam1End] = '\0'; nCnt = Communicate(fdser, yAddress); if (nCnt > 0 && TransState((int)szSerBuffer[aState],_opGetCounters,TRUE)) { paramValPtr = szCvrtLong(szSerBuffer); if (bVerbose) fprintf(stderr, "value %12lu\n",(unsigned long)paramValPtr); } else return(-1); paramValLong = (unsigned long)paramValPtr; if (bVerbose) fprintf(stderr, "paramValLong %12lu\n",(unsigned long)paramValLong); years = paramValLong / SecsInYear; paramValLong -= (years * SecsInYear); if (bVerbose) fprintf(stderr, "paramValLong %12li\tyears %3i\n",(unsigned long)paramValLong,years); days = paramValLong / SecsInDay; paramValLong -= (days * SecsInDay); if (bVerbose) fprintf(stderr, "paramValLong %12li\tdays %3i\n",(unsigned long)paramValLong,days); hours = paramValLong / SecsInHour; paramValLong -= (hours * SecsInHour); if (bVerbose) fprintf(stderr, "paramValLong %12li\thours %3i\n",(unsigned long)paramValLong,hours); minutes = paramValLong / SecsInMinute; paramValLong -= (minutes * SecsInMinute); if (bVerbose) fprintf(stderr, "paramValLong %12li\tminutes %3i\n",(unsigned long)paramValLong,minutes); seconds = paramValLong; if (bVerbose) fprintf(stderr, "paramValLong %12li\tseconds %3i\n",(unsigned long)paramValLong,seconds); sprintf(uptime,"%3d %3d %02d:%02d:%02d",years,days,hours,minutes,seconds); if (bVerbose) fprintf(stderr, "uptime: %s\n",uptime); return(0); } /*-------------------------------------------------------------------------- exceededRT ----------------------------------------------------------------------------*/ BOOL exceededRT() { time_t timeValue; if (yMaxRunTime > 0) { timeValue = time(NULL); if ((timeValue-startTimeValue) > yMaxRunTime) { fprintf(stderr, "\nMaximum %i second runtime exceeded (%luS)\n",yMaxRunTime,timeValue-startTimeValue); return(TRUE); } } return(FALSE); } /*-------------------------------------------------------------------------- Communicate ----------------------------------------------------------------------------*/ int Communicate(int fdser, int yAddress) { int i = 0; int nCnt; char szSerBufferSave[_szSerBufferLen]; int CRCrc = -1; int attempts = 1; struct timeval curtv; long long int curtvusecs = 0, lastcommtvusecs = 0, elapsedtvusecs = 0; if (exceededRT()) return(-1); memcpy(szSerBufferSave,_clearCMD,sizeof(szSerBufferSave)); memcpy(szSerBufferSave,szSerBuffer,_szSerBufferLen); gettimeofday(&curtv, NULL); while(CRCrc < 0 && attempts <= yMaxAttempts) { if (lastcommtv.tv_sec == 0 || lastcommtv.tv_usec == 0) { lastcommtv.tv_sec = curtv.tv_sec; lastcommtv.tv_usec = curtv.tv_usec; } else { curtvusecs = (curtv.tv_sec*1000000) + curtv.tv_usec; lastcommtvusecs = (lastcommtv.tv_sec*1000000) + lastcommtv.tv_usec; elapsedtvusecs = curtvusecs - lastcommtvusecs; } memcpy(szSerBuffer, szSerBufferSave,_szSerBufferLen); if (bVerbose) fprintf(stderr, "\nElapsed time since last comm %llu us\nAttempt %i",elapsedtvusecs,attempts); if (yCommPause > 0 && elapsedtvusecs < yCommPause) { if (bVerbose) fprintf(stderr, " Sleeping for %llu us",yCommPause-elapsedtvusecs); usleep(yCommPause-elapsedtvusecs); } if (bVerbose) fprintf(stderr, "\nClearing read buffer "); errno = 0; if (tcflush(fdser,TCIFLUSH)) fprintf(stderr, "- Problem clearing buffer: (%i)\n%s\n",errno,strerror (errno)); else if (bVerbose) fprintf(stderr, "Success!\n"); if (bVerbose) { fprintf(stderr, "szSerBufferSave "); if (strcmp(szSerBuffer,szSerBufferSave) == 0) fprintf(stderr, "OK! "); else fprintf(stderr, "ERROR! "); for (i = 0; i < cSIZE; i++) { fprintf(stderr, "%02x ",(unsigned char)szSerBufferSave[i]); } fprintf(stderr, "\n"); } crcValue = crc16(szSerBuffer, 8); szSerBuffer[cCRC_L] = LOBYTE(crcValue); szSerBuffer[cCRC_H] = HIBYTE(crcValue); szSerBuffer[cEND] = '\0'; if (bVerbose) { fprintf(stderr, "command: "); for (i = 0; i < cSIZE; i++) { fprintf(stderr, "%02x ",(unsigned char)szSerBuffer[i]); } fprintf(stderr, "\nFlushing serial device buffer... "); } errno = 0; if (tcflush(fdser,TCIOFLUSH)) fprintf(stderr, "Problem flushing before sending command: (%i) %s\n",errno,strerror (errno)); else if (bVerbose) fprintf(stderr, "Success!\nSending command... "); nCnt = write(fdser, &szSerBuffer, cSIZE); /* send it */ if (bVerbose) fprintf(stderr, "sent %d characters\nDraining serial device buffer... ", nCnt); errno = 0; if (tcdrain(fdser)) fprintf(stderr, "Problem draining command: (%i) %s\n",errno,strerror (errno)); else if (bVerbose) fprintf(stderr, "Success!\n"); memcpy(szSerBuffer, _clearCMD,sizeof(szSerBuffer)); if (bVerbose) { fprintf(stderr, "Cleared data buffer: "); for (i = 0; i < cSIZE; i++) { fprintf(stderr, "%02x ",(unsigned char)szSerBuffer[i]); } fprintf(stderr, "\n"); } tcflush(fdser,TCIFLUSH); if (yReadPause > 0) { if (bVerbose) fprintf(stderr, "Waiting %d milli-seconds before reading inverter response\n",yReadPause); else if (bRptReadPause) fprintf(stderr, "\n%s: %s: Waiting %d milli-seconds before reading inverter response",getCurTime(),ProgramName,yReadPause); usleep(yReadPause*1000); } nCnt = ReadToBuffer(fdser, szSerBuffer, aSIZE); if (bVerbose) { fprintf(stderr, "answer: "); if (nCnt > 0) { for (i = 0; i < nCnt; i++) { fprintf(stderr, "%02x ",(unsigned char)szSerBuffer[i]); } fprintf(stderr, "\nreceived %d characters\n", nCnt); } else fprintf(stderr, "Got %d characters\n", nCnt); } if (nCnt > 0) { crcValue = crc16(szSerBuffer, 6); if ((unsigned char)szSerBuffer[aCRC_L] != LOBYTE(crcValue) || (unsigned char)szSerBuffer[aCRC_H] != HIBYTE(crcValue)) { if (yMaxAttempts == 1 || attempts == yMaxAttempts) if (!bCommCheck) { if (! bVerbose && bRptReadPause) fprintf(stderr, "\n"); fprintf(stderr, "%s: CRC receive error (%i attempts made) %04x %02x %02x\n",getCurTime(),attempts,crcValue,(unsigned char)szSerBuffer[aCRC_H],(unsigned char)szSerBuffer[aCRC_L]); } } else { if (bVerbose) fprintf(stderr, "CRC receive OK %04x\n",crcValue); CRCrc = 0; } } gettimeofday(&curtv, NULL); lastcommtv.tv_sec = curtv.tv_sec; lastcommtv.tv_usec = curtv.tv_usec; attempts++; } if (CRCrc < 0) return(-1); if (bRptReties) { fprintf(stderr, "\n%s: %s: %i attempts made",getCurTime(),ProgramName,attempts-1); if (bVerbose) fprintf(stderr, "\n"); } else if (bRptReadPause) fprintf(stderr, "\n"); return(nCnt); } /*-------------------------------------------------------------------------- szCvrtFloat Converts a 4 char string to a float. ----------------------------------------------------------------------------*/ float *szCvrtFloat(char *Buffer) { unsigned char cValue[4]; float *value; if (! bSwapEndian) { cValue[0] = Buffer[aParam4]; cValue[1] = Buffer[aParam3]; cValue[2] = Buffer[aParam2]; cValue[3] = Buffer[aParam1]; } else { cValue[0] = Buffer[aParam1]; cValue[1] = Buffer[aParam2]; cValue[2] = Buffer[aParam3]; cValue[3] = Buffer[aParam4]; } value = (float *)cValue; if (bVerbose) fprintf(stderr, "szCvrtFloat %12.6f 0x%02x%02x%02x%02x\n",*value,cValue[3],cValue[2],cValue[1],cValue[0]); return(value); } /*-------------------------------------------------------------------------- szCvrtShort Converts a 2 char string to a short. ----------------------------------------------------------------------------*/ unsigned short szCvrtShort(char *Buffer) { unsigned char cValue[2]; unsigned short *value = 0; if (! bSwapEndian) { cValue[0] = Buffer[aParam2] & 0xff; cValue[1] = Buffer[aParam1] & 0xff; } else { cValue[0] = Buffer[aParam1] & 0xff; cValue[1] = Buffer[aParam2] & 0xff; } value = (unsigned short *)cValue; if (bVerbose) fprintf(stderr, "szCvrtShort %12u 0x%02x%02x\n",*value & 0xffff,cValue[1],cValue[0]); return(*value & 0xffff); } /*-------------------------------------------------------------------------- szCvrtLong Converts a 4 char string to a long. ----------------------------------------------------------------------------*/ unsigned long szCvrtLong(char *Buffer) { unsigned char cValue[4]; unsigned long *value = 0; if (! bSwapEndian) { cValue[0] = Buffer[aParam4] & 0xff; cValue[1] = Buffer[aParam3] & 0xff; cValue[2] = Buffer[aParam2] & 0xff; cValue[3] = Buffer[aParam1] & 0xff; } else { cValue[0] = Buffer[aParam1] & 0xff; cValue[1] = Buffer[aParam2] & 0xff; cValue[2] = Buffer[aParam3] & 0xff; cValue[3] = Buffer[aParam4] & 0xff; } value = (unsigned long *)cValue; if (bVerbose) fprintf(stderr, "szCvrtLong %12lu 0x%02x%02x%02x%02x\n",*value & 0xffffffff,cValue[3],cValue[2],cValue[1],cValue[0]); return(*value & 0xffffffff); } /*-------------------------------------------------------------------------- cvrtShort Converts a 2 char string to a short. ----------------------------------------------------------------------------*/ /* not used at this time unsigned short cvrtShort(char *Buffer) { unsigned char cValue[2]; unsigned short *value = 0; if (! bSwapEndian) { cValue[0] = Buffer[1] & 0xff; cValue[1] = Buffer[0] & 0xff; } else { cValue[0] = Buffer[0] & 0xff; cValue[1] = Buffer[1] & 0xff; } value = (unsigned short *)cValue; if (bVerbose) fprintf(stderr, "cvrtShort %12u 0x%02x%02x\n",*value & 0xffff,cValue[1],cValue[0]); return(*value & 0xffff); } */ /*-------------------------------------------------------------------------- cvrtLong Converts a 4 char string to a long. ----------------------------------------------------------------------------*/ unsigned long cvrtLong(char *Buffer) { unsigned char cValue[4]; unsigned long *value = 0; if (! bSwapEndian) { cValue[0] = Buffer[3] & 0xff; cValue[1] = Buffer[2] & 0xff; cValue[2] = Buffer[1] & 0xff; cValue[3] = Buffer[0] & 0xff; } else { cValue[0] = Buffer[0] & 0xff; cValue[1] = Buffer[1] & 0xff; cValue[2] = Buffer[2] & 0xff; cValue[3] = Buffer[3] & 0xff; } value = (unsigned long *)cValue; if (bVerbose) fprintf(stderr, "cvrtLong %12lu 0x%02x%02x%02x%02x\n",*value & 0xffffffff,cValue[3],cValue[2],cValue[1],cValue[0]); return(*value & 0xffffffff); } /*-------------------------------------------------------------------------- FindString Reads command line parameters. ----------------------------------------------------------------------------*/ char* FindString(WORD wRule, char *ptr) { while(wRule--) { /* walk thru the null terminators */ while(*ptr++) ; } return ptr; } /*-------------------------------------------------------------------------- ReadNextChar Reads the next character from the serial device. Returns zero if no character was available. ----------------------------------------------------------------------------*/ int ReadNextChar(int nfd, char *pChar, int timeout) { int nResult = -1; long int eUsecs, sSecs, cSecs, sUsecs, cUsecs; struct timeval tv; if (exceededRT()) return(-1); errno = 0; sUsecs = cUsecs = 0; eUsecs = sSecs = cSecs = sUsecs = cUsecs = 0; memset (pChar, 0, sizeof (*pChar)); eUsecs = 0; gettimeofday(&tv, NULL); sSecs = tv.tv_sec; sUsecs = tv.tv_usec; nResult = read(nfd, pChar, 1); gettimeofday(&tv, NULL); cSecs = tv.tv_sec; cUsecs = tv.tv_usec; eUsecs = ((cSecs-sSecs)*1000000) + (cUsecs-sUsecs); if (errno != 0) fprintf (stderr, "\naurora: (TO) Problem reading serial device, (nResult %i) (errno %i) %s.\n",nResult,errno,strerror (errno)); if (nResult == -1) { if (errno == 0) perror("\naurora: (TO) Problem reading serial device. \n"); RestorePort(nfd); ClrSerLock(PID); fprintf (stderr, "\n"); exit(2); } if (bVerbose) { fprintf(stderr, "RC=%i (%02x) ",nResult,(unsigned char)*pChar); if ((cUsecs-sUsecs) > 0) fprintf(stderr, "waited/max %8i/%-8i uS ",(int)eUsecs,(timeout*1000)+(yDelay*1000000)); } return nResult; } /*-------------------------------------------------------------------------- ReadToBuffer Reads data to a buffer until no more characters are available. If the buffer overflows, returns -1. Otherwise, returns the number of characters read. ----------------------------------------------------------------------------*/ int ReadToBuffer(int nfd, char *pszBuffer, int nBufSize) { int nPos = 0; /* current character position */ int attempts = 0; char *pBuf = pszBuffer; int rc = 0; int sanity = 0; while(nPos < nBufSize && sanity < MAX(1,yTimeout/100)) { if (bVerbose) { attempts++; fprintf(stderr, "Read char #%i ",nPos+1); } rc = ReadNextChar(nfd, pBuf, yTimeout); if (bVerbose && attempts > 1) fprintf(stderr, "attempts %i ",attempts); if (rc < 0) return nPos; /* no character available */ if (rc > 0) { pBuf++; nPos++; attempts = sanity = 0; } else sanity += MAX(1,yDelay); if (bVerbose) fprintf(stderr, "\n"); } if (nPos < nBufSize) return -1; /* problem */ return nPos; } /*-------------------------------------------------------------------------- crc16 16 12 5 this is the CCITT CRC 16 polynomial X + X + X + 1. This is 0x1021 when x is 2, but the way the algorithm works we use 0x8408 (the reverse of the bit pattern). The high bit is always assumed to be set, thus we only use 16 bits to represent the 17 bit value. ----------------------------------------------------------------------------*/ #define POLY 0x8408 /* 1021H bit reversed */ WORD crc16(char *data_p, unsigned short length) { unsigned char i; unsigned int data; unsigned int crc = 0xffff; if (length == 0) return (~crc); do { for (i=0, data=(unsigned int)0xff & *data_p++; i < 8; i++, data >>= 1) { if ((crc & 0x0001) ^ (data & 0x0001)) crc = (crc >> 1) ^ POLY; else crc >>= 1; } } while (--length); crc = ~crc; return (crc); } /*-------------------------------------------------------------------------- Delay Delays by the number of seconds and microseconds. ----------------------------------------------------------------------------*/ void Delay(int secs, long microsecs) { static struct timeval t1; t1.tv_sec = (long)secs; t1.tv_usec = microsecs; if ( select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t1) < 0 ) perror("Internal error: error in select()"); return; } aurora-1.8.8/PaxHeaders.21049/CRONTAB0000644000000000000000000000007411271162144013574 xustar0030 atime=1353288464.124557994 30 ctime=1412796558.489608955 aurora-1.8.8/CRONTAB0000775000000000001440000000066111271162144014230 0ustar00rootusers00000000000000 I use this cron command to collect data when the sun is out. It creates a new data file for each day based on the date. * 5-21 * * * /usr/local/bin/aurora -T -c -e -d -a 2 /dev/ttyS1 >> /data01/Solar/data/`date +\%Y\%m\%d`.dat 2>> /data01/Solar/logs/`date +\%Y\%m\%d`.err or * 5-21 * * * /usr/local/bin/aurora -T -c -e -d -a 2 -o /data01/Solar/data/`date +\%Y\%m\%d`.dat /dev/ttyS1 2>> /data01/Solar/logs/`date +\%Y\%m\%d`.err aurora-1.8.8/PaxHeaders.21049/docs0000644000000000000000000000007411347023067013440 xustar0030 atime=1353288464.157557995 30 ctime=1412796558.489608955 aurora-1.8.8/docs/0000775000000000001440000000000011347023067014143 5ustar00rootusers00000000000000aurora-1.8.8/docs/PaxHeaders.21049/man0000644000000000000000000000013112342123145014177 xustar0029 mtime=1401464421.00846575 30 atime=1353288464.157557995 30 ctime=1412796558.489608955 aurora-1.8.8/docs/man/0000775000000000001440000000000012342123145014710 5ustar00rootusers00000000000000aurora-1.8.8/docs/man/PaxHeaders.21049/aurora.10000644000000000000000000000013212342123144015627 xustar0030 mtime=1401464420.996465591 30 atime=1401464420.996465591 30 ctime=1412796558.489608955 aurora-1.8.8/docs/man/aurora.10000775000000000001440000001552112342123144016271 0ustar00rootusers00000000000000.TH aurora 1 "25 Mar 2014" aurora "aurora" .SH NAME \fBaurora\fP \- communicate with an Magnetek Aurora Photovoltaic (solar) Power Inverter .SH SYNOPSIS .BI "aurora [Options] -a InverterAddress Device" .SH "REQUIRED PARAMETERS" .TP .B -a , --address= Inverter address. 1-31 on older inverters, 1-63 on newer inverters. .TP .B Device Serial Device. Example, \fI/dev/ttyUSB0\fP or \fI/dev/ttyS0\fP. .SH OPTIONS .TP .B -A, --last-alarms Get last four alarms (once displayed FIFO queue is cleared) .TP .B -b, --verbose Verbose mode. For maximum effectiveness should be the first option on the command line .TP .B -C , --calc-value= Calculate monetary value using * kWh. ":$" is optional and if included the character(s) represented by the "$" will be used to denote monetary type in the output. Defaults to "$" .TP .B -c, --columnize Output data in columns --> for -d, -e, -D, -3, -E, -t options only, will disable all other options -- if value ends with an "*" reporting of that item may not be in inverters firmware .TP .B -d , --get-dsp= Get DSP data indicates string to get data for. 0 indicates both 1 for only string 1, 2 for only string 2. is required for short option and is optional for long option and if omitted for long option data for both input strings will be retrieved .TP .B -D, --get-dsp-extended Get more DSP data .TP .B -3, --get-dsp-3phase Get 3-Phase DSP data .TP .B -e, --get-energy Get Cumulated Energy readings (Excluding Central) .TP .B -E , --get-energy-central= Get Cumulated Float Energy readings (Central & TRIO only) days 1 to 366 Default 366 is required for short option and optional for long option .TP .B -f, --firmware-ver Query for Firmware Version string .TP .B -g, --mfg-date Query for Inverter Manufacturing Date .TP .B -h, --help This text .TP .B -i , --get-count= Display Inverter Time Counters is required for short option is optional for long option and if omitted for long option then all counters will be displayed and Partial counter will be reset .RS 1 = "Total Run Time" 4 = "Grid Connection Time" .RE .RS 2 = "Partial Run Time" 8 = "Reset Partial Run Time" .RE .TP .B -j, --get-joules Display Energy accumulated in the last 10 seconds .TP .B -K, --use-kmult= Adjust vaules reported by -k, --daily-kwh by "" multiplier .TP .B -k , --daily-kwh= Get past daily KWH for days (1-366) is optional for long option and if omitted all 366 days or as many that are found will be displayed. It is suggested that the -Y option be used with this due to the extensive length of time it takes to get all the data from the inverter .TP .B -L , --adjust-time= Automatically adjust the inverter time if it differs from the computer time. If is 0 (zero) do a Daylight Savings Time check. If is >= 1 change the inverter time if it differs by or more seconds. See the README for more information and the constraints this option uses to the determine if the time should be changed due to Daylight Savings Time .TP .B -l , --read-wait= Timeout for the read to the serial port. in 1/10ths seconds. Default is 1 (0.1 sec). See the README file for important information on this option .TP .B -M , --max-runtime= Maximum amount of time in seconds that aurora will run trying to get data from the inverter .TP .B -m, --get-conf Query for Inverter System Configuration .TP .B -n, --serial-number Query for Inverter Serial Number .TP .B -N , --central= ** Experimental ** Indicates Aurora Central 0 indicates Master, 1 indicates Slave .TP .B -o , --output-file= Append data to file (Created if nonexistant) Note: If -c option is used only -d, -e, -D, -3, -E, -t, & -T options will output to file .TP .B -O, --part-number-central Query for Inverter Part Number (Central only) .TP .B -p, --part-number Query for Inverter Part Number .TP .B -P , --comm-pause= Wait uS between sending commands to inverter (1-1000000) .TP .B -Q, --use-qmult Use inverter specific multiplier if known to adjust values reported by -q, --energy-sent .TP .B -q , --energy-sent= ** Experimental ** Get past energy delivered to the grid at 10 second intervals for minutes (1-1440) starting with the oldest data available. is optional for long option and if omitted all data, ~24 hours worth will be reported. It is suggested that the -Y option be used with this due to the extensive length of time it takes to get all the data from the inverter. See the README file for important information on this option .TP .B -R , --read-timeout= Serial port read retry timeout value when reading a character from the Inverter (mS - minimum 200) See the README file for important information on this option .TP .B -r, --calc-grid-power Calc Grid power using Grid Voltage * Grid Current, instead of reporting the Inverter's value. --> for -d option only, ignored when used with -c option. (Inverter typically reports a lower value. This affects Inverter conversion efficiency value.) .TP .B -S, --set-time Set Inverter Date/Time to system time .TP .B -s, --get-state Get Inverter State .TP .B -T, --get-loctime Display computer Date/Time .TP .B -t, --get-invtime Display Inverter Date/Time .TP .B -U , --read-pause= Pause milli-seconds after sending command to inverter before reading response from inverter (1-10000) .TP .B -u, --rpt-read-pause Report when/that pausing before read .TP .B -V, --version Aurora communications program version .TP .B -v, --inv-version Query for Version string .TP .B -W, --swap-endian Swap Endianness .TP .B -w , --lock-wait= Seconds to wait to lock serial port. (1-30) .TP .B -X, --rts-cts Enable RTS/CTS on the serial port. .TP .B -x, --xon-xoff Enable XON/XOFF on the serial port. .TP .B -Y , --retries= Retry failed communications with inverter up to times (1-100) .TP .B -y, --rpt-retries Report the number of retires done .SH DESCRIPTION \fBaurora\fP is a program that communicates with Aurora Magnetek Photovoltaic (solar) Power Inverters written by Curt Blank. It can retrieve data and statistics from a variety of Aurora Inverters through either USB or Serial interfaces. .SH EXAMPLES aurora -T -c -e -d 0 -a 2 -w 15 /dev/ttyS0 aurora -Y 100 -T -a 2 -w 10 -e /dev/ttyUSB0 .SH "SEE ALSO" .TP \fIhttp://www.curtronics.com/Solar/AuroraData.html\fP .PD .SH AUTHOR This manpage was initially written by Dustin Kirkland and is maintained by Curt Blank . Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 published by the Free Software Foundation. aurora-1.8.8/PaxHeaders.21049/LICENSE0000644000000000000000000000007410452061027013564 xustar0030 atime=1353288464.125557994 30 ctime=1412796558.489608955 aurora-1.8.8/LICENSE0000775000000000001440000000202710452061027014216 0ustar00rootusers00000000000000/* * aurora - Communications with Magnetek Aurora Inverter * * Copyright (C) 2006 Curtis J. Blank curt@cutronics.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program may be used and hosted free of charge by anyone for * personal purposes as long as this and all included copyright * notice(s) remain intact. * * Obtain permission before selling the code for this program or * hosting this software on a commercial website, excluding if it is * solely hosted for distribution, that is allowable . In all cases * copyright must remain intact. * * This work based on Magnetek's 'Aurora PV Inverter - Communications * Protocol -' document, Rel. 1.8 09/05/2005 * * Special thanks to Tron Melzl at Magnetek for all his help including, * but not limited to, supplying the Communications Protocol document * */ aurora-1.8.8/PaxHeaders.21049/main.c0000644000000000000000000000013212461565715013661 xustar0030 mtime=1422322637.397517079 30 atime=1411060085.398024356 30 ctime=1422322637.415518342 aurora-1.8.8/main.c0000775000000000001440000014341112461565715014323 0ustar00rootusers00000000000000/* * aurora - Communications with Magnetek Aurora Inverter * * Copyright (C) 2006-2015 Curtis J. Blank curt@curtronics.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program may be used and hosted free of charge by anyone for * personal purposes as long as this and all included copyright * notice(s) remain intact. * * Obtain permission before selling the code for this program or * hosting this software on a commercial website, excluding if it is * solely hosted for distribution, that is allowable . In all cases * copyright must remain intact. * * This work based on Magnetek's 'Aurora PV Inverter - Communications * Protocol -' document, Rel. 1.8 09/05/2005 * Starting with v1.5-0 this work based on Power One's 'Aurora Inverter * Series - Communication Protocol -' document, Rel. 4.6 25/02/09 * * Special thanks to Tron Melzl at Magnetek for all his help including, but * by no means limited to, supplying the Communications Protocol document * And another thanks to Jonathan Duddington on the other side of the pond * for his contribution of items he gathered while reverse engineering the * inverters communication some of which were incorporated beginning with * verison 1.7.8 * * modified 17-jul-2006 cjb 1. v1.2-6 Last 7 Days production value has been dropped * in the v2.3 Communications Protocol doc * modified 27-jul-2006 cjb 1. add bVerbose in ClrSerLock * modified 13-oct-2006 cjb 1. make this v1.3-0 * modified 25-apr-2007 cjb 1. take into account Daylight Savings Time when setting the Aurora's time * modified 29-dec-2008 cjb 1. correct an error in strftime that only may show up in the first or last * week of the year (%G vs %Y) * modified 19-aug-2009 cjb 1. fix determining if serial port is in use * modified 22-aug-2009 cjb 1. disable XON/XOFF flow control on output * modified 29-sep-2009 cjb 1. don't set lckCNT = -1 when clearing stale serial port lock * modified 12-oct-2009 cjb 1. add -o option to output data to a file * modified 25-oct-2009 cjb 1. serial port configuration tweaks * modified 17-oct-2010 cjb 1. added -x option to enable XON/XOFF * modified 07-mar-2010 cjb 1. added -Y retries option and -y option to report the number of attempt made * modified 13-mar-2010 cjb 1. added -P option to delay read after sending command to inverter * 2. rename -P to -U and add -u to report it * 3. changed -U seconds to wait to milli-seconds to wait * modified 28-mar-2010 cjb 1. working on adding more DSP information * modified 27-jul-2010 cjb 1. added -P option to throttle commands sent to the inverter * modified 21-sep-2010 cjb 1. added -A option to read "Last four alarms" * modified 22-jan-2011 cjb 1. added -k option to get up to a years worth of daily generation history * modified 19-mar-2011 cjb 1. added -X option to enable RTS/CTS on the serial port * modified 13-aug-2001 cjb 1. increase the allowed values from 31 to 63 for inverter address (-a) * as allowed in newer inverters * modified 22-aug-2011 cjb 1. clean up compile 'unused-but-set' messages * modified 05-nov-2011 cjb 1. remove size restriction on monetary identifier of the -C option * 2. added -q --energy-sent option * modified 09-nov-2011 cjb 1. added -L --adjust-time option * modified 13-nov-2011 cjb 1. if a bad return code is returned from any function display a * message before exiting (used to just exit silently) * 2. added -W option swap endian * modified 26-nov-2011 cjb 1. make sure the value passed to the -d option is numeric * modified 02-jan-2012 cjb 1. add bad return code tracking * modified 30-jan-2012 cjb 1. added -M option maximum amount of time in seconds that aurora will run * modified 18-feb-2012 cjb 1. changed --delay to --read-wait as the long option for -l so as to better * reflect it's function * modified 24-feb-2012 cjb 1. modify -i, --get-count option to accept a bitmask * modified 25-feb-2012 cjb 1. minor changes to help * modified 12-jun-2012 cjb 1. make sure errno is initialized * */ static char VersionM[] = "1.8.8"; char VersionC[7]; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "include/main.h" #include "include/comm.h" #include "include/names.h" BOOL bVerbose = FALSE; BOOL bColumns = FALSE; /* Output data in columns */ int yGetDSP = -1; /* Measure request to the DSP */ BOOL bGetDSPExtended = FALSE; /* Measure request to the DSP more parameters */ BOOL bGetDSP3Phase = FALSE; /* Measure request to the DSP three-phase parameter */ BOOL bHideDSP = FALSE; BOOL bGetEnergy = FALSE; /* Cumulated Energy Readings */ int yGetEnergyCen = -1; /* Cumulated Energy Readings Central & TRIO only */ BOOL bGetInvTime = FALSE; /* Display Inverter time flag */ BOOL bGetLocTime = FALSE; /* Display computer time flag */ BOOL bCommCheck = FALSE; BOOL bColOutput = FALSE; BOOL bCalcGridPwr = FALSE; BOOL bXonXoff = FALSE; BOOL bRTSCTS = FALSE; BOOL bRptReties = FALSE; BOOL bRptReadPause = FALSE; BOOL bSwapEndian = FALSE; BOOL bUseMultiplierQ = FALSE; float yMultiplierK = 1.0; int yTimeout = 0; /* read timeout value in us */ long unsigned int PID; int yMaxAttempts = 1; int yReadPause = 0; long int yCommPause = 0; unsigned char yDelay; /* Read wait time */ int yGetCount = 0; /* Get Time Counters */ time_t startTimeValue; int yCentral = -1; int yMaxRunTime = 0; /* max seconds aurora will run trying to get data from the inverter */ int yCheckSetTime = -1; /* Check the time on the inverter and if different then system time set it */ struct timeval lastcommtv; FILE *outfp; char VersionSHc[6]; float yCost = 0.0; char *sCostType = NULL; /* local Data */ static char VersionCHc[6] = VersionCH; static char VersionMHc[6] = VersionMH; static char VersionNHc[6] = VersionNH; static int yAddress = 0; /* Inverter address 1-63 */ static char *szttyDevice = NULL; static char *outfile = NULL; static BOOL bHelp = FALSE; /* Print the help text */ static BOOL bGetPN = FALSE; /* Get Inverter Part Number */ static BOOL bGetPNC = FALSE; /* Get Inverter Part Number (Central Only) */ static BOOL bGetVer = FALSE; /* Get version string */ static BOOL bGetVerFW = FALSE; /* Get firmware version string */ static BOOL bGetSN = FALSE; /* Get Serial Number */ static BOOL bGetMfg = FALSE; /* Get Manufacturing Date */ static BOOL bGetConf = FALSE; /* Get System Configuration */ static BOOL bGetState = FALSE; /* State request */ static BOOL bGetJoules = FALSE; /* Energy cumulated in the last 10 seconds */ static BOOL bSetTime = FALSE; /* Set time flag */ static BOOL bVersion = FALSE; /* Display program version */ static BOOL bGetTime; static BOOL bGetLastAlarms = FALSE; /* Get last four alarms */ static BOOL bFileError = FALSE; static int yGetEnergyDaily = 0; static int yGetEnergySent = 0; static int yLockWait = 0; /* Seconds to wait to lock serial port */ char *devLCKfile = NULL; char *devLCKfileNew = NULL; static struct termios oldtio; /* current serial device configuration */ /* local functions */ static int GetParms(int argc, char *argv[]); static void *getMemPtr(size_t mSize); static void Version(); /*-------------------------------------------------------------------------- getCurTime ----------------------------------------------------------------------------*/ char* getCurTime() { time_t curTimeValue; struct tm timStruct; static char CurTime[18] = " "; curTimeValue = time(NULL); timStruct = *(localtime(&curTimeValue)); strftime(CurTime,sizeof(CurTime),"%Y%m%d-%H:%M:%S",&timStruct); CurTime[sizeof(CurTime)-1] = '\0'; return CurTime; } /*-------------------------------------------------------------------------- main ----------------------------------------------------------------------------*/ int main(int argc, char *argv[]) { int fdser; /* serial device fd */ FILE *fdserlck = NULL; struct termios newtio; /* serial device configuration */ int rc = 0; struct tm timStruct; time_t endTimeValue; char RunTime[18] = " "; char EndTime[18] = " "; long unsigned int rPID; char sPID[10]; int bRead, bWrite, lckCNT; int errno_save = 0; int fLen = 0; char *cmdFile = NULL; char *command = NULL; char *SubStrPos = NULL; long L=1; void *Ptr=&L; char Endian=*(char*)Ptr; lastcommtv.tv_sec = 0; lastcommtv.tv_usec = 0; startTimeValue = time(NULL); timStruct = *(localtime(&startTimeValue)); strftime(RunTime,sizeof(RunTime),"%Y%m%d-%H:%M:%S",&timStruct); RunTime[sizeof(RunTime)-1] = '\0'; errno = 0; PID = getpid(); /* Get command line parms */ if ((!GetParms(argc, argv) && !bVersion) || bHelp) { printf("\nSee http://www.curtronics.com/Solar/ for Solar Site example\n\n"); printf("Usage: %s [Options] Device\t\t\tv%s\n\n",ProgramName,VersionM); printf("Options:\n"); printf(" -A, --last-alarms Get last four alarms (once displayed FIFO queue is cleared)\n"); printf(" -b, --verbose Verbose mode. For maximum effectiveness should be the first option\n"); printf(" on the command line\n"); printf(" -C, --calc-value= Calculate monetary value using * kWh. \":$\" is optional and if\n"); printf(" included the character(s) represented by the \"$\" will be used to\n"); printf(" denote monetary type in the output. Defaults to \"$\"\n"); printf(" -c, --columnize Output data in columns --> for -d, -e, -D, -3, -E, -t, & -T options\n"); printf(" only will disable any other options -- if value ends with an\n"); printf(" \"*\" reporting of that item may not be in inverters firmware\n"); printf(" -d , --get-dsp= Get DSP data indicates string to get data for. 0 indicates both\n"); printf(" 1 for only string 1, 2 for only string 2. is required for \n"); printf(" short option and is optional for long option and if omitted\n"); printf(" for long option data for both input strings will be retrieved\n"); printf(" -D, --get-dsp-extended Get more DSP data\n"); printf(" -3, --get-dsp-3phase Get 3-Phase DSP data\n"); printf(" -e, --get-energy Get Cumulated Energy readings (Excluding Central)\n"); printf(" -E , --get-energy-central= Get Cumulated Float Energy readings (Central & TRIO only) days\n"); printf(" 1 to 366 Default 366 is required for short option and optional\n"); printf(" for long option\n"); printf(" -f, --firmware-ver Query for Firmware Version string\n"); printf(" -g, --mfg-date Query for Inverter Manufacturing Date\n"); printf(" -h, --help This text\n"); printf(" -i, --get-count= Display Inverter Time Counters is required for short option\n"); printf(" is optional for long option and if omitted for long option then all\n"); printf(" counters will be displayed and Partial counter will be reset\n"); printf(" 1 = \"Total Run Time\" 4 = \"Grid Connection Time\"\n"); printf(" 2 = \"Partial Run Time\" 8 = \"Reset Partial Run Time\"\n"); printf(" -j, --get-joules Display Energy cumulated in the last 10 seconds\n"); printf(" -K, --use-kmult= Adjust vaules reported by -k, --daily-kwh by \"\" multiplier\n"); printf(" -k , --daily-kwh= Get past daily kWh for days (1-366)\n"); printf(" is required for short option and optional for long option\n"); printf(" and if omitted for long option then all 366 days or as many that\n"); printf(" are found will be displayed\n"); printf(" -L , --adjust-time= Automatically adjust the inverter time if it differs from the \n"); printf(" computer time. If is 0 (zero) do a Daylight Savings Time\n"); printf(" check. If is >= 1 change the inverter time if it differs\n"); printf(" by or more seconds. See the README for more information\n"); printf(" and constraints\n"); printf(" -l , --read-wait= Timeout for the read to the serial port. in 1/10ths seconds.\n"); printf(" Default is 1 (0.1 sec). See the README file for important\n"); printf(" information on this option\n"); printf(" -M , --max-runtime= Maximum amount of time in seconds that aurora will run trying to\n"); printf(" get data from the inverter\n"); printf(" -m, --get-conf Query for Inverter System Configuration\n"); printf(" -n, --serial-number Query for Inverter Serial Number\n"); printf(" -N , --central= Indicates Aurora Central ** Experimental **\n"); printf(" 0 indicates Master, 1 indicates Slave\n"); printf(" -o, --output-file= Append data to file (Created if nonexistant) Note: If -c option is\n"); printf(" used only -d, -e, -D, -3, -E, -t, & -T options will output to file\n"); printf(" -O, --part-number-central Query for Inverter Part Number (Central only)\n"); printf(" -p, --part-number Query for Inverter Part Number\n"); printf(" -P , --comm-pause= Wait us between sending commands to inverter (1-1000000)\n"); printf(" -Q, --use-qmult Use inverter specific multiplier if known to adjust values reported\n"); printf(" by -q, --energy-sent\n"); printf(" -q , --energy-sent= Get past energy delivered to the grid ** Experimental **\n"); printf(" in 10 second intervals for minutes (1-1440). is\n"); printf(" optional for long option and if omitted all data, ~24 hours\n"); printf(" worth will be reported. It is suggested the -Y option be used\n"); printf(" with this due to the extensive length of time this could take.\n"); printf(" See the README file for important information on this option\n"); printf(" -R , --read-timeout= Serial port read retry timeout value when reading a character from\n"); printf(" the Inverter (mS - minimum 200) See the README file for\n"); printf(" important information on this option\n"); printf(" -r, --calc-grid-power Calc Grid power using Grid Voltage * Grid Current, instead of\n"); printf(" reporting the Inverter's value. --> for -d option only,\n"); printf(" ignored when used with -c option (Inverter typically reports a\n"); printf(" lower value. This affects Inverter conversion efficiency value.)\n"); printf(" -S, --set-time Set Inverter Date/Time to system time\n"); printf(" -s, --get-state Get Inverter State\n"); printf(" -T, --get-loctime Display computer Date/Time\n"); printf(" -t, --get-invtime Display Inverter Date/Time\n"); printf(" -V, --version Aurora communications program version\n"); printf(" -v, --inv-version Query for Version string\n"); printf(" -U , --read-pause= Pause milli-seconds after sending command to inverter before\n"); printf(" reading response from inverter (1-10000)\n"); printf(" -u, --rpt-read-pause Report when/that pausing before read\n"); printf(" -W, --swap-endian Swap Endianness\n"); printf(" -w , --lock-wait= Seconds to wait to lock serial port. (1-30)\n"); printf(" -X, --rts-cts Enable RTS/CTS on the serial port.\n"); printf(" -x, --xon-xoff Enable XON/XOFF on the serial port.\n"); printf(" -Y , --retries= Retry failed communications with inverter up to times (1-100)\n"); printf(" -y, --rpt-retries Report the number of retires done\n\n"); printf(" *** Required Parameters ***\n"); printf(" -a , --address= Inverter address. 1-31 on older inverters, 1-63 on newer inverters.\n"); printf(" Device Serial Device.\n"); printf("\n"); if (bHelp) exit(0); else exit(2); } if (bVerbose) { fprintf(stderr, "\nRunTime %s v%-6s\nEndian : %s\ntm_gmtoff : ",RunTime,VersionM,Endian ? "Little" : "Big"); #ifdef NO_TM_GMTOFF fprintf(stderr, "no\n"); #else fprintf(stderr, "yes\n"); #endif } if (yCost > 0.0 && sCostType == NULL) { sCostType = getMemPtr(2); strcpy(sCostType,"$"); sCostType[1] = '\0'; if (bVerbose) fprintf (stderr, "Monetary type \"%s\"\n",sCostType); } if (bVerbose) fprintf (stderr, "PID : %lu\n", PID); if (bVersion) { Version(); exit(0); } if (bVerbose) fprintf(stderr, "\nAttempting to get lock on Serial Port %s...\n",szttyDevice); fdserlck = fopen((const char *)devLCKfile, "a"); if (fdserlck == NULL) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: Problem locking serial device, can't open lock file: %s for write.\n\n",getCurTime(),ProgramName,devLCKfile); exit(2); } bWrite = fprintf(fdserlck, "%lu\n", PID); errno_save = errno; fclose(fdserlck); fdserlck = NULL; if (bWrite < 0 || errno_save != 0) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: Problem locking serial device, can't write lock file: %s.\n%s\n\n",getCurTime(),ProgramName,devLCKfile,strerror (errno_save)); exit(2); } rPID = 0; lckCNT = -1; while(rPID != PID && lckCNT++ < yLockWait) { if (bVerbose && lckCNT == 0) fprintf(stderr, "Checking for lock\n"); SubStrPos = NULL; fdserlck = fopen(devLCKfile, "r"); if (fdserlck == NULL) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: Problem locking serial device, can't open lock file: %s for read.\n\n",getCurTime(),ProgramName,devLCKfile); exit(2); } bRead = fscanf(fdserlck, "%lu", &rPID); errno_save = errno; fclose(fdserlck); if (bVerbose) fprintf(stderr, "\nChecking process %lu for lock\n",rPID); fdserlck = NULL; if (bRead == EOF || errno_save != 0) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: Problem locking serial device, can't read lock file: %s.\n%s\n\n",getCurTime(),ProgramName,devLCKfile,strerror (errno_save)); exit(2); } sPID[0] = '\0'; sprintf(sPID,"%lu",rPID); cmdFile = getMemPtr(strlen(sPID)+14+1); cmdFile[0] = '\0'; sprintf(cmdFile,"/proc/%lu/cmdline",rPID); cmdFile[strlen(cmdFile)] = '\0'; fdserlck = fopen(cmdFile, "r"); if (fdserlck != NULL) { fLen = 0; while (fgetc(fdserlck) != EOF) fLen++; if (fLen > 0) { command = getMemPtr(fLen+1); command[0] = '\0'; rewind(fdserlck); bRead = fscanf(fdserlck, "%s", command); command[strlen(command)] = '\0'; } fclose(fdserlck); fdserlck = NULL; if (command != NULL) SubStrPos = strstr(command, ProgramName); } if (cmdFile != NULL) { free(cmdFile); cmdFile = NULL; } if (bVerbose) { fprintf (stderr, "rPID: %lu SubStrPos: %s command: %s",rPID,SubStrPos,command); if (rPID == PID) fprintf (stderr, " = me"); fprintf (stderr, "\n"); } if (command != NULL) { free(command); command = NULL; } if (rPID != PID) { if (SubStrPos == NULL) { if (bVerbose) fprintf (stderr, "\n"); fprintf(stderr, "%s: %s: Clearing stale serial port lock. (%lu)\n",getCurTime(),ProgramName,rPID); ClrSerLock(rPID); } else if (yLockWait > 0) sleep(1); } } if (bVerbose && rPID == PID) fprintf(stderr, "Appears we got the lock.\n"); if (rPID != PID) { ClrSerLock(PID); if (bVerbose) fprintf (stderr, "\n"); fprintf(stderr, "%s: %s: Problem locking serial device %s, couldn't get the lock for %lu, locked by %lu.\n\n",getCurTime(),ProgramName,szttyDevice,PID,rPID); exit(2); } if (bVerbose) fprintf(stderr, "\nOpening Serial Port %s... ", szttyDevice); fdser = open(szttyDevice, O_RDWR | O_NOCTTY ); if (fdser < 0) { ClrSerLock(PID); if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: Problem opening serial device, check device name.\n\n",getCurTime(),ProgramName); exit(2); } if (bVerbose) fprintf(stderr, "Serial Port %s successfully opened.\n", szttyDevice); tcgetattr(fdser, &oldtio); /* save previous port settings */ memset(&newtio, 0, sizeof(newtio)); newtio.c_cflag &= ~PARENB; /* no parity */ newtio.c_cflag &= ~CSTOPB; /* on stop bit */ newtio.c_cflag &= ~CSIZE; /* character size mask */ newtio.c_cflag &= ~HUPCL; /* no hangup */ if (bRTSCTS) newtio.c_cflag |= ~CRTSCTS; /* enable hardware flow control */ else newtio.c_cflag &= ~CRTSCTS; /* disable hardware flow control */ newtio.c_cflag |= CS8 | CLOCAL | CREAD; /* 8 bit - ignore modem control lines - enable receiver */ if (bXonXoff) newtio.c_iflag |= IXON | IXOFF; /* enable XON/XOFF flow control on output & input */ else { newtio.c_iflag &= ~IXON; /* disable XON/XOFF flow control on output */ newtio.c_iflag &= ~IXOFF; /* disable XON/XOFF flow control on input */ } newtio.c_iflag |= IGNBRK | IGNPAR; /* ignore BREAK condition on input & framing errors & parity errors */ newtio.c_oflag = 0; /* set serial device input mode (non-canonical, no echo,...) */ newtio.c_oflag &= ~OPOST; /* enable output processing */ newtio.c_lflag = 0; newtio.c_cc[VTIME] = yDelay; /* timeout in 1/10 sec intervals */ newtio.c_cc[VMIN] = 0; /* block until char or timeout */ if (cfsetospeed (&newtio, B19200)) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "\n%s: %s: Problem setting serial output speed.\n\n",getCurTime(),ProgramName); if (bVerbose) fprintf(stderr, "Closing Serial Port %s...",szttyDevice); if (close(fdser)) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: Problem closing serial device.\n",getCurTime(),ProgramName); } if (bVerbose) { fprintf(stderr, " Success!\n"); } ClrSerLock(PID); exit(2); } if (cfsetispeed (&newtio, B19200)) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "\n%s: %s: Problem setting serial input speed.\n\n",getCurTime(),ProgramName); if (bVerbose) fprintf(stderr, "Closing Serial Port %s...",szttyDevice); if (close(fdser)) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: Problem closing serial device.\n",getCurTime(),ProgramName); } if (bVerbose) { fprintf(stderr, " Success!\n"); } ClrSerLock(PID); exit(2); } if (bVerbose) { fprintf(stderr, "Configuring serial device... Flushing unread data first... "); } errno = 0; if (tcflush(fdser, TCIFLUSH)) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "\n%s: %s: Problem flushing serial device: (%i) %s\n\n",getCurTime(),ProgramName,errno,strerror(errno)); } if (tcsetattr(fdser, TCSANOW, &newtio)) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "\n%s: %s: Problem configuring serial device.\n\n",getCurTime(),ProgramName); if (bVerbose) fprintf(stderr, "Closing Serial Port %s...",szttyDevice); if (close(fdser)) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: Problem closing serial device.\n",getCurTime(),ProgramName); } if (bVerbose) { fprintf(stderr, " Success!\n"); } ClrSerLock(PID); exit(2); } if (bVerbose) { fprintf(stderr, " Success!\nFlushing serial device buffer..."); } errno = 0; if (tcflush(fdser, TCIOFLUSH)) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "\n%s: %s: Problem flushing serial device: (%i) %s\n\n",getCurTime(),ProgramName,errno,strerror(errno)); if (bVerbose) fprintf(stderr, "Closing Serial Port %s...",szttyDevice); if (close(fdser)) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: Problem closing serial device.\n",getCurTime(),ProgramName); } if (bVerbose) { fprintf(stderr, " Success!\n"); } ClrSerLock(PID); exit(2); } if (bVerbose) { fprintf(stderr, " Success!\n"); } bCommCheck = TRUE; if (bVerbose) { fprintf( stderr, "\nComm Check: Let's see if the Aurora is listening... "); } outfp = stderr; if (CommCheck(fdser,yAddress) >= 0) { if (bVerbose) fprintf(stderr, "Comm Check: OK\n"); } else { if (bVerbose) fprintf(stderr, "Comm Check: Failure, aborting...\n"); else { if (bRptReadPause) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: No response after %i attempts\n",getCurTime(),ProgramName,yMaxAttempts); } rc = -1; } bCommCheck = FALSE; if (rc == 0 && bSetTime) { rc = SetTime(fdser,yAddress,FALSE); } if (rc == 0 && yCheckSetTime >= 0) { rc = CheckSetTime(fdser,yAddress); } if (outfile != NULL) { if (! (outfp = fopen(outfile, "a"))) { fprintf(stderr, "%s: %s: Problem opening output file %s\n",getCurTime(),ProgramName,outfile); bFileError = TRUE; } } else { outfp = stdout; } if (! bFileError) { bGetTime = bGetInvTime | bGetLocTime; if (rc == 0 && bGetTime) { if (!bColumns && !bSetTime) fprintf(outfp, "\n"); rc |= GetTime(fdser,yAddress); if (!bColumns) fprintf(outfp, "\n"); } if (!bColumns) { if (rc == 0 && bGetPN) rc |= GetPN(fdser,yAddress); if (rc == 0 && bGetPNC) rc |= GetPNC(fdser,yAddress); if (rc == 0 && bGetSN) rc |= GetSN(fdser,yAddress); if (rc == 0 && bGetVerFW) rc |= GetVerFW(fdser,yAddress); if (rc == 0 && bGetMfg) rc |= GetMfgDate(fdser,yAddress); if (rc == 0 && bGetVer) rc |= GetVer(fdser,yAddress); if (rc == 0 && bGetConf) rc |= GetConf(fdser,yAddress); if (rc == 0 && bGetJoules) rc |= GetJoules(fdser,yAddress); if (rc == 0 && bGetState) rc |= GetState(fdser,yAddress); if (rc == 0 && yGetCount > 0) rc |= GetCounters(fdser,yAddress); if (rc == 0 && bGetLastAlarms) rc |= GetLastAlarms(fdser,yAddress); if (rc == 0 && yGetEnergyDaily > 0) rc |= GetCEDaily(fdser,yAddress,yGetEnergyDaily); if (rc == 0 && yGetEnergySent > 0) rc |= GetCESent(fdser,yAddress,yGetEnergySent); } if (rc == 0 && yGetDSP >= 0) rc |= GetDSP(fdser,yAddress); if (rc == 0 && bGetEnergy) rc |= GetCE(fdser,yAddress); if (rc == 0 && bGetDSPExtended) rc |= GetDSPExtended(fdser,yAddress); if (rc == 0 && bGetDSP3Phase) rc |= GetDSP3Phase(fdser,yAddress); if (rc == 0 && yGetEnergyCen >= 1) rc |= GetCEC(fdser,yAddress,yGetEnergyCen); } if (rc >= 0) { if (bColumns && bColOutput) fprintf(outfp, " OK\n"); else fprintf(outfp, "\n"); if (bVerbose) fprintf(stderr, "Complete.\n\n"); } else if (bColumns && bColOutput) fprintf(outfp, "\n"); if (bVerbose && rc >= 0) fprintf(stderr, "rc: %d\n\n",rc); if (outfile != NULL && ! bFileError) fclose(outfp); /* all done, exit */ RestorePort(fdser); ClrSerLock(PID); if (rc < 0) { if (bRptReties) fprintf(stderr, "\n"); if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: ERROR: Received bad return code (%i %i",getCurTime(),ProgramName,rc,invOp); if (invFunc > 0) fprintf(stderr, " %i)\n",invFunc); else fprintf(stderr, ")\n"); } endTimeValue = time(NULL); timStruct = *(localtime(&endTimeValue)); strftime(EndTime,sizeof(EndTime),"%Y%m%d-%H:%M:%S",&timStruct); EndTime[sizeof(EndTime)-1] = '\0'; if (bVerbose) fprintf(stderr, "\nComplete %s\n\n",EndTime); if (rc >= 0) exit(0); exit(1); } /*-------------------------------------------------------------------------- RestorePort Restore Serial Port Settings ----------------------------------------------------------------------------*/ int RestorePort(int fdser) { if (bVerbose) fprintf(stderr, "\nRestoring Serial Port settings %s...", szttyDevice); if (tcsetattr(fdser, TCSANOW, &oldtio)) { /* restore previous port settings */ if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: Problem restoring serial device settings.\n",getCurTime(),ProgramName); if (bVerbose) fprintf(stderr, "Closing Serial Port %s...",szttyDevice); if (close(fdser)) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: Problem closing serial device, check device name.\n",getCurTime(),ProgramName); } if (bVerbose) fprintf(stderr, " Success!\n"); return 2; } if (bVerbose) { fprintf(stderr, " Success!\nFlushing serial device buffer..."); } errno = 0; if (tcflush(fdser, TCIOFLUSH)) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "\n%s: %s: Problem flushing serial device: (%i) %s\n\n",getCurTime(),ProgramName,errno,strerror(errno)); if (bVerbose) fprintf(stderr, "Closing Serial Port %s...",szttyDevice); if (close(fdser)) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: Problem closing serial device.\n",getCurTime(),ProgramName); } if (bVerbose) { fprintf(stderr, " Success!\n"); } return 2; } if (bVerbose) fprintf(stderr, " Success!\nClosing Serial Port %s...", szttyDevice); if (close(fdser)) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "%s: %s: Problem closing serial device.\n",getCurTime(),ProgramName); return 2; } if (bVerbose) fprintf(stderr, " Success!\n"); return 0; } /*-------------------------------------------------------------------------- ClrSerLock Clear Serial Port lock. ----------------------------------------------------------------------------*/ int ClrSerLock(long unsigned int PID) { FILE *fdserlck, *fdserlcknew; long unsigned int rPID; int bWrite, bRead; int errno_save = 0; errno = 0; if (bVerbose) fprintf(stderr, "\ndevLCKfile: <%s>\ndevLCKfileNew: <%s>\nClearing Serial Port Lock (%lu)...", devLCKfile, devLCKfileNew, PID); fdserlck = fopen(devLCKfile, "r"); if (fdserlck == NULL) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "\n%s: %s: Problem opening serial device lock file to clear PID %lu: %s for read.\n\n",getCurTime(),ProgramName,PID,devLCKfile); return(0); } fdserlcknew = fopen(devLCKfileNew, "w"); if (fdserlcknew == NULL) { if (bVerbose) fprintf(stderr, "\n"); fprintf(stderr, "\n%s: %s: Problem opening new serial device lock file to clear PID %lu: %s for write.\n\n",getCurTime(),ProgramName,PID,devLCKfileNew); fclose(fdserlck); return(0); } bRead = fscanf(fdserlck, "%lu", &rPID); while (bRead != EOF) { if (rPID != PID) { errno = 0; bWrite = fprintf(fdserlcknew, "%lu\n", rPID); errno_save = errno; if (bWrite < 0 || errno_save != 0) { fprintf(stderr, "\n%s: %s: Problem clearing serial device lock, can't write lock file: %s.\n%s\n\n",getCurTime(),ProgramName,devLCKfile,strerror (errno_save)); fclose(fdserlcknew); return(0); } } bRead = fscanf(fdserlck, "%lu", &rPID); } fclose(fdserlck); fclose(fdserlcknew); errno = 0; if (rename(devLCKfileNew,devLCKfile)) fprintf(stderr, "\n%s: %s: Problem clearing serial device lock, can't update lock file: %s.\n%s\n\n",getCurTime(),ProgramName,devLCKfile,strerror (errno)); if (bVerbose) fprintf(stderr, " done.\n"); return -1; } /*-------------------------------------------------------------------------- isNumeric ----------------------------------------------------------------------------*/ BOOL isNumeric(char *p) { int i; for (i = 0; i <= strlen(p); i++) if (p[i] != '\0' && ! isdigit(p[i])) return(FALSE); return(TRUE); } /*-------------------------------------------------------------------------- GetParms Reads command line parameters. ----------------------------------------------------------------------------*/ int GetParms(int argc, char *argv[]) { extern char *optarg; extern int optind, opterr, optopt; int c; int i = 0; BOOL b = FALSE; char *pos; char *SubStrPos = NULL; char sPID[10]; static char *Cost = NULL; if (strpbrk(VersionM,"abcdefghijklmnopqurtsuvwxyz") != NULL) fprintf(stderr, "\n**** THIS IS EXPERIMENTAL CODE %-6s ****\n",VersionM); if (strcmp(VersionM,VersionC) != 0) { fprintf(stderr, "\n**** MODULE VERSION MISMATCH ****\n"); fprintf(stderr, " Main module : %-6s\n",VersionM); fprintf(stderr, " Comm module : %-6s\n",VersionC); return 0; } while (! b && i < argc) if (strcmp(argv[i++],"-b") == 0) b = TRUE; if (b) { fprintf(stderr, "\n"); i = 0; while (i < argc) fprintf(stderr, "%s ",argv[i++]); fprintf(stderr, "\n"); } /* options descriptor */ static struct option longopts[] = { { "address", required_argument, 0, 'a' }, { "last-alarms", no_argument, 0, 'A' }, { "verbose", no_argument, 0, 'b' }, { "calc-value", required_argument, 0, 'C' }, { "columnize", no_argument, 0, 'c' }, { "get-dsp", optional_argument, 0, 'd' }, { "get-dsp-extended", no_argument, 0, 'D' }, { "get-dsp-3phase", no_argument, 0, '3' }, { "get-energy", no_argument, 0, 'e' }, { "get-energy-central", optional_argument, 0, 'E' }, { "firmware-ver", no_argument, 0, 'f' }, { "mfg-date", no_argument, 0, 'g' }, { "hide-dsp-msg", no_argument, 0, 'H' }, { "help", no_argument, 0, 'h' }, { "get-count", optional_argument, 0, 'i' }, { "get-joules", no_argument, 0, 'j' }, { "use-kmult", required_argument, 0, 'K' }, { "daily-kwh", optional_argument, 0, 'k' }, { "adjust-time", required_argument, 0, 'L' }, { "read-wait", required_argument, 0, 'l' }, { "max-runtime", required_argument, 0, 'M' }, { "get-conf", no_argument, 0, 'm' }, { "central", required_argument, 0, 'N' }, { "serial-number", no_argument, 0, 'n' }, { "part-number-central", no_argument, 0, 'O' }, { "output-file", required_argument, 0, 'o' }, { "part-number", no_argument, 0, 'p' }, { "comm-pause", required_argument, 0, 'P' }, { "use-qmult", no_argument, 0, 'Q' }, { "energy-sent", optional_argument, 0, 'q' }, { "read-timeout", required_argument, 0, 'R' }, { "calc-grid-power", no_argument, 0, 'r' }, { "set-time", no_argument, 0, 'S' }, { "get-state", no_argument, 0, 's' }, { "get-invtime", no_argument, 0, 't' }, { "get-loctime", no_argument, 0, 'T' }, { "version", no_argument, 0, 'V' }, { "inv-version", no_argument, 0, 'v' }, { "read-pause", required_argument, 0, 'U' }, { "rpt-read-pause", no_argument, 0, 'u' }, { "swap-endian", no_argument, 0, 'W' }, { "lock-wait", required_argument, 0, 'w' }, { "rts-cts", no_argument, 0, 'X' }, { "xon-xoff", no_argument, 0, 'x' }, { "retries", required_argument, 0, 'Y' }, { "rpt-retries", no_argument, 0, 'y' }, { NULL, 0, NULL, 0 } }; /* Set command line defaults */ yDelay = 1; if (argc == 1) return 0; /* no parms at all */ while ((c = getopt_long(argc, argv, "3a:AbC:cDd:E:efgHhi:jK:k:L:l:M:mN:nOo:P:pQq:R:rSsTtVvU:uWw:XxY:y", longopts, NULL )) != EOF) { switch (c) { case 'a': /* Inverter address */ yAddress = atoi(optarg); break; case 'A': bGetLastAlarms = TRUE; break; case 'b': bVerbose = TRUE; break; case 'C': SubStrPos = strstr(optarg, ":"); if (SubStrPos == NULL) yCost = atof(optarg); else { Cost = getMemPtr(SubStrPos-optarg); strncpy(Cost,optarg,SubStrPos-optarg); Cost[strlen(Cost)] = '\0'; yCost = atof(Cost); sCostType = getMemPtr(strlen(optarg)-(SubStrPos-optarg)); strcpy(sCostType,SubStrPos+1); sCostType[strlen(sCostType)] = '\0'; free(Cost); Cost = NULL; } if (bVerbose) fprintf(stderr, "\nCost: %f Type: \"%s\"\n",yCost,sCostType); break; case 'c': bColumns = TRUE; break; case 'd': if (optarg != NULL && ! isNumeric(optarg)) { fprintf(stderr, "\n%s: %s: -d value is not numeric, 0 to 2.\n",getCurTime(),ProgramName); return 0; } if (optarg == NULL) { yGetDSP = 0; } else { i = atoi(optarg); if (i < 0 || i > 2) { fprintf(stderr, "\n%s: %s: -d value out of range, 0 to 2.\n",getCurTime(),ProgramName); return 0; } yGetDSP = i; } break; case 'D': bGetDSPExtended = TRUE; break; case '3': bGetDSP3Phase = TRUE; break; case 'e': bGetEnergy = TRUE; break; case 'E': if (optarg != NULL && ! isNumeric(optarg)) { fprintf(stderr, "\n%s: %s: -d value is not numeric, 1 to 366.\n",getCurTime(),ProgramName); return 0; } if (optarg == NULL) { yGetDSP = 366; } else { i = atoi(optarg); if (i < 1 || i > 366) { fprintf(stderr, "\n%s: %s: -d value out of range, 1 to 366.\n",getCurTime(),ProgramName); return 0; } yGetEnergyCen = i; } break; case 'f': bGetVerFW = TRUE; break; case 'g': bGetMfg = TRUE; break; case 'H': bHideDSP = TRUE; break; case 'h': bHelp = TRUE; break; case 'i': if (optarg == NULL) { yGetCount = 0x0f; } else { i = atoi(optarg); if (i < 1 || i > 15) { fprintf(stderr, "\n%s: %s: -i value out of range, 1 (0x01) to 15 (0x0f).\n",getCurTime(),ProgramName); return 0; } yGetCount = i; } break; case 'j': bGetJoules = TRUE; break; case 'K': yMultiplierK = atof(optarg); if (yMultiplierK <= 0) { fprintf(stderr, "\n%s: %s: -K value out of range, > 0.\n",getCurTime(),ProgramName); return 0; } break; case 'k': /* Get ECC */ if (optarg == NULL) { yGetEnergyDaily = 366; } else { i = atoi(optarg); if (i < 1 || i > 366) { fprintf(stderr, "\n%s: %s: -k value out of range, 1 to 366.\n",getCurTime(),ProgramName); return 0; } yGetEnergyDaily = i; } break; case 'L': i = atoi(optarg); if (i < 0) { fprintf(stderr, "\n%s: %s: -L value out of range, 0 or >=1 0 = check for DST change >=1 = Reconcile with computer time\n",getCurTime(),ProgramName); return 0; } yCheckSetTime = i; break; case 'l': /* Get delay time */ i = atoi(optarg); if (i < 0 || i > 255) { fprintf(stderr, "\n%s: %s: -l Illegal read wait specified.\n",getCurTime(),ProgramName); return 0; } yDelay = (unsigned char)i; break; case 'M': i = atoi(optarg); if (i < 0) { fprintf(stderr, "\n%s: %s: -l Illegal max runtime specified.\n",getCurTime(),ProgramName); return 0; } yMaxRunTime = i; break; case 'm': bGetConf = TRUE; break; case 'n': bGetSN = TRUE; break; case 'N': i = atoi(optarg); if (i < 0 || i > 1) { fprintf(stderr, "\n%s: %s: -l Illegal Master/Slave specified.\n",getCurTime(),ProgramName); return 0; } yCentral = i; break; case 'O': bGetPNC = TRUE; break; case 'o': outfile = getMemPtr(strlen(optarg)+1); strcpy(outfile, optarg); outfile[strlen(outfile)] = '\0'; break; case 'p': bGetPN = TRUE; break; case 'P': yCommPause = atoi(optarg); if (yCommPause <= 0 || yCommPause > 1000000) { fprintf(stderr, "\n%s: %s: -P Comm Pause micro-seconds (%li) out of range, 1-1000000.\n",getCurTime(),ProgramName,yCommPause); return 0; } break; case 'Q': bUseMultiplierQ = TRUE; break; case 'q': /* Get Energy Sent */ if (optarg == NULL) { yGetEnergySent = 4320; } else { i = atoi(optarg); if (i < 1 || i > 1440) { fprintf(stderr, "\n%s: %s: -k value out of range, 1 to 1440.\n",getCurTime(),ProgramName); return 0; } yGetEnergySent = i*3; } break; case 'R': /* read timeout value in mS */ i = atoi(optarg); if (i < 200) { fprintf(stderr, "\n%s: %s: -R value out of range, minimum 200.\n",getCurTime(),ProgramName); return 0; } yTimeout = i; break; case 'r': bCalcGridPwr = TRUE; break; case 'S': bSetTime = TRUE; break; case 's': bGetState = TRUE; break; case 'T': bGetLocTime = TRUE; break; case 't': bGetInvTime = TRUE; break; case 'U': yReadPause = atoi(optarg); if (yReadPause < 1 || yReadPause > 10000) { fprintf(stderr, "\n%s: %s: -U Read Pause milli-seconds (%d) out of range, 1-10000.\n",getCurTime(),ProgramName,yReadPause); return 0; } break; case 'u': bRptReadPause = TRUE; break; case 'W': bSwapEndian = TRUE; break; case 'w': yLockWait = atoi(optarg); if (yLockWait < 1 || yLockWait > 30) { fprintf(stderr, "\n%s: %s: -w Lock Wait seconds (%d) out of range, 1-30.\n",getCurTime(),ProgramName,yLockWait); return 0; } break; case 'X': bRTSCTS = TRUE; break; case 'x': bXonXoff = TRUE; break; case 'Y': yMaxAttempts = atoi(optarg); if (yMaxAttempts < 1 || yMaxAttempts > 100) { fprintf(stderr, "\n%s: %s: -Y Retries (%d) out of range, 1-100.\n",getCurTime(),ProgramName,yMaxAttempts); return 0; } break; case 'y': bRptReties = TRUE; break; case 'V': bVersion = TRUE; break; case 'v': bGetVer = TRUE; break; case '?': /* user entered unknown option */ case ':': /* user entered option without required value */ return 0; default: break; } } if (optind < argc) { /* get serial device name */ szttyDevice = getMemPtr(strlen(argv[optind])+1); strcpy(szttyDevice, argv[optind]); szttyDevice[strlen(szttyDevice)] = '\0'; } else { if (!bVersion && ! bHelp) fprintf(stderr, "\n%s: %s: No serial device specified\n",getCurTime(),ProgramName); return 0; } pos = strrchr(szttyDevice, '/'); if (pos > 0) { pos++; devLCKfile = getMemPtr(strlen(ttyLCKloc)+(strlen(szttyDevice)-(pos-szttyDevice))+1); devLCKfile[0] = '\0'; strcpy(devLCKfile,ttyLCKloc); strcat(devLCKfile, pos); devLCKfile[strlen(devLCKfile)] = '\0'; sprintf(sPID,"%lu",PID); devLCKfileNew = getMemPtr(strlen(devLCKfile)+strlen(sPID)+2); /* dot & terminator */ devLCKfileNew[0] = '\0'; strcpy(devLCKfileNew,devLCKfile); sprintf(devLCKfileNew,"%s.%lu",devLCKfile,PID); devLCKfileNew[strlen(devLCKfileNew)] = '\0'; } else { devLCKfile = NULL; } if (bVerbose) { fprintf(stderr, "\nszttyDevice: %s\nyDelay: %i\nyTimeout %i mS\nyMaxRunTime ",szttyDevice,yDelay,yTimeout); yMaxRunTime ? fprintf(stderr, "%i S",yMaxRunTime) : fprintf(stderr, "~"); fprintf(stderr, "\ndevLCKfile: <%s>\ndevLCKfileNew: <%s>\n",devLCKfile,devLCKfileNew); } if (bSetTime && yCheckSetTime >= 0) { fprintf(stderr, "\n%s: %s: -L and -S are mutually exclusive.\n",getCurTime(),ProgramName); return 0; } if (yAddress < 1 || yAddress > 63) { fprintf(stderr, "\n%s: %s: Illegal address (%d) specified.\n",getCurTime(),ProgramName,yAddress); return 0; } if (bVerbose) fprintf(stderr, "Got Params\n"); return -1; } /*-------------------------------------------------------------------------- getMemPtr ----------------------------------------------------------------------------*/ void *getMemPtr(size_t mSize) { void *ptr; char *cptr; int i; ptr = malloc(mSize); if (!ptr) { fprintf(stderr, "\nvproweather: malloc failed\n"); exit(2); } cptr = (char *)ptr; for (i = 0; i < mSize; i++) cptr[i] = '\0'; return ptr; } /*-------------------------------------------------------------------------- Version Display program component versions ----------------------------------------------------------------------------*/ void Version() { printf("\nAurora module versions:\n"); printf("Main module : %-6s\n",VersionM); printf("Comm module : %-6s\n",VersionC); printf("main.h : %-6s\n",VersionMHc); printf("comm.h : %-6s\n",VersionCHc); printf("names.h : %-6s\n",VersionNHc); printf("states.h : %-6s\n\n",VersionSHc); } aurora-1.8.8/PaxHeaders.21049/Makefile0000644000000000000000000000013212242011706014210 xustar0030 mtime=1384649670.307376636 30 atime=1384649670.307376636 30 ctime=1412796558.489608955 aurora-1.8.8/Makefile0000775000000000001440000000660012242011706014650 0ustar00rootusers00000000000000# uncomment and/or set to match processor # ** ONLY IF ** automatic determination of these compile flags is # not working properly. uncommenting these variables will override # automatic determination of them #ARCH = native #TUNE = native CC = gcc CFLAGS = -O2 -Wall -I/usr/include -I./include OFILES = main.o comm.o INSTALLSITEMAN1DIR = ${mandir}/man1 DISTMAN1DIR = docs/man bindir = ${exec_prefix}/bin datarootdir = ${prefix}/share exec_prefix = ${prefix} mandir = ${datarootdir}/man prefix = /usr/local BIT := $(shell getconf LONG_BIT) BIT64 = -Dbit$(BIT) CFLAGS += $(BIT64) GCCVER = $(shell expr `gcc -dumpversion` \>= 4.2) GFLAGS1 = $(shell echo 'int main(){return 0;}' > /tmp/test-arch-tune.c && gcc -v -Q -march=native -O2 /tmp/test-arch-tune.c -o /tmp/test-arch-tune 2>&1 | sed -e 's/[\(|\)]//g' | grep march && rm /tmp/test-arch-tune*) GNONATIVE = $(shell echo ${GFLAGS1} | grep -e "error" -e "bad value native" | awk '{for (i =1; i <= NF; i++) print $$i}' | grep -e "bad" -e "error") GGMTOFF = $(shell echo '\#include ' > /tmp/test-arch-tune.c && echo 'int main(){long int g;struct tm t;g = t.tm_gmtoff;return (g);}' >> /tmp/test-arch-tune.c && gcc -march=native -O2 /tmp/test-arch-tune.c -o /tmp/test-arch-tune 2>&1 && rm /tmp/test-arch-tune*) ifeq "$(strip $(GNONATIVE))" "" GFLAGS = $(shell echo ${GFLAGS1} | awk '{for (i =1; i <= NF; i++) print $$i}' | grep -e "^-march=" -e "^-mtune=" | sort -u) endif ifdef GFLAGS ifndef ARCH GARCH1 = $(shell echo ${GFLAGS} | awk '{for (i =1; i <= NF; i++) print $$i}' | grep -e "^-march=" | sed -e 's/-march=//') GARCH = $(shell echo ${GARCH1} | sed -e 's/ native//' -e 's/native //') endif ifndef TUNE GTUNE1 = $(shell echo ${GFLAGS} | awk '{for (i =1; i <= NF; i++) print $$i}' | grep -e "^-mtune=" | sed -e 's/-mtune=//') GTUNE = $(shell echo ${GTUNE1} | sed -e 's/ native//' -e 's/native //') endif endif ifndef ARCH ifdef GARCH ARCH = ${GARCH} else ifeq ($(GCCVER),1) ifeq "$(strip $(GNONATIVE))" "" ARCH = native endif endif endif endif ifndef TUNE ifdef GTUNE TUNE = ${GTUNE} else ifeq ($(GCCVER),1) ifneq "$(strip $(GNONATIVE))" "" TUNE = native endif endif endif endif ifneq "$(strip $(GNONATIVE))" "" ifeq ($(ARCH),native) ARCH = endif ifeq ($(TUNE),native) TUNE = endif endif ifneq "$(strip $(GGMTOFF))" "" CFLAGS += -DNO_TM_GMTOFF endif ifneq "$(strip $(ARCH))" "" ARCH2 = $(shell echo ${ARCH} | awk '{for (i =1; i <= NF; i++) print "-march="$$i}') CFLAGS += $(ARCH2) endif ifneq "$(strip $(TUNE))" "" TUNE2 = $(shell echo ${TUNE} | awk '{for (i =1; i <= NF; i++) print "-mtune="$$i}') CFLAGS += $(TUNE2) endif TARGET = aurora .PHONY: install all: $(TARGET) $(TARGET): check $(OFILES) $(CC) $(OFILES) -o $(TARGET) chmod 4711 $(TARGET) check: ifeq ($(BIT),64) @echo -n "Compiling for 64bit " else @echo -n "Compiling for 32bit " endif ifneq "$(strip $(GNONATIVE))" "" @echo -n "NoNative " endif ifdef ARCH @echo -n "$(ARCH) " endif ifdef TUNE ifneq ($(ARCH),$(TUNE)) @echo -n "$(TUNE) " endif endif @echo main.o: Makefile main.c include/main.h include/comm.h include/names.h include/states.h $(CC) $(CFLAGS) -c main.c comm.o: Makefile comm.c include/main.h include/comm.h include/names.h include/states.h $(CC) $(CFLAGS) -c comm.c clean: rm -f $(TARGET) *.o install: aurora install -m 4711 $(TARGET) $(bindir) install -m 0644 ${DISTMAN1DIR}/$(TARGET).1 ${INSTALLSITEMAN1DIR} uninstall: rm -f $(bindir)/$(TARGET) ${INSTALLSITEMAN1DIR}/$(TARGET).1 aurora-1.8.8/PaxHeaders.21049/RELEASENOTES0000644000000000000000000000013212461572417014402 xustar0030 mtime=1422325007.493463935 30 atime=1401638138.673520341 30 ctime=1422325007.509465064 aurora-1.8.8/RELEASENOTES0000775000000000001440000002374412461572417015052 0ustar00rootusers00000000000000NOTE!! This is kind of some early work to improve 3 phase reporting and include reporting for Central ind Trio nverters. There were some issues with floating point numbers not being converted correctly but last I heard they were correct without any changes made to aurora so I'm skeptical. It is possible it was due to the computer/architecture/OS that was being used and not an aurora issue. So PLEASE PLEASE if you are using aurora with a 3 phase or Central or Trio inverter and notice any anomalies with aurora do let me know. v1.8.8 - fixed negative values being reported in verbose mode v1.8.7 - ** NOTE ** -E, --get-dsp-3phase has changed to -3, --get-dsp-3phase - temperatures can be below zero i.e. negative (inverters installed outdoors) - NOTE: -e, --get-energy excludes Aurora Central - added -O , --central= ** Experimental ** Indicates Aurora Central (Work in process) - added -E , --get-energy-central= Get Cumulated Float Energy readings (Central & TRIO only) - correct reporting wrong model when -Q is not used - updated -v inverter version reporting - update COLUMNS.key file v1.8.6 - calculate tm_gmtoff if it is not supplied in tm structure - it was requested to just #ifdef it out but that could cause the -k, -q, -L, -S, & -t options to set/report dates/times incorrectly. make (Makefile) will determine whether to calculate it or use the tm structure v1.8.5 - NOTE: added -Q, --use-qmult option to use inverter specific Multiplier (if known) for -q, --energy-sent. These Multiplers were were added in version 1.7.8 and used by defualt. These Multipliers are no longer used by default so this option must be used if you want the Multiplier used. This Multiplier adjusts the values reported by -q, --energy-sent. - added -K, --use-kmult option to adjust vaules reported by -k, --daily-kwh by value supplied with option. Seems how the data is being stored may be different on different inverter models v1.8.3 - make sure errno is initialized - set the mask on the binary on make v1.8.0 - minor changes to help and man page - initialize some variables so as to avoid compiler warnings - check validity of time value returned by query to inverter to get its time - allow display of out of order dates for -k (--daily-kwh) if they appear to be valid this may then require the output be sorted - handle out of order dates for -k (--daily-kwh) by sorting them and suppressing duplicate entries for a date v1.7.9 - modify -i, --get-count option to accept a bitmask indicating which couters should be displayed and whether or not the Partial Energy counter should be reset to zero v1.7.8 - README updated - changed --delay to --read-wait as the long option for -l so as to better reflect it's function - --daily-kwh date started tomorrow instead of today, adjusted timebase - dynamically adjust timebase for --daily-kwh if it looks to be off - watch for out of order or duplicate dates in --daily-kwh - be more aggressive and at the same time patient trying to read characters from slow to respond inverters (READ! the README for the impacts this has) - added -M option maximum amount of time in seconds that aurora will run - updated list of models - use multiplier for --energy-sent if known for inverter model - revamp --daily-kwh after discovering data may not always be contiguous v1.7.7 - add bad return code tracking to identify operation - fix W not kW in all spots for --energy-sent. My bad. - timing issues again setting the inverter time waiting for inverter response. See README for more information. v1.7.6 - --energy-sent values are W not kW Doh! - Grid Current & Grid Power can now return negative values. This occurs when the PV panels are not providing enough power to run the inverter so it sucks some power from the Grid v1.7.5 - fix man page for -W - fixed some bad trailing characters showing up in date strings on MIPS platforms - -k will now also output to stdout when -b is used not just to stderr. This was by design while -k was considered experimental v1.7.4 - if a bad return code is returned from any function display a message to STDERR before exiting (used to just exit silently) - added -W option to swap endian for ARM and MIPS architectures - fixed -k, -n, & -p strings output that were overflowing on occasion - make sure the value passed to the -d option is numeric - removed ** Experimental ** status from -k, --daily-kwh see the README for more information - tweaked the new -q, --energy-sent option, make sure the last data value is reported when starting in the middle of a WORD value pair and had the same strings output issue as -k, -n, & -p on MIPS architectures - fixed a malloc corruption when trying to open the lock file v1.7.3 - changed permissions on the aurora executable to 4711 for none root users to be able to run aurora. Had it set to 4755 orginally but pulled it back to 4750, needs to be at least 4711. - added -L --adjust-time option. See the README for information regarding this option v1.7.2 - added -q --energy-sent option, see the README for important information regarding this option - remove size restriction on monetary identifier of the -C option - changed permissions on the aurora executable to 4750. This allows users other then root to run aurora and not fail due to inaccessibility of the lock file when reading/writing it - remove size restriction on various strings - checked the TimeBase now that we're back on CST and it checks out correctly. Timezone calculations work. Can remove it from the TODO list v1.7.1 - modify "-d --get-dsp" option. **NOTE** if using "-d" it must be changed to "-d 0", if using "--get-dsp" no change is needed - modify "-C, --calc-value=" added "[:$]" to allow monetary type to be chosen v1.7.0 - clean up some compiler warnings for variable set but not used v1.6.9 - Starting with version 1.6.9 the 'make' tries to determine the gcc 'march' & 'mtune' compile flags for optimization - corrected joule reading, output conversion error - Makefile modifications no longer have to modify the 64bit flag, may not have to modify "arch" & "tune" parameters if gcc >= 4.2 on AMD & Intel platforms - fixed a integer conversion issue for -k due to some architectures - fixed bizarreness with -bt - adjust TimeBase to true UTC-0000 and take into account timezone in GetTime (-t) and SetTime (-S) functions - added 'make check' that reports what the compile will be for architecture wise - tweaked Makefile to determine "arch" & "tune" using gcc if possible - tweaking Makefile for ARM processors - tweaked Makefile again for 'make' versions older then 3.82 which don't have the 'undefine' directive - increase the allowed values from 31 to 63 for inverter address (-a) as allowed in newer inverters v1.6.8 - added -k option to read past days production - this is considered experimental and may or may not work in all instances and especially if there is no data for all the days requested - please report any problems/anomalies encountered - removed -fpack-struct from the compiler CFLAGS - once again caused longopts not to work - added -X option to enable RTS/CTS on the serial port v1.6.7 - added -A option to read "Last four alarms" - fix using wrong param when displaying TransState message - pass TransState the command description so if it gets a non-zero status it can report for what command it got it v1.6.6 - added -P option to throttle commands sent to the inverter v1.6.2 - added -D & -E to report more DSP information v1.6.0 - added -U option to delay read after sending command to inverter and -u option to report it - version numbering now Number dot Number dot Number - manpage now included - 'make' now has 'install' and 'uninstall' options v1.5-7 - fix sizeof pointer passing in memset - add -Y retries option and -y option to report the number of attempts made and use in the Communicate function - in ReadNextChar restore serial port settings and clear lock if exiting v1.5-5 - added -x option to enable XON/XOFF v1.5-1 - serial port configuration tweaks v1.5-0 - Starting with v1.5-0 this work based on Power One's 'Aurora Inverter Series - Communication Protocol -' document, Rel. 4.6 25/02/09 v1.4-5 - add -o option to output data to a file v1.4-4 - don't set lckCNT = -1 when clearing stale serial port lock really bonehead move... As Dierks Bentley would say, What was I thinkin'? v1.4.3 - add cCommandEnd = '\0' v1.4.2 - disable XON/XOFF flow control on output v1.3-4 - fix determining if serial port is in use - correct szSerBuffer size v1.3-3 - correct an error in strftime that only may show up in the first or last week of the year v1.3-2 - take into account Daylight Savings Time when setting the Aurora's time v1.3-1 - new release v1.3-0 - new release v1.2-9 - fix -n & -p problem that left serial port locked - disable all options except -d & -e when -c is used - only format time for columns for options -d or -e - all verbose output goes to stderr - update help v1.2-5 - add locking of serial port v1.0-0 - This work based on Magnetek's 'Aurora PV Inverter - Communications Protocol -' document, Rel. 1.8 09/05/2005 aurora-1.8.8/PaxHeaders.21049/README0000644000000000000000000000007411717740613013451 xustar0030 atime=1353288464.125557994 30 ctime=1412796558.489608955 aurora-1.8.8/README0000775000000000001440000004033111717740613014103 0ustar00rootusers00000000000000 0 - Reporting Bugs I - Intro II - -k option III - Setting the Inverter Time IV - Some Known Issues V - Operation Tid Bits VI - ** NEW -q --energy-sent option ** VII - ** NEW -L, --adjust-time option ** VIII - removed ** Experimental ** status from -k, --daily-kwh IX - more on setting Setting the Inverter Time X - reading from inverter more aggresively and patiently ********************************** 0 - Reporting Bugs If you run into things that you think might be a bug and would like to report it please follow these guidelines to streamline the process. If a bad "rc" value in the form of "(-1 nn nn)" is reported please include it in your message. If it can be reproduced include the stdout output and the verbose stderr output in the following format. aurora -b >option.dat 2>option.err Example: aurora -b -a2 -k366 -Y10 /dev/ttyS0 > k.dat 2>k.err Adding numbers after the (in this case k) if multiple ones are sent. ********************************** I - Intro If you are using this software to download the data from your Aurora Inverter and have a public web site showing your data send me an email with the URL. I will be creating a web page on my Solar Web Site with those links. Tell everyone that you know about this to do that also. Email Solar at curtronics dot com with your URL. If you are using this software to download data from your Aurora Inverter and are doing so using the USB port on the inverter I would like to hear from you. I'm particularly interested it whether or not you are getting lots of CRC errors. I am working with one installation that is constantly getting CRC errors on a USB connection and has to run the program multiple times before it successfully gets the data. I'd like to determine where the problem is in order to work towards eliminating it. Email Solar at curtronics dot com with your info. Thank you. ********************************** II - -k option The -k option is considered ** Experimental ** because it is an un-Publicly documented option so it may or may not provide correct information. It appears the inverter stores the past 365 days of KWH prodcution data in a block of memory. The exact location of that memory block seems to differ in each inverter, it may be model related it may not. A pointer is available that points to the current days value but no offset information has been found to indicate at what position in the block of memory that is. So the beginning and end of the block of memory is not accurately known. aurora attempts to watch for the end of the block and then loop back to the beginning of the block (round robin storage) to continue gathering data. This method works for inverters that have 366 days (current day included) worth of data but for inveters that don't the results of the readings are currently unknown. ********************************** III - Setting the Inverter Time Setting the time on the inverter using the -S option has been known to clear (reset to zero) the energy values reported by the -e option (except the Total Energy reported value) and also the history reported by the -k option but apparently not for the -q option. This is how it behaves on my inveter that has a manufacture date of 06 16. However on newer inverters it may no longer do this, i.e. zero the data. I know of one inverter that has a manufacture date of 10 42 that setting the time via the -S option did not clear these data values. ********************************** IV - Some Known Issues There have been many reports of communications problems when using the USB port on Aurora inverters. A work around was added awhile back, the -Y option to get around this issue. Recently someone indicated that there needs to be a minimum of 400 uS between the sending of commands to the inverter when communicating via the USB port. With this information in hand the -P option was added and testing was conducted using the -P option on inverters that are communicating via the USB port that exhibit this problem. In some cases it corrected this USB problem, in other cases it did not correct the problem and the -Y option still had to be used. In short, the -P option will cause aurora to not send commands unless the time specified in the -P option has elapsed since the last command was sent. So, if you are experiencing problems with communicating via the USB port try using the -P option starting with a value of 400 and increase or decrease the value until reliable communication is attained. If that does not eliminate the problem then try using the -Y option. There have been reports saying that Power One is claiming the USB port is not designed/should not be used for continuous data gathering/communication. However, this has not been confirmed with Power One. Getting more reports from users that Power One is claiming the USB port is not designed/should not be used for continuous data gathering/communication. So more users are switching to RS-485 adapters, that being said it has been reported that using RTS/CTS control on the serial port when using a RS-485 adapter improves the communication reliability. So the -X option has been added to enable RTS/CTS control on the serial port. ********************************** V - Operation Tid Bits If aurora cannot communicate with the Aurora Inverter it dies a silent death to STDOUT but reports the lack of response to STDERR. This is on purpose for data collection purposes so you can pipe the data to a file without having any error messages in the file. If a CRC error is encountered it will also be reported on STDERR regardless. If in doubt about what's going on, use the verbose option to see. This program has been tested using a standard serial port, i.e. /dev/ttyS1, and a USB serial port, /dev/ttyUSB0 with equal success. The USB serial port was the BB DYNEX variety, DX-UBDB9 using the Prolific Technology, Inc. PL2303 Serial Port. Development and testing was done on a SuSE Linux 10.0 (custom gen'd kernel) AMD Sempron 3000 laptop system, for ease of being able to test by the Aurora Inverter, final destination has it running the data collection on a SuSE Linux 10.0 (custom kernel) AMD Athlon(tm) XP 3000+ server. An update to the platform in use, it is now SuSE Linux 11.4 with their default kernel on a AMD Phenom 1090T with 16G of memory and a battery backed up caching raid controller. ********************************** VI - ** NEW -q --energy-sent option ** This was reverse engineered since it is not in the documentation that is released to the public. Therefore, it may not work on every Aurora inverter. If you suspect it isn't reporting the correct data or they are any problems when using it *PLEASE* report them so as to help improve this option and aurora on the whole. This option will report the amount of energy sent to the grid at 10 second intervals for the past 24 hours. Well that's according to the manufacturer. In use it may report more then 24 hours worth of data, not sure if it will report less then 24 hours so if you see that it does please report that fact. When this option is invoked the timestamp of the reported data may look like YYYYMMDD-nnnn instead of 20111106-09:23:14 for example. Where YYYYMMDD is just that, those characters and not a real date and time, the nnnn will be an incrementing sequence. This is due to not having found a timestamp packet in the data stream as of yet. Once a timestamp packet is found the valid date and time for the energy values will then be reported. This is not a problem IMO, the manufacturers Windoze software gets the same data they just choose to hide it instead of displaying it. In other words, they throw out any data that is received until a timestamp packet comes their way. This will more then likely always occur to some degree, the reason being due to how this historical data is stored in the inverter. At some point in time the timestamp for the oldest data gets overwritten thus is no longer available. So why does aurora choose to display it? Well a couple of reasons. In my experience it can take 10 minutes for this option to run to completion, it's doing a lot of I/O's to the inverter. If nothing, i.e. no output, is displayed during lets say the first 3 minutes, some people may think it's not working when it actually is. Second, even if the date and time is not known for that data it may be possible to sync its date and time using previously recorded data for the time period in question. Once the date and time is displayed if the time looks to be off please report that fact. And note, the time displayed is that of the time that was on the inverter when it stored the data. So if the inverters time is off by 10 minutes, or and hour, that may make it look like something is wrong so check the time on the front panel on the inverter. The -t option could be used to do that but there could be an issue due to timezone settings so the best bet is to look at the inverter. And in the 'It would be nice' department... Before anyone asks, having the ability to skip the data that the date and time is not known for, or picking a starting time, etc., would be nice but... Because of how the data is stored it has to be read through in a serial manner in order to find the date and time for the block of data following it. There are no entry points except for the beginning, there are no offsets or block length values, nothing. So the data has to be read in a serial manner and as long as it's being read, it might as well be displayed. Here is the output in a graphical format: http://www.curtronics.com/Solar/Samples/EnergySentSample.html ********************************** VII - ** NEW -L, --adjust-time ** This option will automatically adjust the inverter's time if it is found to differ from the computer's time and then only if the following constraints are met. If is >= 1 the inverter's time will only be changed to match the time on the computer if the inverter's time differs from the computer's time by or more seconds. If is 0 (zero) a Daylight Savings Time check will be done. This check will only modify the time on the inverter on the day that any Daylight Savings Time change takes effect and only after it has taken effect and also only if the time is found to differ by 15 minutes or more. This check will compare the inverter's current time to the computer's current time. If the results of the comparision indicate the two times differ by 15 minutes or more and it is on the day that a Daylight Savings Time change takes effect, and after it has taken effect, the inverter's time will be set to match that of the computer. The added 15 minute constraint when doing the Daylight Savings Time check is to prevent frivolous changing of the time. The clocks on the inverters tend to have a large amount of drift over time. Since the change to or from Daylight Savings Time is typically an hour, using a minimum window of it differing by 15 minutes will help to insure that the time is only changed once on that day even if this option is continually used throughout the day. It would be safe to use this option all the time it won't change the time unless the constraints are met according to the above. The idea is to have it running using the "0" choice on the day that a Daylight Savings Time change takes effect. That way first thing in the morning once the inverter wakes up its time will be set properly and internal history will be recorded with the correct date and time. ***** WARNING ****** ****** WARNING ****** ****** WARNING ***** Setting the Date and Time has been known to clear all History except "Total Energy" on some inverters. This is not caused by aurora but instead is how some inverters are designed to operate. It is suggested that the -S option be used to determine if your inverter exhibits this behavior and if it does and is unacceptable then do not use this option. ********************************** VIII - removed ** Experimental ** status from -k, --daily-kwh After further testing I have decided to remove the ** Experimental ** status from this option. One big question in its operation was how it would handle inverters that had been running for less then a year thus did not have a full years worth of data to report. Field testing on a new inverter install has revealed that it operates as designed, as I had hoped, but as with anything that is reverse engineered one never knows for sure until it can be tested. But do remember, it was reverse engineered so if any anomalies are encountered please report them with verbose ouput. ********************************** IX - more on setting Setting the Inverter Time It has come to my attention that the Set Time function is no longer documented in the Protocol Documents supplied by Power One, at least not the two latest ones I have. So it appears they quietly removed that function from their documentation, probably instead of making it work properly, it was easier to just undocument it, but it still works and may or may not on all inverters. That being said... Sometimes when setting the time on the inverter using the -S or -L options the inverter may not return the status of that operation in a timely fashion but the time may still have been set. When this occurs you will see the message "no response, comparing time" if you then see the message "Inverter date/time set (checked)" the time was successfully set within +/- 2 seconds. If you do not see this message the time on the inverter is not within 2 seconds of the computer. If you see the message "Inverter date/time set (successful)" the inverter did respond and the time was successfully set. As mentioned previously on some inverter models, typically older inverters, history data may be cleared (zeroed) for Daily, Weekly, Monthly, and Yearly Energy and for --daily-kwh (-k) history, but not for Total Energy and apparently not for --energy-sent (-q) history either. ********************************** X - reading from inverter more aggresively and patiently How aurora reads responses from the inverter has changed but it's a double edged sword. It will try harder to get each character from the inverter at the cost of taking a lot more time to do so. This may improve USB communications to the inverter. It will wait up to the value supplied with the -R (--read-timeout) or -l (--read-wait) option per character or the sum of both if both are used. Since all repsonses are 8 characters if -R 5000 (5 seconds) is used that could make the time it takes to read the response approach 40 seconds. Since most options require multiple operations (commands to the inverter) to get all the data this could make it look like aurora is not doing anything. If in doubt run aurora in verbose mode (-b) to see what it is doing. If running aurora every minute to collect data this could mean that a previous running instance of aurora (when using a large value for the -R and/or -l option) hasn't completed executing when another instance of aurora starts running. To avoid this scenario use the -M option to give aurora a maximum amount time to run, specified in seconds. If aurora has not completed in the amount of time specified by the -M options value it will exit when it has exceeded the amount of time that was specified. If having problems communicating with the inveter it is recommended that the -l option be tried first using values up to and including 10. If that does not improve the communication then try the -R option starting at 500 (without using the -l option) and working up to a value of 2000. And then if still encountering problems use a combination of the -l option and the -R option. Noting that the amount of time that aurora will try to read each character from the inverter will be the sum of the times specified by the -l and -R options. Example: Using --read-wait=15 --read-timeout=3000 aurora will wait (15 * 1/10) + (3000 / 1000) = 1.5 + 3.0 = 4.5 seconds to read each character of the response from the inverter. Each response from the inveter is 8 characters in length so reading one complete response could take up to 36 seconds in this example and reading some data from the inverter requires multiple responses. aurora-1.8.8/PaxHeaders.21049/INSTALL0000644000000000000000000000007411620554614013617 xustar0030 atime=1353288464.165557998 30 ctime=1412796558.489608955 aurora-1.8.8/INSTALL0000775000000000001440000000302511620554614014250 0ustar00rootusers00000000000000 Starting with version 1.6.9 the 'make' tries to determine the optimum compile method. Most of the time you can simply untar and do a 'make' and you're good to go on AMD and Intel platforms. However on other platforms such as ARM processors you may have to manually tweak the Makefile to optimize the compile. Then doing 'make install' will put the binary in /usr/local/bin/ and the manpage in /usr/local/share/man/man1/ (Thank you Dustin Kirkland for initial creation of the manpage.) If you get any errors from the 'make' please provide the output of the 'make' including the command line so that the process can be improved. You can do a 'make check' to determine how the compile will be done. It will report 64bit verses 32bit and the 'arch' and 'tune' flags used for the processor. If it reports 'NoNative' the 'arch' and 'tune' flags will have to be manually set if you chose to do so for optimization. In that case you may have to uncomment and set/adjust the "ARCH =" and "TUNE =" variables at he beginning of the Makefile and set them to the proper values for your processor. Manually setting these variable will override any automatic determination of them. You can then do a 'make check' to see if the values you set will be used. If you set the values to 'native' and you still see NoNative that can be due to gcc not supporting 'native' due to its version or the architecture. You can access the documentation via 'aurora -h' or the manpage, or for more in depth documentation, read the code. [Content moved to README >= v1.6.5] aurora-1.8.8/PaxHeaders.21049/include0000644000000000000000000000013212461566032014130 xustar0030 mtime=1422322714.313904082 30 atime=1353288464.124557994 30 ctime=1422322714.313904082 aurora-1.8.8/include/0000775000000000001440000000000012461566032014640 5ustar00rootusers00000000000000aurora-1.8.8/include/PaxHeaders.21049/names.h0000644000000000000000000000012612461566020015461 xustar0029 mtime=1422322704.61822671 28 atime=1401637062.8511659 29 ctime=1422322704.62322706 aurora-1.8.8/include/names.h0000775000000000001440000003341512461566020016122 0ustar00rootusers00000000000000/* * aurora - Communications with Magnetek Aurora Inverter * * Copyright (C) 2006-2015 Curtis J. Blank curt@curtronics.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program may be used and hosted free of charge by anyone for * personal purposes as long as this and all included copyright * notice(s) remain intact. * * Obtain permission before selling the code for this program or * hosting this software on a commercial website, excluding if it is * solely hosted for distribution, that is allowable . In all cases * copyright must remain intact. * * This work based on Magnetek's 'Aurora PV Inverter - Communications * Protocol -' document, Rel. 1.8 09/05/2005 * Staring with v1.5-0 this work based on Power One's 'Aurora Inverter * Series - Communication Protocol -' document, Rel. 4.6 25/02/09 * * Special thanks to Tron Melzl at Magnetek for all his help including, but * by no means limited to, supplying the Communications Protocol document * */ #define VersionNH "1.8.7" /* # 50 State Request */ #define opGetState 50 #define _opGetState "State Request" /* # 52 P/N Reading */ #define opGetPN 52 #define _opGetPN "P/N Reading" #define aChar6 0 #define aChar5 1 #define aChar4 2 #define aChar3 3 #define aChar2 4 #define aChar1 5 /* # 58 Version Reading */ #define opGetVer 58 #define _opGetVer "Version Reading" #define aPar1 2 #define aPar1i "PVI-2000" #define aPar1o "PVI-2000-OUTD" #define aPar1I "PVI-3600" #define aPar1O "PVI-3.6-OUTD" #define aPar15 "PVI-5000-OUTD" #define aPar16 "PVI-6000-OUTD" #define aPar1P "3-phase interface (3G74)" #define aPar1C "PVI-CENTRAL-50 module" #define aPar14 "PVI-4.2-OUTD" #define aPar13 "PVI-3.6-OUTD" #define aPar12 "PVI-3.3-OUTD" #define aPar11 "PVI-3.0-OUTD" #define aPar1D "PVI-12.5-OUTD" #define aPar1X "PVI-10.0-OUTD" #define aPar1H "PVI-4.6-I-OUTD" #define aPar1h "PVI-3.8-I-OUTD" #define aPar1T "PVI-12.0-I-OUTD (output 480 VAC)" #define aPar1t "PVI-10.0-I-OUTD (output 480 VAC)" #define aPar1U "PVI-12.0-I-OUTD (output 208 VAC)" #define aPar1u "PVI-10.0-I-OUTD (output 208 VAC)" #define aPar1V "PVI-12.0-I-OUTD (output 380 VAC)" #define aPar1v "PVI-10.0-I-OUTD (output 380 VAC)" #define aPar1Z "PVI-12.0-I-OUTD (output 600 VAC)" #define aPar1z "PVI-10.0-I-OUTD (output 600 VAC)" #define aPar1M "PVI-CENTRAL-250" #define aPar1w "PVI-10.0-I-OUTD (output 480 VAC current limit 12 A)" #define aPar1Y "TRIO-27.6-TL-OUTD" #define aPar1y "TRIO-20-TL" #define aPar1g "UNO-2.0-I" #define aPar1G "UNO-2.5-I" #define aPar1L "PVI-CENTRAL-350 Liquid Cooled (control board)" #define aPar1B "PVI-CENTRAL-350 Liquid Cooled (display board)" #define aPar1A "PVI-CENTRAL-350 Liquid Cooled (AC gathering)" #define aPar2 3 #define aPar2A "USA - UL1741" #define aPar2E "Germany - VDE0126" #define aPar2S "Spain - DR 1663/2000" #define aPar2I "Italy - ENEL DK 5950" #define aPar2U "UK - UK G83" #define aPar2K "Australia - AS 4777" #define aPar2F "France - VDE French Model" #define aPar2R "Ireland - EN50438" #define aPar2B "Belgium - VDE Belgium Model" #define aPar2O "Korea" #define aPar2G "Greece - VDE Greece Model" #define aPar2T "Taiwan" #define aPar2C "Czech Republic" #define aPar2Q "People’s Republic of China" #define aPar2a "USA - UL1741 Vout = 208 single phase" #define aPar2b "USA - UL1741 Vout = 240 single phase" #define aPar2c "USA - UL1741 Vout = 277 single phase" #define aPar2X "Debug Standard 1" #define aPar2x "Debug Standard 2" #define aPar2u "UK – UK-G59" #define aPar2k "Israel – Derived from AS 4777" #define aPar2W "Germany – BDEW" #define aPar2H "Hungary" #define aPar2o "Corsica" #define aPar2P "Portugal" #define aPar2e "VDE AR-N-4105" #define aPar3 4 #define aPar3T "Transformer Version" #define aPar3N "Transformerless Version" #define aPar3t "Transformer HF version" #define aPar3X "Dummy transformer type" #define aPar4 5 #define aPar4W "Wind Version" #define aPar4N "Photovoltaic Version" #define aPar4X "Dummy inverter type" /* # 59 Measure request to the DSP - Type of Measure */ #define opGetDSP 59 #define _opGetDSP "Measure request to the DSP" #define ToM1 1 /* Grid Voltage (All) */ #define ToM2 2 /* Grid Currrent (All) */ #define ToM3 3 /* Grid Power (All) */ #define ToM4 4 /* Frequency All) */ #define ToM5 5 /* VBulk was Ileak (Dc/Dc) reading All) */ #define ToM6 6 /* Ileak (Dc/Dc) was Ileak (Inverter) Reading*/ #define ToM7 7 /* Ileak (Inverter) */ #define ToM8 8 /* Pin 1 (All) */ #define ToM9 9 /* Pin 2 */ #define ToM21 21 /* Inverter Temperature (Grid-Tied) */ #define ToM22 22 /* Booster Temperatuer (Grid-Tied) */ #define ToM23 23 /* Input 1 Voltage */ #define ToM25 25 /* Input 1 Current (All) */ #define ToM26 26 /* Input 2 Voltage (Grid-Tied) */ #define ToM27 27 /* Input 2 Current (Grid-Tied) */ #define ToM28 28 /* Grid Voltage (Dc/Dc) (Grid-Tied) */ #define ToM29 29 /* Grid Frequency (Dc/Dc) (Grid-Tied) */ #define ToM30 30 /* Isolation Resistance (Riso) (All) */ #define ToM31 31 /* Vbulk (Dc/Dc) (Grid-Tied) */ #define ToM32 32 /* Average Grid Voltage (VgridAvg) (Grid-Tied) */ #define ToM33 33 /* Vbulk Mid (Grid-Tied) */ #define ToM34 34 /* Power Peak (All) */ #define ToM35 35 /* Power Peak Today (All) */ #define ToM36 36 /* Grid Voltage neutral (Grid-Tied) */ #define ToM37 37 /* Wind Generator Frequency */ #define ToM38 38 /* Grid Voltage neutral-phase (Central) */ #define ToM39 39 /* Grid Current phase r (Central & 3 Phase) */ #define ToM40 40 /* Grid Current phase s (Central & 3 Phase) */ #define ToM41 41 /* Grid Current phase t (Central & 3 Phase) */ #define ToM42 42 /* Frequency phase r (Central & 3 Phase) */ #define ToM43 43 /* Frequency phase s (Central & 3 Phase) */ #define ToM44 44 /* Frequency phase t (Central & 3 Phase) */ #define ToM45 45 /* Vbulk + (Central & 3 Phase) */ #define ToM46 46 /* Vbulk - (Central) */ #define ToM47 47 /* Supervisor Temperature (Central) */ #define ToM48 48 /* Alim Temperature (Central) */ #define ToM49 49 /* Heak Sink Temperature (Central) */ #define ToM50 50 /* Temperature 1 (Central) */ #define ToM51 51 /* Temperature 2 (Central) */ #define ToM52 52 /* Temperature 3 (Central) */ #define ToM53 53 /* Fan 1 Speed (Central) */ #define ToM54 54 /* Fan 2 Speed (Central) */ #define ToM55 55 /* Fan 3 Speed (Central) */ #define ToM56 56 /* Fan 4 Speed (Central) */ #define ToM57 57 /* Fan 5 Speed (Central) */ #define ToM58 58 /* Power Saturation limit (Der.) (Central) */ #define ToM59 59 /* Reference Ring Bulk (Central) */ #define ToM60 60 /* Vpanel micro (Central) */ #define ToM61 61 /* Grid Voltage phase r (Central & 3 Phase) */ #define ToM62 62 /* Grid Voltage phase s (Central & 3 Phase) */ #define ToM63 63 /* Grid Voltage phase t (Central & 3 Phase) */ #define ToM95 95 /* Fan 1 Speed (rpm) (Central) */ #define ToM96 96 /* Fan 2 Speed (rpm) (Central) */ #define ToM97 97 /* Fan 3 Speed (rpm) (Central) */ #define ToM98 98 /* Fan 4 Speed (rpm) (Central) */ #define ToM99 99 /* Fan 5 Speed (rpm) (Central) */ #define ToM100 100 /* Fan 6 Speed (rpm) (Central) */ #define ToM101 101 /* Fan 7 Speed (rpm) (Central) */ #define _ToM1 "Grid Voltage Reading " /* Global */ #define _ToM2 "Grid Current Reading " /* Global */ #define _ToM3 "Grid Power Reading " /* Global */ #define _ToM3C "Grid Power Calculated" #define _ToM4 "Frequency Reading" #define _ToM5 "Vbulk" /* was"Ileak (Dc/Dc) Reading" */ #define _ToM6 "Ileak (Dc/Dc) Reading" /* was "Ileak (Inverter) Reading" */ #define _ToM7 "Ileak (Inverter) Reading" #define _ToM8 "Pin 1 " /* Global */ #define _ToM9 "Pin 2" #define _ToM21 "Inverter Temperature" #define _ToM22 "Booster Temperature" /* was Environment Temperature */ #define _ToM23 "Input 1 Voltage" /* Global was "West String Voltage" */ #define _ToM25 "Input 1 Current" /* was "West String Current" */ #define _ToM26 "Input 2 Voltage" /* was "East String Voltage" */ #define _ToM27 "Input 2 Current" /* was "East String Current" */ #define _ToM28 "Grid Voltage (Dc/Dc)" #define _ToM29 "Grid Frequency (Dc/Dc)" #define _ToM30 "Isolation Resistance (Riso)" #define _ToM31 "Vbulk (Dc/Dc)" #define _ToM32 "Grid Voltage Average (VgridAvg)" #define _ToM33 "Vbulk Mid" #define _ToM34 "Power Peak" #define _ToM35 "Power Peak Today" #define _ToM36 "Grid Voltage neutral" #define _ToM37 "Wind Generator Frequency" #define _ToM38 "Grid Voltage neutral-phase" #define _ToM39 "Grid Current phase r" #define _ToM40 "Grid Current phase s" #define _ToM41 "Grid Current phase t" #define _ToM42 "Frequency phase r" #define _ToM43 "Frequency phase s" #define _ToM44 "Frequency phase t" #define _ToM45 "Vbulk +" #define _ToM46 "Vbulk -" #define _ToM47 "Supervisor Temperature" #define _ToM48 "Alim Temperature" #define _ToM49 "Heak Sink Temperature" #define _ToM50 "Temperature 1" #define _ToM51 "Temperature 2" #define _ToM52 "Temperature 3" #define _ToM53 "Fan 1 Speed" #define _ToM54 "Fan 2 Speed" #define _ToM55 "Fan 3 Speed" #define _ToM56 "Fan 4 Speed" #define _ToM57 "Fan 5 Speed" #define _ToM58 "Power Saturation limit (Der.)" #define _ToM59 "Reference Ring Bulk" #define _ToM60 "Vpanel micro" #define _ToM61 "Grid Voltage phase r" #define _ToM62 "Grid Voltage phase s" #define _ToM63 "Grid Voltage phase t" #define _ToM95 "Fan 1 RPM" #define _ToM96 "Fan 2 RPM" #define _ToM97 "Fan 3 RPM" #define _ToM98 "Fan 4 RPM" #define _ToM99 "Fan 5 RPM" #define _ToM100 "Fan 6 RPM" #define _ToM101 "Fan 7 RPM" #define _Str1P "Input 1 Power" /* was "West String Power" */ #define _Str2P "Input 2 Power" /* was "East String Power" */ #define _DcAcEff "DC/AC Conversion Efficiency" /* # 63 Serial Number */ #define opGetSN 63 #define _opGetSN "Serial Number" /* # 65 Manufacturing Week and Year */ #define opGetMfg 65 #define _opGetMfg "Manufacturing Week and Year" #define aWeekH 2 #define aWeekL 3 #define aYearH 4 #define aYearL 5 /* # 68 Cumulated Float Energy (Central & TRIO only)*/ #define opGetCEC 68 #define _opGetCEC "Cumulated Float Energy" #define CECpar1 1 /* Daily Energy */ #define CECpar2 2 /* Weekly Energy */ #define CECpar3 3 /* Monthly Energy */ #define CECpar4 4 /* Yearly Energy */ #define CECpar5 5 /* nDays Energy */ #define CECpar6 6 /* Total Energy (total lifetime) */ #define CECpar7 7 /* Partial Energy (cumulated since reset) */ #define _CECpar1 "Daily Energy" #define _CECpar2 "Weekly Energy" #define _CECpar3 "Monthly Energy" #define _CECpar4 "Yearly Energy" #define _CECpar5 "Days Energy" #define _CECpar6 "Total Energy" #define _CECpar7 "Partial Energy" /* # 70 0x46 Get Time/Date */ #define opGetTime 70 #define _opGetTime "Get Time/Date" /* # 71 Set Time/Date */ #define opSetTime 71 #define _opSetTime "Set Time/Date" /* # 72 Firmware Release */ #define opGetVerFW 72 #define _opGetVerFW "Firmware Release" #define aRel3 2 #define aRel2 3 #define aRel1 4 #define aRel0 5 /* # 75 Energy delivred to grip every 10 seconds ** Experimental ** */ #define opGetCESent 0x4b01 /* 75 01 */ #define _opGetCESent "Energy Sent To Grid" #define aCESMemAdd 0x000a #define aCESMaxCnt 4320 /* # 75 Energy cumulated each day address ** Experimental ** */ #define opGetCEAdd 0x4b02 /* 75 02 */ #define _opGetCEAdd "Daily Cumulated Energy Address" #define aCEAddH 2 #define aCEAddL 3 /* # 76 Energy cumulated in the last 10 seconds */ #define opGetEnergy10Sec 76 #define _opGetEnergy10Sec "Energy cumulated in the last 10 seconds" #define aEnergyH 2 #define aEnergyL 3 /* # 77 System Configuration */ #define opGetConfig 77 #define _opGetConfig "System Configuration" #define aConfCode 2 #define ConfCode0 0 #define ConfCode1 1 #define ConfCode2 2 #define _ConfCode0 "System operating with both strings." #define _ConfCode1 "String 1 connected, String 2 disconnected." #define _ConfCode2 "String 2 connected, String 1 disconnected." /* # 78 Cumulated Energy */ #define opGetCE 78 #define _opGetCE "Cumulated Energy" #define CEpar0 0 /* Daily Energy */ #define CEpar1 1 /* Weekly Energy */ #define CEpar2 2 /* Energy of last 7 days */ #define CEpar3 3 /* Monthly Energy */ #define CEpar4 4 /* Yearly Energy */ #define CEpar5 5 /* Total Energy (total lifetime) */ #define CEpar6 6 /* Partial Energy (cumulated since reset) */ #define _CEpar0 "Daily Energy" #define _CEpar1 "Weekly Energy" #define _CEpar2 "Energy last 7 days" #define _CEpar3 "Monthly Energy" #define _CEpar4 "Yearly Energy" #define _CEpar5 "Total Energy" #define _CEpar6 "Partial Energy" /* # 79 Daily Cumulated Energy ** Experimental ** */ #define opGetCEValue 79 #define _opGetCEValue "Cumulated Energy" #define cCEDailyAddH 2 #define cCEDailyAddL 3 #define cCEDailyEnd 4 #define aCEDailyDaysH 2 #define aCEDailyDaysL 3 #define aCEDailyValH 4 #define aCEDailyValL 5 /* # 80 Time Counter */ #define opGetCounters 80 #define _opGetCounters "Time Counter" #define cTotalRun 0 #define cPartialRun 1 #define cTotalGrid 2 #define cResetPartial 3 #define _cTotalRun "Total Running Time (Lifetime)" #define _cPartialRun "Partial Running Time (since reset)" #define _cTotalGrid "Total Time With Grid Connection" #define _cResetPartial "Reset of Partial (Time & Energy)" /* # 86 Last four alarms */ #define opGetLastAlarms 86 #define _opGetLastAlarms "Last four alarms" /* return codes same as alarms from # 50 State request */ /* # 105 P/N Reading */ #define opGetPNC 105 #define _opGetPNC "P/N Reading (Central)" #define aChar6 0 #define aChar5 1 #define aChar4 2 #define aChar3 3 #define aChar2 4 #define aChar1 5 /* # 56 0x38 unknown */ #define opGet0x38 56 #define _opGet0x38 "0x38 unknown" /* # 82 0x52 unknown */ #define opGet0x52 82 #define _opGet0x52 "0x52 unknown" /* # 83 0x53 unknown */ #define opGet0x53 83 #define _opGet0x53 "0x53 unknown" aurora-1.8.8/include/PaxHeaders.21049/comm.h0000644000000000000000000000013112461565766015325 xustar0030 mtime=1422322678.589406479 30 atime=1395860463.290805882 29 ctime=1422322678.59740704 aurora-1.8.8/include/comm.h0000775000000000001440000000516412461565766015772 0ustar00rootusers00000000000000/* * aurora - Communications with Magnetek Aurora Inverter * * Copyright (C) 2006-2015 Curtis J. Blank curt@curtronics.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program may be used and hosted free of charge by anyone for * personal purposes as long as this and all included copyright * notice(s) remain intact. * * Obtain permission before selling the code for this program or * hosting this software on a commercial website, excluding if it is * solely hosted for distribution, that is allowable . In all cases * copyright must remain intact. * * This work based on Magnetek's 'Aurora PV Inverter - Communications * Protocol -' document, Rel. 1.8 09/05/2005 * Staring with v1.5-0 this work based on Power One's 'Aurora Inverter * Series - Communication Protocol -' document, Rel. 4.6 25/02/09 * * Special thanks to Tron Melzl at Magnetek for all his help including, but * by no means limited to, supplying the Communications Protocol document * */ #define VersionCH "1.8.7" extern int CommCheck(int fdser, int yAddress); extern int GetState(int fdser, int yAddress); extern int GetPN(int fdser, int yAddress); extern int GetPNC(int fdser, int yAddress); extern int GetVer(int fdser, int yAddress); extern int GetSN(int fdser, int yAddress); extern int GetVerFW(int fdser, int yAddress); extern int GetMfgDate(int fdser, int yAddress); extern int GetConf(int fdser, int yAddress); extern int GetDSP(int fdser, int yAddress); extern int GetDSPExtended(int fdser, int yAddress); extern int GetDSP3Phase(int fdser, int yAddress); extern int GetCE(int fdser, int yAddress); extern int GetCEC(int fdser, int yAddress, int yGetEnergyCen); extern int GetCESent(int fdser, int yAddress, int yGetEnergySent); extern int GetCEDaily(int fdser, int yAddress, int yGetEnergyDaily); extern int GetJoules(int fdser, int yAddress); extern int GetCounters(int fdser, int yAddress); extern int GetTime(int fdser, int yAddress); extern int SetTime(int fdser, int yAddress, BOOL force); extern int CheckSetTime(int fdser, int yAddress); extern int GetLastAlarms(int fdser, int yAddress); extern char VersionC[]; extern char VersionSHc[6]; extern int invOp; extern int invFunc; #define _clearCMD "\0\0\0\0\0\0\0\0\0\0\0" #define _clrAttemps 1000 #define _szSerBufferLen 11 #define TimeBase 946684800 #define SecsInMinute 60 #define SecsInHour (60*SecsInMinute) #define SecsInDay (24*SecsInHour) #define SecsInYear (365*SecsInDay) aurora-1.8.8/include/PaxHeaders.21049/states.h0000644000000000000000000000013212461566032015661 xustar0030 mtime=1422322714.302903314 30 atime=1397232810.702387058 30 ctime=1422322714.313904082 aurora-1.8.8/include/states.h0000775000000000001440000003526212461566032016327 0ustar00rootusers00000000000000/* * aurora - Communications with Magnetek Aurora Inverter * * Copyright (C) 2006-2015 Curtis J. Blank curt@curtronics.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program may be used and hosted free of charge by anyone for * personal purposes as long as this and all included copyright * notice(s) remain intact. * * Obtain permission before selling the code for this program or * hosting this software on a commercial website, excluding if it is * solely hosted for distribution, that is allowable . In all cases * copyright must remain intact. * * This work based on Magnetek's 'Aurora PV Inverter - Communications * Protocol -' document, Rel. 1.8 09/05/2005 * Staring with v1.5-0 this work based on Power One's 'Aurora Inverter * Series - Communication Protocol -' document, Rel. 4.6 25/02/09 * * Special thanks to Tron Melzl at Magnetek for all his help including, but * by no means limited to, supplying the Communications Protocol document * */ #define VersionSH "1.8.6" /* Transmission States */ static char szTransStates[] = "Everything is OK\0" /* # 0 */ "Unknown Transmission State 1\0" /* # 1 These are all placeholders */ "Unknown Transmission State 2\0" /* # 2 */ "Unknown Transmission State 3\0" /* # 3 */ "Unknown Transmission State 4\0" /* # 4 */ "Unknown Transmission State 5\0" /* # 5 */ "Unknown Transmission State 6\0" /* # 6 */ "Unknown Transmission State 7\0" /* # 7 */ "Unknown Transmission State 8\0" /* # 8 */ "Unknown Transmission State 9\0" /* # 9 */ "Unknown Transmission State 10\0" /* # 10 */ "Unknown Transmission State 11\0" /* # 11 */ "Unknown Transmission State 12\0" /* # 12 */ "Unknown Transmission State 13\0" /* # 13 */ "Unknown Transmission State 14\0" /* # 14 */ "Unknown Transmission State 15\0" /* # 15 */ "Unknown Transmission State 16\0" /* # 16 */ "Unknown Transmission State 17\0" /* # 17 */ "Unknown Transmission State 18\0" /* # 18 */ "Unknown Transmission State 19\0" /* # 19 */ "Unknown Transmission State 20\0" /* # 20 */ "Unknown Transmission State 21\0" /* # 21 */ "Unknown Transmission State 22\0" /* # 22 */ "Unknown Transmission State 23\0" /* # 23 */ "Unknown Transmission State 24\0" /* # 24 */ "Unknown Transmission State 25\0" /* # 25 */ "Unknown Transmission State 26\0" /* # 26 */ "Unknown Transmission State 27\0" /* # 27 */ "Unknown Transmission State 28\0" /* # 28 */ "Unknown Transmission State 29\0" /* # 29 */ "Unknown Transmission State 30\0" /* # 30 */ "Unknown Transmission State 31\0" /* # 31 */ "Unknown Transmission State 32\0" /* # 32 */ "Unknown Transmission State 33\0" /* # 33 */ "Unknown Transmission State 34\0" /* # 34 */ "Unknown Transmission State 35\0" /* # 35 */ "Unknown Transmission State 36\0" /* # 36 */ "Unknown Transmission State 37\0" /* # 37 */ "Unknown Transmission State 38\0" /* # 38 */ "Unknown Transmission State 39\0" /* # 39 */ "Unknown Transmission State 40\0" /* # 40 */ "Unknown Transmission State 41\0" /* # 41 */ "Unknown Transmission State 42\0" /* # 42 */ "Unknown Transmission State 43\0" /* # 43 */ "Unknown Transmission State 44\0" /* # 44 */ "Unknown Transmission State 45\0" /* # 45 */ "Unknown Transmission State 46\0" /* # 46 */ "Unknown Transmission State 47\0" /* # 47 */ "Unknown Transmission State 48\0" /* # 48 */ "Unknown Transmission State 49\0" /* # 49 */ "Unknown Transmission State 50\0" /* # 50 */ "Command is not implemented\0" /* # 51 */ "Variable does not exist\0" /* # 52 */ "Variable value is out of range\0" /* # 53 */ "EEprom not accessible\0" /* # 54 */ "Not Toggled Service Mode\0" /* # 55 */ "Cannot send the command to internal micro\0" /* # 56 */ "Command not Executed\0" /* # 57 */ "The variable is not available, retry\0"; /* # 58 */ /* Global States */ static char szGlobalStates[] = "Sending Parameters\0" /* # 0 */ "Wait Sun/Grid\0" /* # 1 */ "Checking Grid\0" /* # 2 */ "Measuring Riso\0" /* # 3 */ "DcDc Start\0" /* # 4 */ "Inverter Turn-On\0" /* # 5 */ "Run\0" /* # 6 */ "Recovery\0" /* # 7 */ "Pause\0" /* # 8 */ "Ground Fault\0" /* # 9 */ "OTH Fault\0" /* # 10 */ "Address Setting\0" /* # 11 */ "Self Test\0" /* # 12 */ "Self Test Fail\0" /* # 13 */ "Sensor Test + Measure Riso\0" /* # 14 */ "Leak Fault\0" /* # 15 */ "Waiting for manual reset\0" /* # 16 */ "Internal Error E026\0" /* # 17 */ "Internal Error E027\0" /* # 18 */ "Internal Error E028\0" /* # 19 */ "Internal Error E029\0" /* # 20 */ "Internal Error E030\0" /* # 21 */ "Sending Wind Table\0" /* # 22 */ "Failed Sending Table\0" /* # 23 */ "UTH Fault\0" /* # 24 */ "Remote Off\0" /* # 25 */ "Interlock Fail\0" /* # 26 */ "Executing Autotest\0" /* # 27 */ "Unknown Global State 28\0" /* # 28 Placeholder */ "Unknown Global State 29\0" /* # 29 Placeholder */ "Waiting Sun\0" /* # 30 */ "Temperature Fault\0" /* # 31 */ "Fan Staucked\0" /* # 32 */ "Int. Com. Fail\0" /* # 33 */ "Slave Insertion\0" /* # 34 */ "DC Switch Open\0" /* # 35 */ "TRAS Switch Open\0" /* # 36 */ "MASTER Exclusion\0" /* # 37 */ "Auto Exclusion\0" /* # 38 */ "Unknown Global State 39\0" /* # 39 These are all placeholders for the last 4 */ "Unknown Global State 40\0" /* # 40 */ "Unknown Global State 41\0" /* # 41 */ "Unknown Global State 42\0" /* # 42 */ "Unknown Global State 43\0" /* # 43 */ "Unknown Global State 44\0" /* # 44 */ "Unknown Global State 45\0" /* # 45 */ "Unknown Global State 46\0" /* # 46 */ "Unknown Global State 47\0" /* # 47 */ "Unknown Global State 48\0" /* # 48 */ "Unknown Global State 49\0" /* # 49 */ "Unknown Global State 50\0" /* # 50 */ "Unknown Global State 51\0" /* # 51 */ "Unknown Global State 52\0" /* # 52 */ "Unknown Global State 53\0" /* # 53 */ "Unknown Global State 54\0" /* # 54 */ "Unknown Global State 55\0" /* # 55 */ "Unknown Global State 56\0" /* # 56 */ "Unknown Global State 57\0" /* # 57 */ "Unknown Global State 58\0" /* # 58 */ "Unknown Global State 59\0" /* # 59 */ "Unknown Global State 60\0" /* # 60 */ "Unknown Global State 61\0" /* # 61 */ "Unknown Global State 62\0" /* # 62 */ "Unknown Global State 63\0" /* # 36 */ "Unknown Global State 64\0" /* # 64 */ "Unknown Global State 65\0" /* # 65 */ "Unknown Global State 66\0" /* # 66 */ "Unknown Global State 67\0" /* # 67 */ "Unknown Global State 68\0" /* # 68 */ "Unknown Global State 69\0" /* # 69 */ "Unknown Global State 70\0" /* # 70 */ "Unknown Global State 71\0" /* # 71 */ "Unknown Global State 72\0" /* # 72 */ "Unknown Global State 73\0" /* # 73 */ "Unknown Global State 74\0" /* # 74 */ "Unknown Global State 75\0" /* # 75 */ "Unknown Global State 76\0" /* # 76 */ "Unknown Global State 77\0" /* # 77 */ "Unknown Global State 78\0" /* # 78 */ "Unknown Global State 79\0" /* # 79 */ "Unknown Global State 80\0" /* # 80 */ "Unknown Global State 81\0" /* # 81 */ "Unknown Global State 82\0" /* # 82 */ "Unknown Global State 83\0" /* # 83 */ "Unknown Global State 84\0" /* # 84 */ "Unknown Global State 85\0" /* # 85 */ "Unknown Global State 86\0" /* # 86 */ "Unknown Global State 87\0" /* # 87 */ "Unknown Global State 88\0" /* # 88 */ "Unknown Global State 89\0" /* # 89 */ "Unknown Global State 90\0" /* # 90 */ "Unknown Global State 91\0" /* # 91 */ "Unknown Global State 92\0" /* # 92 */ "Unknown Global State 93\0" /* # 93 */ "Unknown Global State 94\0" /* # 94 */ "Unknown Global State 95\0" /* # 95 */ "Unknown Global State 96\0" /* # 96 */ "Unknown Global State 97\0" /* # 97 */ "Erasing Internal EEprom\0" /* # 98 */ "Erasing External EEprom\0" /* # 99 was Erasing EEPROM */ "Counting EEprom\0" /* # 100 */ "Freeze\0" ; /* # 101 */ /* DcDc Status */ static char szDcDcStatus[] = "DcDc OFF\0" /* # 0 */ "Ramp Start\0" /* # 1 */ "MPPT\0" /* # 2 */ "not used\0" /* # 3 */ "Input Over Current\0" /* # 4 */ "Input Under Voltage\0" /* # 5 */ "Input Over Voltage\0" /* # 6 */ "Input Low\0" /* # 7 */ "No Parameters\0" /* # 8 */ "Bulk Over Voltage\0" /* # 9 */ "Communication Error\0" /* # 10 */ "Ramp Fail\0" /* # 11 */ "Internal Error\0" /* # 12 */ "Input mode Error\0" /* # 13 */ "Ground Fault\0" /* # 14 */ "Inverter Fail\0" /* # 15 */ "DcDc IGBT Sat\0" /* # 16 */ "DcDc ILEAK Fail\0" /* # 17 */ "DcDc Grid Fail\0" /* # 18 */ "DcDc Comm. Error\0" ; /* # 19 */ /* Inverter State */ static char szInverterState[] = "Stand By\0" /* # 0 */ "Checking Grid\0" /* # 1 */ "Run\0" /* # 2 */ "Bulk Over Voltage\0" /* # 3 */ "Out Over Current\0" /* # 4 */ "IGBT Sat\0" /* # 5 */ "Bulk Under Voltage\0" /* # 6 */ "Degauss Error\0" /* # 7 */ "No Parameters\0" /* # 8 */ "Bulk Low\0" /* # 9 */ "Grid Over Voltage\0" /* # 10 */ "Communication Error\0" /* # 11 */ "Degaussing\0" /* # 12 */ "Starting\0" /* # 13 */ "Bulk Cap Fail\0" /* # 14 */ "Leak Fail\0" /* # 15 */ "DcDc Fail\0" /* # 16 */ "Ileak Sensor Fail\0" /* # 17 */ "SelfTest: relay inverter\0" /* # 18 */ "SelfTest: wait for sensor test\0" /* # 19 */ "SelfTest: test relay DcDc + sensor\0" /* # 20 */ "SelfTest: relay inverter fail\0" /* # 21 */ "SelfTest: timeout fail\0" /* # 22 */ "SelfTest: relay DcDc fail\0" /* # 23 */ "Self Test 1\0" /* # 24 */ "Waiting self test start\0" /* # 25 */ "Dc Injection\0" /* # 26 */ "Self Test 2\0" /* # 27 */ "Self Test 3\0" /* # 28 */ "Self Test 4\0" /* # 29 */ "Internal Error (30)\0" /* # 30 */ "Internal Error (31)\0" /* # 31 */ "Unknown Inverter State 32\0" /* # 32 These are all placeholders */ "Unknown Inverter State 33\0" /* # 33 */ "Unknown Inverter State 34\0" /* # 34 */ "Unknown Inverter State 35\0" /* # 35 */ "Unknown Inverter State 36\0" /* # 36 */ "Unknown Inverter State 37\0" /* # 37 */ "Unknown Inverter State 38\0" /* # 38 */ "Unknown Inverter State 39\0" /* # 39 */ "Forbidden State\0" /* # 40 */ "Input UC\0" /* # 41 */ "Zero Power\0" /* # 42 */ "Grid Not Present\0" /* # 43 */ "Waiting Start\0" /* # 44 */ "MPPT\0" /* # 45 */ "Grid Fail\0" /* # 46 */ "Input OC\0" ; /* # 47 */ /* Alarm State */ static char szAlarmState[] = "No Alarm\0" /* # 0 */ "Sun Low W001 (1)\0" /* # 1 */ "Input Over Current E001\0" /* # 2 */ "Input Under Voltage W002\0" /* # 3 */ "Input Over Voltage E002\0" /* # 4 */ "Sun Low W001 (5)\0" /* # 5 */ "No Parameters E003\0" /* # 6 was Internal error E003 */ "Bulk Over Voltage E004\0" /* # 7 */ "Comm. Error E005\0" /* # 8 was Internal error E005 */ "Output Over Current E006\0" /* # 9 */ "IGBT Sat E007\0" /* # 10 was Internal error E007 */ "Bulk UV W011\0" /* # 11 was Internal error E008 */ "Internal error E009\0" /* # 12 was Internal error E009 */ "Grid Fail W003\0" /* # 13 */ "Bulk Low E010\0" /* # 14 was Internal error E010 */ "Ramp Fail E011\0" /* # 15 was Internal error E011 */ "Dc/Dc Fail E012\0" /* # 16 */ "Wrong Mode E013\0" /* # 17 */ "Ground Fault (18)\0" /* # 18 */ "Over Temp. E014\0" /* # 19 */ "Bulk Cap Fail E015\0" /* # 20 */ "Inverter Fail E016\0" /* # 21 */ "Start Timeout E017\0" /* # 22 was Internal error E017 */ "Ground Fault E018 (23)\0" /* # 23 */ "Degauss error (24)\0" /* # 24 */ "Ileak Sens. fail E019\0" /* # 25 was Internal error E019 */ "DcDc Fail E012\0" /* # 26 */ "Self Test Error 1 E020\0" /* # 27 was Internal error E020 */ "Self Test Error 2 E021\0" /* # 28 was Internal error E021 */ "Self Test Error 3 E019\0" /* # 29 was Internal error E019 */ "Self Test Error 4 E022\0" /* # 30 was Internal error E022 */ "DC inj error E023\0" /* # 31 was Internal error E023 */ "Grid Over Voltage W004\0" /* # 32 */ "Grid Under Voltage W005\0" /* # 33 */ "Grid OF W006\0" /* # 34 */ "Grid UF W007\0" /* # 35 */ "Z grid Hi W008\0" /* # 36 */ "Internal error E024\0" /* # 37 */ "Riso Low E025\0" /* # 38 */ "Vref Error E026\0" /* # 39 was Internal error E026 */ "Error Meas V E027\0" /* # 40 was Internal error E027 */ "Error Meas F E028\0" /* # 41 was Internal error E028 */ "Error Meas I E029\0" /* # 42 was Internal error E029 */ "Error Meas Ileak E030\0" /* # 43 was Internal error E030 */ "Read Error V E031\0" /* # 44 was Internal error E031 */ "Read Error I E032\0" /* # 45 was Internal error E032 */ "Table fail W009\0" /* # 46 was Empty Wind Table W009 */ "Fan Fail W010\0" /* # 47 */ "UTH E033\0" /* # 48 was Internal error E033 */ "Interlock Fail\0" /* # 49 */ "Remote Off\0" /* # 50 */ "Vout Avg error\0" /* # 51 */ "Battery low\0" /* # 52 */ "Clk fail\0" /* # 53 */ "Input UC\0" /* # 54 */ "Zero Power\0" /* # 55 */ "Fan Stucked\0" /* # 56 */ "DC Switch Open\0" /* # 57 */ "Tras Switch Open\0" /* # 58 */ "AC Switch Open\0" /* # 59 */ "Bulk UV\0" /* # 60 */ "Autoexclusion\0" /* # 61 */ "Grid df/dt\0" /* # 62 */ "Den switch Open\0" /* # 63 */ "Jbox fail\0" ; /* # 64 */ #define _ModelNameLen 55 struct model { int ID; float multipler; char name[_ModelNameLen]; }; static struct model model_names[] = { {'1', 0.0970019, "PVI-3.0-OUTD"}, {'2', 0.1617742, "PVI-3.3-OUTD"}, {'3', 0.1617742, "PVI-3.6-OUTD"}, {'4', 0.1617742, "PVI-4.2-OUTD"}, {'5', 0.1617742, "PVI-5000-OUTD"}, {'6', 0.1617742, "PVI-6000-OUTD"}, {'A', 0.1617742, "PVI-CENTRAL-350 Liquid Cooled (AC gathering)"}, {'B', 0.1617742, "PVI-CENTRAL-350 Liquid Cooled (display board)"}, {'C', 0.1617742, "PVI-CENTRAL-50 module"}, {'D', 0.5320955, "PVI-12.5-OUTD"}, {'G', -1, "UNO-2.5-I"}, {'g', -1, "UNO-2.0-I"}, {'H', -1, "PVI-4.6-I-OUTD"}, {'h', -1, "PVI-3.8-I-OUTD"}, {'I', 0.1004004, "PVI-3600"}, {'i', 0.0557842, "PVI-2000"}, {'L', 0.1617742, "PVI-CENTRAL-350 Liquid Cooled (control board)"}, {'M', 0.5320955, "PVI-CENTRAL-250"}, {'O', 0.1004004, "PVI-3.6-OUTD"}, {'o', 0.0557842, "PVI-2000-OUTD"}, {'P', 0.1617742, "3-phase interface (3G74)"}, {'T', -1, "PVI-12.0-I-OUTD (output 480 VAC)"}, {'t', -1, "PVI-10.0-I-OUTD (output 480 VAC)"}, {'U', -1, "PVI-12.0-I-OUTD (output 208 VAC)"}, {'u', -1, "PVI-10.0-I-OUTD (output 208 VAC)"}, {'V', -1, "PVI-12.0-I-OUTD (output 380 VAC)"}, {'v', -1, "PVI-10.0-I-OUTD (output 380 VAC)"}, {'w', -1, "PVI-10.0-I-OUTD (output 480 VAC current limit 12 A)"}, {'X', 0.5320955, "PVI-10.0-OUTD"}, {'Y', -1, "TRIO-27.6-TL-OUTD"}, {'y', -1, "TRIO-20-TL"}, {'Z', -1, "PVI-12.0-I-OUTD (output 600 VAC)"}, {'z', -1, "PVI-10.0-I-OUTD (output 600 VAC)"}, {-1, -1, "unknown\0"} }; aurora-1.8.8/include/PaxHeaders.21049/main.h0000644000000000000000000000012612461565777015324 xustar0029 mtime=1422322687.59603751 28 atime=1396099613.3882378 29 ctime=1422322687.60103786 aurora-1.8.8/include/main.h0000775000000000001440000000652012461565777015762 0ustar00rootusers00000000000000/* * aurora - Communications with Magnetek Aurora Inverter * * Copyright (C) 2006-2015 Curtis J. Blank curt@curtronics.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program may be used and hosted free of charge by anyone for * personal purposes as long as this and all included copyright * notice(s) remain intact. * * Obtain permission before selling the code for this program or * hosting this software on a commercial website, excluding if it is * solely hosted for distribution, that is allowable . In all cases * copyright must remain intact. * * This work based on Magnetek's 'Aurora PV Inverter - Communications * Protocol -' document, Rel. 1.8 09/05/2005 * Staring with v1.5-0 this work based on Power One's 'Aurora Inverter * Series - Communication Protocol -' document, Rel. 4.6 25/02/09 * * Special thanks to Tron Melzl at Magnetek for all his help including, but * by no means limited to, supplying the Communications Protocol document * */ #define VersionMH "1.8.7" #ifndef __MAIN_H__ #define __MAIN_H__ #ifdef __cplusplus #define extern "C" { /* respect c++ callers */ #endif #define ProgramName "aurora" typedef int BOOL; /* yet another bool definition */ #define TRUE 1 #define FALSE 0 #define _ERROR_ -999999999 typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; #define LOBYTE(w) ((BYTE)(w)) #define HIBYTE(w) ((BYTE)(((WORD)(w) >> (BYTE)8) & 0xff)) extern BOOL bVerbose; /* Verbose Mode */ extern BOOL bColumns; extern BOOL bGetInvTime; extern BOOL bGetLocTime; extern int yGetDSP; extern BOOL bGetDSPExtended; extern BOOL bGetDSP3Phase; extern BOOL bHideDSP; extern BOOL bGetEnergy; extern BOOL bCommCheck; extern BOOL bColOutput; extern BOOL bCalcGridPwr; extern BOOL bRptReties; extern BOOL bRptReadPause; extern BOOL bSwapEndian; extern BOOL bUseMultiplierQ; extern float yMultiplierK; extern float yCost; extern char *sCostType; extern int yTimeout; extern long unsigned int PID; extern int yMaxAttempts; extern int yReadPause; extern long int yCommPause; extern unsigned char yDelay; extern time_t startTimeValue; extern int yGetCount; extern int yCentral; extern int yMaxRunTime; extern int yCheckSetTime; extern struct timeval lastcommtv; extern FILE *outfp; extern char* getCurTime(); extern int ClrSerLock(long unsigned int PID); extern int RestorePort(int fdser); #define ttyLCKloc "/var/lock/LCK.." /* location and prefix of serial port lock file */ /* macros */ #define MAX(a,b) ({ typeof (a) _a = (a); typeof (b) _b = (b); _a > _b ? _a : _b; }) /* command structure */ #define cAddress 0 #define cCommand 1 #define cCommandEnd 2 #define cParam1 2 #define cParam1End 3 #define cParam2 3 #define cParam2End 4 #define cParam3 4 #define cParam4 5 #define cParam4End 6 #define cParam5 6 #define cParam6 7 #define cCRC_L 8 #define cCRC_H 9 #define cEND 10 #define cSIZE 10 /* answer structure */ #define aState 0 #define aMState 1 #define aParam1 2 #define aParam2 3 #define aParam3 4 #define aParam4 5 #define aCRC_L 6 #define aCRC_H 7 #define aEND 8 #define aSIZE 8 #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __MAIN_H__ */ aurora-1.8.8/PaxHeaders.21049/COLUMNS.key0000644000000000000000000000013212342644754014422 xustar0030 mtime=1401637356.795088188 30 atime=1401637356.795088188 30 ctime=1412796558.489608955 aurora-1.8.8/COLUMNS.key0000775000000000001440000000367612342644754015074 0ustar00rootusers00000000000000Output order: -T -d -e -D -3 -E -d option STR1-V STR1-C STR1-P STR2-V STR2-C STR2-P Grid-V Grid-C Grid-P Grid-Hz DcAcCvrEff InvTemp EnvTemp [OK] -e option DailyEnery WeeklyEnergy Last7DaysEnergy MonthlyEnergy YearlyEnergy TotalEnergy PartialEnergy [OK] Note: Last7DaysEnerg obsolete on some inverters -D Bulk-V BilkM-V BulkPlusC-V BulkMinusC-V Bulk-DC Leak-DC Leak-C IsoRes GridV-DC GridAvg-V GridN-V GridDC-Hz PeakP-W PeakTodayP-W TempSupC TempAlimC TempHeatSinkC Temp1C Temp2C Temp3C FanSpd1C FanSpd2C FanSpd3C FanSpd4C FanSpd5C Pin1-W Pin2-W PwrSatC-W BilkRefRingC-V MicroC-V WindGen-Hz [OK] -3 GridN-V GridR-V GridS-V GridT-V GridR-C GridS-C GridT-C GridR-Hz GridS-Hz GridT-Hz [OK] -E DailyEnery WeeklyEnergy MonthlyEnergy YearlyEnergy NumDaysEnergy TotalEnergy PartialEnergy [OK] -T & -d option Date-Time STR1-V STR1-C STR1-P STR2-V STR2-C STR2-P Grid-V Grid-C Grid-P Grid-Hz DcAcCvrEff InvTemp EnvTemp [OK] -T & -e option Date-Time DailyEnery WeeklyEnergy Last7DaysEnergy MonthlyEnergy YearlyEnergy TotalEnergy PartialEnergy [OK] -T & -d & -e option combined in 1 run Date-Time STR1-V STR1-C STR1-P STR2-V STR2-C STR2-P Grid-V Grid-C Grid-P Grid-Hz DcAcCvrEff InvTemp EnvTemp DailyEnery WeeklyEnergy Last7DaysEnergy MonthlyEnergy YearlyEnergy TotalEnergy PartialEnergy [OK] "OK" will only be printed at the end of the data *if* all data collection from the Inverter was successful. If any data was missed or any CRC errors occurred, "OK" will *not* be printed at the end of the line. This covers periods of time like in the morning when the Inverter is attempting to startup but there is not enough sunlight, i.e power available to startup. This is similiar to when the Inverter shuts down at night due to low sunlight but continually tries to startup to keep running. NOTE: An asterik (*) may be printed next to a value if the value is suspect i.e may not be valid for the inverter. Values may be reported as zero if the value is not valid for the inverter. aurora-1.8.8/PaxHeaders.21049/TODO0000644000000000000000000000007411656364730013265 xustar0030 atime=1353288464.165557998 30 ctime=1412796558.489608955 aurora-1.8.8/TODO0000775000000000001440000000006011656364730013712 0ustar00rootusers00000000000000 Can't think of anything more at the moment....