/* * WetterStation * Version: 0.0 * Author: Hendrik Langer */ #include #include #include extern "C" { #include #include "user_interface.h" } #include #include #include #include #include #include #include #include #include #include #include #include "main.h" const char* server = "ingress.opensensemap.org"; #define MQTT_MAX_PACKET_SIZE 512 const char* mqttserver = "home.xd0.de"; const char* mqttusername = "esp-weatherstation"; const char* mqttpassword = "password4"; constexpr unsigned int postingInterval = 60000; //Uploadintervall in Millisekunden constexpr unsigned int dhcp_interval = 60*60*1000; int loop_count = 0; #define EXTERNAL_POWER 1 //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; // documentation says 0.2 (make sure value doesn't get negative if subtracting!) #ifndef EXTERNAL_POWER ADC_MODE(ADC_VCC); #endif ESP8266WiFiMulti wifiMulti; os_timer_t Timer1; RunningAverage geigeraverage(10); 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; unsigned long last_wifi_activity = 0; unsigned long last_dhcp = 0; IPAddress ip, dns, gateway, subnet; char ssid[64]; char password[64]; struct __attribute__((packed)) SENSOR_DATA { float temperature; float humidity; float pressure; float temp2; float p10; float p25; float cpm; float radioactivity; float voltage; float rssi; } sd; /* void sendESPNOW() { // unsigned long espnowmillis = millis(); uint8_t remoteMac[] = {0x5C, 0xCF, 0x7F, 0x5, 0xFD, 0xF0}; #define WIFI_CHANNEL 1 WiFi.forceSleepWake(); delay(1); // yield(); digitalWrite(LED_BUILTIN, LOW); 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)); for (int i=0; i<20; i++) esp_now_send(NULL, bs, sizeof(sd)); // max ESP_NOW_MAX_DATA_LEN } else { DEBUG_MSG("error configuring ESP NOW\n"); } } else { DEBUG_MSG("error initializing ESP NOW\n"); } last_wifi_activity = millis(); esp_now_deinit(); WiFi.mode(WIFI_OFF); WiFi.forceSleepBegin(); delay(1); // yield(); digitalWrite(LED_BUILTIN, HIGH); // DEBUG_MSG("sendESPNOW() took %d ms\n", millis()-espnowmillis); } */ void ICACHE_FLASH_ATTR sendValues() { sd.temperature = dht.readTemperature(); sd.humidity = dht.readHumidity(); bmp.getPressure(&(sd.pressure)); sd.pressure /= 100; bmp.getTemperature(&(sd.temp2)); #ifndef EXTERNAL_POWER sd.voltage = ESP.getVcc()/1024.0; #else sd.voltage = analogRead(A0)*0.04285078 -0.05942125; // by linear regression for my(!) voltage divider. else: sd.voltage = analogRead(A0)*3.3*(R1+R2)/(R2*1024) #endif int sds_error = sds.read(&(sd.p25), &(sd.p10)); if(!sds_error) { // DEBUG_MSG("SDS011 updated.\n"); } else { // DEBUG_MSG("SDS011 no new values.\n"); } // sds.sleep(); if (millis() - geiger_previousMillis > 60000) { sd.cpm = geiger_counts * 60000 / (millis() - geiger_previousMillis); geiger_previousMillis = millis(); geiger_counts = 0; geigeraverage.addValue(sd.cpm); } //geiger_runningaverage = geigeraverage.getAverage()*10; float constexpr own_cpm = OWN_BACKGROUND_CPS * 60; sd.radioactivity = (sd.cpm - own_cpm) * CONV_FACTOR; DEBUG_MSG("Temperature : %6.2f°C (DHT22)\n", sd.temperature); DEBUG_MSG("Humidity : %6.2f%% (DHT22)\n", sd.humidity); DEBUG_MSG("Temperature : %6.2f°C (BMP180)\n", sd.temp2); DEBUG_MSG("Pressure : %6.2fhPa (BMP180)\n", sd.pressure); if (!sds_error) DEBUG_MSG("Particles 10 : %6.2fµg/m³ (SDS011)\n", sd.p10); if (!sds_error) DEBUG_MSG("Particles 2.5: %6.2fµg/m³ (SDS011)\n", sd.p25); if (sd.cpm > 0) DEBUG_MSG("Radiation : %6.2fµSv/h (J305)\n", sd.radioactivity); DEBUG_MSG("Voltage : %6.2fV (ESP8266)\n", sd.voltage); DynamicJsonBuffer jsonBuffer; JsonArray& array = jsonBuffer.createArray(); DynamicJsonBuffer jsonBuffer2; JsonObject& root = jsonBuffer.createObject(); JsonObject& temperatureObject = array.createNestedObject(); temperatureObject["sensor"] = SENSOR1_ID; temperatureObject["value"] = sd.temperature; root["temperature"] = sd.temperature; JsonObject& humidityObject = array.createNestedObject(); humidityObject["sensor"] = SENSOR2_ID; humidityObject["value"] = sd.humidity; root["humidity"] = sd.humidity; JsonObject& pressureObject = array.createNestedObject(); pressureObject["sensor"] = SENSOR3_ID; pressureObject["value"] = sd.pressure; root["pressure"] = sd.pressure; if (!sds_error) { JsonObject& pm10Object = array.createNestedObject(); pm10Object["sensor"] = SENSOR4_ID; pm10Object["value"] = sd.p10; root["pm10"] = sd.p10; JsonObject& pm25Object = array.createNestedObject(); pm25Object["sensor"] = SENSOR5_ID; pm25Object["value"] = sd.p25; root["pm2.5"] = sd.p25; } if (sd.cpm > 0) { JsonObject& cpmObject = array.createNestedObject(); cpmObject["sensor"] = SENSOR6_ID; cpmObject["value"] = sd.radioactivity; root["cpm"] = sd.cpm; root["radioactivity"] = sd.radioactivity; } JsonObject& voltageObject = array.createNestedObject(); voltageObject["sensor"] = SENSOR7_ID; voltageObject["value"] = sd.voltage; root["voltage"] = sd.voltage; JsonObject& rssiObject = array.createNestedObject(); rssiObject["sensor"] = SENSOR8_ID; rssiObject["value"] = sd.rssi; root["rssi"] = sd.rssi; char buffer[500]; array.printTo(buffer, sizeof(buffer)); 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("hw1_gast", "password3"); wifiMulti.addAP("Freifunk", ""); if ( ip != INADDR_NONE && dns != INADDR_NONE && gateway != INADDR_NONE && subnet != INADDR_NONE && ((ip[0] == 192 && ip[1] == 168) || (ip[0] == 172 && ip[1] == 16)) && strlen(ssid) > 0 && strlen(password) > 0 && (millis() - last_dhcp < dhcp_interval) ) { DEBUG_MSG("static ip\n"); WiFi.config(ip, dns, gateway, subnet); WiFi.begin(ssid, password); int tries = 0; constexpr unsigned int retry_delay = 500; constexpr unsigned int max_retry_delay = 10000; while (WiFi.status() != WL_CONNECTED) { tries++; DEBUG_MSG("."); if (tries*retry_delay >= max_retry_delay) { DEBUG_MSG(" [ERROR]\n"); DEBUG_MSG("Rebooting..\n"); ESP.restart(); } delay(retry_delay); } DEBUG_MSG(" [CONNECTED, static]\n"); DEBUG_MSG("IP address: "); DEBUG_MSG("%s\n", String(WiFi.localIP()).c_str()); } else { DEBUG_MSG("dhcp\n"); int tries = 0; constexpr unsigned int retry_delay = 500; constexpr unsigned int max_retry_delay = 12000; while (wifiMulti.run() != WL_CONNECTED) { tries++; DEBUG_MSG("."); if (tries*retry_delay >= max_retry_delay) { DEBUG_MSG(" [ERROR]\n"); DEBUG_MSG("Rebooting..\n"); ESP.restart(); } delay(retry_delay); } DEBUG_MSG(" [CONNECTED, dhcp]\n"); DEBUG_MSG("IP address: "); DEBUG_MSG("%s\n", String(WiFi.localIP()).c_str()); ip = WiFi.localIP(); dns = WiFi.dnsIP(); gateway = WiFi.gatewayIP(); subnet = WiFi.subnetMask(); strncpy(ssid, WiFi.SSID().c_str(), 64); strncpy(password, WiFi.psk().c_str(), 64); last_dhcp = millis(); } sd.rssi = WiFi.RSSI(); 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); DEBUG_MSG("\n"); } else { DEBUG_MSG("[HTTP] POST... failed, error: %s\n", httpclient.errorToString(httpCode).c_str()); } } httpclient.end(); } WiFiClientSecure net; MQTTClient mqttclient(MQTT_MAX_PACKET_SIZE); mqttclient.begin(mqttserver, 8883, net); int tries = 0; constexpr unsigned int retry_delay = 500; constexpr unsigned int max_retry_delay = 5000; while (!mqttclient.connect(mqttusername, mqttusername, mqttpassword)) { tries++; DEBUG_MSG("."); if (tries*retry_delay >= max_retry_delay) { DEBUG_MSG(" [ERROR]\n"); DEBUG_MSG("Rebooting..\n"); ESP.restart(); } delay(retry_delay); } mqttclient.loop(); root.printTo(buffer, sizeof(buffer)); if (mqttclient.publish("sensor/esp-weatherstation/01/json", buffer, strlen(buffer))) { DEBUG_MSG("mqtt done\n"); } else { DEBUG_MSG("mqtt failed\n"); } mqttclient.loop(); mqttclient.disconnect(); if (loop_count == 1) { XD0OTA ota; ota.update(); } loop_count++; last_wifi_activity = millis(); WiFi.disconnect(); WiFi.mode(WIFI_OFF); WiFi.forceSleepBegin(); delay(1); // yield(); } void ICACHE_RAM_ATTR ISR_geiger_impulse() { geiger_counts++; } void setup() { #ifdef USERDEBUG Serial.begin(115200); #endif pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); // turn OFF board led sds.begin(SDS_TX, SDS_RX); sds.mode_mon_300(); Wire.begin(BMP_SDA, BMP_SCL); if (!bmp.begin(BMP085_MODE_STANDARD)) { DEBUG_MSG("No valid BMP085 sensor!\n"); } dht.begin(); pinMode(GEIGER_PIN, INPUT); attachInterrupt(digitalPinToInterrupt(GEIGER_PIN), ISR_geiger_impulse, FALLING); geigeraverage.clear(); DEBUG_MSG("ready.\n"); Serial.flush(); } void loop() { //DEBUG_MSG("%d\n", millis() - last_wifi_activity); sendValues(); delay(postingInterval); }