เครื่องวัดน้ำฝน กับ ESP32 และ YF-S201

เจอกันทุก ๆวันหยุดสัปดาห์ กับ  SamongIOT  หนึ่งในทีมงาน  สมองไทยแลนด์
วันนี้มานำเสนอ  โครงการ weather station  เพื่อจะเป็นฐานข้อมูลการพยากรณ์น้ำท่วมในพื้นที่นั้น ๆ กัน
โดยโครงการนี้เราจะใช้ ESP32 สำหรับการวัด  สภาพบรรยากาศ คือ  วัดอุณหภูมิ  วัดความชื้นและวัดปริมาณน้ำฝน   โดยมีอุปกรณ์ประกอบดังนี้

  1. Am2301  ที่จะใช้เป็นเครื่องวัดอุณหภูมิและวัดความชื้น
  2. Flow Sensor YF-S201  ที่จะมาประยุกต์เป็นตัวปริมาณน้ำฝนที่รวบรวมผ่านกรวยลงมาอีกครั้งหนึ่ง
  3. กระบอกพลาสติครับฝน   ขนาดเส้นผ่าศูนย์กลาง 10 cm
  4. ท่อสายยาง
  5. ESP32
  6. กล่องพลาสติค สำหรับการติดตั้งอุปกรณ์

เทคนิคการวัดอุณหภูมิ เรากล่าวกันไว้แล้วในตอนก่อน   ในตอนนี้จะมาดูการวัด  flow  น้ำด้วย  ESP32 ร่วมกับ YF-S201   โดยสาระสำคัญของเรื่องนี้คือการใช้ประโยชน์จากขา Interrupt  ของ ESP32  ซึ่งยอมรับว่าจัดมาให้เยอะแยะจริงๆ   โดยเราจะเผื่อเอาไว้ใช้ในการวัดทิศทางลม  และความเร็วลมในโอกาสต่อไป  ในตอนนี้จะว่ากันเฉพาะการวัด  flow  น้ำก่อน



การต่อสาย  Sensor YF-S201  ไปยัง  ESP32

  • 3V3  สายสีแดง
  • GND  สายสีดำ
  • GPIO18  สายสีเหลือง

ส่วนโค้ดนั้น  จะใช้การวัดสัญญาณ  Interrupt  ที่ขา  GPIO18  ซึ่ง  ESP32 สามารถใช้ขา  IO ทุกขาเป็น  Interrupt ได้ซึ่งเป็นจุดเด่นที่สำคัญของ  ESP32
เทคนิคที่สำคัญในครั้งนี้  คือ  การอ่านขา  Interrupt  ของ ESP32 ที่จะต้องทำการหยุดอ่านขยะที่ทำการเชื่อมต่อสัญญาณเพื่อส่งไปยัง Server (ซึงปัญหานี้  ไม่เจอในกรณีการใช้การเชื่อมต่อ Ethernet
สำหรับโค้ด  ก็ตามนี้เลย  ขอขอบคุณเวบไซต์  และ  github ที่มีโค้ดตัวอย่างให้ศึกษา
โดยในโค้ดนี้  จะมีตัว  sensor  วัดอุณหภูมิ  วัดความชื้นเข้ามาด้วย

/*
 *  This sketch sends data via HTTP GET requests to data.sparkfun.com service.
 *
 *  You need to get streamId and privateKey at data.sparkfun.com and paste them
 *  below. Or just customize this script to talk to other HTTP servers.
 *  Set board NodeMCU-32S pr ESP32 Dev Module
 *  Set Programmer AVRISP mkll
 */
//===== AM2301 - DHT21 setting
// Unified Sensor Library Example
// Written by Tony DiCola for Adafruit Industries
// Released under an MIT license.
// Depends on the following Arduino libraries:
// - Adafruit Unified Sensor Library: https://github.com/adafruit/Adafruit_Sensor
// - DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library
// Use 3V3 GIOP 2 ESP32 Dev Module
// Programmer AVRSIP mkll
#include <Adafruit_Sensor.h>
#include <DHT.h>  // กรณีนี้ต้องใช้คู่กันกับ  DHT_U.h
#include <DHT_U.h>
#define DHTPIN  2 // Pin which is connected to the DHT sensor.
// Uncomment the type of sensor in use:
//#define DHTTYPE   DHT11     // DHT 11
//#define DHTTYPE   DHT22     // DHT 22 (AM2302)
#define DHTTYPE   DHT21     // DHT 21 (AM2301)
// See guide for details on sensor wiring and usage:
//   https://learn.adafruit.com/dht/overview
DHT_Unified dht(DHTPIN, DHTTYPE);
uint32_t delayMS;
//=========
#include <WiFi.h>
//======
 //====
const char* ssid     = "Arsenal2019_2.4G";
const char* password = "xxxxxxxxxx";
const char* host = "xxxxxx.com";
const char* code = "xxxxxxxxx";  // code ของ device
const char* dID = "xxx";
float temp_0 = 0;
float humid_0 = 0;
float vHumidity = 0;
float vTemperature = 0;
float data1=15;
float data2=33;
float data3=33;
float data4=140;
float data5=200;
float data6=33;
float data7=33;
float data8=33;
float data9=33;
float data10=33;
float data11=33;
float data12=33;
float data13=33;
float data14=33;
float data15=33;
float data16=33;
float data17=33;
float data18=33;
float data19=33;
float data20=33;
float cone_diameter =10;
float cd = cone_diameter;
float rainmmhr = 0;
// Credit:
// - https://diyhacking.com/arduino-flow-rate-sensor
// - http://www.instructables.com/id/Flowmeter-NodeMcu-Counting-Litres/
#include <Arduino.h>
#include <EEPROM.h>
#define USE_SERIAL Serial
#include <WiFi.h>
// Variable init
const int buttonPin = 2; // variable for D2 pin
const int ledPin = 7;
char push_data[200]; //string used to send info to the server ThingSpeak
int addr = 0; //endereço eeprom
byte sensorInterrupt = 18; // 0 = digital pin 2
// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
// litre/minute of flow.
float calibrationFactor = 4.5;
volatile byte pulseCount;
float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;
unsigned long oldTime;
void rain_sensor_setup() {
    Serial.begin(115200); // Start the Serial communication to send messages to the computer
    delay(10);
    Serial.println('\n');
    //WiFiClient client;
    //startWIFI();
    pulseCount = 0;
    flowRate = 0.0;
    rainmmhr = 0.0;
    flowMilliLitres = 0;
    totalMilliLitres = 0;
    oldTime = 0;
    //digitalWrite(buttonPin, HIGH);
    attachInterrupt(sensorInterrupt, pulseCounter, RISING);
}
void AM2301_setup() {
  Serial.begin(115200);
  // Initialize device.
  dht.begin();
  Serial.println("DHTxx Unified Sensor Example");
  // Print temperature sensor details.
  sensor_t sensor;
  dht.temperature().getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.println("Temperature");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" *C");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" *C");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" *C");
  Serial.println("------------------------------------");
  // Print humidity sensor details.
  dht.humidity().getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.println("Humidity");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println("%");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println("%");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println("%");
  Serial.println("------------------------------------");
  // Set delay between sensor readings based on sensor details.
  delayMS = sensor.min_delay / 1000;
}
// Main setup ========
void setup()
{
    Serial.begin(115200);
    rain_sensor_setup();
    AM2301_setup();
    delay(100);
    // We start by connecting to a WiFi network
    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
}
int value = 0;
void loop()
{
    delay(100);
    rain_sensor_loop();
    AM2301_loop();
//    scanSensor_Box_Temperature();
    //data1 = vTemperature;
    ++value;
    data1 = temp_0;
    data2 = humid_0;
    data3 = flowRate;
    data4 = rainmmhr;
    data5 = flowMilliLitres;
    Serial.print("connecting to ");
    Serial.println(host);
    // Use WiFiClient class to create TCP connections
    WiFiClient client;
    const int httpPort = 80;
    if (!client.connect(host, httpPort)) {
        Serial.println("connection failed");
        return;
    }
    // We now create a URI for the request
     String url = "/api/insertData?device_id=" + String(dID)+"&code="+String(code)+"&data1=" +String(data1) +"&data2="
   + String(data2)+"&data3=" +String(data3)+"&data4=" +String(data4)+"&data5=" +String(data5)
   +"&data6=" +String(data6)+"&data7=" +String(data7)+"&data8=" +String(data8)+"&data9=" +String(data9)
   +"&data10=" +String(data10)+"&data11=" +String(data11)+"&data12=" +String(data12)+"&data13=" +String(data13)
   +"&data14=" +String(data14)+"&data15=" +String(data15)+"&data16=" +String(data16)+"&data17=" +String(data17)
   +"&data18=" +String(data18)+"&data19=" +String(data19)+"&data20=" +String(data20);
    Serial.print("Requesting URL: ");
    Serial.println(url);
    // This will send the request to the server
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                 "Host: " + host + "\r\n" +
                 "Connection: close\r\n\r\n");
    //unsigned long timeout = millis();
    delay(1000);
    while (client.available() == 0) {
       /* if (millis() - timeout > 5000) {*/
            Serial.println(">>> Client Timeout !");
            client.stop();
            return;
       /* }*/
    }
    // Read all the lines of the reply from server and print them to Serial
    while(client.available()) {
        String line = client.readStringUntil('\r');
        //Serial.print(line);
    }
    Serial.println();
    Serial.println("closing connection");
    delay(100);
}
//====
void AM2301_loop() {
  // Delay between measurements.
  delay(delayMS);
  // Get temperature event and print its value.
  sensors_event_t event;
  dht.temperature().getEvent(&event);
  if (isnan(event.temperature)) {
    Serial.println("Error reading temperature!");
  }
  else {
    Serial.print("Temperature: ");
    Serial.print(event.temperature);
    Serial.println(" *C");
    temp_0 = event.temperature;
  }
  // Get humidity event and print its value.
  dht.humidity().getEvent(&event);
  if (isnan(event.relative_humidity)) {
    Serial.println("Error reading humidity!");
  }
  else {
    Serial.print("Humidity: ");
    Serial.print(event.relative_humidity);
    Serial.println("%");
    humid_0 = event.relative_humidity;
  }
}
void rain_sensor_loop() {
    if (WiFi.status() == WL_CONNECTED && (millis() - oldTime) > 1000) // Only process counters once per second
    {
        // Disable the interrupt while calculating flow rate and sending the value to
        // the host
        detachInterrupt(sensorInterrupt);
        // Because this loop may not complete in exactly 1 second intervals we calculate
        // the number of milliseconds that have passed since the last execution and use
        // that to scale the output. We also apply the calibrationFactor to scale the output
        // based on the number of pulses per second per units of measure (litres/minute in
        // this case) coming from the sensor.
        flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
        rainmmhr = flowRate*1000/(3.14*(cd*cd))*60;  // แปลงเป็น  mm ใน 1 ชม.
        // Note the time this processing pass was executed. Note that because we've
        // disabled interrupts the millis() function won't actually be incrementing right
        // at this point, but it will still return the value it was set to just before
        // interrupts went away.
        oldTime = millis();
        // Divide the flow rate in litres/minute by 60 to determine how many litres have
        // passed through the sensor in this 1 second interval, then multiply by 1000 to
        // convert to millilitres.
        flowMilliLitres = (flowRate / 60) * 1000;
        // Add the millilitres passed in this second to the cumulative total
        totalMilliLitres += flowMilliLitres;
        unsigned int frac;
        // Print the flow rate for this second in litres / minute
        Serial.print("Flow rate: ");
        Serial.print(int(flowRate)); // Print the integer part of the variable
        Serial.print("."); // Print the decimal point
        // Determine the fractional part. The 10 multiplier gives us 1 decimal place.
        frac = (flowRate - int(flowRate)) * 10;
        Serial.print(frac, DEC); // Print the fractional part of the variable
        Serial.print("L/min");
        // Print the number of litres flowed in this second
        Serial.print("  Current Liquid Flowing: "); // Output separator
        Serial.print(flowMilliLitres);
        Serial.print("mL/Sec");
        // Print the cumulative total of litres flowed since starting
        Serial.print("  Output Liquid Quantity: "); // Output separator
        Serial.print(totalMilliLitres);
        Serial.println("mL");
        // Reset the pulse counter so we can start incrementing again
        pulseCount = 0;
        // Enable the interrupt again now that we've finished sending output
        attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
    } else if (WiFi.status() != WL_CONNECTED) {
       // startWIFI();
    }
}
/*
Insterrupt Service Routine
 */
void pulseCounter() {
    // Increment the pulse counter
    pulseCount++;
}
/*
void startWIFI(void) {
    digitalWrite(ledPin, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(100);
    WiFi.begin(ssid, password); // Connect to the network
    Serial.print("Connecting to ");
    Serial.print(ssid);
    Serial.println(" ...");
    oldTime = 0;
    int i = 0;
    digitalWrite(ledPin, LOW);    // turn the LED off by making the voltage LOW
    delay(100);
    while (WiFi.status() != WL_CONNECTED) { // Wait for the Wi-Fi to connect
        digitalWrite(ledPin, HIGH);   // turn the LED on (HIGH is the voltage level)
        delay(2000);
        Serial.print(++i);
        Serial.print('.');
        digitalWrite(ledPin, LOW);    // turn the LED off by making the voltage LOW
        delay(100);
    }
    delay(2000);
    Serial.print('\n');
    Serial.print("Connection established!");
    Serial.print("IP address:\t");
    Serial.print(WiFi.localIP()); // Send the IP address of the ESP8266 to the computer
}
*/

ว่าแล้วก็ลองยกอุปกรณ์ไปวางกลางหาว  เพื่อรับน้ำฝนได้เต็มที่   ส่วนการสอบเทียบค่าเดี่ยวมาว่ากันอีก

ขอบคุณตามลิงก์ครับ   https://gist.github.com/klanjabrik/367d7d370f27703425e7a77475b18b16
ลำดับต่อไป  ก็มาหา  เครื่องวัดความเร็วลม  ทิศทางลม  ก็จะครบเรื่อง  เรื่อง  การวัดอากาศ  เข้าสู่ระบบการพยากรณ์น้ำท่วม