Arduino Ethercard library and ENC28J60. Posting data not working

I've been trying to post data to my Apache web server at home with no luck. I can see that the server receives the request in the log file but headers are all messed up and the server cannot process the request.

Arduino code used to send the data are as follows:

char website[] PROGMEM = "10.0.0.200";
ether.hisip[0] = 10;
ether.hisip[1] = 0;
ether.hisip[2] = 0;
ether.hisip[3] = 200;

byte sd = stash.create();
    stash.print("?Controller=");
    stash.println(String(Controller));
    stash.print("&Sensor=");
    stash.println(String(Door1SensorId));
    stash.save();

Stash::prepare(PSTR("POST http://$F/addDoorData.php HTTP/1.1" "\r\n"
                      "Host: $F" "\r\n"
                      "Content-Type: application/x-www-form-urlencoded"  "\r\n"
                       "Content-Length: $D" "\r\n"
                       "\r\n"
                       "$H"),
                 website, website, stash.size(), sd);
 
ether.tcpSend();

The result that I receive on the server looks as follows: "POST http://\x95\x1f\x93\xcf\x93\xdf\x93\xeb\x01@\x91q\x05P\xe0)/0\xe0B...." 400 572 "-" "-" request failed: error reading the headers.

If anyone can help it would be greatly appreciated.

    stash.println(String(Controller));

Stupid! There is no reason to piss away resources wrapping an int in a String, and forcing the println() method to unwrap the string that the String instance created from the int, when the println() method is perfectly capable of creating a string from an int.

Stash::prepare(PSTR("POST http://$F/addDoorData.php HTTP/1.1" "\r\n"

The POST command's argument list does NOT include a protocol. It ONLY knows how to deal with the http:// protocol.

Hi Paul,

Thank you for the reply.

So I removed the http:// portion from the header, but still get funny results:

Stash::prepare(PSTR("POST $F/addDoorData.php HTTP/1.1" "\r\n"

Same result as previously.

Removing http://$F

Stash::prepare(PSTR("POST /addDoorData.php HTTP/1.1" "\r\n"

Requests never reach the server.

Do you have any ideas?

byte sd = stash.create();
    stash.print("?Controller=");
    stash.println(String(Controller));
    stash.print("&Sensor=");
    stash.println(String(Door1SensorId));
    stash.save();

That println() in the middle should be print().

Do you have any ideas?

I have the idea that you shouldn’t make us guess what your code looks like.

Why are you trying to POST the data? A GET request is so much simpler.

Thanks Paul.
Nothing seems to work, I did not include the complete code to keep it to the point, but I’ll post the complete code as well.

Even changing it to a get yields the same result.

"GET \xdd\x82\xe1\x80\x93v\x05`\xe0\x81\xe0\x90\xe0~\xdd\x10\x92m\x05\..."
#include <EtherCard.h>
#include <Time.h>
#include <SPI.h>
//RTC 3231
//Library Page - http://www.rinkydinkelectronics.com/library.php?id=73
#include <DS3231.h>

int Controller=2;

// ethernet interface mac address
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[1000];
boolean TimeFound = false;
boolean ReqSend = false;
#define INTERVAL                10000
static byte ntpServer[] = {132,163,4,101};
static byte srcPort = 0;

// Init the DS3231 using the hardware interface
DS3231  rtc(SDA, SCL);  //Pin 20/21 on Mega. A4/A5 on Uno
Time CurrTime;
time_t CheckTime;
int ChechSensorsInterval = 300;  //in seconds e.g. 60 = 1 min
time_t NextCheck = 0;

boolean DebugEnabled = 1;                      //Enable or Disable Debug
const  long timeZoneOffset = 7200L;            // set this to the offset in seconds to your local time; Currently GMT+2
const unsigned long seventyYears = 2208988800UL;  // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
unsigned long lastTime = 0;
uint32_t timeStamp;

//Track Door statuses
const int Door1OpenPin = 6;  //Garage Door Open
const int Door1ClosedPin = 7;  //Garage Door Closed
const int Door1SensorId = 2;  //Door one (Garage Door) Sensor ID in the Web server DB.
int Door1Status = 1;     //1 - Closed, 0 - Open, 2 - Opening, 3 - Closing
const int Door1SwitchPin = 2;
Stash stash;

void setup() {
  if (DebugEnabled) {
    Serial.begin(9600);
  }
  
  //Set relay Pins for output
  

  // Initialize the rtc object
  rtc.begin();
  
  if (!ether.begin(sizeof Ethernet::buffer, mymac, 53))
    Serial.println( "Failed to access Ethernet controller");
 else
   Serial.println("Ethernet controller initialized");
 
  if (!ether.dhcpSetup())
    Serial.println("Failed to get configuration from DHCP");
  else
    Serial.println("DHCP configuration done");

  ether.printIp("IP Address:\t", ether.myip);
  
}

void loop() {
  
  CheckTime = rtc.getUnixTime(rtc.getTime());
  CurrTime = rtc.getTime();
  
  ether.packetLoop(ether.packetReceive());
  
  if(ether.ntpProcessAnswer(&timeStamp, srcPort) && !TimeFound) {
    Serial.println("NTP answer received");
    Serial.println();
    Serial.print("Timestamp: ");
    Serial.println(timeStamp);
    Serial.println();
    timeStamp = timeStamp - seventyYears + timeZoneOffset;
    
    if (DebugEnabled) {
      Serial.print("NTP Time BEFORE set: ");
      Serial.print(weekday(timeStamp));
      Serial.print(", ");
      Serial.print(day(timeStamp));
      Serial.print(" ");
      Serial.print(month(timeStamp));
      Serial.print(" ");
      Serial.print(year(timeStamp));
      Serial.print(" ");
      Serial.print(hour(timeStamp));
      Serial.print(":");
      Serial.print(minute(timeStamp));
      Serial.print(":");
      Serial.println(second(timeStamp));      
    }

    // set the initial time here:
    // DS3231 seconds, minutes, hours, day, date, month, year
    //setDS3231time(second(epoch),minute(epoch),hour(epoch),weekday(epoch),day(epoch),month(epoch),year(epoch)-2000); //year should be 15 for e.g. 2015 hence -2000

    // The following lines can be uncommented to set the date and time
    rtc.setDOW(weekday(timeStamp));     // Set Day-of-Week to SUNDAY
    rtc.setTime(hour(timeStamp), minute(timeStamp), second(timeStamp));     // Set the time to 12:00:00 (24hr format)
    rtc.setDate(day(timeStamp), month(timeStamp), year(timeStamp));   // Set the date to January 1st, 2014
    setTime(timeStamp);

    if (DebugEnabled) {
      Serial.println("RTC time:");
      CurrTime = rtc.getTime();
      Serial.print(rtc.getDOWStr());
      Serial.print(", ");
      Serial.print(CurrTime.date);
      Serial.print(" ");
      Serial.print(rtc.getMonthStr());
      Serial.print(" ");
      Serial.print(CurrTime.year);
      int hours = CurrTime.hour;
      Serial.print(" ");
      if (hours < 10) {
        Serial.print("0");
      }
      Serial.print(hours);
      Serial.print(":");
      int mins = CurrTime.min;
      if (mins < 10) {
        Serial.print("0");
      }
      Serial.print(mins);
      Serial.print(":"); 
      int secs = CurrTime.sec;
      if (secs < 10) {
        Serial.print("0");
      }
      Serial.println(secs);  
    }    
    TimeFound = true;
  }
  
  unsigned long time = millis();;
  if(time - lastTime > INTERVAL && !TimeFound && !ReqSend) {
    lastTime = time;
    ether.ntpRequest(ntpServer, srcPort);
    Serial.println("NTP request sent");
    TimeFound = false;
    ReqSend = true;
  }
  
  int CurrStatus;
  //Check Read Door Status
  boolean Door1OpenStatus = digitalRead(Door1OpenPin);
  boolean Door1ClosedStatus = digitalRead(Door1ClosedPin);
    
  if (Door1ClosedStatus) {
    //Door is closed.
    CurrStatus = 1;
  } else if (Door1OpenStatus) {
    //Door is open
    CurrStatus = 0;
  } else {
    //Door is in the process of opening or closing
    if (Door1Status == 1 || Door1Status == 2) {
      //Opening
      CurrStatus = 2;
    } else {
      //Closing
      CurrStatus = 3;
    }
  }
    
  if (CurrStatus != Door1Status) {
    Serial.print("Garage Door Status Changed to: ");
    if (CurrStatus == 1) {
      Serial.println("Closed");
    } else if (CurrStatus == 0){
      Serial.println("Open");
    } else if (CurrStatus == 2){
      Serial.println("In process of opening");
    } else {
      Serial.println("In process of closing");
    }
    
    
    
    // generate two fake values as payload - by using a separate stash,
    // we can determine the size of the generated message ahead of time
    
    char website[] PROGMEM = "10.0.0.200";
    ether.hisip[0] = 10;
    ether.hisip[1] = 0;
    ether.hisip[2] = 0;
    ether.hisip[3] = 200;
    
    Serial.println("Sending data to server.");
    
    byte sd = stash.create();
    stash.print("?Controller=");
    stash.print(Controller);
    stash.print("&Sensor=");
    stash.println(Door1SensorId);
    stash.save();
    
    Serial.println(stash.freeCount());
    
    Stash::prepare(PSTR("GET $F/addDoorData.php HTTP/1.1" "\r\n"
                      "Host: $F" "\r\n"
                      "Content-Type: application/x-www-form-urlencoded"  "\r\n"
                       "Content-Length: $D" "\r\n"
                       "\r\n"
                       "$H"),
                 website, website, stash.size(), sd);
 
    // send the packet - this also releases all stash buffers once done
    ether.tcpSend();
    
    /*
    if (client.connect(IPAddress(10,0,0,200),80)) { // REPLACE WITH YOUR SERVER ADDRESS
      if (client.connected()) {
        client.println("POST /addDoorData.php HTTP/1.1"); 
        client.println("Host: 10.0.0.200"); // SERVER ADDRESS HERE TOO
        client.println("Content-Type: application/x-www-form-urlencoded"); 
        client.print("Content-Length: "); 
        client.println(data.length()); 
        client.println(); 
        client.print(data); 
      } else {
        Serial.println("No Post not connected to webserver!!");
      }
    } else {
      //Connection to server failed. Log data to SD card for upload later.
      Serial.println("Failed to connect to webserver!!");
    }
    */
    
    Door1Status = CurrStatus;   
  }
    
  //Read sensors at an interval e.g. 5mins. This is for sensors that continuously change, like temprature.
  if (CheckTime >= NextCheck) {
    //check required sensors
    NextCheck = CheckTime + ChechSensorsInterval;
  }
}


// called when the client request is complete
static void my_callback (byte status, word off, word len) {
  Serial.println(">>>");
  Ethernet::buffer[off+300] = 0;
  Serial.print((const char*) Ethernet::buffer + off);
  Serial.println("...");
}
                      "Content-Type: application/x-www-form-urlencoded"  "\r\n"
                       "Content-Length: $D" "\r\n"
                       "\r\n"

These are not needed for a GET request. If you look at the mess you got, you can see that the data you wanted to send was encoded, because you told it to be. If you don't want it encoded, stop telling it to be encoded.

Ok even removing that does not make a difference.
Looking at the string received it's not URL encoded as specified in the header.

Looking at the string received

Received where? How are you looking at it?

Is it possible for someone else, with a real Ethernet shield (OK, a different kind of Ethernet shield) to access the site?

I'm suspecting that the issue is with the Stash::prepare() method.

The string is in the apache log.
I'm posting data from another arduino to the same page on a WizNet chip with the erhernet lib and that works fine.

I've never worked with stach or ethercard so I'm really in the dark, the NTP portion of the code works perfectly, I'm sure it's just something small just can;t find it

I've never worked with stach or ethercard so I'm really in the dark

You have the source code. You don't NEED to remain in the dark.

Im going to interject something here. I gave up on using EtherCard.h, I had a lot of similar issues with it.

Instead I started using UIPEthernet (UIPEthernet.h) https://github.com/ntruchsess/arduino_uip

It seemed to fix all my issues, used a little less space, and is function compatible with the stock Ethernet.h

Just my $0.02

thanks CyberLink1.

I've tried using UIPEthernet, but have found that it's unreliable and only works sometimes.
Thank you for your input.