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.php
和 cat-script.php
正常,即脚本正在上传和发送电子邮件。
Arduino
Arduino 应用程序应执行以下操作:
- 接收来自压力传感器的输入
- 验证是否超过阈值
- 使用内置相机拍照
- 上传图片到网站
- 发送邮件通知上传
压力传感器()也在读取和打印,阈值已经校准。
但是 NetworkedCat.pde
不是由串行事件触发的。
请注意:
Arduino Processing 在另一个 port 80
打开 localhost
,因为 php server
在 8080
.
上工作
如果我缩短处理代码,只测试图像捕获和上传,它就可以工作。因此,该错误必须与系列事件有关。
为什么下面的处理代码不起作用?
/*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"
)
现在一切正常。
背景 我想要压力传感器(它们正在工作)触发内置摄像头并在猫睡觉时拍照,上传照片并通过电子邮件发送给我,这样我就可以去网站上查看实时图像。
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.php
和 cat-script.php
正常,即脚本正在上传和发送电子邮件。
Arduino
Arduino 应用程序应执行以下操作:
- 接收来自压力传感器的输入
- 验证是否超过阈值
- 使用内置相机拍照
- 上传图片到网站
- 发送邮件通知上传
压力传感器()也在读取和打印,阈值已经校准。
但是 NetworkedCat.pde
不是由串行事件触发的。
请注意:
Arduino Processing 在另一个 port 80
打开 localhost
,因为 php server
在 8080
.
如果我缩短处理代码,只测试图像捕获和上传,它就可以工作。因此,该错误必须与系列事件有关。
为什么下面的处理代码不起作用?
/*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"
)
现在一切正常。