Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 8 of 8

Thread: Arduino code example for ENC28J60 Ethernet upload to Thingspeak

  1. #1
    Senior Member
    Join Date
    Oct 2012
    Location
    Portland OR
    Posts
    595

    Arduino code example for ENC28J60 Ethernet upload to Thingspeak

    Someone requested the code I used to have an old-school Arduino type board ("Jeenode" 3.3V ATmega328p at 16 MHz) with ENC28J60 based ethernet board to upload data to Thingspeak (one data point, the analog level on A0). I have several versions of similar code but I *think* below is basically the code I had running for over 1 year without any problems (that is longest I've ever had a networked embedded system run with no maintenance). I do not know how applicable it is to Teensy 2/3 if at all. At the very least you have to put your own network config, Thingspeak API key etc.

    Note also there are more recent code examples online, such as http://nathanhein.com/2013/02/gettin...h-an-enc28j60/

    Code:
    /*
     ThingSpeak Client to Update Channel Feeds
     
     The ThingSpeak Client sketch is designed for the Arduino + Ethernet Shield.
     This sketch updates a channel feed with an analog input reading via the
     ThingSpeak API (http://community.thingspeak.com/documentation/)
     using HTTP POST.
     
     Getting Started with ThingSpeak:
     
        * Sign Up for New User Account - https://www.thingspeak.com/users/new
        * Create a New Channel by selecting Channels and then Create New Channel
        * Enter the Write API Key in this sketch under "ThingSpeak Settings"
     
     Created: January 25, 2011 by Hans Scharler (http://www.iamshadowlord.com)
     
     Additional Credits: Example sketches from Tom Igoe and David A. Mellis
    */
    
    #include <SPI.h>
    #include <Ethernet.h>
    
    // Local Network Settings
    byte mac[]     = { 0xD4, 0x28, 0xB2, 0xFF, 0xA0, 0xA1 }; // Must be unique on local network
    byte ip[]      = { 192, 168,   0,  249 };                // Must be unique on local network
    byte gateway[] = { 192, 168,   0,   1 };
    byte subnet[]  = { 255, 255, 255,   0 };
    
    // ThingSpeak Settings
    byte server[]  = { 184, 106, 153, 149 }; // IP Address for the ThingSpeak API
    String writeAPIKey = "Write API Key";    // Write API Key for a ThingSpeak Channel
    const int updateInterval = 30000;        // Time interval in milliseconds to update ThingSpeak   
    Client client(server, 80);
    
    // Variable Setup
    long lastConnectionTime = 0; 
    boolean lastConnected = false;
    int resetCounter = 0;
    
    void setup()
    {
      Ethernet.begin(mac, ip, gateway, subnet);
      Serial.begin(9600);
      delay(1000);
    }
    
    void loop()
    {
      String analogPin0 = String(analogRead(A0), DEC);
      
      // Print Update Response to Serial Monitor
      if (client.available())
      {
        char c = client.read();
        Serial.print(c);
      }
      
      // Disconnect from ThingSpeak
      if (!client.connected() && lastConnected)
      {
        Serial.println();
        Serial.println("...disconnected.");
        Serial.println();
        
        client.stop();
      }
      
      // Update ThingSpeak
      if(!client.connected() && (millis() - lastConnectionTime > updateInterval))
      {
        updateThingSpeak("field1="+analogPin0);
      }
      
      lastConnected = client.connected();
    }
    
    void updateThingSpeak(String tsData)
    {
      if (client.connect())
      { 
        Serial.println("Connected to ThingSpeak...");
        Serial.println();
            
        client.print("POST /update HTTP/1.1\n");
        client.print("Host: api.thingspeak.com\n");
        client.print("Connection: close\n");
        client.print("X-THINGSPEAKAPIKEY: "+writeAPIKey+"\n");
        client.print("Content-Type: application/x-www-form-urlencoded\n");
        client.print("Content-Length: ");
        client.print(tsData.length());
        client.print("\n\n");
    
        client.print(tsData);
        
        lastConnectionTime = millis();
        
        resetCounter = 0;
        
      }
      else
      {
        Serial.println("Connection Failed.");   
        Serial.println();
        
        resetCounter++;
        
        if (resetCounter >=5 ) {resetEthernetShield();}
    
        lastConnectionTime = millis(); 
      }
    }
    
    void resetEthernetShield()
    {
      Serial.println("Resetting Ethernet Shield.");   
      Serial.println();
      
      client.stop();
      delay(1000);
      
      Ethernet.begin(mac, ip, gateway, subnet);
      delay(1000);
    }

  2. #2
    Junior Member
    Join Date
    May 2014
    Posts
    1
    Hmmm... well this code uses the Ethernet library that as far as I know, works only with the Wiznet chip (original ethernet shield) and not with the microchip's enc28j60 and relative modules, for which other libraries exist (e.g. Ethercard)

  3. #3
    Senior Member
    Join Date
    Oct 2012
    Location
    Portland OR
    Posts
    595
    EtherCard is a driver for the ENC28J60 chip, compatible with Arduino IDE.
    Adapted and extended from code written by Guido Socher and Pascal Stang.
    http://jeelabs.net/projects/ethercard/wiki

  4. #4
    Member
    Join Date
    Nov 2012
    Location
    Belgium
    Posts
    20
    @JBeale, the comment from vfotop1 is correct : your example does NOT use ethercard/ENC28J60 but ethernet.h and the "server" and "client" objects that are in the standard Ethernet library, only compatible with wiznet chips.

    Can you post the code you talk about (used with a JeeNode) ? I have been using EtherCard on a DINo for more than one year as well, publishing a few values to cosm/xively, but I can confirm it will occasionally crash (roughly every 5-6 weeks), probably because of a DHCP bug in EtherCard that was documented somewhere on a forum.

    I never saw thingspeak code for ENC28J60. So if you can find it back and share it, that would be welcome.
    Tip : you should find "ether.packetLoop(ether.packetReceive());" somewhere in your loop, that's what handles TCP.

  5. #5
    Senior Member
    Join Date
    Oct 2012
    Location
    Portland OR
    Posts
    595
    Quote Originally Posted by tochinet View Post
    Can you post the code you talk about (used with a JeeNode) ? I have been using EtherCard on a DINo for more than one year as well, publishing a few values to cosm/xively, but I can confirm it will occasionally crash (roughly every 5-6 weeks), probably because of a DHCP bug in EtherCard that was documented somewhere on a forum.

    I never saw thingspeak code for ENC28J60. So if you can find it back and share it, that would be welcome.
    Sorry for finding the wrong example before. I believe the below code is what I used with the JeeNode (just substituted "MySecretKey") and I think I used a fixed IP address instead of DHCP to avoid issues.
    Code:
    // Arduino demo sketch for testing RFM12B + ENC28J60 ethernet
    // Listens for RF12 messages and displays valid messages on a webpage
    // Memory usage exceeds 1K, so use Atmega328 or decrease history/buffers
    //
    // This sketch is derived from RF12eth.pde:
    // May 2010, Andras Tucsni, http://opensource.org/licenses/mit-license.php
    // The EtherCard library is based on Guido Socher's driver, licensed as GPL2. 
    // Based on Mods by jcw, 2010-05-20, Jeelabs.org 
    // 
    // Author: Glyn Hudson and Trystan lea openenergymonitor.org
    // Date: 2/5/2011
    //
    // mods: working  John Beale - May 5-7 2011
    // based on info in http://tuxgraphics.org/electronics/200905/embedded-tcp-ip-stack.shtml
    // 22   162 ms   162 ms   162 ms  pepper.tuxgraphics.org [77.37.2.152]
    
    #include <EtherCard.h>
    #include <Ports.h>
    #include <RF12.h> // needed to avoid a linker error :(
    
    // ethernet interface mac address
    // D4-28-B2-FF-E2-F6 
    static byte mymac[6] = { 0xd4,0x28,0xb2,0xff,0xe2,0xf6 };
    // ethernet interface ip address
    static byte myip[4] = { 192,168,10,140 };
    // gateway ip address
    static byte gwip[4] = { 192,168,10,1 };
    // remote website ip address and port
    static byte hisip[4] = { 184,106,153,149 };  // address of remote server: ThingSpeak
    
    static word hisport = 80;
    
    // fixed RF12 settings
    #define MYNODE 31            //node ID of nanode
    #define freq RF12_915MHZ     //frequency
    #define group 212            //network group 
    
    //################################################################
    //Data Structure to be received 
    //################################################################
    typedef struct {              //data structure to be received, must be same as on transmitter 
     int sec;
     int power;
     int temp;
    } Payload;
    Payload measurement; 
    //########################################################
    
    EtherCard eth;
    MilliTimer requestTimer;
    int test=1767;
    unsigned long lastRead;    // millisecond timestamp of last analog input reading
    
    static BufferFiller bufill;
    static byte buf[300];   // a very small tcp/ip buffer is enough here
    
    
    char tsHeader[] PROGMEM =    "GET /update?key=MySecretKey&field1=";
           
     char host[] PROGMEM =     "api.thingspeak.com";    
        
    // called to fill in a request to send out data to the client
    static word my_datafill_cb (byte fd) {
        BufferFiller bfill = eth.tcpOffset(buf);
        
        bfill.emit_p(PSTR("$F$D&field2=$D&field3=$D"), 
          tsHeader,measurement.sec,measurement.power,measurement.temp);
        bfill.emit_p(PSTR(" HTTP/1.1\r\n" "Host: $F\r\n" "\r\n"),host);
          
        return bfill.position();
    }
    
    // called when the client request is complete
    static byte my_result_cb (byte fd, byte status, word off, word len) {
        Serial.print("<<< reply ");
        Serial.println((int) status);
        Serial.print((const char*) buf + off);
        return 0;
    }
    
    void setup () {
        Serial.begin(57600);
        Serial.println("\n[EtherServe test]");
        char ipaddr[18];
        mk_net_str(ipaddr,myip,4,'.',10);
        Serial.print("My IP: ");
        Serial.println(ipaddr);
            
        eth.spiInit();
        eth.initialize(mymac);
        eth.initIp(mymac, myip, 80);
        eth.clientSetGwIp(gwip);    // outgoing requests need a gateway
        eth.clientSetServerIp(hisip);
        
        rf12_initialize(MYNODE, freq,group);
        delay(1000);             // wait a second, just to be on safe side
        pinMode(0,INPUT);        // use pin 0 as (analog) input
        requestTimer.set(1); // send first request as soon as possible
        
        }
        
    char okHeader[] PROGMEM = 
        "HTTP/1.0 200 OK\r\n"
        "Content-Type: text/html\r\n"
        "Pragma: no-cache\r\n"
        ;
    
    static void homePage(BufferFiller& buf) {
       buf.emit_p(PSTR("$F\r\n"
       "<html><body>Analog Data<br>Time:$D Power:$D Temp:$D</body></html>"),
         okHeader,measurement.sec,measurement.power,measurement.temp);
    }
    
    void loop () {
        word len = eth.packetReceive(buf, sizeof buf);
        word pos = eth.packetLoop(buf, len);   // receive data from ENC28J60
     
        if (pos) {  // pos !=0 of there was a valid HTTP GET received
          bufill = eth.tcpOffset(buf);
          char* data = (char *) buf + pos;
          Serial.println(data);
    
           //receive buf hasn't been clobbered by reply yet
           if (strncmp("GET / ", data, 6) == 0) homePage(bufill); 
            
           eth.httpServerReply(buf,bufill.position()); // send web page data
        }
           
           
        // Receive data from RFM12
        //if (rf12_recvDone() && rf12_crc == 0 && (rf12_hdr & RF12_HDR_CTL) == 0  )  
        if (rf12_recvDone() && rf12_crc == 0 && rf12_len==sizeof(Payload) ) {
            measurement=*(Payload*) rf12_data;      //decode packet binary data into known data structure (same as Tx) http://jeelabs.org/2010/12/08/binary-packet-decoding-%E2%80%93-part-2/
            Serial.print("Data: "); Serial.println(measurement.power);        
         } else {
           if ((millis() - lastRead) > 1000) {
             lastRead = millis();
             measurement.sec = (int) (lastRead / 1000);
             measurement.power = analogRead(0); 
             measurement.temp = analogRead(1);
           }
         }
            
        
        if (eth.clientWaitingGw())
            return;
        
        if (requestTimer.poll(120000)) {
            Serial.print(">>> PUT# ");
            byte id = eth.clientTcpReq(my_result_cb, my_datafill_cb, hisport);
            Serial.println((int) id);
        }
    }

  6. #6
    Member
    Join Date
    Nov 2012
    Location
    Belgium
    Posts
    20
    Thanks a lot. A though nut to crack at first sight : it looks more as a server (with strings for a OK header and a html page) than as a client. Did you program thingspeak to connect to your JeeNode ? OTOH, the "PUT" at the end looks opposite.

    If this sketch allows to have both a server and a client on the same Arduino-ish device with ENC28J60, that's really very very attractive ! Any volunteer to help wit the autopsia ?

  7. #7
    Member
    Join Date
    Nov 2012
    Location
    Belgium
    Posts
    20
    Quote Originally Posted by tochinet View Post
    Any volunteer to help wit the autopsia ?
    Apparently, here as on other forums, this won't attract masses...
    Apologies to paul for hijacking his forum, since JeeNode and ENC28J60 is not directly Teensy related. Still there is _very little_ on the subject to be found on Internet, and most is outdated, so this page gets high on Google's ranking now !

    I just like to add that one fellow programmer called Phil Grant did also a sketch linking Thingspeak and ENC28J60. It's called Blank_Thingspeak_Ethercard.ino and seems recent (2014).
    I didn't reproduce it here since there may be rights. It is very close to the original Pachube/Cosm/Xively example from Jeelabs, but interestingly, it uses the POST method, while your/John's code uses GET and/or PUT.

  8. #8
    Senior Member
    Join Date
    Oct 2012
    Location
    Portland OR
    Posts
    595
    Hey it's only 5 years later, I'll try to fix some damage... that code I posted in 2014 was for an apparently early/ nonstandard/ obsolete version of the EtherCard library. It was doing two different things at once (both pushing data to Thingspeak, and acting as a super-simple local webserver). Anyway it does not compile with current versions of the library.

    I still have that particular (now unobtainum) Jeelabs EtherShield rev0.1 device and I just tried it out today. It does work with the current library, for example in https://github.com/njh/EtherCard with the only change being the slave-select line "SS" in the ether.begin() setup call is changed to "8" because my board was wired for Pin 8 as slave select, instead of the more common Pin 10.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •