Srážkoměr MS-WH-SP-RG
Jedná se o kód v testovací fázi, o který se autor podělil. Poptávalo mě už více uživatelů, že by srážky chtěli měřit, tak pokud kód vylepšíte nebo máte vlastní řešení, tak se o něj prosím podělte na multi@tricker.cz.
Obecně je srážky potřeba měřit jako samostatné čidlo a v administraci TMEPu zvolit typ „Spotřeba“ - aby se zaslané hodnoty sčítaly. Nicméně kód níže si je sčítá sám za 1 den, takže tady by to naopak bylo na škodu.
Autor: Jan Vašák (vasak.jv@seznam.cz)
Úvodní informace
Používám sadu čidel k meteostanici DS-15901, k sehnání např. zde: Hadex nebo ještě lépe samotný srážkoměr LáskaKit, datasheet. Pro Arduino existuje knihovna pro anemometr i srážkoměr. Srážkoměr je v kódu přírůstkový a má nastavené nulování po půlnoci. Jistě lze vymyslet i jinak. Tato verze kódu je mladá (1 den) a je ve fázi testování. Vzhledem k nulování každý den lze tedy využít i jiný typ čidla než „spotřeba“.
- ESP32.
- Implementováno OTA s heslem admin.
- Data ze srážkoměru, směr a rychlost větru, teplota vlhkost z DHT22, tlak z BMP280. Připojení na wifi a kontrola - v případě výpadku opětovné připojení.
- Web sériový monitor (asi zbytečnost).
- Logování každých 5 minut.
Kód programu
#include <WiFi.h> #include <HTTPClient.h> #include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_BMP280.h> #include <DHT.h> #include <SparkFun_Weather_Meter_Kit_Arduino_Library.h> #include <ArduinoOTA.h> #include <ESPAsyncWebServer.h> #include <WebSerial.h> #include <time.h> #define DHTPIN 21 #define DHTTYPE DHT22 #define BMPSDAPin 22 #define BMPSCLPin 23 #define rainSensorPin 25 #define windSpeedSensorPin 4 #define windDirectionPin 36 #define BMP280_ADDRESS 0x76 // nebo 0x77, pokud je senzor nastaven na jinou adresu const char* ssid = "nazev_site"; const char* password = "heslo_site"; const char* domain1 = "http://domena1.tmep.cz/"; const char* domain2 = "http://domena2.tmep.cz/"; DHT dht(DHTPIN, DHTTYPE); Adafruit_BMP280 bmp; SFEWeatherMeterKit weatherMeterKit(windDirectionPin, windSpeedSensorPin, rainSensorPin); AsyncWebServer server(80); unsigned long previousMillis = 0; const long interval = 300000; // 5 minut v ms void checkWiFiConnection() { if (WiFi.status() != WL_CONNECTED) { Serial.println("WiFi connection lost. Reconnecting..."); WiFi.disconnect(); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Reconnecting to WiFi..."); } Serial.println("Reconnected to WiFi"); } } void setup() { Serial.begin(115200); Wire.begin(BMPSDAPin, BMPSCLPin); // Initialize DHT sensor dht.begin(); // Initialize BMP280 sensor with explicit address if (!bmp.begin(BMP280_ADDRESS)) { Serial.println("Nemohu najit BMP280 - zkontroluj zapojeni!"); } else { Serial.println("BMP280 inicializovan."); } // Begin weather meter kit weatherMeterKit.begin(); // Connect to Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Pripojuji se k WiFi..."); } Serial.println("Pripojeno k WiFi"); Serial.print("IP Addresa: "); Serial.println(WiFi.localIP()); // Setup OTA ArduinoOTA.setHostname("esp32"); ArduinoOTA.setPassword("admin"); ArduinoOTA.onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) { type = "sketch"; } else { // U_SPIFFS type = "filesystem"; } Serial.println("Start aktualizace " + type); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) { Serial.println("Chyba autentizace"); } else if (error == OTA_BEGIN_ERROR) { Serial.println("Begin Failed"); } else if (error == OTA_CONNECT_ERROR) { Serial.println("Connect Failed"); } else if (error == OTA_RECEIVE_ERROR) { Serial.println("Receive Failed"); } else if (error == OTA_END_ERROR) { Serial.println("End Failed"); } }); ArduinoOTA.begin(); // Initialize WebSerial WebSerial.begin(&server); // Serve a simple web page to show IP address and debugging info server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ String html = "<html><body><h1>ESP32 Debug Info</h1>"; html += "<p>IP Address: "; html += WiFi.localIP().toString(); html += "</p>"; html += "<p><a href=\"/webserial\">Open WebSerial Debug</a></p>"; html += "</body></html>"; request->send(200, "text/html", html); }); server.begin(); Serial.println("Meteostanice v chodu"); configTime(3600, 3600, "pool.ntp.org"); // NTP server for time synchronization with CET/CEST while (!time(nullptr)) { Serial.println("Cekam na synchronizaci NTP..."); delay(1000); } } void loop() { unsigned long currentMillis = millis(); // OTA handling ArduinoOTA.handle(); // Check WiFi connection checkWiFiConnection(); // Only run sensor code at the specified interval if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; float humidity = NAN; float temperatureDHT = NAN; float pressure = NAN; // Read DHT sensor humidity = dht.readHumidity(); temperatureDHT = dht.readTemperature(); if (isnan(humidity) || isnan(temperatureDHT)) { Serial.println("Nepodarilo se nacist data z DHT senzoru!"); humidity = 0.0; temperatureDHT = 0.0; } // Read BMP280 sensor pressure = bmp.readPressure() / 100.0F; if (isnan(pressure)) { Serial.println("Nepodarilo se nacist data z BMP280 senzoru!"); pressure = 0.0; } // Read weather meter kit sensors float rainAmount = weatherMeterKit.getTotalRainfall(); float windSpeed = weatherMeterKit.getWindSpeed(); int windDirection = weatherMeterKit.getWindDirection(); int rssi = WiFi.RSSI(); float voltage = analogRead(36) * (3.3 / 4096.0); // Měření napětí ESP32, upravit podle potřeby // Log data to domain1 if (WiFi.status() == WL_CONNECTED) { HTTPClient http; String url1 = String(domain1) + "?temp=" + String(temperatureDHT, 1) + "&humi=" + String(humidity, 1) + "&pres=" + String(pressure, 1) + "&v=" + String(voltage, 2) + "&rssi=" + String(rssi); Serial.println("Sending HTTP GET request to domain1:"); Serial.println(url1); // Výpis URL pro domenu1 http.begin(url1); int httpCode1 = http.GET(); if (httpCode1 > 0) { Serial.printf("HTTP GET success, code: %d\n", httpCode1); WebSerial.print("HTTP GET success, code: " + String(httpCode1) + "\n"); } else { Serial.printf("HTTP GET failed, error: %s\n", http.errorToString(httpCode1).c_str()); WebSerial.print("HTTP GET failed, error: " + String(http.errorToString(httpCode1).c_str()) + "\n"); } http.end(); } else { Serial.println("WiFi not connected"); } // Log data to domain2 if (WiFi.status() == WL_CONNECTED) { HTTPClient http; String url2 = String(domain2) + "?winds=" + String(windSpeed, 1) + "&windd=" + String(windDirection) + "&rain=" + String(rainAmount, 1) + "&v=" + String(voltage, 2) + "&rssi=" + String(rssi); Serial.println("Sending HTTP GET request to domain2:"); Serial.println(url2); // Výpis URL pro domenu2 http.begin(url2); int httpCode2 = http.GET(); if (httpCode2 > 0) { Serial.printf("HTTP GET success, code: %d\n", httpCode2); WebSerial.print("HTTP GET success, code: " + String(httpCode2) + "\n"); } else { Serial.printf("HTTP GET failed, error: %s\n", http.errorToString(httpCode2).c_str()); WebSerial.print("HTTP GET failed, error: " + String(http.errorToString(httpCode2).c_str()) + "\n"); } http.end(); } else { Serial.println("WiFi not connected"); } } // Daily reset at midnight struct tm timeinfo; if (!getLocalTime(&timeinfo)) { Serial.println("Failed to obtain time"); return; } if (timeinfo.tm_hour == 0 && timeinfo.tm_min == 0 && timeinfo.tm_sec == 0) { weatherMeterKit.resetTotalRainfall(); Serial.println("Daily rainfall reset"); delay(1000); //Ochrana pred vicenasobnym resetem } }