天天看點

arduino esp32 讀福申甲醛傳感器

arduino esp32 讀福申甲醛傳感器

    • 想法
    • 源代碼

想法

arduino庫豐富,幾行代碼即可完成需求描述。

缺點是不能Debug。

想持續監測甲醛變化。

使用杜邦線連接配接,需要将傳感器的輸出線焊接杜邦線做轉換。

杜邦線是一公一母。

源代碼

可以開啟軟AP,也可以連到無線路由器。

買到的UNO D1 R32 ,無線性能不好,距離路由器2米,信号強度都到-90多了。

這裡,将網絡改為AP。

#include <HTTPServer.hpp>
#include <HTTPRequest.hpp>
#include <HTTPResponse.hpp>
#include <WebsocketHandler.hpp>
#include <WiFi.h>

#define ESP_getChipId()   ((uint32_t)ESP.getEfuseMac())
#define MAX_CLIENTS 4

// http
using namespace httpsserver;
HTTPServer secureServer = HTTPServer();
void handleRoot(HTTPRequest * req, HTTPResponse * res);
char crc(String s);

int data = 0;
float value = 0;
String buffer = "";
String buffer2 = "";
String result;

class ChatHandler : public WebsocketHandler {
  public:
    static WebsocketHandler* create();
    void onClose();
};
ChatHandler* activeClients[MAX_CLIENTS];

void setup() {
  // Initialize the slots
  for (int i = 0; i < MAX_CLIENTS; i++) activeClients[i] = nullptr;

  Serial.begin(9600);
  Serial2.begin(9600);

  // wifi
  IPAddress ip(192, 168, 3, 1);
  IPAddress gw(192, 168, 3, 1);
  IPAddress mask(255, 255, 255, 0);
  WiFi.softAPConfig(ip, gw, mask);
  String chip_id = "ESP_" + String(ESP_getChipId());
  const char *ssid = chip_id.c_str();
  WiFi.softAP(ssid);

  // http
  ResourceNode * nodeRoot = new ResourceNode("/", "GET", &handleRoot);
  secureServer.registerNode(nodeRoot);
  // chat register
  WebsocketNode * chatNode = new WebsocketNode("/chat", &ChatHandler::create);
  secureServer.registerNode(chatNode);

  secureServer.start();

  //
}

void loop() {
  // 讀甲醛傳感器
  while (Serial2.available() > 0) {
    data = Serial2.read();
    Serial.println(data);

    buffer += (char)data;
    buffer2 += String(data, HEX) + " ";

  }  // while 0

  if (buffer.charAt(0) == 0xff && buffer.length() == 9) {
    // 驗證crc
    char crcValue = crc(buffer);
    if (crcValue == buffer.charAt(8))
      value = (float)(buffer.charAt(4) * 256 + buffer.charAt(5)) / 1000.0;
    else
      Serial.println("crc not equal");
    buffer = "";
    result = "結果:" + String(value) + ",資料:" + buffer2;
    buffer2 = "";
  }  // if 1

  if (buffer.length() >= 9)
    buffer = "";

  Serial2.flush();

  // web
  secureServer.loop();

  // 發送資料
  for (int i = 0; i < MAX_CLIENTS; i++) {
    if (activeClients[i] != nullptr) {
      activeClients[i]->send(result.c_str(), WebsocketHandler::SEND_TYPE_TEXT);
    }
  }

  // delay
  delay(100);

  // loop
}


void handleRoot(HTTPRequest * req, HTTPResponse * res) {
  // Status code is 200 OK by default.
  // We want to deliver a simple HTML page, so we send a corresponding content type:
  res->setHeader("Content-Type", "text/html");

  // The response implements the Print interface, so you can use it just like
  // you would write to Serial etc.
  res->println("<!DOCTYPE html>");
  res->println("<html  en\">");
  res->println("<head><meta charset=\"UTF-8\"><title>Hello World!</title></head>");
  res->println("<body>");
  res->println("<h3>甲醛讀數</h3>");

  res->print("<p>伺服器已運作 ");
  res->print((int)(millis() / 1000 / 60), DEC);
  res->println(" 分.</p>");

  res->println("<p>數值(毫克/立方米.): </p>");
  res->print("<div id=\"id_value\">");
  res->print(value, DEC);
  res->println("</div>");

  res->println("</body>");
  res->println("</html>");

  res->print(
    "    <script type=\"text/javascript\">\n"
    "        const divOut =  document.getElementById(\"id_value\");\n"
    "\n"
    "        class Chat {\n"
    "            constructor() {\n"
    "                this.connecting = false;\n"
    "                this.connected = false;\n"
    "                this.ws = null;\n"
    "            };\n"
    "            connect() {\n"
    "                if (this.ws === null) {\n"
    "                    this.connecting = true;\n"
    "                    this.ws = new WebSocket(\"ws://\" + document.location.host + \"/chat\");\n"
    "                    this.ws.onopen = e => {\n"
    "                        this.connecting = false;\n"
    "                        this.connected = true;\n"
    "                    };\n"
    "                    this.ws.onmessage = e => {\n"
    "                        divOut.innerHTML =\"<p>\"+e.data+\"</p>\";\n"
    "                        //console.log(e.data);\n"
    "                    }\n"
    "                    this.ws.onclose = e => {\n"
    "                        this.disconnect();\n"
    "                    }\n"
    "                }\n"
    "            };\n"
    "            disconnect() {\n"
    "                if (this.ws !== null) {\n"
    "                    this.ws.close();\n"
    "                    this.ws = null;\n"
    "                }\n"
    "                if (this.connected) {\n"
    "                    this.connected = false;\n"
    "                }\n"
    "            }};\n"
    "        let chat = new Chat();\n"
    "        if (!chat.connected && !chat.connecting) {\n"
    "                chat.connect();\n"
    "            }\n"
    "    </script>\n"
  );
}

WebsocketHandler * ChatHandler::create() {
  Serial.println("Creating new chat client!");
  ChatHandler * handler = new ChatHandler();
  for (int i = 0; i < MAX_CLIENTS; i++) {
    if (activeClients[i] == nullptr) {
      activeClients[i] = handler;
      break;
    }
  }
  return handler;
}

// When the websocket is closing, we remove the client from the array
void ChatHandler::onClose() {
  for (int i = 0; i < MAX_CLIENTS; i++) {
    if (activeClients[i] == this) {
      activeClients[i] = nullptr;
    }
  }
}

// CRC計算
char crc(String s) {
  int sum = 0;
  for (int i = 1; i < s.length() - 1; i++)
    sum += s[i];
  int value = ~sum + 1;
  return value & 0xff;

}
           

繼續閱讀