kevinzhang 发表于 2015-12-21 13:50:51

PM2.5采集器(支持微信查询)

本帖最后由 kevinzhang 于 2015-12-21 14:01 编辑

该终端设备采集办公室空气质量(包括:PM1、PM2.5、PM10)、温湿度、照明和噪声,并可通过微信公众号实时查询7个数据。

终端设备如下图:


微信查询结果如下图:


拓扑结构图如下图:

kevinzhang 发表于 2015-12-21 14:03:54

终端设备细节如下图:


kevinzhang 发表于 2015-12-21 14:06:55

Arduino Uno代码如下::lol

#include "Arduino.h"
#include "serialReadPMValue.h"
#include <DHT22.h>
#include <stdio.h>
#include <SPI.h>
#include <Ethernet.h>

// 数字PIN 3 --> LED 红
// 数字PIN 7 --> DHT22温湿度
// 数字PIN 9 --> 蜂鸣器
// 模拟PIN 0 --> 模拟声音
// 模拟PIN 3 --> LX1972环境光

uint16_t PM01Value= 0;// PM1.0
uint16_t PM2_5Value = 0;// PM2.5
uint16_t PM10Value= 0;// PM10
#define receiveDatIndex 32
uint8_t receiveDat;

#define DHT22_PIN 7
DHT22 myDHT22(DHT22_PIN);

int valLight = 0;// 光线Value
int valSound = 0;// 声音Value

byte mac[]   = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress server(116, 236, 162, 186);   // 项目服务器公网IP
IPAddress      ip(192, 168, 1, 76);   // 内网IP(该终端设备的内网IP)
EthernetClient client;

String myTempPM01= "";
String myTempPM25= "";
String myTempPM10= "";
String myTempLight = "";
String myTempSound = "";
String myTempTemp= "";
String myTempHumi= "";

void setup()
{
Serial.begin(9600);
Ethernet.begin(mac, ip);
pinMode(3, OUTPUT);
pinMode(9, OUTPUT);
}

void loop()
{
int length   = serialRead(Serial, receiveDat, receiveDatIndex, 5);
int checkSum = checkValue(receiveDat, receiveDatIndex);
if(length&&checkSum)
{
    PM01Value= transmitPM01(receiveDat);   //取PM1.0
    PM2_5Value = transmitPM2_5(receiveDat);//取PM2.5
    PM10Value= transmitPM10(receiveDat);   //取PM10
}
static unsigned long OledTimer = millis();
if (millis() - OledTimer >= 5000)
{
    OledTimer=millis();
   
    cDHT22();
   
    valLight = analogRead(3);   // 取光线Value
    valSound = analogRead(0);   // 取声音Value
   
    digitalWrite(3, HIGH);// LED点亮
    digitalWrite(9, HIGH);// 蜂鸣器鸣叫
    Serial.println("");

    myTempPM01= String(PM01Value);   // 将int转换成String
    myTempPM25= String(PM2_5Value);
    myTempPM10= String(PM10Value);
    myTempLight = String(valLight);
    myTempSound = String(valSound);
   
    Serial.println("PM01:" + myTempPM01 + "ug/m3, PM25:" + myTempPM25 + "ug/m3, PM10:" + myTempPM10 + "ug/m3");
    Serial.println("Temperature:" + myTempTemp + "C, Humidity:" + myTempHumi + "%");
    Serial.println("Light:" + myTempLight + ", Sound:" + myTempSound);
   
    if (client.connect(server, 80))   // 提交的项目服务器80端口
    {
      Serial.println("Connected");
      // HTTP请求,携带7个参数
      client.println("POST http://116.236.162.186/servlet/mypm?unoVar01=" + myTempPM01 + "&unoVar02=" + myTempPM25 + "&unoVar03=" + myTempPM10 + "&unoVar04=" + myTempTemp + "&unoVar05=" + myTempHumi + "&unoVar06=" + myTempLight + "&unoVar07=" + myTempSound + " HTTP/1.1");
      client.println("Host:116.236.162.186");
      client.println();
    }
    else
    {
      Serial.println("connection failed");
    }
    Serial.println();
    client.stop();
}

digitalWrite(3, LOW);
digitalWrite(9, LOW);
}

void cDHT22()
{
    DHT22_ERROR_t errorCode;
    errorCode = myDHT22.readData();
    if (errorCode == DHT_ERROR_NONE)
    {
      myTempTemp = String(myDHT22.getTemperatureC());//取温度
      myTempHumi = String(myDHT22.getHumidity());//取湿度
   }
}

kevinzhang 发表于 2015-12-21 14:11:09

本帖最后由 kevinzhang 于 2015-12-21 14:12 编辑

MySQL数据库,mypm库t01表结构如下图:

kevinzhang 发表于 2015-12-21 14:15:20

本帖最后由 kevinzhang 于 2015-12-21 14:18 编辑

项目服务器验证代码(成为微信开发者前验证用,Java代码,文件名wxtest.java):

import java.io.IOException;
import java.io.PrintWriter;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.util.Arrays;// 数据用来进行字符串排序
import org.apache.commons.codec.digest.DigestUtils;// 使用Apahce Commons Codec项目,完成SHA1加密

@WebServlet(urlPatterns = {"/wxtest"})
public class wxtest extends HttpServlet
{
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
      response.setContentType("text/html;charset=UTF-8");
      request.setCharacterEncoding("UTF-8");
      response.setCharacterEncoding("UTF-8");
      PrintWriter out = response.getWriter();
      
      String myToken      = "CO1drluxieGlUvoafl9THLawr2aspiAB";
      String mySignature= request.getParameter("signature");// 抓取微信服务器送来的4个参数
      String myTimestamp= request.getParameter("timestamp");
      String myNonce      = request.getParameter("nonce");
      String myEchostr    = request.getParameter("echostr");
      String encodeString = "";
      String finalString= "";
      
      if(mySignature==null||myTimestamp==null||myNonce==null||myEchostr==null)
      {
            System.out.println("There is at least one null in pararmeters.");
      }
      else
      {
            String[] myString = new String;
            myString = myToken;
            myString = myTimestamp;
            myString = myNonce;
            
            Arrays.sort(myString);// 通过数组,3个字符串按字典序排序
            encodeString = myString + myString + myString;
            finalString= DigestUtils.sha1Hex(encodeString);// 完成SHA1加密
      }
      
      if (mySignature.equals(finalString))// 加密后的字符串与微信传过来的signature字符串比较
      {
            System.out.println("same...");
            out.print(myEchostr);// 两者相同,则证明请求来自微信服务器,原样返回Echostr字符串
            out.close();
            System.out.println("Sent ok ...");
      }
      else
      {
            System.out.println("different...");
      }
    }
}

只需一次,通过验证后的公众号不需要再次验证。

kevinzhang 发表于 2015-12-21 14:21:00

服务器端,监听终端设备数据并写入数据库,代码如下:

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// MySQL connection package
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;

@WebServlet(urlPatterns = {"/mypm"})
public class mypm extends HttpServlet
{
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
      response.setContentType("text/html;charset=UTF-8");
      request.setCharacterEncoding("UTF-8");
      response.setCharacterEncoding("UTF-8");
      
      String myPm01 = request.getParameter("unoVar01");// 抓取7个参数
      String myPm25 = request.getParameter("unoVar02");
      String myPm10 = request.getParameter("unoVar03");
      String myTemp = request.getParameter("unoVar04");
      String myHumi = request.getParameter("unoVar05");
      String myLight = request.getParameter("unoVar06");
      String mySound = request.getParameter("unoVar07");
      
      Connection conn = null;
      Statement stmt = null;
      ResultSet rs1 = null;
      int i;
      String mySQL = "INSERT INTO t01 (tpm01, tpm25, tpm10, ttemp, thumi, tlight, tsound) VALUES('" +
                myPm01       + "','" +
                myPm25       + "','" +
                myPm10       + "','" +
                myTemp       + "','" +
                myHumi       + "','" +
                myLight      + "','" +
                mySound      + "')";
      try
      {
            conn = DriverManager.getConnection("jdbc:mysql://localhost/mypm?" +
                                 "user=root&password=15186okia");
            stmt = conn.createStatement();
            i = stmt.executeUpdate(mySQL);// 写入数据表
            System.out.println("inserting...");
      }
      catch (SQLException ex)
      {
            System.out.println("Error in connection: " + ex.toString());
            System.out.println("SQLException: " + ex.getMessage());
            System.out.println("SQLState: " + ex.getSQLState());
            System.out.println("VendorError: " + ex.getErrorCode());
      }
      
      System.out.println("Written...");
      System.out.println("PM 1: " + myPm01);
      System.out.println("PM2.5:" + myPm25);
      System.out.println("PM10: " + myPm10);
      System.out.println("Temperature:" + myTemp + "C");
      System.out.println("Humidity: " + myHumi + "%");
      System.out.println("Light: " + myLight);
      System.out.println("Sound: " + mySound);
      System.out.println("==");
    }
}

kevinzhang 发表于 2015-12-21 14:24:13

注意XML格式:

    <xml>
      <ToUserName><!]></ToUserName>
      <FromUserName><!]></FromUserName>
      <CreateTime><!]></CreateTime>
      <MsgType><!]></MsgType>
      <Content><!]></Content>
    </xml>

kevinzhang 发表于 2015-12-21 14:27:51

项目服务器回复微信服务器的查询(Java,即用户通过微信查询终端数据):

import java.io.IOException;
import java.io.PrintWriter;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.dom4j.*;
import org.dom4j.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;

@WebServlet(urlPatterns = {"/wxtest"})
public class wxtest extends HttpServlet
{
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
      response.setContentType("text/html;charset=UTF-8");
      request.setCharacterEncoding("UTF-8");
      response.setCharacterEncoding("UTF-8");
      PrintWriter out = response.getWriter();
               
      String myVal01 = ""; //7个变量对应7个参数
      String myVal02 = "";
      String myVal03 = "";
      String myVal04 = "";
      String myVal05 = "";
      String myVal06 = "";
      String myVal07 = "";
      
      Connection conn = null;// 涉及数据库打交道的变量
      Statement stmt = null;
      ResultSet rs1 = null;
      int i = 0;
      String mySQL = "SELECT * FROM t01 ORDER BY tid DESC LIMIT 1;"; // 从数据表里读取最后那条记录的SQL语句
      try
      {
            conn = DriverManager.getConnection("jdbc:mysql://localhost/mypm?" +
                                 "user=root&password=15186okia");
            stmt = conn.createStatement();
            rs1 = stmt.executeQuery(mySQL);
            
            while(rs1.next())
            {
                myVal01 = rs1.getString(2); //分别将获得的数据写入7个变量
                myVal02 = rs1.getString(3);
                myVal03 = rs1.getString(4);
                myVal04 = rs1.getString(5);
                myVal05 = rs1.getString(6);
                myVal06 = rs1.getString(7);
                myVal07 = rs1.getString(8);
            }
      }
      catch (SQLException ex)
      {
            System.out.println("Error in connection: " + ex.toString());
            System.out.println("SQLException: " + ex.getMessage());
            System.out.println("SQLState: " + ex.getSQLState());
            System.out.println("VendorError: " + ex.getErrorCode());
      }
      
      InputStreampostIn = request.getInputStream(); //从输入流获取微信服务器传过来的整个字符串
      
      try
      {
            SAXReader reader = new SAXReader();
            Document myDocument = reader.read(postIn); // 转成dom4j可以处理的格式
            Element root = myDocument.getRootElement(); // 从XML字符串内获取全部元素,组成一棵树
            Element myToUserName = root.element("ToUserName"); // 分别获取需要的值
            Element myFromUserName = root.element("FromUserName");
            Element myCreateTime = root.element("CreateTime");
            Element myMsgType = root.element("MsgType");
            Element myContent = root.element("Content");
            Element myMsgId = root.element("MsgId");
            String sToUserName = myToUserName.getText(); // 转成String类型
            String sFromUserName = myFromUserName.getText();
            String sCreateTime = myCreateTime.getText();
            String sMsgType = myMsgType.getText();
            String sContent = myContent.getText();
            String sMsgId = myMsgId.getText();
            
            if (sMsgType.equals("text") && sContent.equals("/??")) // 用户发来的是文本消息且是查询数据关键词吗?
            {
                long lCreateTime = System.currentTimeMillis()/1000L; // 消息创建的时间
                String mySendContent = "";
                // 以下手工封装回复文本消息的XML字符串
                mySendContent = "PM1:" + myVal01 + "ug/m3\nPM2.5:" + myVal02 + "ug/m3\nPM10:" + myVal03 + "ug/m3\n温度:" + myVal04 +
                        "℃\n湿度:" + myVal05 + "%\n亮度:" + myVal06 + "\n噪声:" + myVal07;
                String xmlString01 = "<xml>";
                String xmlString02 = "<ToUserName><!]></ToUserName>";
                String xmlString03 = "<FromUserName><!]></FromUserName>";
                String xmlString04 = "<CreateTime><!]></CreateTime>";
                String xmlString05 = "<MsgType><!]></MsgType>";
                String xmlString06 = "<Content><!]></Content>";
                String xmlString07 = "</xml>";
                String xmlAll = xmlString01 + xmlString02 + xmlString03 + xmlString04 + xmlString05 + xmlString06
                  + xmlString07;
                System.out.println(xmlAll);
                out.print(xmlAll); // 回复给微信服务器,由其转发给用户手机
                out.close();
            }
            System.out.println("== Done ==");
      }
      catch (DocumentException ex)
      {
            System.out.println("dom4j Document: " + ex.toString());
      }
}

老胖熊 发表于 2015-12-21 14:41:17

这个看着不错,微信现在很流行。

mikeliujia 发表于 2015-12-21 21:35:18

有个公网IP不错:lol

kevinzhang 发表于 2015-12-21 21:53:54

mikeliujia 发表于 2015-12-21 21:35 static/image/common/back.gif
有个公网IP不错

现在管得严,不容易搞到。

davidce 发表于 2015-12-21 22:31:35

公众号的回调和传感器数据的存储都可以在arduino 上实现

kevinzhang 发表于 2015-12-22 06:59:47

davidce 发表于 2015-12-21 22:31 static/image/common/back.gif
公众号的回调和传感器数据的存储都可以在arduino 上实现

Uno内存小,有点悬,也没法扩展,外部访问困难

yzhkpli 发表于 2015-12-26 17:11:29

求问楼主用的传感器都哪写啊。
温度用ds18B20?

一个湿度传感器
一个co2传感器
一个激光pm2.5传感器(攀藤G3?)
还有啥?
另外底板是在哪里可以买到呢?

kevinzhang 发表于 2015-12-27 18:17:16

yzhkpli 发表于 2015-12-26 17:11 static/image/common/back.gif
求问楼主用的传感器都哪写啊。
温度用ds18B20?



1, DFRduino UNO控制器(78元)
2. DFRobot Ethernet W5100网络板(98元)
3. IO扩展板 V7.1(55元)
4. DHT22温湿度传感器模块(65元)
5.MIC声音传感器(40元)
6.LX1972光传感器(30元)
7.数字蜂鸣器模块(15元)
8.食人鱼LED(10元)
9.PM2.5激光粉尘传感器(215元)

我特懒,这些都在DFrobot买的,其他店里兼容板子都可以完成同样的功能。
页: [1] 2
查看完整版本: PM2.5采集器(支持微信查询)