Arduino 处理客户端无法将文件上传到 PHP 服务器

Arduino Processing client fails to upload file to PHP server

背景 我想要压力传感器(它们正在工作)触发内置摄像头并在猫睡觉时拍照,上传照片并通过电子邮件发送给我,这样我就可以去网站上查看实时图像。

PHP 服务器 我在这个结构的根部有一个 php server running 127.0.0.1:8080

 NetworkedCat -->
                  data --> script-cat.php
                  index.html 
                  NetworkedCat.pde 
                  img.jpg
                  save2web.php
                  swiftmailer --> libs, etc

在浏览器上测试,save2web.phpcat-script.php 正常,即脚本正在上传和发送电子邮件。

Arduino

Arduino 应用程序应执行以下操作:

  1. 接收来自压力传感器的输入
  2. 验证是否超过阈值
  3. 使用内置相机拍照
  4. 上传图片到网站
  5. 发送邮件通知上传

压力传感器()也在读取和打印,阈值已经校准。

但是 NetworkedCat.pde 不是由串行事件触发的。

请注意:

Arduino Processing 在另一个 port 80 打开 localhost,因为 php server8080.

上工作

如果我缩短处理代码,只测试图像捕获和上传,它就可以工作。因此,该错误必须与系列事件有关。

为什么下面的处理代码不起作用?

/*Serial String reader
Context: Arduino

Reads in a string of characters until it gets a linefeed (ASCII 10).
then converts the string into a number
*/

import processing.serial.*;
import processing.video.*;
import processing.net.*;

Serial myPort;              //the serial port
float sensorValue = 0;      //the value form the sensor
float prevSensorValue = 0;  //previous value from the sensor
int threshold = 200;        //above this number, the cat is on the mat

int currentTime = 0;       //the current time as a single number
int lastMailTime = 0;      //last minute you sent a mail
int mailInterval = 60;     //minimum seconds betweeen mails
String mailUrl = "cat-script.php";
int lastPicture = 0;       //last minute you sent a picture
int lastPictureTime = 0;   //last minute you sent a picture
int pictureInterval = 10;  //minimum seconds between pictures

Capture myCam;            //camera capture library instance
String fileName = "img.jpg"; //file name for the picture

//location on your server for the picture script:
String pictureScriptUrl = "save2web.php";
String boundary = "----H4rkNrF"; //string boundary for the post request

Client thisClient;        //instance for the net library


//float xPos = 0;             //horizontal position of the graph
//float lastXPos = 0;         //previous horizontal position  



void setup(){
  size(400, 300);
  //list all the available serial ports
  println(Serial.list());

  myPort = new Serial(this, Serial.list()[7], 9600);

  //reads bytes into a buffer until you get a newline (ASCII 10);
  myPort.bufferUntil('\n');

  //set initial background and smooth drawing:
  background(#543174);
  smooth();
  //for a list of cameras on your computer, use this line:
  println(Capture.list());

  //use the default camera for capture at 30 fps
  myCam = new Capture(this, width, height, 30);
  myCam.start();
}

void draw(){
  //make a single number fmor the current hour, minute, and second
  currentTime = hour() * 3600 + minute() * 60 + second();

  if (myCam.available() == true) {
    //draw the camera image to the screen;
    myCam.read();
    set(0, 0, myCam);

    //get the time as a string
    String timeStamp = nf(hour(), 2) + ":" + nf(minute(), 2)
    + ":" + nf(second(), 2) + "   " + nf(day(), 2) + "-"
    + nf(month(), 2) + "-" + nf(year(), 4);

    //draw a dropshadow for the time text:
    fill(15);
    text(timeStamp, 11, height - 19);
    //draw the main time next
    fill(255);
    text(timeStamp, 10, height - 20);
  }
}

void serialEvent (Serial myPort){
  //get the ASCII string
  String inString = myPort.readStringUntil('\n');

  if (inString != null){
    //trim off any whitespace:
    inString = trim(inString);
    //convert to an int and map to the screen height
    sensorValue = float(inString);
    //println(sensorValue);
    sensorValue = map(sensorValue, 0, 1023, 0, height);
    println(sensorValue);

    if (sensorValue > threshold){
      if(currentTime - lastPictureTime > pictureInterval){
        PImage thisFrame = get();
        thisFrame.save(fileName);
        postPicture();
        lastPictureTime = currentTime;
      }
      //if the last reading was less than the threshold
      //then the cat just got on the mat
      if(prevSensorValue <= threshold){
        println("Cat is on the mat.");
        sendMail();
      }
    }
    else{
      //if the sensor value is less than the threshold,
      //and the previous value was greater, then the cat
      //just left the mat
      if (prevSensorValue > threshold){
        println("Cat is not on the mat.");
      }
    }
    //save the current value for the next time
    prevSensorValue = sensorValue;
  }
}


void sendMail(){
  //how long has passed since the last mail
  int timeDifference = currentTime - lastMailTime;

  if( timeDifference > mailInterval){
    String[] mailScript = loadStrings(mailUrl);
    println("results from mail script:");
    println(mailScript);

    //save the current minute for next time
    lastMailTime = currentTime;
  }
}

编辑:

通过排除,bug在最后一个函数中,但我还没找到:

void postPicture(){
 //load the saved image into an array of bytes
  byte[] thisFile=loadBytes(fileName);


//open a new connection to the server
 thisClient = new Client(this, "localhost", 80);

//make an HTTP POST request:
thisClient.write("POST " + pictureScriptUrl + " HTTP/1.1\n");

thisClient.write("Host: localhost\n");

//tell the server you're sending the POST in multiple parts
//and send a unique string that will delineate the parts
thisClient.write("Content-Type: multipart/form-data; boundary=");

thisClient.write(boundary + "\n");


//form the beginning of the request
String requestHead ="--" + boundary + "\n";

requestHead +="Content-Disposition: form-data; name=\"file\"; ";
requestHead += "filename=\"" + fileName + "\"\n";
requestHead +="Content-Type: image/jpeg\n\n";


//form the end of the request
String tail="\n\n--" + boundary + "--\n";


//calculate and send the length of the total request
//including the head of the request, the file, and the tail
int contentLength = requestHead.length() + thisFile.length + tail.length();

 thisClient.write("Content-Length: " + contentLength + "\n\n");
 //send the header of the request, the file and the tail
 thisClient.write(requestHead);
 thisClient.write(thisFile);
 thisClient.write(tail);
 }

这是正在提出的问题:

java.lang.NullPointerException
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at    javax.imageio.stream.FileCacheImageOutputStream.close(FileCacheImageOutputStream.java:238)
at com.sun.imageio.stream.StreamCloser$CloseAction.performAction(StreamCloser.java:130)
at com.sun.imageio.stream.StreamCloser.run(StreamCloser.java:74)
at java.lang.Thread.run(Thread.java:745)

加上一个 Not a Number 异常:

sensorValue = map(NaN, 1023, 0, height);

我的系统是Unix。

最好在 Arduino 特定版本的堆栈交换上问这个问题。

我的建议让Arduino Processing拍下(猫的)照片。并让它上传图片到 PHP 网络应用程序。

然后 PHP 网络应用程序应该接收文件上传(图片)并发送电子邮件给那些喜欢通过电子邮件接收它的人。

看来你是 运行 端口 8080 上的 PHP 服务器,那么 Arduino Processing 应用程序也需要连接到该端口!所以更新你的代码,让客户端连接到服务器:

Arduino Processing(客户端)需要知道 PHP 服务器在网络上的位置。所以它需要知道服务器的 DNS 名称或 IP 地址。所以在下面的代码中更正字符串 "name-or-ip"

//open a new connection to the server
thisClient = new Client(this, "name-or-ip", 8080);

提示: 如果 Arduino Processing 运行 在与 PHP 服务器相同的计算机上,则 "localhost" 将用作服务器连接.

String mailUrl 应该包括整个字符串:"http://127.0.0.1:8080/cat-script.php",而不仅仅是相对于 root 目录的脚本位置 cat-script.php

此外,save2web.php 脚本中有一个错误 - 此问题中没有,它阻止了图像的上传。 move_uploaded_file($fileTempName, $path.fileName); 没有包含 ".fileName")

现在一切正常。