A weather station
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

290 lines
7.5 KiB

/*
* WetterStation
* Version: 0.0
* Author: Hendrik Langer <hendrik+dev@xd0.de>
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
7 years ago
#include <ESP8266WiFiMulti.h>
extern "C" {
#include <espnow.h>
}
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>
#include <DHT.h>
#include <SDS011.h>
const char* server = "ingress.opensensemap.org";
7 years ago
//const char* ssid = "Freifunk";
//const char* password = "";
constexpr unsigned int postingInterval = 60000; //Uploadintervall in Millisekunden
constexpr unsigned int powerbankInterval = 10000;
//senseBox ID
#define SENSEBOX_ID "5a9e9e38f55bff001a494877"
//Sensor IDs
// Temperature
#define SENSOR1_ID "5a9e9e38f55bff001a49487e"
// Humidity
#define SENSOR2_ID "5a9e9e38f55bff001a49487d"
// Pressure
#define SENSOR3_ID "5a9e9e38f55bff001a49487c"
// PM10
#define SENSOR4_ID "5a9e9e38f55bff001a49487b"
// PM2.5
#define SENSOR5_ID "5a9e9e38f55bff001a49487a"
// Radioactivity
#define SENSOR6_ID "5a9e9e38f55bff001a494879"
// Voltage
#define SENSOR7_ID "5a9e9e38f55bff001a494878"
// RSSI
#define SENSOR8_ID "5a9eddb1f55bff001a51de52"
static constexpr uint8_t BMP_SCL = D4;
static constexpr uint8_t BMP_SDA = D3;
static constexpr uint8_t DHT22_PIN = D7;
static constexpr uint8_t DHTTYPE = DHT22; // DHT 22 (AM2302)
static constexpr uint8_t SDS_TX = D1;
static constexpr uint8_t SDS_RX = D2;
static constexpr uint8_t GEIGER_PIN = D6;
static constexpr float CONV_FACTOR = 0.008120;
static constexpr float OWN_BACKGROUND_CPS = 0.2;
static constexpr unsigned long logging_period_ms = 60000;
ADC_MODE(ADC_VCC);
7 years ago
ESP8266WiFiMulti wifiMulti;
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);
DHT dht(DHT22_PIN, DHTTYPE);
SDS011 sds;
volatile unsigned long geiger_counts = 0;
unsigned long geiger_previousMillis;
struct __attribute__((packed)) SENSOR_DATA {
float temperature;
float humidity;
float pressure;
float temp2;
float p10;
float p25;
float radioactivity;
float voltage;
float rssi;
} sd;
void ICACHE_FLASH_ATTR sendValues() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
float pressure, temp2;
bmp.getPressure(&pressure);
pressure /= 100;
bmp.getTemperature(&temp2);
float p10, p2_5;
int sds_error = sds.read(&p2_5, &p10);
if(!sds_error) {
7 years ago
// Serial.println("SDS011 updated.");
} else {
7 years ago
// Serial.println("SDS011 no new values.");
}
// sds.sleep();
unsigned long cpm = 0;
7 years ago
float radiationValue = -1;
if (millis() - geiger_previousMillis > logging_period_ms) {
cpm = geiger_counts * 60000 / (millis() - geiger_previousMillis);
unsigned long constexpr own_cpm = OWN_BACKGROUND_CPS * 60;
geiger_previousMillis = millis();
geiger_counts = 0;
radiationValue = (cpm - own_cpm) * CONV_FACTOR;
7 years ago
// Serial.println(cpm);
} else {
7 years ago
// Serial.println("Geiger Counter: no new value");
}
7 years ago
Serial.printf("Temperature : %6.2f°C (DHT22)\n", temperature);
Serial.printf("Humidity : %6.2f% (DHT22)\n", humidity);
Serial.printf("Temperature : %6.2f°C (BMP180)\n", temp2);
Serial.printf("Pressure : %6.2fhPa (BMP180)\n", pressure);
if (!sds_error) Serial.printf("Particles 10 : %6.2fµg/m³ (SDS011)\n", p10);
if (!sds_error) Serial.printf("Particles 2.5: %6.2fµg/m³ (SDS011)\n", p2_5);
if (cpm > 0) Serial.printf("Radiation : %6.2fµSv/h (J305)\n", radiationValue);
DynamicJsonBuffer jsonBuffer;
JsonArray& array = jsonBuffer.createArray();
JsonObject& temperatureObject = array.createNestedObject();
temperatureObject["sensor"] = SENSOR1_ID;
temperatureObject["value"] = temperature;
JsonObject& humidityObject = array.createNestedObject();
humidityObject["sensor"] = SENSOR2_ID;
humidityObject["value"] = humidity;
JsonObject& pressureObject = array.createNestedObject();
pressureObject["sensor"] = SENSOR3_ID;
pressureObject["value"] = pressure;
if (!sds_error) {
JsonObject& pm10Object = array.createNestedObject();
pm10Object["sensor"] = SENSOR4_ID;
pm10Object["value"] = p10;
JsonObject& pm25Object = array.createNestedObject();
pm25Object["sensor"] = SENSOR5_ID;
pm25Object["value"] = p2_5;
}
if (cpm > 0) {
JsonObject& cpmObject = array.createNestedObject();
cpmObject["sensor"] = SENSOR6_ID;
cpmObject["value"] = radiationValue;
}
JsonObject& voltageObject = array.createNestedObject();
voltageObject["sensor"] = SENSOR7_ID;
voltageObject["value"] = ESP.getVcc()/1024.0;
JsonObject& rssiObject = array.createNestedObject();
rssiObject["sensor"] = SENSOR8_ID;
rssiObject["value"] = WiFi.RSSI();
char buffer[500];
array.printTo(buffer, sizeof(buffer));
7 years ago
WiFi.forceSleepWake();
delay(1); // yield();
WiFi.persistent(false); // don't load and save credentials to flash
WiFi.mode(WIFI_STA);
wifiMulti.addAP("nether.net", "password1");
wifiMulti.addAP("LNet", "password2");
wifiMulti.addAP("Freifunk", "");
int tries = 0;
while (wifiMulti.run() != WL_CONNECTED) {
tries++;
Serial.print(".");
if (tries > 20) {
Serial.println(" [ERROR]");
Serial.println("Retrying in 1 minute..");
delay(postingInterval);
ESP.restart();
}
delay(500);
}
Serial.println(" [CONNECTED]");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
int httpCode = 0;
for (int tries=0; tries<3 && httpCode != HTTP_CODE_CREATED; tries++) {
HTTPClient httpclient;
char url[100];
sprintf(url, "http://%s/boxes/%s/data", server, SENSEBOX_ID);
httpclient.begin(url);
httpclient.addHeader("Content-Type", "application/json");
httpCode = httpclient.POST(buffer);
if (httpCode > 0) {
if (httpCode == HTTP_CODE_CREATED) {
httpclient.writeToStream(&Serial);
Serial.println();
} else {
Serial.printf("[HTTP] POST... failed, error: %s\n", httpclient.errorToString(httpCode).c_str());
}
}
httpclient.end();
}
WiFi.disconnect();
WiFi.mode(WIFI_OFF);
WiFi.forceSleepBegin();
7 years ago
delay(1); // yield();
}
7 years ago
void sendESPNOW() {
unsigned long espnowmillis = millis();
uint8_t remoteMac[] = {0x5C, 0xCF, 0x7F, 0x5, 0xFD, 0xF0};
#define WIFI_CHANNEL 1
WiFi.forceSleepWake();
delay(1); // yield();
WiFi.persistent(false); // don't load and save credentials to flash
WiFi.mode(WIFI_STA);
if (esp_now_init()==0) {
if(esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER)==0){
esp_now_add_peer(remoteMac, ESP_NOW_ROLE_SLAVE, WIFI_CHANNEL, NULL, 0);
u8 bs[sizeof(sd)];
memcpy(bs, &sd, sizeof(sd));
esp_now_send(NULL, bs, sizeof(sd)); // max ESP_NOW_MAX_DATA_LEN
} else {
Serial.println("error configuring ESP NOW");
}
} else {
Serial.println("error initializing ESP NOW");
}
esp_now_deinit();
WiFi.mode(WIFI_OFF);
WiFi.forceSleepBegin();
delay(1); // yield();
Serial.printf("sendESPNOW() took %d ms\n", millis()-espnowmillis);
}
void ICACHE_RAM_ATTR ISR_geiger_impulse() {
geiger_counts++;
}
7 years ago
void setup() {
Serial.begin(115200);
sds.begin(SDS_TX, SDS_RX);
sds.mode_mon_300();
Wire.begin(BMP_SDA, BMP_SCL);
if (!bmp.begin(BMP085_MODE_STANDARD)) {
Serial.println("No valid BMP085 sensor!");
}
dht.begin();
pinMode(GEIGER_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(GEIGER_PIN), ISR_geiger_impulse, FALLING);
7 years ago
}
void loop() {
sendValues();
/* keep powerbank happy */
for(int i=0; i<(postingInterval/powerbankInterval)-1; i++) {
delay(powerbankInterval);
sendESPNOW();
}
delay(powerbankInterval);
7 years ago
}