Send jpg file to webserver via MultiPart

Hi all,

I'm currently implementing a weather station for our model flying club.

I'm using a

  • Arduino MEGA
  • weatherPiArduino shield with their weather station
  • cc3000 Wifi shield with SD card
  • two Arducam mini with OV5642.

There are three major parts of my programme

  1. the two cameras take jpg images and store them to a SD card
  2. Weather data is collected and directly posted to a MySQL database on our webserver
  3. The jpg files are uploaded to the website to be displayed (every 20 minutes as long as light is available)

As we have no fixed line internet at the club house, we are using a 3G wires router to connect to the internet.

So far so good.

Item 1 and 2 are done and working fine. But I have my problems with item 3.

I have searched the web and found some examples, but I could not get them working.

I get the message that the file was sent, but I cannot see the file on the webserver. If I use the same php on the server using a html file to POST the jpg file is uploaded.

Please see the sketch and the PHP below, maybe you can see what is going wrong here.

Many thanks!!

#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>
#include <string.h>
#include "utility/debug.h"
#include<stdlib.h>
#include <SD.h>

// Define CC3000 chip pins
#define ADAFRUIT_CC3000_IRQ 3
#define ADAFRUIT_CC3000_VBAT 5
#define ADAFRUIT_CC3000_CS 10

// WiFi network (change with your settings !)
#define WLAN_SSID "mywirelessnetwork"
#define WLAN_PASS "mypassword"
#define WLAN_SECURITY WLAN_SEC_WPA2


// Create CC3000 instances
// WIFi setup
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,SPI_CLOCK_DIV2);
Adafruit_CC3000_Client client;

char filename[14] = "CAM1.jpg";
int i = 0;
int keyIndex = 1;
int port = 80; //Server Port 
uint32_t MANip = 0;

void setup() {

  Serial.begin(115200);

  // Initialise the module
  Serial.println(F("\nInitializing..."));
  if (!cc3000.begin()){
    Serial.println(F("Couldn't begin()! Check your wiring?"));
    while(1);
  }


  // Connect to WiFi network
  cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);
  Serial.println(F("Connected!"));

  // Display connection details
  Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP()){
    delay(100);
  }
  Serial.println("Ready");
 Serial.println("-------");

 //Get MAN IP address

  getMANip();


  // Prepare HTTP request
  String start_request = "";
  String end_request = "";
  start_request = start_request + "\n" + "--AaB03x" + "\n" + "Content-Disposition: form-data; name=\"fileToUpload\"; filename="+filename+"\n" + "Content-Type: file" + "\n" + "Content-Transfer-Encoding: binary" + "\n" + "\n";
  end_request = end_request + "\n" + "--AaB03x--" + "\n";



  //Initialise SD Card
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  } 
  Serial.println("initialization of SD done.");
 
 File myFile = SD.open("CAM1.jpg");
  uint16_t jpglen = myFile.size();
  uint16_t extra_length;
  extra_length = start_request.length() + end_request.length();
  uint16_t len = jpglen + extra_length;

  // Set up TCP connection with web server
  client = cc3000.connectTCP(MANip, port);


  
  if (client.connected()) {
    Serial.println("Start uploading...");

    client.println(F("POST /~modelavi/plugins/upload.php HTTP/1.1"));

    client.println(F("Host: www.modelaviationnorthland.co.nz"));
    client.println(F("Content-Type: multipart/form-data; boundary=AaB03x"));
    client.print(F("Content-Length: "));
    client.println(len);
    client.println(start_request);

    Serial.println(F("Host: www.modelaviationnorthland.co.nz"));
    Serial.println(F("Content-Type: multipart/form-data; boundary=AaB03x"));
    Serial.print(F("Content-Length: "));
    Serial.println(len);
    Serial.println(start_request);
  
 if (myFile) {
  byte clientBuf[32];
  int clientCount = 0;

  while(myFile.available())
  {
    clientBuf[clientCount] = myFile.read();
    clientCount++;

    if(clientCount > 31)
    {
      client.write(clientBuf,32);
      clientCount = 0;
    }
  }
  if(clientCount > 0) client.write(clientBuf,clientCount);

  client.print(end_request);
  client.println();
  }
  else{
       Serial.println("File not found");
      }
  }    
  else{
    Serial.println("Web server connection failed");
  }
 
  myFile.close();  
  client.close();
  
  Serial.println("done...");

 
}

void loop() {



delay(10000);

}


void getMANip(){
#ifndef CC3000_TINY_DRIVER
  /* Try looking up www.modelaviationnorthland.co.nz */
    //Serial.print(F("www.modelaviationnorthland.co.nz -> "));
  while  (MANip  ==  0)  {
    if  (!  cc3000.getHostByName("www.modelaviationnorthland.co.nz", &MANip))  {
      //Serial.println(F("Couldn't resolve!"));
    }
    delay(500);
  }  
  //cc3000.printIPdotsRev(MANip);
#endif
}

PHP file

<?php
$target_dir = "/home/modelavi/public_html/images/weathercam/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file); 
echo("Done");
?>

Cheers
Andreas

What is that PHP file supposed to do with the POSTed data? Nothing that I can see...

Hi Paul,
The posted file gets moved from temp to the target folder with the move_uploaded_file() function.

The posted file gets moved from temp to the target folder with the move_uploaded_file() function.

Is that a standard function? I don't recognize it.

How do the files get in the temp folder? I don't see anything that makes use of the POSTed data.

Hi Paul,
have a look here.

When you remove the checks, that's what is left.

<?php $target_dir = "/home/modelavi/public_html/images/weathercam/"; $target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]); move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file); ?>

AndreasGabler:
Hi all,

I'm currently implementing a weather station for our model flying club.

I'm using a

  • Arduino MEGA
  • weatherPiArduino shield with their weather station
  • cc3000 Wifi shield with SD card
  • two Arducam mini with OV5642.

There are three major parts of my programme

  1. the two cameras take jpg images and store them to a SD card
  2. Weather data is collected and directly posted to a MySQL database on our webserver
  3. The jpg files are uploaded to the website to be displayed (every 20 minutes as long as light is available)

As we have no fixed line internet at the club house, we are using a 3G wires router to connect to the internet.

So far so good.

Item 1 and 2 are done and working fine. But I have my problems with item 3.

I have searched the web and found some examples, but I could not get them working.

I get the message that the file was sent, but I cannot see the file on the webserver. If I use the same php on the server using a html file to POST the jpg file is uploaded.

Please see the sketch and the PHP below, maybe you can see what is going wrong here.

Many thanks!!

#include <Adafruit_CC3000.h>

#include <ccspi.h>
#include <SPI.h>
#include <string.h>
#include "utility/debug.h"
#include<stdlib.h>
#include <SD.h>

// Define CC3000 chip pins
#define ADAFRUIT_CC3000_IRQ 3
#define ADAFRUIT_CC3000_VBAT 5
#define ADAFRUIT_CC3000_CS 10

// WiFi network (change with your settings !)
#define WLAN_SSID "mywirelessnetwork"
#define WLAN_PASS "mypassword"
#define WLAN_SECURITY WLAN_SEC_WPA2

// Create CC3000 instances
// WIFi setup
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,SPI_CLOCK_DIV2);
Adafruit_CC3000_Client client;

char filename[14] = "CAM1.jpg";
int i = 0;
int keyIndex = 1;
int port = 80; //Server Port
uint32_t MANip = 0;

void setup() {

Serial.begin(115200);

// Initialise the module
  Serial.println(F("\nInitializing..."));
  if (!cc3000.begin()){
    Serial.println(F("Couldn't begin()! Check your wiring?"));
    while(1);
  }

// Connect to WiFi network
  cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);
  Serial.println(F("Connected!"));

// Display connection details
  Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP()){
    delay(100);
  }
  Serial.println("Ready");
Serial.println("-------");

//Get MAN IP address

getMANip();

// Prepare HTTP request
  String start_request = "";
  String end_request = "";
  start_request = start_request + "\n" + "--AaB03x" + "\n" + "Content-Disposition: form-data; name="fileToUpload"; filename="+filename+"\n" + "Content-Type: file" + "\n" + "Content-Transfer-Encoding: binary" + "\n" + "\n";
  end_request = end_request + "\n" + "--AaB03x--" + "\n";

//Initialise SD Card
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization of SD done.");

File myFile = SD.open("CAM1.jpg");
  uint16_t jpglen = myFile.size();
  uint16_t extra_length;
  extra_length = start_request.length() + end_request.length();
  uint16_t len = jpglen + extra_length;

// Set up TCP connection with web server
  client = cc3000.connectTCP(MANip, port);

if (client.connected()) {
    Serial.println("Start uploading...");

client.println(F("POST /~modelavi/plugins/upload.php HTTP/1.1"));

client.println(F("Host: www.modelaviationnorthland.co.nz"));
    client.println(F("Content-Type: multipart/form-data; boundary=AaB03x"));
    client.print(F("Content-Length: "));
    client.println(len);
    client.println(start_request);

Serial.println(F("Host: www.modelaviationnorthland.co.nz"));
    Serial.println(F("Content-Type: multipart/form-data; boundary=AaB03x"));
    Serial.print(F("Content-Length: "));
    Serial.println(len);
    Serial.println(start_request);
 
if (myFile) {
  byte clientBuf[32];
  int clientCount = 0;

while(myFile.available())
  {
    clientBuf[clientCount] = myFile.read();
    clientCount++;

if(clientCount > 31)
    {
      client.write(clientBuf,32);
      clientCount = 0;
    }
  }
  if(clientCount > 0) client.write(clientBuf,clientCount);

client.print(end_request);
  client.println();
  }
  else{
      Serial.println("File not found");
      }
  }   
  else{
    Serial.println("Web server connection failed");
  }

myFile.close(); 
  client.close();
 
  Serial.println("done...");

}

void loop() {

delay(10000);

}

void getMANip(){
#ifndef CC3000_TINY_DRIVER
  /* Try looking up www.modelaviationnorthland.co.nz */
    //Serial.print(F("www.modelaviationnorthland.co.nz -> "));
  while  (MANip  ==  0)  {
    if  (!  cc3000.getHostByName("www.modelaviationnorthland.co.nz", &MANip))  {
      //Serial.println(F("Couldn't resolve!"));
    }
    delay(500);
  } 
  //cc3000.printIPdotsRev(MANip);
#endif
}




PHP file


<?php

$target_dir = "/home/modelavi/public_html/images/weathercam/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file);
echo("Done");
?>






Cheers
Andreas

Hi AndreasGabler. any updates on this one? Did you find the answer to your problem? I'm also trying to send a photo to my server. but when trying you code I got stuck in the "Start uploading..." as I have monitored it on the Serial monitor. Really need this one. Thanks

AndreasGabler,

I am doing a very similar thing with an esp8266 and Arducam , your code was very helpful in getting it working, there seem to be very little out there on posting files.

My program
-wakes every 270 seconds.
-check how bright it is

  • if dark goes back to deep sleep for 15min.
  • if not dark turns on the camera with a mosfet on its GND side of Cam
    -connects to the wireless
    -takes a picture and posts it to my home webserver from the cameras fifo.
    -goes back to deep sleep for 270 seconds.

I has been running for 6 days so far on 3AA rechargeable batteries(around 4volts).
-That a little over voltage on the esp8266 but the cam needs that to operate with drop across the mosfet and it seem to be doing fine.

Couple of things try:
-You have an extra line feed in the post change.
client.println(len); to client.print(len);
-Check the error log on webserver make sure you rights to write
-In the end, my error was that my post did not include the multipart stuff in the length, I was just putting the file length, your code appears fine for this, and that is what help me the most.
-you PHP code worked fine for me, I did my own to put date time stamp on bottom left of picture, and to save the last 12 snapshots

I will post my sketch once the batteries die on my test, and have a chance to clean up the code a bit.

My php code

<?php
$target_dir = "/var/www/gr/ac/pics/";
//$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
//move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file); 

for ($x = 12; $x >= 2; $x--) {
    copy($target_dir."a".($x-1).".jpg", $target_dir."a".$x.".jpg"); 
}
copy($target_dir."a1t.jpg", $target_dir."a1.jpg");

$fileName = $_FILES['fileToUpload']['name'];
$tmpName  = $_FILES['fileToUpload']['tmp_name'];
$LightLevel =$_REQUEST['LightLevel'];
$im = imagecreatefromjpeg($tmpName);

$date = new DateTime();
$ds= $date->format('Y-m-d g:i:s A');

$PEN_color1 = imagecolorallocate($im, 255, 255, 255);
$PEN_color2 = imagecolorallocate($im, 0, 0, 0);

imagefilledrectangle ( $im , 1 , 460 , 250, 480 , $PEN_color2 );
imagestring($im, 2, 10, 463,  $ds." LightReading=".$LightLevel , $PEN_color1);

imagejpeg($im, $target_dir."a1t.jpg", 95); 
imagedestroy($im);
echo("Done"); 
?>

View from chicken coop at dusk.jpg

My sketch referenced in previous post

//Hookup notes
// By James Eckert adapted form many sources from Arducam Examples and HTTP Post was fixed with code in forum question by AndreasGabler https://forum.arduino.cc/index.php?topic=348012.0
// For Use with ArduCAM_Mini_OV2640 
// Runs on 3AA Nickle Metal hydride It is over power on the ESP8266 but cam needs extra power going through Mosfet 
// Esp seems ok with higher voltage of course it is only on for about 30sec at a time
// ESP hookup
//   Standard ESP connection as well as  GPIO16--1K--RST  ( for Deep Sleep Control)
//   Light Sensor Vcc--1K--CDS-(A0)-1K--GND
// ArduCAM_Mini Cam hookup
//   CAM Power control GPIO5 to Gate of BS170 Mosfet, Arducam Gound to Drain and Source to Ground
//   SDA=GPIO0  SDL=GPIO2
//   CS=GPIO4  MOSI=GPIO13 SCK=GPIO14 MOS0=GPIO12
//Operation 
// -wakes every 270 seconds.
// -check how bright it is
// -if dark goes back to deep sleep for 15min.
// -if not dark turns on the camera with a mosfet on its GND side of Cam
// -connects to the wireless I connection fail go back to sleep
// -takes a picture and posts it to my home webserver from the cameras fifo.
// -goes back to deep sleep for 270 seconds.


#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

#include <Wire.h>
#include <ArduCAM.h>
#include <SPI.h>
#include "memorysaver.h"

// Enabe debug tracing to Serial port.
#define DEBUGGING

// Here we define a maximum framelength to 64 bytes. Default is 256.
#define MAX_FRAME_LENGTH 64

// Define how many callback functions you have. Default is 1.
#define CALLBACK_FUNCTIONS 1

// set GPIO4 as the slave select :
const int CS = 4;
int LightLevel=0;
int bfcnt=1;
int wfcnt=0;
const char* ssid = "YourSsid"; // Put your SSID here
const char* password = "YourKey"; // Put your PASSWORD here

ArduCAM myCAM(OV2640, CS);

void start_capture(){
  myCAM.clear_fifo_flag();
  Serial.println("Slight Pause");
  delay(3500);  //Give cam more time to adjust to light
  myCAM.start_capture();
}

void camCapture(ArduCAM myCAM){
  WiFiClient client ;

  uint8_t temp, temp_last;
  static int i = 0;
  static uint8_t first_packet = 1;
  byte buf[2048];
  uint32_t length = 0;
  length = myCAM.read_fifo_length();
  
  size_t len = myCAM.read_fifo_length();
  if (len >= 393216){
    Serial.println("Over size.");
    return;
  }else if (len == 0 ){
    Serial.println("Size is 0.");
    return;
  }
  
  myCAM.CS_LOW();
  myCAM.set_fifo_burst();
  SPI.transfer(0xFF);
 
  ////////////////////////////////
  // Prepare HTTP Post request
  ////////////////////////////////

 if (client.connect("10.16.10.11", 8980)) {
    Serial.println("Start uploading...");
  String start_request = "";
  String end_request = "";
  String filename="test.jpg";
  
  start_request = start_request + "\n" + "--AaB03x" + "\n" + "Content-Disposition: form-data; name=\"fileToUpload\";filename="+filename+"\n" + "Content-Type: file" + "\n" + "Content-Transfer-Encoding: binary" + "\n" + "\n";
  end_request = end_request + "\n" + "--AaB03x--" + "\n";
  len=len+start_request.length();
  len=len+end_request.length();
  client.println("POST /tempgr/upload.php?LightLevel="+String(LightLevel)+"  HTTP/1.1");
  client.println(F("Host: 10.16.10.11"));
  client.println(F("Content-Type: multipart/form-data; boundary=AaB03x"));
  client.print(F("Content-Length: "));
  client.println(String(len));
  client.print(start_request);

  Serial.println(F("POST /tempgr/upload.php HTTP/1.1"));
  Serial.println(F("Host: 10.16.10.11"));
  Serial.println(F("Content-Type: multipart/form-data; boundary=AaB03x"));
  Serial.print(F("Content-Length: "));
  Serial.println(String(len));
  Serial.print(start_request);
  Serial.println("#################################################");
    
//////////////////////////////////////

while ( (temp != 0xD9) | (temp_last != 0xFF)) {
   //Serial.println(i,DEC);
   // yield();
    temp_last = temp;
    temp = SPI.transfer(0x00);
    //Write image data to buffer if not full
    // yield();
    if (i < 2048)
    {
      buf[i++] = temp;
    }
    else
    {
      if (first_packet == 1)
      {
        Serial.print("Step One:");
        Serial.println(i,DEC);
        client.write((char*)buf, 2048);
        first_packet = 0;
       // yield();
      }
      else
      {
        Serial.print("Step Two:");
        Serial.println(i,DEC);
        client.write((char*)buf, 2048);
        //yield();
      }
      i = 0;
      buf[i++] = temp;
      }
  }
  //Write the remain bytes in the buffer
    Serial.print("leftover:");
    Serial.println(i,DEC);
  
  if (i > 0)
  {
    Serial.print("finish write last");
    Serial.println(i,DEC);
    client.write((char*)buf, i);
    i = 0;
    first_packet = 1;
  }
    Serial.print("leftover:");
    Serial.println(i,DEC);
  //////////////////////////////////////////////////////////////////////
  client.println(end_request);
  Serial.println(end_request);
  myCAM.CS_HIGH();
 }
}

void serverCapture(){
  start_capture();
  Serial.println("CAM Capturing");
  int total_time = 0;
  total_time = millis();
  while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
  total_time = millis() - total_time;
  Serial.print("capture total_time used (in miliseconds):");
  Serial.println(total_time, DEC);
  total_time = 0;
  Serial.println("CAM Capture Done!");
  total_time = millis();
  camCapture(myCAM);
  total_time = millis() - total_time;
  Serial.print("send total_time used (in miliseconds):");
  Serial.println(total_time, DEC);
  Serial.println("CAM send Done!");
  delay(500);
  digitalWrite(5, LOW);
  delay(1000);
  SleepyTime(270);
  }

void SleepyTime(int slsec ) {
  Serial.println("Time:"+String(millis()));
  Serial.println("Going to Sleep For:"+String(slsec));
  ESP.deepSleep(slsec * 1000000,WAKE_NO_RFCAL);
  //ESP.deepSleep(30 * 1000000,WAKE_NO_RFCAL);
}

void setup() {
  uint8_t vid, pid;
  uint8_t temp;
  Wire.begin(0,2);
  Serial.begin(115200);
  Serial.println("ArduCAM Post Start!");
  pinMode(5, OUTPUT);
  LightLevel = analogRead(A0);
  Serial.println("ADC:"+String(LightLevel));
  if ( LightLevel<350 ) {  // if it is to dark go back to sleep
    digitalWrite(5, LOW);
    SleepyTime(900);
  }
  digitalWrite(5, HIGH);   // Turn on cam Drives Mosfet connected to Cameras Ground (BS170 MOSFET N-CHANNEL)
  delay(200);
  // set the CS as an output:
  pinMode(CS, OUTPUT);
  // initialize SPI:
  SPI.begin();
  SPI.setFrequency(4000000); //8MHz
  //Check if the ArduCAM SPI bus is OK
  myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
  temp = myCAM.read_reg(ARDUCHIP_TEST1);
  if (temp != 0x55){
    Serial.println("SPI1 interface Error!");
    while(1);
  }

  //Check if the camera module type is OV2640
  myCAM.wrSensorReg8_8(0xff, 0x01);
  //myCAM.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
  //myCAM.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid);
  
  // if cam was used in lowpower/powerdown mode it needs to be cleared (I had server version of this sketch that uses it)
  // myCAM.clear_bit(ARDUCHIP_GPIO,GPIO_PWDN_MASK);  
  // myCAM.clear_bit(ARDUCHIP_TIM,FIFO_PWRDN_MASK);
  // myCAM.clear_bit(ARDUCHIP_TIM,LOW_POWER_MODE);
  
  //Change to JPEG capture mode and initialize the OV2640 module
  myCAM.set_format(JPEG);
  myCAM.InitCAM();
  myCAM.OV2640_set_JPEG_size(OV2640_640x480);
  myCAM.clear_fifo_flag();
  myCAM.write_reg(ARDUCHIP_FRAMES, 0x00);
  
  // Next 2 line seem to be needed to connect to wifi after Wake up
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
  yield();
  /////////////////////////
  // Connect to WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  //it connects faster with static IP
  IPAddress ip(10, 16, 10, 60);  
  IPAddress gw(10, 16, 10, 1);
  IPAddress sbnm(255, 255, 255, 0);
  WiFi.config(ip, gw, gw, sbnm); 
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {  // try to connect wifi for 6 sec then reset
      delay(250);
      Serial.print(".");
      wfcnt++;
        if (wfcnt >25 ){
          SleepyTime(270); ;  //Wifi not connecting stop wasting bat and sleep
        }
     }
    Serial.println("WiFi connected");
    Serial.println("");
    Serial.println(WiFi.localIP());
  serverCapture();
}

void loop() {  // should never hit the loop but if does it will go to sleep for 5 min and try agian.
  if ( millis()>500000 ){
    SleepyTime(270);
  }
  yield();
  delay(6000);
  
}