Obsah

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“.

  1. ESP32.
  2. Implementováno OTA s heslem admin.
  3. 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í.
  4. Web sériový monitor (asi zbytečnost).
  5. 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
  }
}