Need help Sending jpeg/bytes to the Webserver with Linksprite serial ttl camera

I just picked up linksprite infrared serial camera and i am using it with particle.I was able to take a picture and print the bytes/hex in the serial monitor(FF D8-FF D9).Now my struggle is to send the jpeg to the webserver.I have already set up the server, and i tested it with simple HTTP POST from the particle and data is sent fine.Now i need help writing these series bytes to the server.I have tried to write one byte at a time in for loop (as shown in the code below) but nothing is written to the server.The particle does connect to the server but nothing happens.I have looked into other people’s code, but didn’t work for me.Since i already got the bytes can anyone show me how to send them to the server, i am sure i am not playing with these bytes right.Thank you in advance.

byte incomingbyte;
int a=0x0000,j=0,k=0,count=0;                    
uint8_t MH,ML;
boolean EndFlag=0;
void setup()
{ 
  Serial.begin(9600);
  Serial1.begin(38400);
  SendResetCmd();
}

void loop()
{
 SendTakePhotoCmd();
 delay(1000);
 while(Serial1.available()>0)
      {
        incomingbyte=Serial1.read();

      }

 uint16_t jpglen = camFrameLength();
 
    //Prepare request
   String start_request = "";
   String end_request = "";
   start_request = start_request  + "--AaB03x" + "\n"
                                   + "Content-Disposition: form-data; name=\"picture\"; filename=\"cam.jpg\"" + "\n"
                                   + "Content-Type: image/jpeg" + "\n" + "Content-Transfer-Encoding: binary";
  end_request = end_request + "\n" + "--AaB03x--" + "\n";

  uint16_t extra_length;
  extra_length = start_request.length() + end_request.length();
  uint16_t len = jpglen + extra_length;

  byte a[32];
 
  //TCP connection
  if (client.connect(HOST, 80)) {
   Serial.println("Connected to the host");
  client.println("POST /api/images HTTP/1.1");
  client.println("Host: myapp.herokuapp.com");
  client.println("Accept: */*");
  client.println("Content-Type: multipart/form-data; boundary=AaB03x");
  client.print("Content-Length: ");
  client.println(len);
  client.println(start_request);
  client.println();

   //Start reading jpeg
  while(!EndFlag)
  {
     j=0;
     k=0;
     count=0;
     SendReadDataCmd();

     delay(25);
      while(Serial1.available()>0)
      {
           incomingbyte=Serial1.read();
           k++;
           if((k>5)&&(j<32)&&(!EndFlag))
           {
           a[j]=incomingbyte;
           if((a[j-1]==0xFF)&&(a[j]==0xD9))
           EndFlag=1;
           j++;
     count++;
           }
      }
  // Here is where i need help
      for(j=0;j<count;j++)
      {   if(a[j]<0x10)
          client.write(a[j]);
      }

  }
   //End the request when all is done
   client.print(end_request);
   client.println();
   client.stop();
  }
    delay(500);
while(1);
}

     void SendResetCmd()
{
      mySerial.write(0x56);
      mySerial.write((byte)0);
      mySerial.write(0x26);
      mySerial.write((byte)0);
}

//Send take picture command
void SendTakePhotoCmd()
{
      mySerial.write(0x56);
      mySerial.write((byte)0);
      mySerial.write(0x36);
      mySerial.write(0x01);
      mySerial.write((byte)0);  
}

//Read data
void SendReadDataCmd()
{
      MH=a/0x100;
      ML=a%0x100;
      mySerial.write(0x56);
      mySerial.write((byte)0);
      mySerial.write(0x32);
      mySerial.write(0x0c);
      mySerial.write((byte)0); 
      mySerial.write(0x0a);
      mySerial.write((byte)0);
      mySerial.write((byte)0);
      mySerial.write(MH);
      mySerial.write(ML);   
      mySerial.write((byte)0);
      mySerial.write((byte)0);
      mySerial.write((byte)0);
      mySerial.write(0x20);
      mySerial.write((byte)0);  
      mySerial.write(0x0a);
      a+=0x20;                           
}
1 Like

If you found a solution that sends some arbitrary bytes and it works for them, the same solution will work for you too if you just replace their arbitrary bytes with yours, I'd guess :wink:

This thread has a nice code to look at
Sending large data off Photon using TCPClient

1 Like

Thanks @ScruffR This could be a good starting point.

client.write() returns -1 . I used the same code as in the link, (i just had to plug in my server name ) but client.write() returns -1 constantly (falls in this block "ERROR write failed %d"). I am not sure whats wrong.Here is my code

#define HOST "myapp.herokuapp.com"
byte buffer[1024];
int bufOffset = 0;
long dataSize = 1024 * 1024;
long dataSent = 0;
byte startByte = 0;
byte nextByte = 0;

TCPClient client;
int port = 80;


enum { STATE_CONNECT, STATE_FILL_BUFFER, STATE_WRITE };

int state = STATE_CONNECT;

void setup() {
    Serial.begin(9600);
}

void loop() {
    switch(state) {
      case STATE_CONNECT:
        if (client.connect(HOST, port)) {
            dataSent = 0;
            nextByte = startByte++;
            state = STATE_FILL_BUFFER;
        }
        else {
            Serial.println("ERROR failed to connect");
            delay(5000);
        }
        break;

      case STATE_FILL_BUFFER:
        for(int ii = 0; ii < sizeof(buffer); ii++) {
            buffer[ii] = nextByte++;
        }
        bufOffset = 0;
        state = STATE_WRITE;
        // Fall through

      case STATE_WRITE:
        int requestSize = sizeof(buffer) - bufOffset;

        int count = client.write(&buffer[bufOffset], requestSize);
        if (count == -16) {
          
            delay(10);
        }
        else
        if (count < 0) {
            Serial.printlnf("ERROR write failed %d", count);
            client.stop();
            state = STATE_CONNECT;
            delay(1000);
        }
        else {
          
            bufOffset += count;
            if (bufOffset >= sizeof(buffer)) {
                // Done sending this buffer
                dataSent += sizeof(buffer);
                if (dataSent >= dataSize) {
                    // Sent all of the buffers for this connection
                    Serial.printlnf("SUCCESS %ld bytes sent", dataSent);
                    client.stop();
                    state = STATE_CONNECT;
                }
                else {
                    // Load the buffer with data again
                    state = STATE_FILL_BUFFER;
                }
          }
          else {
            //Serial.printlnf("sent count=%d", count);
          }
        }
        break;
    }
}

Is the device an Electron? You probably need to reduce the size of buffer to 512 bytes. Maybe 256.

Yes it is Electron.Let me try to do that.Thanks rickkas.

That didn’t work unfortunately , still returning -1. I changed it even down to 32 .

byte buffer[32];
long dataSize = 32 * 32;

I have been playing with Linksprite serial camera and electron particle. I can take a picture but i am still struggling sending that jpeg to the server.I built a simple Node js web app/server( deployed to heroku) to receive the image.When i upload the image with Curl the file get uploaded fine but when i upload from an electron i get an error at=error code=H13 desc="Connection closed without response" which the error is explained here. In short it seems like the socket closes before it receives anything.int data_sent = client.write(&buffer[256], sizeof(buffer)); returns/prints 256 for about 5 seconds and then starts spitting out -1 .So right after the server throws a H13 error i start getting -1 on serial Monitor.Since Curl can upload the file just fine i know the problem is on Particle side.Anybody that can guide me in the right direction i would appreciate.Thanks.Here is my code

    byte incomingbyte;
    int a=0x0000,j=0,k=0,count=0;                    
    uint8_t MH,ML;
    boolean EndFlag=0;
    void setup()
    { 
      Serial.begin(9600);
      Serial1.begin(38400);
      SendResetCmd();
    }
    
    void loop()
    {
     SendTakePhotoCmd();
     delay(1000);
     while(Serial1.available()>0)
          {
            incomingbyte=Serial1.read();
    
          }
        //Prepare request
       String start_request = "";
       String end_request = "";
       start_request = start_request  + "--AaB03x" + "\n"
                                       + "Content-Disposition: form-data; name=\"picture\"; filename=\"cam.jpg\"" + "\n"
                                       + "Content-Type: image/jpeg" + "\n" + "Content-Transfer-Encoding: binary";
      end_request = end_request + "\n" + "--AaB03x--" + "\n";
    
    
      byte a[256];
     
      //TCP connection
      if (client.connect(HOST, 80)) {
       Serial.println("Connected to the host");
      client.println("POST /api/images HTTP/1.1");
      client.println("Host: myapp.herokuapp.com");
      client.println("Accept: */*");
      client.println("Content-Type: multipart/form-data; boundary=AaB03x");
      client.println(start_request);
      client.println();
    
       //Start reading jpeg
      while(!EndFlag)
      {
         j=0;
         k=0;
         count=0;
         SendReadDataCmd();
    
         delay(25);
          while(Serial1.available()>0)
          {
               incomingbyte=Serial1.read();
               k++;
               if((k>5)&&(j<256)&&(!EndFlag))
               {
               a[j]=incomingbyte;
               if((a[j-1]==0xFF)&&(a[j]==0xD9))
               EndFlag=1;
               j++;
         count++;
               }
          }
       //write it to the server
        int data_sent = client.write(&buffer[256], sizeof(buffer)); 
      }
       //End the request when all is done
       client.print(end_request);
       client.println();
       client.stop();
      }
        delay(500);
    while(1);
    }

You can stick with that one thread since there is not really anything that different to your original problem.

From the code above…i have improved ,now i get a clean server log statement at=info method=POST path="/api/binary" host=myapp.herokuapp.com request_id=d9aa4bc9-e53a-4644-9f1e-b1e806a247fb fwd="176.83.209.31" dyno=web.1 connect=0ms service=22ms status=200 bytes=229 No errors.But in the route i am debugging the request body like so (console.log(request.body)); and this returns undefined which is a sign a request was not understood or formated properly. Looking in my code above i don’t see anything wrong maybe somebody can point it out something?

I think the empty client.println() should be before the client.println(start_request). The empty println marks the end of the HTTP header, and the start_request should actually be part of the body data, because it’s a multipart/form-data body.

1 Like

Yes you are right and i had like that before and just tried again.When i put it before client.println(start_request). the request doesn’t hit the server at all.

Follow up on my previous comment…Now it does hit the server but the request object is still undefined which still means there is something wrong with my Http request.

I finally got it to work and sent my first jpeg file to my web app. I just needed to re-format my http headers and pass the right content length length = start_request.length +end_request.length + (jpeg_length * byte_array_size) In my case byte array size was 32.

3 Likes

Hi @sparkz19
I m going to buy the same cam you use for your projet and I am totally a newbie with Photon.
Could you please publish your updated code?
Thanks in advance

1 Like
 void setup() {
    Serial.begin(9600);
    Serial1.begin(38400);

  SendResetCmd();
   delay(4000);
  SendTakePhotoCmd();
  delay(1000);
  uint16_t jpglen = camFrameLength();


      byte a[32];
      Serial.println(jpglen);
      String end_request = "";
    
    if (client.connect(HOST,80)) {
            
             String start_request = "";

             start_request = start_request  + "--AaB03x" + "\r\n"
                                     + "Content-Disposition: form-data; name=picture; filename=cam.jpg" + "\r\n"
                                     + "Content-Type: image/jpeg" + "\r\n" + "Content-Transfer-Encoding: binary" + "\r\n"+ "\r\n";
            end_request = end_request +  "\r\n--AaB03x--\r\n";
            uint16_t len = start_request.length() + end_request.length()+ (jpglen*32);
            client.println("POST /api/images HTTP/1.1");
            client.println("Host: seaty.herokuapp.com");
            client.println("Accept: */*");
            client.println("Content-Type: multipart/form-data; boundary=AaB03x");
            client.print("Content-Length: ");
            client.println(len);
            client.println();
            client.print(start_request);

          while(Serial1.available()>0)
           {
             incomingbyte=Serial1.read();

           }

      while(!EndFlag)
     {
        j=0;
        k=0;
        count=0;
        SendReadDataCmd();

        delay(25);
         while(Serial1.available()>0)
         {
              incomingbyte=Serial1.read();
              k++;
              if((k>5)&&(j<32)&&(!EndFlag))
              {
              a[j]=incomingbyte;
              if((a[j-1]==0xFF)&&(a[j]==0xD9))
               EndFlag=1;
               j++;
               count++;
              }
         }

        int buffer_size = sizeof(a);

        int coun = client.write(a,buffer_size);
        Serial.println(coun);
     }

              delay(1000);

         client.print(end_request);

          client.stop();
        Serial.println("stopping now");
    }

}
1 Like

Big thanks for sharing the codes. I am quite new to this community and have some simple questions regarding the codes:

  1. It seems that the setup() method alone can finish uploading the jpg file to the server. If I want to periodically take snaps (like once per hour), can you give me some suggestions on how to construct the loop() and modify the setup()?

  2. How to determine the camFrameLength()?

Thanks a lot.

Looking for a way to send an image from an Electron to a server online.

Do you think your code would work just fine for sending data via the Electron instead of a Photon?

Also what type of server were you sending the images to?

Any help would be appreciated!

Have you ever found a way to do this? I’m also very interested in this, but so far can’t find much helpful information on it.

So far I think this camera and library would be the best way to go about it since it has a nice up to date library for creating small or large images.

https://www.4dsystems.com.au/product/uCAM_III/

I did find a few ways to upload images from an SD card that worked so all we need to do have this camera save the pictures to an SD card and then push that image file to an FTP server using the code we already have.

You should buy the camera and do some testing for us :slight_smile:

Also, 4D Systems has a good forum with product engineers on there to help with questions or issues should they come up which is always a good thing.