W życiu każdego majsterkowicza przychodzi ten moment, kiedy postanawia zrobić Stację Pogody.
Ze mną jest nie inaczej.
Projekt zasadniczo będzie składał się z kilku części. Pierwsza z nich to główny zestaw czujników zewnętrznych:
- ciśnienia atmosferycznego
- temperatury
- wilgotności
- nasłonecznienia
- opadu atmosferycznego
Zestaw komunikuje się za pomocą modułu 433Mhz z odbiornikiem, który będzie stanowić koleją część projektu.
Wspomniane czujniki zasilane są z ogniwa 3.7V a jest ono doładowywane z panela słonecznego.
Z racji użycia czujnika opadu atmosferycznego oraz panelu słonecznego, cała obudowa jest wystawiona na działanie deszczu i słońca. Co niestety prowadzi do sporych przekłamań w odczycie temperatury. W związku z tym przygotowałem oddzielny czujnik temperatury przygruntowej. Ten element pojawi się w trzeciej odsłonie projektu (czekam na części).
Schemat
Zmontowany moduł
Jak widać poniżej, obudowa jest hermetyczna i zamykana przezroczystym wiekiem, pod którym umieściłem panel słoneczny. Poniżej panela znajduje się czujnik nasłonecznienia LDR. Przez wieko przechodzą dwa goldpiny do czujnika opadów atmosferycznych. Wspomniane elementy podpięte są do złącza ETH co umożliwia szybkie i wygodne rozpięcie wieka od obudowy.
Ponieważ zależało mi na hermetyczności obudowy, czujniki ciśnienia oraz wilgotności znajdują się na zewnątrz, a przewody do nich, prowadzone są przez dławik.
Kod programu
Jak już wspomniałem, urządzenia gada z odbiornikiem za pomocą nadajnika FS1000A na 433Mhz. Oczywistym jest tu użycie biblioteki VirtualWire, ale tylko do czasu, gdy po stronie odbiorczej też będziemy mieć Arduino. Taka była też pierwsza wersja mojej stacji. Po stronie odbiorczej było drugie Nano, które odebrane dane wyrzucało na wyświetlacz. Ale ponieważ gdzieś zalegał mi ESP8266 12E, postanowiłem wysłać moje dane do internetu! Jednak wykorzystanie ESP8266 tylko w roli “nadajnika WiFi” dla Arduino jest… no cóż- słabe, musiałem znaleźć sposób na komunikację Arduino Nano bezpośrednio z ESP8266 za pomocą wspomnianych RF linków. Niecałe dwa dni później… Udało mi się zestawić połączenie z wykorzystaniem (cudownej) biblioteki RadioHead.
Dane z czujników gromadzone są w 5 minutowych odstępach i wysyłane bez większej obróbki do ESP8266. Pomiędzy kolejnymi odczytami Arduino jest usypiane przy wykorzystaniu biblioteki LowPower.
Ponieważ planuję odczytywać więcej urządzeń, każdemu z nich nadaję DEVICE_ID. Ten zestaw ma ID=99.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
#include <RH_ASK.h> #include <SPI.h> RH_ASK driver(2000, 0, 10, 0); #include "LowPower.h" int ledPin = 13; const char DEVICE_ID = 99; #include "DHT.h" #define DHTPIN 5 #define DHTTYPE DHT22 //AM2302 DHT dht(DHTPIN, DHTTYPE); #include <Adafruit_BMP085.h> Adafruit_BMP085 bmp; #include <Wire.h> #include <OneWire.h> #include <DallasTemperature.h> #define ONE_WIRE_BUS 11 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); const int rainSensPinAnalog = A0; const int ldrPin = A1; const int solarPin = A2; char body[10] = {0}; char temp[10]; /* Czujnik opadow: gnd/+5v, analog pin. Wartosci od 1023(sucho) do 0(bardzo mokro) Długosc anteny 16.2cm dla 433Mhz */ void setup() { delay(3000); Serial.begin(9600); if (!driver.init()) Serial.println("RadioHead init failed"); dht.begin(); sensors.begin(); if (!bmp.begin()) { Serial.println("BMP085 / BMP180 Not found"); while (1) {} } Serial.println("pogodaNadajnik_v4_esp"); } void loop() { char buf[10]; int result; Serial.println(""); //ds18b20 sensors.requestTemperatures(); float intT = sensors.getTempCByIndex(0); result = (int)roundf(intT); if (isnan(intT)) { Serial.println("Failed to read from ds18b20 sensor!"); return; } Serial.print("[01]Internal temperature: "); Serial.println(intT); char ftc[5]; //float to char dtostrf(intT, 1, 1, ftc); sendMessage("01", ftc); //AM2302 float h = dht.readHumidity(); float t = dht.readTemperature(); // Check if any reads failed and exit early (to try again). if (isnan(h) || isnan(t)) { Serial.println("Failed to read from DHT sensor!"); return; } //////////////////////////wilogotnosc Serial.print("[02]Humidity: "); Serial.print(h); Serial.println(" %t"); dtostrf(h, 1, 1, ftc); sendMessage("02", ftc); //////////////////////////temperatura Serial.print("[03]TempAir: "); Serial.print(t); Serial.println(" *Ct"); dtostrf(t, 1, 1, ftc); sendMessage("03", ftc); //////////////////////////index ciepla float hic = dht.computeHeatIndex(t, h, false); Serial.print("[04]HeatIndex: "); Serial.print(hic); Serial.println(" *C "); dtostrf(hic, 1, 1, ftc); sendMessage("04", ftc); //////////////////////////BMP180 float btmp = bmp.readTemperature(); Serial.print("[05]BMP180Temp:"); Serial.print(btmp); Serial.println(" *C"); dtostrf(btmp, 1, 1, ftc); sendMessage("05", ftc); float pr = (bmp.readPressure() / 100); Serial.print("[06]Pressure:"); Serial.print(pr); Serial.println(" hPa"); dtostrf(pr, 1, 1, ftc); sendMessage("06", ftc); float att = bmp.readAltitude(); Serial.print("[07]Altitude:"); Serial.print(att); Serial.println(" metrow"); dtostrf(att, 1, 1, ftc); sendMessage("07", ftc); ///////////////SealevelPressure float slp = (bmp.readSealevelPressure(260) / 100); Serial.print("[08]SealevelPressure:"); Serial.print(slp); Serial.println(" hPa"); dtostrf(slp, 1, 1, ftc); sendMessage("08", ftc); int rain; //opady Serial.print("[09]Rain: "); //juz nie mapuje na % tylko wysylam surowe // rain = map(analogRead(rainSensPinAnalog), 220, 1020, 100, 0); // Serial.print(rain); rain = analogRead(rainSensPinAnalog); // Serial.print(rain); // Serial.print("%, raw="); Serial.println(analogRead(rainSensPinAnalog)); strcpy(body, itoa(rain , temp, 10)); sendMessage("09", body); //napiecie baterii long batt = readVcc(); Serial.print("[10]Battery: "); Serial.print(batt ); Serial.println("uV"); // Serial.println("---------------------------n"); strcpy(body, itoa(batt , temp, 10)); sendMessage("10", body); //PHOTOCELL ldr int light = analogRead(ldrPin); Serial.print("[11]Light: "); Serial.println(light); strcpy(body, itoa(light , temp, 10)); sendMessage("11", body); //panel fotowoltaiczny int solarV = analogRead(solarPin); // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V): // float voltageS = solarV * (5.0 / 1023.0); Serial.print("[12]SolarVoltage: "); Serial.println(solarV); // char ftc[10]; //float to char // dtostrf(voltageS, 1, 2, ftc); // sendMessage("12", ftc); strcpy(body, itoa(solarV , temp, 10)); sendMessage("12", body); sendMessage("00", "0000"); //sekwencja uspienia } void sendMessage(char* id, char *value) { delay(100); char tmp[5]; /* ZAPIS BITOWY 00-DEVICE_ID 00-id parametru 0000-wartosc parametru */ if (strlen(value) > 0) { char packetData[10] = {0}; strcat(packetData, itoa(DEVICE_ID , tmp, 10)); strcat(packetData, ";"); strcat(packetData, id); strcat(packetData, ";"); strcat(packetData, value); // Serial.print("["); // Serial.print(id); // Serial.print("]packetData: "); // Serial.println(packetData); for (int i = 0; i < 4; i++) { driver.send((uint8_t *)packetData, strlen(packetData)); driver.waitPacketSent(); delay(100); } if (strcmp(packetData, "99;00;0000") == 0) { Serial.println("sleep now"); delay(100); // for(int i=0;i<75;i++) for (int i = 0; i < 68; i++) //12=60 sekund //26=120 sekund //54=240 sekundy //68=300 sekund { LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF); } } } memset(body, 0, sizeof body); memset(temp, 0, sizeof temp); } /*odczyta zasilania*/ long readVcc() { long result; // Read 1.1V reference against AVcc ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); delay(2); // Wait for Vref to settle ADCSRA |= _BV(ADSC); // Convert while (bit_is_set(ADCSRA, ADSC)); result = ADCL; result |= ADCH << 8; result = 1126400L / result; // Back-calculate AVcc in mV return result; } |
Kilka rzeczy w kodzie o których warto wspomnieć
RH_ASK driver(2000, 0, 10, 0);
tu inicjujemy transmisję gdzie pierwszy parametr to prędkość a 3 to numer pinu gdzie podpinamy radiolink
dtostrf(h, 1, 1, ftc);
wszystkie floaty przed wysłaniem są obcinane do jednego miejsca po przecinku
sendMessage(“01”, ftc);
dla własnej wygody/ciekawości odczytuję także temperaturę wewnątrz urządzenia’
float btmp = bmp.readTemperature();
podobnie temperaturę czujnika barometrycznego
float slp = (bmp.readSealevelPressure(260) / 100);
260 to wysokość npm na której zamontowane są moje czujniki
long batt = readVcc();
oprócz danych pogodowych mierze także napięcie na Arduino
int solarV = analogRead(solarPin);
oraz napięcie na ogniwie słonecznym
sendMessage(“00”, “0000”);
to sekwencja która powinna zawsze znajdować się na końcu odczytu czujników. Usypia ona mikro-kontroler na 5 minut.
Długosc anteny 16.2cm dla 433Mhz
dlaczego 16.2cm? To długość tego białego drucika (nad klawiaturą) któremu dla 433Mhz zmierzyłem VSWR 1.16
Koszty
- 6V 1.1W 200mA Polycrystalline Silicon Epoxy Solar Panels Module Power Mini Solar Cells Portable Outdoor Charger 112x84mm 2,76$
- Nano CH340/ATmega328P 2,49$
- 1pcs DHT22 digital temperature and humidity sensor 2.32$
- 5V 1A Micro USB 18650 Lithium Battery Charging Board Charger 0,6$
- Battery Storage Case Plastic for 2 x 18650 0,7$
- Snow/Raindrops Detection Sensor Module 0,5$
- 433Mhz RF transmitter and receiver Module 0,8$
- Obudowa hermetyczna około 30 PLN
- Akumulator -odzysk
Panie, ale czy to działa?
Ciekawa odsłona stacji pogodowej, również rozpocząłem budowę swojej ale jestem na etapie założeń i czekam na części. Projekt super.
Leszek Biały dzięki za dobre słowo. Może znajdziesz w moim projekcie coś dla Twojej stacji pogody :)
Dzięki, skorzystam napewno z transmisji bo wstępnie miało być na kabelku
Kabelek jest OK, ale na myśl o wierceniu we framugach i ewentualnych mostkach cieplnych, mam dreszcze :) No i jeszcze moje drugie piętro i plan czujnika przygruntowego… musi być radio. Poza tym, już planuję przesyłanie do odbiornika sygnałów z kilku innych urządzeń w moim mieszkaniu. BTW, właśnie czytam o ESP32 – jak na razie moduł drogi jak smok, ale jakie możliwości!
A dlaczego ESP32 a nie ESP8266 ?
Może niejasno to napisałem. W odbiorniku użyty jest ESP8266. O ESP32 pisałem kontekście możliwości tych urządzeń.
Profesjonalny projekt DIY! Dodałem RSS do Twojej strony.
Co to za czujnik na schemacie nad panelem fotowoltaicznym?
Jak długo wytrzymuje taki czujnik deszczu? Czy śniedź, rdza na ścieżkach nie “blokuje” sygnału?
I jeszcze pytanie o wspomniany w opisie dławik. Ostatnio miałem problem z hermetycznym podłączeniem oświetlacza LED na ścianie zewnętrznej bo nie mogłem znaleźć nigdzie dławika na płaski kabel. U Ciebie widzę, że jest nawet taśma. Możesz wrzucić link do źródła takich dławików?
Andy, dzięki. Ten “czujnik” to wg fritza antena GSM. Czujnik deszczu jest cynowany, czas pokaże – wcześniej nie używałem. Myślę że jak zacznie śniedzieć to odczyszczę i pocynuję. Może w międzyczasie znajdę inny patent na pomiar opadu. Użyłem taśmy dla wygody i efektu wizualnego ;) Jest delikatnie zrolowana i zabezpieczona termokurczem. Do wody bym tego nie wrzucił, ale do naszych celów powinno wystarczyć. Dławik akurat kupiłem w Casto. Podobnie jak kolanko w którym umieściłem czujniki.
Ooo super, że co raz więcej pojawia się takich stacji!
Podoba mi się pomysł wykorzystania przezroczystej obudowy i montażu ogniwa PV wewnątrz. Niby takie proste, ale wpaść na to już trudniej. Moja stacja jeszcze w powijakach, ale przyszły już czujniki zapylenia SDS011. Potrzebna będzie grzałeczka do ogrzewania powietrza gdy wilgotność jest wyższa niż 65-70%, tak aby odczyty zapylenia nie były fałszowane przez kropelki wody. Później trzeba jeszcze zasilanie tuby geigera mullera rozkminić i będzie można przystąpić do montażu. Jako czujnik środowiskowy wybrałem BME280. Wydaje się być lepszym wyborem niż popularny DHT11/22.
A do prezentacji danych posłuży polski nettemp zainstalowany na malinie, która mieszka w głównej rozdzielnicy. Komunikacja stacji z maliną przez LoRa lub po prostu RFM69HW
Ile czujników sds chcesz zamontować :) Obudowę dobierałem min pod kątem czujnika PM ale konieczność podgrzewania powietrza a co za tym idzie mocniejszego zasilania, sprawiła ze będę pozyskiwał dane o jakości powietrza w inny sposób. Prezentuję wyniki na thingspeak’u bo tak szybko i wygodnie, chociaż niesie to spore ograniczenia. Docelowo szukam rozwiązania na bezpieczne logowanie większej ilości czujników w bazie MySql na zewnętrznym hoście.
Wystarczy mi jeden SDS011. A przyszło trochę więcej bo przed wprowadzeniem do sprzedaży (w Nettigo) chcemy je gruntownie przetestować. Ogólnie to bardzo fajny czujnik, jedyny minus to zakres temperatury podany przez producenta (od -10C), jednakże powietrze i tak trzeba ogrzewać, żeby nie fałszowało pomiarów, więc przy okazji problem niskiej temperatury sam się rozwiązał.
Jeżeli chodzi o prezentację i archiwizowanie danych to nettemp tutaj wymiata. A najlepsze jest to, że można go zainstalować nie tylko na raspberry pi, ale również na “cienkim kliencie” – terminalu z allegro za 40 zł.
Rozumiem że reprezentujesz Nettigo? Jeżeli tak, to czy planujecie może sprzedaż wyświetlaczy Nextion? O nettempie muszę poczytać, dzięki za tipa.
Rok temu proponowałem wprowadzenie Nextionów do oferty. Ale spotkałem się z kilkoma opiniami, że jest to strasznie przereklamowane. Na chwilę obecną nie mamy tego w planach. Chyba, że jakąś partię testową do 10 szt.
KamilK dobry pomysł z ogniwem, jak to się sprawuje? tzn czy starcza energii na ciągła pracę?
i pytanie po co arduino + esp + radio? czy nie prościej nodemcu za 3$ z bootloaderem arduino? Masz wtedy dostęp z każdej przeglądarki, obojętnie jaki OS.
Pokazuję i objaśniam :) Na końcu artykułu znajdziesz link do strony, na której umieściłem dane se stacji. Między innymi stan baterii i napięcie solara. Po tygodniu pojemność baterii to 79.5% Przy jakim takim nasłonecznieniu bilans na koniec dnia jest taki jak na koniec. Czyli daje radę. A jeszcze do wydłubania jest kilka ledów. Dlaczego esp? Będzie ono zbierać dane z różnych czujników za pomocą rf linków i wysyłać na wyświetlacz a przy okazji do sieci. Znacznie taniej jest zbudować 10 czujników na promini niż nodemcu. No i umieszczanie nodemcu w czujniku który co 5 minut sprawdza temperaturę z jednego czujnika, to strzelanie do muchy z armaty. Poza tym rf linki mogą mieć znacznie większy zasięg.
Hej, czy już zrobiłeś odbiornik do tego projektu na module RF 433MHz?
Miałem problemy z dostawcą z Ali. Czekałem prawie 3 mce. na części :( Co gorsze nie doszły i zamówiłem jeszcze raz. Mam kod odbiornika działający na EPS8266 więc całość zadziała, ale nie chcę pokazywać Wam płytki stykowej ale gotowy zamknięty projekt. W między czasie myślę nad obudową oraz interfejsem wyświetlacza nextion :)