Czujnik wiatru i deszczu

SOYER
Posts: 1172
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry

Post

Cześć, z racji tego, że jeden z użytkowników prosił mnie o dodanie dodatkowo obsługi czujnika SDS011, to poniżej wklejam szkic który to powinien robić. Jednak fizycznie nie mam tego czujnika, więc nie mam możliwości sprawdzenia czy ta biblioteka zastosowana i cały szkic będą współdziałać z czujnikiem.
Nie zapomnijcie dodać biblioteki:
https://github.com/ricki-z/SDS011
uzupełnić dane wifi, GUID i AUTH, oraz dane do logowania do serwera.

Jak ktoś ma taki czujnik to może sprawdzić czy to działa. Generalnie szkic bez problemu wgrał się na nodeMCU(8266), uruchomił, zalogował do serwera itd.

Szkic:

Code: Select all

#include <SuplaDevice.h>
#include <SDS011.h>  //  https://github.com/ricki-z/SDS011
#include <Timers.h>   //   https://github.com/nettigo/Timers
#include <supla/sensor/DHT.h>
#include <supla/sensor/DS18B20.h>
#include <supla/network/esp_wifi.h>
#include <supla/sensor/general_purpose_measurement.h>
  Supla::ESPWifi wifi("xx", "xx");
  
#define dsPin 14 //D5
#define dhtPin 5 //D1
#define windPin 12 //D6
#define rainPin 2  //D4

#define rxPin 13 //D7 SDS011
#define txPin 15  //D8 SDS011
float p10, p25;
int error;
bool startOdczyt = 0;
bool odczyt = 0;
SDS011 my_sds;

Timer minut5;
Timer sekund30;
Timer minuta;
Timer sekund1;
Timer sekund6;

int rai=0;
bool r=0;
float mmM2=0;

volatile int half_revolutions_time = 2; //Utworzenie zmiennej połowa pełnego obrotu (half revolutions)
volatile int rpm = 0;
unsigned long static  last_event = 0;
unsigned long static last_event1 = 0;
int sample = 0;
float moment_kmh;
float temp_kmh;
float correct_moment_kmh;
float average_kmh;

Supla::Sensor::GeneralPurposeMeasurement *moment_wind = nullptr;
Supla::Sensor::GeneralPurposeMeasurement *average_wind = nullptr;
Supla::Sensor::GeneralPurposeMeasurement *rain = nullptr;
Supla::Sensor::GeneralPurposeMeasurement *P2 = nullptr;
Supla::Sensor::GeneralPurposeMeasurement *P10 = nullptr;

void ICACHE_RAM_ATTR rn(){// wektor przerwania deszczomierza
  unsigned long static last_event1 = 0;
  if (millis() - last_event1 < 50) {   //debouncing
    return;
  }
  rai++;
  last_event1 = millis();
}
 void ICACHE_RAM_ATTR rpm_fan() { //funkcja rpm_fan
  if (millis() - last_event < 5) {   //debouncing
    return;
  }
  half_revolutions_time = (millis() - last_event);
  last_event = millis();
}
void temporaryRPM(){
    noInterrupts(); 
    if((last_event + 2000) < millis()){    
     rpm=0;
     moment_kmh = 0;
     correct_moment_kmh = 0;
    }
    else{ 
      rpm = (30000 / half_revolutions_time) ;
      moment_kmh = 6.28 * 0.075 * rpm/60.0 * 3.6;// pi x promień czujnika x rpm/60s x ms->km/h
      if(moment_kmh < 10){
        correct_moment_kmh = moment_kmh * 2.8;
      }
      else if((moment_kmh >= 10) && (moment_kmh < 25)){
        correct_moment_kmh = moment_kmh * 2.7;
      }
      else if(moment_kmh >= 25){
        correct_moment_kmh = moment_kmh * 2.8;
      }
    } 
    if(sekund6.available()){
      temp_kmh = temp_kmh + correct_moment_kmh;
      sample++;
      sekund6.restart();
     }
    if(sample==10){
      average_kmh = temp_kmh / 10; 
      temp_kmh = 0;
      sample=0;
      sekund6.restart();
    }
   interrupts() ; //Przywróć przerwania
}

void sds(){
  if((minut5.available()) && (startOdczyt ==0)){
    sekund30.restart();
    startOdczyt = 1;
    odczyt = 1;
    my_sds.wakeup();
  }
  if((sekund30.available()) && (odczyt == 1)){
      error = my_sds.read(&p25, &p10);
       if (!error) {
        P2->setValue(p25);
        P10->setValue(p10);
        Serial.println("P2.5: " + String(p25));
        Serial.println("P10:  " + String(p10));
        minut5.restart();
        startOdczyt = 0;
        odczyt = 0;
        my_sds.sleep();
       }
  }
}

void setup() {
   // Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
  char GUID[SUPLA_GUID_SIZE] = {xx};

  // Replace the following AUTHKEY with value that you can retrieve from: https://www.supla.org/arduino/get-authkey
  char AUTHKEY[SUPLA_AUTHKEY_SIZE] = {xx};
    
      my_sds.begin(rxPin, txPin); //RX, TX
  Serial.begin(9600);
  new Supla::Sensor::DS18B20(dsPin);
    new Supla::Sensor::DHT(dhtPin, DHT22);
    moment_wind = new Supla::Sensor::GeneralPurposeMeasurement();
    average_wind = new Supla::Sensor::GeneralPurposeMeasurement();
    rain = new Supla::Sensor::GeneralPurposeMeasurement();   
    P2 = new Supla::Sensor::GeneralPurposeMeasurement();
    P10 = new Supla::Sensor::GeneralPurposeMeasurement();
    pinMode(windPin,INPUT_PULLUP);
    pinMode(rainPin,INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(rainPin), rn, RISING); 
    attachInterrupt(digitalPinToInterrupt(windPin), rpm_fan, FALLING);
    minut5.begin(299999);
    sekund30.begin(30001);
    minuta.begin(59999);
    sekund6.begin(6000);
    sekund1.begin(1000);
    last_event = millis();
    last_event1 = millis();
       SuplaDevice.begin(GUID,              // Global Unique Identifier 
                    "svrxx.supla.org",  // SUPLA server address
                    "xxx@wp.pl",   // Email address used to login to Supla Cloud
                    AUTHKEY);          // Authorization key
}

void loop() {
    SuplaDevice.iterate();
    temporaryRPM();
    sendSupla();
    sds();
}
void sendSupla(){
    if(sekund1.available()){  
      moment_wind->setValue(correct_moment_kmh);
      sekund1.restart();
    }
    if(minuta.available()){  
      mmM2=rai*0.15; // dwa przerwnia na jedną kolebkę, więc 0.15
      rain->setValue(mmM2);
      average_wind->setValue(average_kmh);
      rai=0;
      minuta.restart();
    }
}
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
SOYER
Posts: 1172
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry

Post

SOYER wrote: Sun Nov 03, 2024 4:05 pm W kpop ja zmieniłem ikonki, jednostki, nazwę kanału, dodałem historię dla wiatru co minutę i deszczu, ustawiłem interwał odświeżania dla deszczu i wiatru średniego na 60000ms, a wiatru chwilowego na 1000ms.
Po dzisiejszych poszukiwaniach przyczyn błędu wyświetlania danych na wykresie i w apk, chcę dodać, że w cloud należy jeszcze ustawić liczbę miejsc po przecinku na "2", a jeśli ktoś chce powiadomienie o deszczu to ustawienia jak na screenie poniżej.
You do not have the required permissions to view the files attached to this post.
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
Pietras81
Posts: 2098
Joined: Sun Feb 17, 2019 6:56 am
Location: Osielsko

Post

Tak zapytam nieśmiało, będziesz dodawał integrację z aqi.eco. Zastanawiam się czy robić aktualizacje swojej stacji czy trochę jeszcze poczekać.??
https://pietras-81.aqi.eco/
User avatar
shimano73
Posts: 2040
Joined: Sun Feb 28, 2016 12:27 pm
Location: Orzesze

Post

Tak , tak, zrób , nie bedę musiał ja robić :lol:
W elektronice jak nie wiadomo o co chodzi to zwykle chodzi o zasilanie

Wezmę udział w Supla Offline Party 2024 :)
SOYER
Posts: 1172
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry

Post

Pietras81 wrote: Sat Nov 16, 2024 7:26 pm Tak zapytam nieśmiało, będziesz dodawał integrację z aqi.eco. Zastanawiam się czy robić aktualizacje swojej stacji czy trochę jeszcze poczekać.??
Nie nie z aqi.eco bo mam bardzo rozproszoną bazę urządzeń, na każdym inne czujniki. Rozmawiałem z Tomkiem z aqi i dowiedziałem się, że tam każde dodane urządzenie musi przesyłać odczyt PM z czujnika smogu. Więc u mnie odpada ten serwis, aktualnie walczę z weathercloud…
Może ktoś pomoże, bo moja wiedza o protokołach web jest znikoma:
https://forbot.pl/forum/topic/24726-dar ... e-odczyty/
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
SOYER
Posts: 1172
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry

Post

SOYER wrote: Sun Nov 17, 2024 1:42 pm
Pietras81 wrote: Sat Nov 16, 2024 7:26 pm Tak zapytam nieśmiało, będziesz dodawał integrację z aqi.eco. Zastanawiam się czy robić aktualizacje swojej stacji czy trochę jeszcze poczekać.??
Nie nie z aqi.eco bo mam bardzo rozproszoną bazę urządzeń, na każdym inne czujniki. Rozmawiałem z Tomkiem z aqi i dowiedziałem się, że tam każde dodane urządzenie musi przesyłać odczyt PM z czujnika smogu. Więc u mnie odpada ten serwis, aktualnie walczę z weathercloud…
Może ktoś pomoże, bo moja wiedza o protokołach web jest znikoma:
https://forbot.pl/forum/topic/24726-dar ... e-odczyty/
Ok udało się.
Mogę udostępniać dane na weathercloud.

https://app.weathercloud.net/d4311785603

Poniżej wklejam mój szkic z wysyłaniem info z czujnika prędkości wiatru, ilości opadu deszczu i temperatury.
Postaram się w najbliższym czasie zmienić soft w pozostałych moich urządzeniach jak i bliżej poznać się z weathercloud, co to umie, a czego nie.

Code: Select all

#include <SuplaDevice.h>
#include <Timers.h>
#include <supla/sensor/DHT.h>
#include <supla/sensor/DS18B20.h>
#include <supla/network/esp_wifi.h>
#include <supla/sensor/general_purpose_measurement.h>
#include <ESP8266HTTPClient.h>
#include <Arduino_JSON.h>
String jsonBuffer;

  Supla::ESPWifi wifi("xx", "xx");

char server [] = "https://api.weathercloud.net";
char IDKryry [] = "xx";
char KeyKryry [] = "xx";
  
#define dsPin 14 //D5
#define dhtPin 5 //D1
#define windPin 12 //D6
#define rainPin 2  //D4

Timer minuta;
Timer sekund1;
Timer sekund6;
Timer minut10;

int rai=0;
bool r=0;
float mmM2=0;
int tempSlonce;

volatile int half_revolutions_time = 2; //Utworzenie zmiennej połowa pełnego obrotu (half revolutions)
volatile int rpm = 0;
unsigned long static  last_event = 0;
unsigned long static last_event1 = 0;
int sample = 0;
float moment_kmh;
float temp_kmh;
float correct_moment_kmh;
float average_kmh;

Supla::Sensor::GeneralPurposeMeasurement *moment_wind = nullptr;
Supla::Sensor::GeneralPurposeMeasurement *average_wind = nullptr;
Supla::Sensor::GeneralPurposeMeasurement *rain = nullptr;
Supla::Sensor::DS18B20 *tempS = nullptr;

void ICACHE_RAM_ATTR rn(){// wektor przerwania deszczomierza
  unsigned long static last_event1 = 0;
  if (millis() - last_event1 < 50) {   //debouncing
    return;
  }
  rai++;
  last_event1 = millis();
}
 void ICACHE_RAM_ATTR rpm_fan() { //funkcja rpm_fan
  if (millis() - last_event < 5) {   //debouncing
    return;
  }
  half_revolutions_time = (millis() - last_event);
  last_event = millis();
}
void temporaryRPM(){
    noInterrupts(); 
    if((last_event + 2000) < millis()){    
     rpm=0;
     moment_kmh = 0;
     correct_moment_kmh = 0;
    }
    else{ 
      rpm = (30000 / half_revolutions_time) ;
      moment_kmh = 6.28 * 0.075 * rpm/60.0 * 3.6;// pi x promień czujnika x rpm/60s x ms->km/h
      if(moment_kmh < 10){
        correct_moment_kmh = moment_kmh * 2.8;
      }
      else if((moment_kmh >= 10) && (moment_kmh < 25)){
        correct_moment_kmh = moment_kmh * 2.7;
      }
      else if(moment_kmh >= 25){
        correct_moment_kmh = moment_kmh * 2.8;
      }
    } 
    if(sekund6.available()){
      temp_kmh = temp_kmh + correct_moment_kmh;
      sample++;
      sekund6.restart();
     }
    if(sample==10){
      average_kmh = temp_kmh / 10; 
      temp_kmh = 0;
      sample=0;
      sekund6.restart();
    }
   interrupts() ; //Przywróć przerwania
}

void setup() {
  Serial.begin(9600);
   // Replace the falowing GUID with value that you can retrieve from https://www.supla.org/arduino/get-guid
  char GUID[SUPLA_GUID_SIZE] = {xx};

  // Replace the following AUTHKEY with value that you can retrieve from: https://www.supla.org/arduino/get-authkey
  char AUTHKEY[SUPLA_AUTHKEY_SIZE] = {xx};
    tempS = new Supla::Sensor::DS18B20(dsPin);
    new Supla::Sensor::DHT(dhtPin, DHT22);
    moment_wind = new Supla::Sensor::GeneralPurposeMeasurement();
    average_wind = new Supla::Sensor::GeneralPurposeMeasurement();
    rain = new Supla::Sensor::GeneralPurposeMeasurement();   
    pinMode(windPin,INPUT_PULLUP);
    pinMode(rainPin,INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(rainPin), rn, RISING); 
    attachInterrupt(digitalPinToInterrupt(windPin), rpm_fan, FALLING);
    minuta.begin(59999);
    sekund6.begin(6000);
    sekund1.begin(1000);
    minut10.begin(610000);
    last_event = millis();
    last_event1 = millis();
       SuplaDevice.begin(GUID,              // Global Unique Identifier 
                    "svrxx.supla.org",  // SUPLA server address
                    "xx@wp.pl",   // Email address used to login to Supla Cloud
                    AUTHKEY);          // Authorization key
}

void loop() {
    SuplaDevice.iterate();
    temporaryRPM();
    sendToAll();
}

void sendToAll(){
    if(sekund1.available()){  
      moment_wind->setValue(correct_moment_kmh);
      sekund1.restart();
    }
    if(minuta.available()){  
      mmM2=rai*0.15; // dwa przerwnia na jedną kolebkę, więc 0.15
      rain->setValue(mmM2);
      average_wind->setValue(average_kmh);
      rai=0;
      tempSlonce = tempS->getValue();
      minuta.restart();
    }
    if(minut10.available()){
      weathercloud(); 
      minut10.restart();
    }
}
void weathercloud(){
  
  String serverPath = String(server) + "/v01/set/wid/" + String(IDKryry) + "/key/" + String(KeyKryry) + "/temp/" + String(tempSlonce) + "/wspdavg/" + String(average_kmh) + "/rain/" + String(mmM2);
      jsonBuffer = httpGETRequest(serverPath.c_str());
      Serial.println(jsonBuffer);
      JSONVar myObject = JSON.parse(jsonBuffer);
      
       if (JSON.typeof(myObject) == "undefined") {
             Serial.println("Parsing input failed!");
        return;
       }
}

String httpGETRequest(const char* serverName) {
  WiFiClientSecure client1;
  HTTPClient http1;
  client1.setInsecure();
  http1.begin(client1, serverName);
  
  // Send HTTP POST request
  int httpResponseCode = http1.GET();
  
  String payload = "{}"; 
  
  if (httpResponseCode>0) {
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    payload = http1.getString();
  }
  else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
  }
  
  http1.end();
  return payload;
}
You do not have the required permissions to view the files attached to this post.
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
SOYER
Posts: 1172
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry

Post

Mam pomysł, zamiast aktualizować szkice we wszystkich urządzeniach, prościej by było jakby esp pobrało z cloud (przez Aapi?), aktualne odczyty potrzebnych czujników i potem je wysłało na weathercloud.
Kto mi pomoże napisać funkcję pobierającą te dane?
Ta funkcja weatherclod() z powyższego szkicu pewnie byłaby pomocna. Tylko jak to zrobić, tak krok po kroku?
Może @klew?
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
User avatar
klew
Posts: 10025
Joined: Thu Jun 27, 2019 12:16 pm
Location: Wrocław

Post

SOYER wrote: Mon Nov 18, 2024 10:53 am Mam pomysł, zamiast aktualizować szkice we wszystkich urządzeniach, prościej by było jakby esp pobrało z cloud (przez Aapi?), aktualne odczyty potrzebnych czujników i potem je wysłało na weathercloud.
Kto mi pomoże napisać funkcję pobierającą te dane?
Ta funkcja weatherclod() z powyższego szkicu pewnie byłaby pomocna. Tylko jak to zrobić, tak krok po kroku?
Może @klew?
Ja tego nigdy nie robiłem, ale GG używa chyba linków bezpośrednich do odczytu.
Są też gdzieś w otchłani forum projektu użytkowników, którzy używali API na ESP. Np. był kiedyś wątek związany z wywozem śmieci, gdzie ESP aktualizowało sobie nazwę kanału z opisami w stylu "kolejny wywóz w poniedziałek". Ale musiałbyś to sobie jakoś odszukać.
SOYER
Posts: 1172
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry

Post

To może linki bezpośrednie w takim razie, ale nie wiem jak ich użyć do pobierania wartości. @krycha88 może coś pomoże;).
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603
SOYER
Posts: 1172
Joined: Wed Aug 10, 2022 12:29 pm
Location: Kryry

Post

Wprawdzie nikt nie pomógł bezpośrednio ale z pomocą szkicu napisanego w innym wątku przez @jamsjamsen udało mi się przerobić mój szkic wysyłający dane do weathercloud, na pobierający za pomocą linku bezpośredniego aktualną wartość kanału z clouda.
Wygląda to tak:

Code: Select all

void weathercloud(){

  String serverPathZEW_press =  "https://xxx.supla.org/direct/880/xxx/read?format=json"; 
      jsonBuffer = httpGET_ZEW_press(serverPathZEW_press.c_str());
      Serial.println(jsonBuffer);
}

String httpGET_ZEW_press(const char* serverName) {
  WiFiClientSecure client1;
  HTTPClient http1;
  client1.setInsecure();
  http1.begin(client1, serverName);
  
  // Send HTTP POST request
  int httpResponseCode = http1.GET();
  
  String payload = "{}"; 
  
  if (httpResponseCode>0) {
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    payload = http1.getString();
    DynamicJsonDocument doc(1024);
    deserializeJson(doc, payload);
    float pressure = doc["value"]; 
    char charVal[10];
    dtostrf(pressure, 6, 2, charVal);
    Serial.println(charVal);
  }
  else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
  }
  
  http1.end();
  return payload;
}
W zmiennej charVal mamy pięknie pobraną wartość ciśnienia z dwoma miejscami po przecinku.
Teraz muszę to jakoś ładnie przerobić na pobieranie większej ilości danych z kilku urządzeń i po obróbce wysłanie ich do weathercloud.
https://kryry01.aqi.eco/pl
https://app.weathercloud.net/d4311785603

Return to “Projekty użytkowników”