From 4d27fcaaa2168e82421446a379e136673be96464 Mon Sep 17 00:00:00 2001 From: Stuart Pittaway Date: Tue, 24 Apr 2012 22:17:58 +0100 Subject: [PATCH] Improved DC power reading code and reduced total code size by merging arrays --- Bluetooth.ino | 10 +- PVoutputOrg.ino | 2 +- SMANetArduino.h | 13 +- SMANetArduino.ino | 32 +++-- SolarStatsCoUk.ino | 4 +- Utility.ino | 2 +- WebSiteService.ino | 14 +- nanodesmapvmonitor.ino | 297 ++++++++++++++++++++++------------------- 8 files changed, 204 insertions(+), 170 deletions(-) diff --git a/Bluetooth.ino b/Bluetooth.ino index 0d090ee..0985847 100644 --- a/Bluetooth.ino +++ b/Bluetooth.ino @@ -25,9 +25,10 @@ NANODE SMA PV MONITOR SoftwareSerial blueToothSerial(RxD,TxD); void BTStart() { + if (!readArrayFromEEPROM(myBTAddress,6,ADDRESS_MY_BTADDRESS) || !readArrayFromEEPROM(smaBTInverterAddressArray,6,ADDRESS_SMAINVERTER_BTADDRESS)) { - debugMsgln("Checksum failed - pairing"); + debugMsgln("Chksum fail-pair"); BTInitStartup(true); } else BTInitStartup(false); @@ -35,6 +36,7 @@ void BTStart() { //Start normal connection to BT chip, it will auto-connect as master to the SMA inverter (slave) blueToothSerial.begin(9600); + debugMsgln("BT Rdy"); //Bluetooth ready } void sendPacket(unsigned char *btbuffer) { @@ -46,7 +48,7 @@ void sendPacket(unsigned char *btbuffer) { void quickblink() { digitalWrite( RED_LED, LOW); - delay(100); + delay(30); digitalWrite( RED_LED, HIGH); } @@ -66,7 +68,7 @@ void BTInitStartup(bool ForcePair) { void BTSwitchOn() { analogWrite(BLUETOOTH_POWER_PIN, 255); //Ensure BT chip is on - delay(1500); //Give chip time to warm up and enter command mode + delay(1800); //Give chip time to warm up and enter command mode } void BTSwitchOff() { @@ -93,7 +95,7 @@ void BTScanForSMAInverterToPairWith() char smabtinverteraddress[14]; unsigned char tempaddress[6]; //BT address - debugMsgln("Config Bluetooth"); + debugMsgln("Config BT"); digitalWrite(BT_KEY, HIGH); // Turn BT chip into command mode (HC05) delay(200); diff --git a/PVoutputOrg.ino b/PVoutputOrg.ino index 8ae1183..9b533e1 100644 --- a/PVoutputOrg.ino +++ b/PVoutputOrg.ino @@ -32,7 +32,7 @@ bool webservicePVoutputOrg::dnsLookup() { void webservicePVoutputOrg::preparePacket(unsigned long totalkWhGenerated,unsigned long spotTotalPowerAC,unsigned long spotTotalPowerDC, time_t dt) { - debugMsg("Uploading to "); Serial.println(pvoutputwebsite); + //debugMsg("Upload to "); Serial.println(pvoutputwebsite); byte sd = stash.create(); stash.print(F("d=")); diff --git a/SMANetArduino.h b/SMANetArduino.h index cdf8dfe..b5dfce0 100644 --- a/SMANetArduino.h +++ b/SMANetArduino.h @@ -18,22 +18,27 @@ NANODE SMA PV MONITOR All code is copyright Stuart Pittaway, (c)2012. */ - -const byte maxlevel1packetsize = 120; -const byte level1headerlength = 18; +#define maxlevel1packetsize 120 +#define level1headerlength 18 +//const byte maxlevel1packetsize = 120; +//const byte level1headerlength = 18; unsigned int packetlength=0; unsigned int cmdcode=0; +//Should be moved into PROGMEM unsigned char sixzeros[6]={ 0x00,0x00,0x00,0x00,0x00,0x00}; +//Should be moved into PROGMEM unsigned char sixff[6]={ 0xff,0xff,0xff,0xff,0xff,0xff}; + unsigned int packetposition=0; + unsigned int FCSChecksum=0xffff; unsigned char Level1SrcAdd[6]; unsigned char Level1DestAdd[6]; -char invertername[15]={0}; +//char invertername[15]={0}; unsigned char packet_send_counter=0; unsigned char lastpacketindex=0; diff --git a/SMANetArduino.ino b/SMANetArduino.ino index dab5a18..3330151 100644 --- a/SMANetArduino.ino +++ b/SMANetArduino.ino @@ -81,11 +81,11 @@ void readLevel1PacketFromBluetoothStream(int index) { packetlength=index+level1headerlength; packetposition=index; } - else Serial.println(F("P wrng snder")); + else debugMsgln("P wrng snder"); } - else Serial.println(F("P wrng dest")); + else debugMsgln("P wrng dest"); } - else Serial.println(F("Inv hdr")); + else debugMsgln("Inv hdr"); } void prepareToReceive(){ @@ -106,14 +106,18 @@ bool containsLevel2Packet() { void waitForPacket(unsigned int cmdcodetowait) { + //debugMsg("waitForPacket=0x"); Serial.print(cmdcodetowait,HEX); + prepareToReceive(); while (cmdcode!=cmdcodetowait) { readLevel1PacketFromBluetoothStream(0); } + //debugMsgln(" done"); } void waitForMultiPacket(unsigned int cmdcodetowait) { + //debugMsg("waitForMultiPacket=0x"); Serial.print(cmdcodetowait,HEX); prepareToReceive(); while (cmdcode!=cmdcodetowait) { @@ -129,6 +133,7 @@ void writeSMANET2Long(unsigned char *btbuffer,unsigned long v) { writeSMANET2SingleByte(btbuffer,(unsigned char)((v >> 24) & 0xFF)) ; } +/* void displaySpotValues(int gap) { unsigned long value = 0; unsigned int valuetype=0; @@ -151,11 +156,10 @@ void displaySpotValues(int gap) { memcpy(&datetime,&level1packet[i+4],4); digitalClockDisplay(datetime); - Serial.print("="); - Serial.println(value); + Serial.print("=");Serial.println(value); } - } +*/ void writeSMANET2SingleByte(unsigned char *btbuffer, unsigned char v) { //Keep a rolling checksum over the payload @@ -170,14 +174,16 @@ void writeSMANET2SingleByte(unsigned char *btbuffer, unsigned char v) { } } -void writeSMANET2Array(unsigned char *btbuffer, unsigned char bytes[],int loopcount) { +void writeSMANET2Array(unsigned char *btbuffer, unsigned char bytes[],byte loopcount) { //Escape the packet if needed.... for(int i=0;idnsLookup()) { ether.copyIp(this->hostip,ether.hisip); @@ -60,14 +60,6 @@ void WebSiteService::stashPrintTwoDigits(byte num) stash.write('0' + (num % 10)); } -/* -void WebSiteService::formatTwoDigits(char* strOut, int num) - { - strOut[0] = '0' + (num / 10); - strOut[1] = '0' + (num % 10); - } - */ - void WebSiteService::CountDownAndUpload(unsigned long totalkWhGenerated,unsigned long spotTotalPowerAC,unsigned long spotTotalPowerDC, time_t dt) { CountDown(); @@ -85,9 +77,9 @@ void WebSiteService::CountDownAndUpload(unsigned long totalkWhGenerated,unsigned //Wait for a bit to process any possible replies, ideally we //would like to wait here for a successful HTTP 200 message //or timeout/error condition - for(int i=0; i<250; i++) + for(int i=0; i<150; i++) { - delay(5); + delay(10); ether.packetLoop(ether.packetReceive()); } } diff --git a/nanodesmapvmonitor.ino b/nanodesmapvmonitor.ino index 8d4327f..f417d58 100644 --- a/nanodesmapvmonitor.ino +++ b/nanodesmapvmonitor.ino @@ -38,11 +38,14 @@ #undef debugMsgln #define debugMsgln(s) (__extension__( {Serial.println(F(s));} )) -//#define debugMsgln(s) (__extension__( {delay(0);} )) +//#define debugMsgln(s) (__extension__( {__asm__("nop\n\t"); } )) + #undef debugMsg #define debugMsg(s) (__extension__( {Serial.print(F(s));} )) -//#define debugMsg(s) (__extension__( { delay(0); } )) +//#define debugMsg(s) (__extension__( { __asm__("nop\n\t"); } )) +//Do we switch off upload to sites when its dark? +//#define allowsleep byte Ethernet::buffer[650]; // tcp/ip send and receive buffer @@ -55,10 +58,8 @@ static time_t datetime=0; Stash stash; //Shared by WebService classes +prog_uchar PROGMEM smanet2packetx80x00x02x00[] ={0x80, 0x00, 0x02, 0x00}; -//Sure these arrays could be merged together if the common elements were stripped out -prog_uchar PROGMEM smanet2packet1[] ={ - 0x80, 0x00, 0x02, 0x00, 0x00}; prog_uchar PROGMEM smanet2packet2[] ={ 0x80, 0x0E, 0x01, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; prog_uchar PROGMEM SMANET2header[] = { @@ -67,78 +68,74 @@ prog_uchar PROGMEM InverterCodeArray[] = { 0x5c, 0xaf, 0xf0, 0x1d, 0x50, 0x00 }; //SCAFFOLDS000 meaningless really! This is our fake address on the SMA NETWORK prog_uchar PROGMEM fourzeros[]= { 0,0,0,0}; -prog_uchar PROGMEM smanet2packet5[]={ - 0x80, 0x00, 0x02, 0x00, 0x58, 0x00, 0x1e, 0x82, 0x00, 0xFF, 0x1e, 0x82, 0x00}; //Inverter name -prog_uchar PROGMEM smanet2packet6[]={ - 0x80, 0x00, 0x02, 0x00, 0x54, 0x00, 0x22, 0x26, 0x00, 0xFF, 0x22, 0x26, 0x00}; -prog_uchar PROGMEM smanet2acspotvalues[]= { - 0x80, 0x00, 0x02, 0x00, 0x51, 0x00, 0x3f, 0x26, 0x00, 0xFF, 0x3f, 0x26, 0x00, 0x0e}; - -prog_uchar PROGMEM smanet2packet7[]={ - 0x83, 0x00, 0x02, 0x80, 0x53, 0x00, 0x00, 0x45, 0x00, 0xFF, 0xFF, 0x45, 0x00 }; +prog_uchar PROGMEM smanet2packet6[]={ + 0x54, 0x00, 0x22, 0x26, 0x00, 0xFF, 0x22, 0x26, 0x00}; -prog_uchar PROGMEM smanet2totalyieldWh[]= { - 0x80, 0x00, 0x02, 0x00, 0x54, 0x00, 0x01, 0x26, 0x00, 0xFF, 0x01, 0x26, 0x00}; -prog_uchar PROGMEM smanet2packet0[]= { - 0x01,0x00,0x00,0x00}; -prog_uchar PROGMEM smanet2packet99[]= { - 0x00,0x04,0x70,0x00}; - -prog_uchar PROGMEM smanet2packet_logon[]={ - 0x80, 0x0C, 0x04, 0xFD, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,0xaa,0xaa,0xbb,0xbb}; - - -//Password needs to be 12 bytes long, with zeros as trailing bytes -//Assume SMA INVERTER PIN code is 0000 +//Password needs to be 12 bytes long, with zeros as trailing bytes (Assume SMA INVERTER PIN code is 0000) unsigned char SMAInverterPasscode[]={ '0','0','0','0',0,0,0,0,0,0,0,0}; void setup() { Serial.begin(115200); //Serial port for debugging output - //debugMsgln("PWR UP"); pinMode(RED_LED, OUTPUT); - digitalWrite( RED_LED, HIGH); + digitalWrite( RED_LED, LOW); //HowMuchMemory(); - BTStart(); - //Make sure you have the latest version of NanodeMAC which works on Arduino 1.0 byte mymac[] = { - 0,0,0,0,0,0 }; + 0,0,0,0,0,0 }; NanodeMAC mac( mymac ); - printMacAddress(mymac); + //printMacAddress(mymac); - debugMsgln("DHCP"); if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) { - debugMsgln("Fail chip"); + //debugMsgln("Fail chip"); error(); } + debugMsg("DHCP "); if (ether.dhcpSetup()) { - //ether.printIp("IP:", ether.myip); + ether.printIp("IP:", ether.myip); //ether.printIp("GW:", ether.gwip); //ether.printIp("DNS:", ether.dnsip); } else { - debugMsgln("DHCP fail"); + //debugMsgln("DHCP fail"); error(); } + //debugMsgln("Done"); + + HowMuchMemory(); + // es.ES_enc28j60PowerDown(); // es.ES_enc28j60PowerUp(); + + } void loop() { - //debugMsgln("LOOP.."); + debugMsgln("loop"); - //HowMuchMemory(); + //DNS lookup is done here otherwise the Serial buffer gets overflowed by the inverter trying to send broadcast messages out + webservicePachube pachube; + pachube.begin(); + + webserviceSolarStats solarstats; + solarstats.begin(); + + webservicePVoutputOrg pvoutputorg; + pvoutputorg.begin(); + + digitalWrite( RED_LED, HIGH); + + BTStart(); initialiseSMAConnection(); @@ -150,16 +147,6 @@ void loop() setSyncInterval(3600); //1 hour setSyncProvider(setTimePeriodically); - //DNS lookup is done here otherwise the Serial buffer gets overflowed by the inverter trying to send broadcast messages out - webservicePachube pachube; - pachube.begin(); - - webserviceSolarStats solarstats; - solarstats.begin(); - - webservicePVoutputOrg pvoutputorg; - pvoutputorg.begin(); - // webserviceemonCMS emoncms; // emoncms.begin(); @@ -167,35 +154,32 @@ void loop() getDailyYield(); //getInverterName(); - //getDCValues(); //HistoricData(); //Default loop - debugMsgln("*LOOP*"); + //debugMsgln("*LOOP*"); time_t checktime=nextMinute(now()); //Store current time to compare against - bool sleeping=false; + //bool sleeping=false; while (1) { + //debugMsgln("Main loop"); + + //HowMuchMemory(); // DHCP expiration is a bit brutal, because all other ethernet activity and // incoming packets will be ignored until a new lease has been acquired if (ether.dhcpExpired() && !ether.dhcpSetup()) { - debugMsgln("DHCP fail"); + //debugMsgln("DHCP fail"); error(); } - //Delay for approx. 2 seconds between instant AC power readings - for(int i=1; i<=20; i++) { - ether.packetLoop(ether.packetReceive()); - delay(100); - } //Populate datetime and spotpowerac variables with latest values + //getInstantDCPower(); getInstantACPower(); - getInstantDCPower(); //At this point the instant AC power reading could be sent over to an XBEE/RF module //to the Open Energy Monitor GLCD display @@ -206,16 +190,17 @@ void loop() } digitalClockDisplay( now() ); - Serial.println(""); + debugMsgln(""); if (now()>=checktime) { + //debugMsgln("Upload time"); - if (sleeping) { - //Force reboot of chip to prevent chip from hanging every 3 or 4 days. - sleeping=false; - softReset(); - } +// if (sleeping) { +// //Force reboot of chip to prevent chip from hanging every 3 or 4 days. +// sleeping=false; +// softReset(); +// } //This routine is called as soon as possible after the clock ticks past the minute //its important to get regular syncronised readings from the solar, or you'll end @@ -232,11 +217,13 @@ void loop() //finally, set waiting time... checktime=nextMinute(now()); + +#ifdef allowsleep if ( (now() > (datetime+3600)) && (spotpowerac==0)) { //Inverter output hasnt changed for an hour, so put Nanode to sleep till the morning - debugMsgln("Bed time"); + //debugMsgln("Bed time"); - sleeping=true; + //sleeping=true; //Get midnight on the day of last solar generation tmElements_t tm; @@ -249,9 +236,9 @@ void loop() time_t midnight=makeTime(tm); //Move to midnight - debugMsg("Midnight "); + //debugMsg("Midnight "); //digitalClockDisplay( midnight ); - debugMsgln(""); + //debugMsgln(""); if (now() < midnight) { //Time to calculate SLEEP time, we only do this if its BEFORE midnight @@ -265,12 +252,21 @@ void loop() checktime=midnight + minutespastmidnight - 15*60; } } +#endif - debugMsg("Wait for "); - digitalClockDisplay( checktime ); - debugMsgln(""); + //debugMsg("Wait for "); + //digitalClockDisplay( checktime ); + //debugMsgln(""); } + + //Delay for approx. 4 seconds between instant AC power readings + //debugMsgln("Ether loop"); + for(int i=1; i<=60; i++) { + ether.packetLoop(ether.packetReceive()); + delay(50); + } + }//end while } @@ -280,12 +276,18 @@ time_t nextMinute(time_t t) { } +prog_uchar PROGMEM smanet2totalyieldWh[]= { + 0x54, 0x00, 0x01, 0x26, 0x00, 0xFF, 0x01, 0x26, 0x00}; + void getTotalPowerGeneration() { + //Gets the total kWh the SMA inverterhas generated in its lifetime... do { - writePacketHeader(level1packet,0x01,0x00,smaBTInverterAddressArray); + writePacketHeader(level1packet); + //writePacketHeader(level1packet,0x01,0x00,smaBTInverterAddressArray); writeSMANET2PlusPacket(level1packet,0x09, 0xa0, packet_send_counter, 0, 0, 0); - writeSMANET2ArrayFromProgmem(level1packet,smanet2totalyieldWh,13); + writeSMANET2ArrayFromProgmem(level1packet,smanet2packetx80x00x02x00,sizeof(smanet2packetx80x00x02x00)); + writeSMANET2ArrayFromProgmem(level1packet,smanet2totalyieldWh,sizeof(smanet2totalyieldWh)); writeSMANET2PlusPacketTrailer(level1packet); writePacketLength(level1packet); @@ -307,12 +309,16 @@ void getTotalPowerGeneration() { } static time_t setTimePeriodically() { - debugMsgln("Fake time resync"); + debugMsgln("Fake time sync"); //Just fake the syncTime functions of time.h return 0; } +prog_uchar PROGMEM smanet2packet99[]= {0x00,0x04,0x70,0x00}; +prog_uchar PROGMEM smanet2packet0[]= {0x01,0x00,0x00,0x00}; + void initialiseSMAConnection() { + //Wait for announcement/broadcast message from PV inverter waitForPacket(0x0002); @@ -322,12 +328,13 @@ void initialiseSMAConnection() { //debugMsg("sma netid=");Serial.println(netid,HEX); writePacketHeader(level1packet,0x02,0x00,smaBTInverterAddressArray); - writeSMANET2ArrayFromProgmem(level1packet,smanet2packet99,4); + writeSMANET2ArrayFromProgmem(level1packet,smanet2packet99,sizeof(smanet2packet99)); writeSMANET2SingleByte(level1packet,netid); - writeSMANET2ArrayFromProgmem(level1packet,fourzeros,4); - writeSMANET2ArrayFromProgmem(level1packet,smanet2packet0,4); + writeSMANET2ArrayFromProgmem(level1packet,fourzeros,sizeof(fourzeros)); + writeSMANET2ArrayFromProgmem(level1packet,smanet2packet0,sizeof(smanet2packet0)); writePacketLength(level1packet); sendPacket(level1packet); + waitForPacket(0x000a); while ((cmdcode!=0x000c) && (cmdcode!=0x0005)) { readLevel1PacketFromBluetoothStream(0); @@ -341,11 +348,13 @@ void initialiseSMAConnection() { do { //First SMANET2 packet - writePacketHeader(level1packet,0x01,0x00,sixff); + writePacketHeader(level1packet,sixff); + //writePacketHeader(level1packet,0x01,0x00,sixff); writeSMANET2PlusPacket(level1packet,0x09, 0xa0, packet_send_counter, 0, 0, 0); - writeSMANET2ArrayFromProgmem(level1packet,smanet2packet1,5); - writeSMANET2ArrayFromProgmem(level1packet,fourzeros,4); - writeSMANET2ArrayFromProgmem(level1packet,fourzeros,4); + writeSMANET2ArrayFromProgmem(level1packet,smanet2packetx80x00x02x00,sizeof(smanet2packetx80x00x02x00)); + writeSMANET2SingleByte(level1packet,0x00); + writeSMANET2ArrayFromProgmem(level1packet,fourzeros,sizeof(fourzeros)); + writeSMANET2ArrayFromProgmem(level1packet,fourzeros,sizeof(fourzeros)); writeSMANET2PlusPacketTrailer(level1packet); writePacketLength(level1packet); sendPacket(level1packet); @@ -356,9 +365,11 @@ void initialiseSMAConnection() { packet_send_counter++; //Second SMANET2 packet - writePacketHeader(level1packet,0x01,0x00,sixff); + writePacketHeader(level1packet,sixff); + //writePacketHeader(level1packet,0x01,0x00,sixff); writeSMANET2PlusPacket(level1packet,0x08, 0xa0, packet_send_counter, 0x00, 0x03, 0x03); - writeSMANET2ArrayFromProgmem(level1packet,smanet2packet2,9); + writeSMANET2ArrayFromProgmem(level1packet,smanet2packet2,sizeof(smanet2packet2)); + writeSMANET2PlusPacketTrailer(level1packet); writePacketLength(level1packet); sendPacket(level1packet); @@ -367,24 +378,24 @@ void initialiseSMAConnection() { } +prog_uchar PROGMEM smanet2packet_logon[]={ + 0x80, 0x0C, 0x04, 0xFD, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,0xaa,0xaa,0xbb,0xbb}; + void logonSMAInverter() { //Third SMANET2 packet - debugMsgln("*Logon*"); + debugMsg("*Logon "); do { - writePacketHeader(level1packet,0x01,0x00,sixff); + writePacketHeader(level1packet,sixff); + //writePacketHeader(level1packet,0x01,0x00,sixff); writeSMANET2PlusPacket(level1packet,0x0e, 0xa0, packet_send_counter, 0x00, 0x01, 0x01); writeSMANET2ArrayFromProgmem(level1packet,smanet2packet_logon,sizeof(smanet2packet_logon)); - //writeSMANET2ArrayFromProgmem(level1packet,smanet2packet90,4); - writeSMANET2ArrayFromProgmem(level1packet,fourzeros,4); + writeSMANET2ArrayFromProgmem(level1packet,fourzeros,sizeof(fourzeros)); //INVERTER PASSWORD - only 4 digits, although it appears packet can hold longer for(int passcodeloop=0;passcodeloop