ESP32 : AM2301 Flow Sensor Soil Humidity
ชื่อเรื่องก็ทราบเลยว่าเป็นการเจอกันของ 3 sensors 4 ค่าวัดบนตัว ESP32 ตัวเดียว และส่งผลเข้าสู่ IOT cloud platform ด้วย Hot Spot
เป็นการสำรวจพื้นที่ชิมลาง ว่า พื้นที่เป้าหมายมีสัญญาณสื่อสาร ช่องทางให้เลือกออกแบบระบบอย่างไรได้บ้าง ว่าสุดท้ายควรจะไปถึงไหน
ปัญหาในครั้งนี้เป็นเรื่อง
- สัญญาณคลื่นบางค่าย หาไม่เจอในพื้นที่เป้าหมาย
- ด้านโปรแกรม Inerrupt ของ ESP32 มี conclict กับขา analog input ในขณะที่ ESP32 มีความสามารถให้เกือบทุก IO เป็นได้ทั้ง Digital & Analog
- สำหรับการเขียนสร้างโ๕้ดแบบไม่อ่าน datasheet ก่อนก็ต้องไปลองเอาว่ามันไม่ทำงานเพราะอะไรได้บ้าง อย่างมากก็เปลี่ยนขาเอา วนไปเรื่อย
ทั้งนี้การทดสอบการทำงาน การอ่านค่าของ sensor 9ต่างๆ ผ่านไปได้ตามปกติ แต่พอมารวมโ๕้ดกันเท่านั้นแหละ ค่า Soilsensor หายไปเลยเท่ากับ 0% ตลอด ทั้งๆ ที่ใช้ขา Input เดียวกัน แต่ดันทะลึ่งไปใช้ขา 14 ที่มานึกออกในตอนหลังว่า ESP32 และ Mega มันจองใช้เป็น Interrupt
สุดท้ายก็ไม่ยาก เปลี่ยนจากขา 14 กระโดไปใช้ขาที่เป็น analog in อย่างเดียว โดดใช้ขา 35 แทน จบเลยผ่านฉลุย เป็นอันว่าเราก็สามารถใช้ sensor ทั้ง 4 บน ESP32 ตัวเดียวกันได้สบาย ๆ ส่วนเรื่องความแม่นยำของ Flow Sensor ที่มาแปลงเป็นการวัดน้ำฝนนั้น ต้องมาทำการ cal กันอีกครั้ง แต่เป้าหมายหลัก ๆ คือ ขอแค่ทราบว่ามีฝนตกพอประมาณกันก่อน ไวเถึงเวลาจริงจังก็ต้องเลือกใช้ของสูงหน่อย 555
/* * 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. //#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 = "AndroidAPxxxxxx"; const char* password = "qcwkxxxxx"; const char* host = "xxxxx.com"; const char* code = "xxxxx"; const char* dID = "xx"; 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> // soil sensor int soilsensorPin = 35 ; int soilsensorValue; // int frac; // 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 = 19; // 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(9600); // Start the Serial communication to send messages to the computer delay(10); Serial.println('\n'); pulseCount = 0; flowRate = 0.0; rainmmhr = 0.0; flowMilliLitres = 0; totalMilliLitres = 0; oldTime = 0; frac = 0; //digitalWrite(buttonPin, HIGH); attachInterrupt(sensorInterrupt, pulseCounter, RISING); } void AM2301_setup() { Serial.begin(9600); // 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(9600); Serial.begin(9600); // set up serial port for 9600 baud (speed) delay(500); // wait for display to boot up 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(1000); SoilSensorloop(); rain_sensor_loop(); AM2301_loop(); //SoilSensor_loop(); // scanSensor_Box_Temperature(); //data1 = vTemperature; ++value; data1 = temp_0; data3 = humid_0; data2 = soilsensorValue; data4 = rainmmhr; data5 = flowMilliLitres; data6 = frac; 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 = "/xxx/xxxxxx?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) // 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. // Serial.print("Check period mil - oldtime ... ");Serial.println(millis()-oldTime); flowRate = ((1000.0 / 4505) * pulseCount) / calibrationFactor; rainmmhr = flowRate*1000/(3.14*(cd*cd))*60; // 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/4; 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 SoilSensorloop() { //int sensorValue; soilsensorValue = analogRead(soilsensorPin)/4; Serial.println(soilsensorValue); soilsensorValue = map(soilsensorValue, 0, 1023, 100, 0); Serial.print("Soil moisture: "); Serial.println(soilsensorValue); Serial.println(" %"); delay(500); //wait for half a second, so it is easier to read }