Stacja Pogody Arduino

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 Li-po 3.7V a ogniwo doładowywane jest 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.

#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(" *C\t");
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 2,76$ BUY/KUP
Nano CH340/ATmega328P 2,49$ BUY/KUP
DHT22 digital temperature and humidity sensor 2.32$ BUY/KUP
5V 1A Micro USB 18650 Lithium Battery Charging Board 0,6$ BUY/KUP
Battery Storage Case Plastic for 2 x 18650 0.7$ BUY/KUP
Snow/Raindrops Detection Sensor Module 0.5$ BUY/KUP
433Mhz RF transmitter and receiver Module 0.8$ BUY/KUP
Obudowa hermetyczna 17PLN BUY/KUP
Akumulator   BUY/KUP

 

Please follow and like us:

5
Dodaj komentarz

avatar
1 Comment threads
4 Thread replies
2 Followers
 
Most reacted comment
Hottest comment thread
2 Comment authors
lockter Recent comment authors
  Subscribe  
najnowszy najstarszy oceniany
Powiadom o
lockter
Gość
lockter

świetny projekt, szukałem inspiracji do zbudowania właśnie czegoś podobnego – stacji z czujnikami która komunikuje się z bazą odczytującą te dane. chodzi mi o to by odczytane dane można było dalej przetwarzać. czy możesz powiedzieć jaki zasięg udało się uzyskać na tych modułach RF433 i czy udaje się zewnętrznemu modułowi bezproblemowo pracować przy zasilaniu solarnemu – czy i jak często trzeba go doładowywać?

czy mógłbyś udostępnić też kody źródłowe?