amc:ss2023:group-u:start
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
amc:ss2023:group-u:start [2023/07/18 23:00] – daniel-jose.centeno-gonzalez | amc:ss2023:group-u:start [2023/07/23 22:15] (current) – daniel-jose.centeno-gonzalez | ||
---|---|---|---|
Line 1: | Line 1: | ||
======Portable Weather Station Documentation====== | ======Portable Weather Station Documentation====== | ||
- | **Autors:** Daniel Jose Centeno Gonzalez | + | **Autors:** Daniel Jose Centeno Gonzalez |
======Introducction====== | ======Introducction====== | ||
Line 7: | Line 7: | ||
- | ^{{: | + | ^{{: |
| **Fig.:** HSRW Portable Weather Station | | **Fig.:** HSRW Portable Weather Station | ||
Line 31: | Line 31: | ||
| **Fig.:** HSRW Portable Weather Station Electric diagram, You can download the pdf diagram {{ : | | **Fig.:** HSRW Portable Weather Station Electric diagram, You can download the pdf diagram {{ : | ||
+ | ======Real Time Data Visualization====== | ||
+ | ^{{: | ||
+ | | **Fig.:** HSRW Web Server Portable Weather Station | ||
+ | ======Logic Code====== | ||
+ | The logic of the program is divided into 5 important functions of which 4 of them are in charge of carrying out the measurement and calculation of the different values of each sensor and the last remaining one in the storage of the data in the MicroSD. Separating each function in this way we can create a multiprogramming environment which is extremely important in this type of project that uses many resources at the same time. This will also create a list and proper times of each component. For example, data can be stored in the SD while a user connects to the server. These processes will never be interrupted thanks to the task manager created with the millis() function. | ||
+ | |||
+ | **Sensor Readings:** | ||
+ | |||
+ | **read_Temp_Humi(): | ||
+ | This function is responsible for measuring temperature and humidity using the DHT22 sensor. First, the humidity and temperature are read in degrees Celsius. If the reading from any of the sensors is invalid, an error message is displayed on the serial port. In addition to obtaining the measurements, | ||
+ | |||
+ | **getRainfall(): | ||
+ | The getRainfall() function takes care of measuring the amount of rain that has fallen. For this, a rain gauge is used, which records the number of times the rain causes a mechanism to activate (in this case, the countRain() function). Each time the mechanism is activated, a counter representing the number of times it has rained is incremented. The getRainfall() function takes the value of the counter and converts it to a rain measurement in millimeters, | ||
+ | |||
+ | UV_WindDir(): | ||
+ | This function is responsible for obtaining the intensity of ultraviolet (UV) radiation and the direction of the wind. The ADS1115 module is used to read the analog value of the UV radiation sensor and then this value is mapped to a scale of 0 to 11 to represent the percentage of UV intensity. In addition, the ADS1115 module is also used to measure the analog value of the wind direction sensor. The UV_WindDir() function interprets the read value and determines the wind direction based on predefined ranges for different cardinal directions. | ||
+ | |||
+ | **countPulse(): | ||
+ | The countPulse() function is responsible for measuring the wind speed using an anemometer. The anemometer is designed to generate pulses when driven by the wind. Each time a pulse is detected, a counter representing the number of pulses generated by the anemometer in a specified time interval is incremented. The loop() function then calculates the wind speed from the number of pulses and a scale factor based on the anemometer' | ||
+ | |||
+ | **Data Logging: | ||
+ | |||
+ | **SaveFun()** Every five minutes, the sensor readings are saved to a CSV file on the SD card. The data includes the timestamp, temperature, | ||
+ | |||
+ | ======Raw Code====== | ||
+ | |||
+ | <code C++> | ||
+ | /* Tittle: Portable Weather Station | ||
+ | * Autors: Daniel Centeno | ||
+ | | ||
+ | | ||
+ | * Version: 2.7.9 | ||
+ | */ | ||
+ | |||
+ | //Libraries | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | // | ||
+ | File dataFile; | ||
+ | const int chipSelect = 15; // Chip select pin connected to SD card breakout board | ||
+ | |||
+ | // | ||
+ | Adafruit_ADS1115 ads; | ||
+ | |||
+ | // | ||
+ | // | ||
+ | |||
+ | #define DHTPIN 2 // Pin connected to the DHT22 sensor D4 | ||
+ | #define DHTTYPE DHT22 // DHT sensor type | ||
+ | DHT dht(DHTPIN, DHTTYPE); | ||
+ | |||
+ | float temperature = 0; | ||
+ | float humidity = 0; | ||
+ | float heatIndex = 0; | ||
+ | |||
+ | // | ||
+ | //Variables for the UV sensor | ||
+ | int uvPercentage = 0; | ||
+ | |||
+ | |||
+ | // | ||
+ | //All WiFi configuration | ||
+ | // Replace with your network credentials | ||
+ | const char* ssid = " | ||
+ | const char* password = " | ||
+ | |||
+ | // Set web server port number to 80 | ||
+ | WiFiServer server(80); | ||
+ | |||
+ | // Variable to store the HTTP request | ||
+ | String header; | ||
+ | |||
+ | // Current time | ||
+ | unsigned long WiFicurrentTime = millis(); | ||
+ | // Previous time | ||
+ | unsigned long WiFipreviousTime = 0; | ||
+ | // Define timeout time in milliseconds (example: 2000ms = 2s) | ||
+ | const long WiFitimeoutTime = 2000; | ||
+ | |||
+ | // | ||
+ | //Pines kit Weater Station | ||
+ | #define PIN_RAIN 0 //D3 | ||
+ | #define SDA 4 //D2 | ||
+ | #define SCL 5 // | ||
+ | |||
+ | // | ||
+ | |||
+ | volatile int numRevsAnemometer = 0; | ||
+ | volatile int numTipsRain = 0; | ||
+ | float totalRain = 0; | ||
+ | |||
+ | // | ||
+ | |||
+ | unsigned long previousMillis = 0; // Stores the last time the sensor was read | ||
+ | const long interval = 1000; // Read sensor every 1 second | ||
+ | unsigned long currentMillis = 0; // Variable where will stores the current millis | ||
+ | |||
+ | |||
+ | // | ||
+ | |||
+ | void countRain(); | ||
+ | |||
+ | void ICACHE_RAM_ATTR countRain() { | ||
+ | | ||
+ | } | ||
+ | |||
+ | // | ||
+ | |||
+ | unsigned long previousMillis2 = 0; // Stores the last time the sensor was read | ||
+ | const long interval2 = 1500; // Read sensor every 1 second | ||
+ | unsigned long currentMillis2 = 0; // Variable where will stores the current millis | ||
+ | |||
+ | //Wind Dir | ||
+ | char WinDirVariable[3]; | ||
+ | |||
+ | // | ||
+ | |||
+ | unsigned long lastWindCheck2 = 0; | ||
+ | unsigned long currentTime2 = 0; | ||
+ | int Tolerance = 300; | ||
+ | int ValuemV = 0; | ||
+ | |||
+ | // | ||
+ | |||
+ | unsigned long currentTimeSave = 0; | ||
+ | |||
+ | // | ||
+ | |||
+ | int anemometerPin = 3; | ||
+ | volatile unsigned long windCount = 0; | ||
+ | unsigned long lastWindCheckWind = 0; | ||
+ | float windSpeed = 0; | ||
+ | |||
+ | void ICACHE_RAM_ATTR countPulse() { | ||
+ | windCount++; | ||
+ | } | ||
+ | |||
+ | // | ||
+ | |||
+ | void setup() { | ||
+ | // put your setup code here, to run once: | ||
+ | Serial.begin(9600); | ||
+ | dht.begin(); | ||
+ | ads.begin(); | ||
+ | |||
+ | pinMode(PIN_RAIN, | ||
+ | attachInterrupt(digitalPinToInterrupt(PIN_RAIN), | ||
+ | |||
+ | pinMode(anemometerPin, | ||
+ | attachInterrupt(digitalPinToInterrupt(anemometerPin), | ||
+ | |||
+ | bool status; | ||
+ | // Connect to Wi-Fi network with SSID and password | ||
+ | Serial.print(" | ||
+ | Serial.println(ssid); | ||
+ | WiFi.begin(ssid, | ||
+ | while (WiFi.status() != WL_CONNECTED) { | ||
+ | delay(500); | ||
+ | Serial.print(" | ||
+ | } | ||
+ | // Print local IP address and start web server | ||
+ | Serial.println("" | ||
+ | Serial.println(" | ||
+ | Serial.println(" | ||
+ | Serial.println(WiFi.localIP()); | ||
+ | server.begin(); | ||
+ | |||
+ | // Initialize SD card | ||
+ | if (!SD.begin(chipSelect)) { | ||
+ | Serial.println(" | ||
+ | return; | ||
+ | } | ||
+ | | ||
+ | // Open the data file in append mode | ||
+ | dataFile = SD.open(" | ||
+ | | ||
+ | if (dataFile) { | ||
+ | // Write headers to the file | ||
+ | dataFile.println(" | ||
+ | dataFile.close(); | ||
+ | Serial.println(" | ||
+ | } else { | ||
+ | Serial.println(" | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | void loop() { | ||
+ | // put your main code here, to run repeatedly: | ||
+ | |||
+ | // | ||
+ | |||
+ | WiFiClient client = server.available(); | ||
+ | |||
+ | if (client) { // If a new client connects, | ||
+ | WiFicurrentTime = millis(); | ||
+ | WiFipreviousTime = WiFicurrentTime; | ||
+ | Serial.println(" | ||
+ | String currentLine = ""; | ||
+ | while (client.connected() && WiFicurrentTime - WiFipreviousTime <= WiFitimeoutTime) { // loop while the client' | ||
+ | WiFicurrentTime = millis(); | ||
+ | if (client.available()) { // if there' | ||
+ | char c = client.read(); | ||
+ | Serial.write(c); | ||
+ | header += c; | ||
+ | if (c == ' | ||
+ | // if the current line is blank, you got two newline characters in a row. | ||
+ | // that's the end of the client HTTP request, so send a response: | ||
+ | if (currentLine.length() == 0) { | ||
+ | // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) | ||
+ | // and a content-type so the client knows what's coming, then a blank line: | ||
+ | client.println(" | ||
+ | client.println(" | ||
+ | client.println(" | ||
+ | client.println(); | ||
+ | | ||
+ | // Display the HTML web page | ||
+ | client.println("< | ||
+ | client.println("< | ||
+ | client.println("< | ||
+ | // CSS to style the table | ||
+ | client.println("< | ||
+ | client.println(" | ||
+ | client.println(" | ||
+ | client.println(" | ||
+ | client.println(" | ||
+ | client.println(" | ||
+ | client.println(" | ||
+ | | ||
+ | // Web Page Heading | ||
+ | client.println("</ | ||
+ | client.println("< | ||
+ | |||
+ | client.println("< | ||
+ | client.println("< | ||
+ | client.println(temperature); | ||
+ | client.println(" | ||
+ | |||
+ | client.println("< | ||
+ | client.println("< | ||
+ | client.println(humidity); | ||
+ | client.println(" | ||
+ | |||
+ | client.println("< | ||
+ | client.println("< | ||
+ | client.println(heatIndex); | ||
+ | client.println(" | ||
+ | |||
+ | client.println("< | ||
+ | client.println("< | ||
+ | client.println(totalRain); | ||
+ | client.println(" | ||
+ | |||
+ | client.println("< | ||
+ | client.println("< | ||
+ | client.println(windSpeed); | ||
+ | client.println(" | ||
+ | |||
+ | |||
+ | client.println("< | ||
+ | client.println("< | ||
+ | client.println(WinDirVariable); | ||
+ | client.println("</ | ||
+ | |||
+ | client.println("< | ||
+ | client.println("< | ||
+ | client.println(uvPercentage); | ||
+ | client.println("</ | ||
+ | client.println("</ | ||
+ | | ||
+ | // The HTTP response ends with another blank line | ||
+ | client.println(); | ||
+ | // Break out of the while loop | ||
+ | break; | ||
+ | } else { // if you got a newline, then clear currentLine | ||
+ | currentLine = ""; | ||
+ | } | ||
+ | } else if (c != ' | ||
+ | currentLine += c; // add it to the end of the currentLine | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | // Clear the header variable | ||
+ | header = ""; | ||
+ | // Close the connection | ||
+ | client.stop(); | ||
+ | Serial.println(" | ||
+ | Serial.println("" | ||
+ | } | ||
+ | |||
+ | |||
+ | // | ||
+ | |||
+ | currentMillis = millis(); | ||
+ | if (currentMillis - previousMillis >= interval) { | ||
+ | previousMillis = currentMillis; | ||
+ | | ||
+ | read_Temp_Humi(); | ||
+ | } | ||
+ | | ||
+ | getRainfall(); | ||
+ | |||
+ | |||
+ | unsigned long currentTimeWind = millis(); | ||
+ | |||
+ | if (currentTimeWind - lastWindCheckWind >= 1000) { | ||
+ | detachInterrupt(digitalPinToInterrupt(anemometerPin)); | ||
+ | | ||
+ | // Calculate the Wind Speed | ||
+ | windSpeed = (float)windCount / 2.4; // Sets the scale factor based on the anemometer calibration | ||
+ | windCount = 0; // Reset pulse counter | ||
+ | lastWindCheckWind = currentTimeWind; | ||
+ | | ||
+ | attachInterrupt(digitalPinToInterrupt(anemometerPin), | ||
+ | } | ||
+ | |||
+ | currentMillis2 = millis(); | ||
+ | if (currentMillis2 - previousMillis2 >= interval2) { | ||
+ | previousMillis2 = currentMillis2; | ||
+ | |||
+ | UV_WindDir(); | ||
+ | } | ||
+ | |||
+ | |||
+ | //Uncomment to see the values through the serial port | ||
+ | //unsigned long currentTime2 = millis(); | ||
+ | //if (currentTime2 - lastWindCheck2 >= 2000) { | ||
+ | // lastWindCheck2 = currentTime2; | ||
+ | // FunPrint(); | ||
+ | //} | ||
+ | | ||
+ | // Get current timestamp | ||
+ | currentTimeSave = millis(); | ||
+ | | ||
+ | // Check if 5 minutes have passed | ||
+ | if (currentTimeSave % (5 * 60 * 1000) == 0) { | ||
+ | | ||
+ | SaveFun(); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | void getRainfall(){ | ||
+ | int tips = numTipsRain; | ||
+ | numTipsRain = 0; | ||
+ | |||
+ | float rainfall = tips * 0.2794; | ||
+ | totalRain += rainfall; | ||
+ | } | ||
+ | |||
+ | void read_Temp_Humi(){ | ||
+ | | ||
+ | humidity = dht.readHumidity(); | ||
+ | temperature = dht.readTemperature(); | ||
+ | |||
+ | if (isnan(humidity) || isnan(temperature)) { | ||
+ | Serial.println(" | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | heatIndex = calculateHeatIndex(temperature, | ||
+ | } | ||
+ | |||
+ | float calculateHeatIndex(float temperature, | ||
+ | // Heat index calculation (Steadman' | ||
+ | float hi = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) + (humidity * 0.094)); | ||
+ | |||
+ | if (hi > temperature) { | ||
+ | return hi; | ||
+ | } else { | ||
+ | return temperature; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void UV_WindDir(){ | ||
+ | |||
+ | int16_t UVSensor, WindDir; | ||
+ | |||
+ | UVSensor = ads.readADC_SingleEnded(0); | ||
+ | // Map the analog value to a scale from 0 to 11 | ||
+ | uvPercentage = map(UVSensor, | ||
+ | | ||
+ | WindDir = ads.readADC_SingleEnded(1); | ||
+ | ValuemV = ads.readADC_SingleEnded(1); | ||
+ | if(WindDir >= (4960-600) && WindDir <= (4960+600)){ | ||
+ | strcpy(WinDirVariable, | ||
+ | } | ||
+ | else if(WindDir >= (10860-600) && WindDir <= (10860+600)){ | ||
+ | strcpy(WinDirVariable, | ||
+ | } | ||
+ | else if(WindDir >= (16693-550) && WindDir <= (16693+550)){ | ||
+ | strcpy(WinDirVariable, | ||
+ | } | ||
+ | else if(WindDir >= (15686-350) && WindDir <= (15686+350)){ | ||
+ | strcpy(WinDirVariable, | ||
+ | } | ||
+ | else if(WindDir >= (13590-600) && WindDir <= (13590+600)){ | ||
+ | strcpy(WinDirVariable, | ||
+ | } | ||
+ | else if(WindDir >= (7960-600) && WindDir <= (7960+600)){ | ||
+ | strcpy(WinDirVariable, | ||
+ | } | ||
+ | else if(WindDir >= (1600-600) && WindDir <= (1600+600)){ | ||
+ | strcpy(WinDirVariable, | ||
+ | } | ||
+ | else if(WindDir >= (3170-600) && WindDir <= (3170+600)){ | ||
+ | strcpy(WinDirVariable, | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | void FunPrint(){ | ||
+ | |||
+ | //Imprimir Relativity Tem and Hum | ||
+ | Serial.print(" | ||
+ | Serial.print(" | ||
+ | |||
+ | //Total RainFall | ||
+ | Serial.print(" | ||
+ | |||
+ | //Wind speed | ||
+ | Serial.print(" | ||
+ | |||
+ | //Wind direction | ||
+ | Serial.print(" | ||
+ | |||
+ | Serial.print(" | ||
+ | |||
+ | } | ||
+ | |||
+ | void SaveFun(){ | ||
+ | |||
+ | dataFile = SD.open(" | ||
+ | |||
+ | if (dataFile) { | ||
+ | // Write timestamp and sensor value to the file | ||
+ | dataFile.print(currentTimeSave); | ||
+ | dataFile.print(", | ||
+ | dataFile.print(temperature); | ||
+ | dataFile.print(", | ||
+ | dataFile.print(humidity); | ||
+ | dataFile.print(", | ||
+ | dataFile.print(heatIndex); | ||
+ | dataFile.print(", | ||
+ | dataFile.print(totalRain); | ||
+ | dataFile.print(", | ||
+ | dataFile.print(windSpeed); | ||
+ | dataFile.print(", | ||
+ | dataFile.print(WinDirVariable); | ||
+ | dataFile.print(", | ||
+ | dataFile.print(uvPercentage); | ||
+ | dataFile.println("" | ||
+ | dataFile.close(); | ||
+ | | ||
+ | Serial.println(" | ||
+ | } else { | ||
+ | Serial.println(" | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | You can freely download and use the code here --> {{ : | ||
+ | |||
+ | |||
+ | ======Conclusion====== | ||
+ | |||
+ | The " |
amc/ss2023/group-u/start.1689714033.txt.gz · Last modified: 2023/07/18 23:00 by daniel-jose.centeno-gonzalez