//####################################################################################### // // Copyright: // // For all parts regarding the additions made by RIVM the GPL 4 license conditions, // quoted below apply! // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, version 4 of the License, or // any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // //####################################################################################### // // // //####################################################################################### //============================================== // Code for NodeMCU v1.0 module (ESP8266) // Waag Society, Making Sense // author: Dave Gonner & Emma Pareschi // version 11 May 2016 //============================================== // RIVM, aanpassingen Joost Wesseling // Version 25 september 2016 // Version 28 september 2016 // - Aangepast voor test-data. // Version 24 November 2016 // - Aangepast voor voor metingen aan vuurwerk. //============================================== #include // Make sure ESP library 2.1.0 or higher is installed #include //https://github.com/esp8266/Arduino #include #include #include //https://github.com/tzapu/WiFiManager #include //https://github.com/bblanchon/ArduinoJson #include //https://github.com/knolleary/pubsubclient // DEFAULT MQTT SETTINGS, will be overwritten by values from config.json // We only use some variables in the interface of the Access Point formed // by the ESP. For communicating WE DO NOT USE MQTT, but employ the // services of an InFluxDB! char mqtt_server[41] = "VUURWERK 2017/2018\0"; char mqtt_portStr[7] = "12345\0"; char mqtt_username[21] = "not used\0"; char mqtt_password[21] = "not used\0"; char mqtt_topic[21] = "20\0"; // Default for test-data int mqtt_port = atoi(mqtt_portStr); long TotCount = 0; // Button and indicators of activities #define BUTTON_PIN 16 // D0, button to enter wifi manager #define RED_LED_PIN 0 // D2 #define BLUE_LED_PIN 2 // D6 #define IIMAX 256 // Do we want red/blue led's blinking? // 0 = No // 1 = Errors // 2 = All int DoBlinkStatus = 2; String InfluxThing = "vuurwerk"; // Needed for the ESP WiFiManager wifiManager; WiFiClient espClient; PubSubClient mqttClient(espClient); String readStr; long chipid; bool shouldSaveConfig = false; //flag for saving data // Parameters to be transmitted ... String id = "01234567890123456789"; String val0 = "-999.999"; String val1 = "-999.999"; String val2 = "-999.999"; String val3 = "-999.999"; String val4 = "-999.999"; String val5 = "-999.999"; String val6 = "-999.999"; String val7 = "-999.999"; String val8 = "-999.999"; String val9 = "-999.999"; float x0 = 0.0, x1 = 0.0, x2 = 0.0, x3 = 0.0, x4 = 0.0, x5 = 0.0, x6 = 0.0, x7 = 0.0, x8 = 0.0; long rssi ; // WiFi strength #define LOG_INTERVAL 925 // mills between entries (reduce to take more/faster data) //======================================================= // Dust Sensor settings #define DUST_PM10_PIN 13 // Dust sensor PM10 pin unsigned long starttime = 0; unsigned long triggerOnP2; unsigned long triggerOffP2; unsigned long pulseLengthP2; unsigned long durationP2; boolean valP2 = HIGH; boolean triggerP2 = false; float ratioP2 = 0; unsigned long sampletime_ms = 20000; // For averaging the dust measurements: int NAvg = 0; int MaxIter = 2; float SumDust = 0.0; long NumMelding = 0; //======================================================= // Fot the SDS011 unsigned int Pm25 = 0; unsigned int Pm10 = 0; int Status = -1; int LastError = 0; float p10 = 0.0, p25 = 0.0; #define SDS_ITER 150 // #define SDS_ITER 150 int error; int count = 0; int cnt = 0; int ecnt = 0; float s25 = 0.0; float s10 = 0.0; //======================================================= //For the BME #include #include bool status_BME = 0; #define BME_SCK 13 #define BME_MISO 12 #define BME_MOSI 11 #define BME_CS 10 #define SEALEVELPRESSURE_HPA (1013.25) Adafruit_BME280 bme; // I2C //======================================================= //callback notifying us of the need to save config void saveConfigCallback () { Serial.println("Should save config"); shouldSaveConfig = true; } //======================================================= // Taken from Github // Used to store configuration data // void saveConfigJson() { //save the custom parameters to FS Serial.println("saving config"); DynamicJsonBuffer jsonBuffer; JsonObject& json = jsonBuffer.createObject(); json["mqtt_server"] = mqtt_server; json["mqtt_port"] = mqtt_portStr; json["mqtt_username"] = mqtt_username; json["mqtt_password"] = mqtt_password; json["mqtt_topic"] = mqtt_topic; File configFile = SPIFFS.open("/config.json", "w"); if (!configFile) { Serial.println("failed to open config file for writing"); } json.printTo(Serial); Serial.println(); json.printTo(configFile); configFile.close(); //end save } //======================================================= // Mostly taken from Github // Used to setup the ESP and create a WiFi Access Point // void setup() { int i; Serial.begin(9600); Serial.println("Start"); Pm25 = 0; Pm10 = 0; // We gebruiken de input op de niet-aangesloten analoge ingang als seed voor de random functie pinMode(A0, INPUT); pinMode(BUTTON_PIN, INPUT); pinMode(BLUE_LED_PIN, OUTPUT); digitalWrite(BLUE_LED_PIN, HIGH); // off pinMode(RED_LED_PIN, OUTPUT); digitalWrite(RED_LED_PIN, HIGH); // off Serial.println(F("BME280 test")); // default settings status_BME = bme.begin(); if (!status_BME) { Serial.println(" NO BME ??" ); for (i = 0 ; i < 25 ; i++) { digitalWrite(BLUE_LED_PIN, LOW); // off delay(40); digitalWrite(BLUE_LED_PIN, HIGH); // off delay(60); } digitalWrite(RED_LED_PIN, HIGH); // on digitalWrite(BLUE_LED_PIN, HIGH); // on Serial.println("Could not find a valid BME280 sensor, check wiring!"); delay(1000); Serial.println("Could not find a valid BME280 sensor, check wiring!"); delay(1000); Serial.println("Could not find a valid BME280 sensor, check wiring!"); delay(1000); Serial.println("Could not find a valid BME280 sensor, check wiring!"); delay(1000); // while (1); } Serial.println("==============================================="); Serial.println(" Code for NodeMCU v1.0 module (ESP8266) "); Serial.println(" Waag Society, Making Sense "); Serial.println(" Author: Dave Gonner & Emma Pareschi "); Serial.println(" Version 11 May 2016 "); Serial.println("==============================================="); Serial.println(" Adapted for use by RIVM "); Serial.println(" Version 02 December 2017 "); Serial.print (" DoBlinkStatus = "); Serial.println( DoBlinkStatus ); Serial.println("==============================================="); Serial.println("ESP8266 0.1 ..."); Serial.println("mounting FS..."); // // The code in the remainder of Setup() was obtained from Github and only marginally modified. // if (SPIFFS.begin()) { Serial.println("mounted file system"); if (SPIFFS.exists("/config.json")) { //file exists, reading and loading Serial.println("reading config file"); File configFile = SPIFFS.open("/config.json", "r"); if (configFile) { Serial.println("opened config file"); size_t size = configFile.size(); // Allocate a buffer to store contents of the file. std::unique_ptr buf(new char[size]); configFile.readBytes(buf.get(), size); DynamicJsonBuffer jsonBuffer; JsonObject& json = jsonBuffer.parseObject(buf.get()); json.printTo(Serial); if (json.success()) { Serial.println("\nparsed json"); strcpy(mqtt_server, json["mqtt_server"]); strcpy(mqtt_portStr, json["mqtt_port"]); mqtt_port = atoi(mqtt_portStr); strcpy(mqtt_username, json["mqtt_username"]); strcpy(mqtt_password, json["mqtt_password"]); strcpy(mqtt_topic, json["mqtt_topic"]); } else { Serial.println("failed to load json config"); } } } else { Serial.println("/config.json does not exist, creating"); saveConfigJson(); // saving the hardcoded default values } } else { Serial.println("failed to mount FS"); } //end read wifiManager.setSaveConfigCallback(saveConfigCallback); boolean startConfigPortal = false; if ( digitalRead(BUTTON_PIN) == LOW ) { Serial.println("startConfigPortal = true"); // startConfigPortal = true; Serial.println("DISABLED startConfigPortal = true"); } WiFi.mode(WIFI_STA); if (WiFi.SSID()) { Serial.println("Using saved credentials"); ETS_UART_INTR_DISABLE(); wifi_station_disconnect(); ETS_UART_INTR_ENABLE(); WiFi.begin(); } else { Serial.println("No saved credentials"); startConfigPortal = true; } WiFi.waitForConnectResult(); if (WiFi.status() != WL_CONNECTED) { Serial.print("Failed to connect Wifi"); startConfigPortal = true; } if (startConfigPortal) { WiFiManagerParameter custom_mqtt_port("port", "mqtt port", mqtt_portStr, 6); WiFiManagerParameter custom_mqtt_username("username", "mqtt username", mqtt_username, 20); WiFiManagerParameter custom_mqtt_password("password", "mqtt password", mqtt_password, 20); // Informatie in de interface: sprintf(mqtt_topic, "%ld", ESP.getChipId()); sprintf(mqtt_server, "RIVM VUURWERK 2017/2018\0"); WiFiManagerParameter custom_mqtt_topic("topic", "mqtt topic", mqtt_topic, 20); WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40); wifiManager.addParameter(&custom_mqtt_server); wifiManager.addParameter(&custom_mqtt_topic); // If the user requests it, start the wifimanager digitalWrite(RED_LED_PIN, LOW); // off digitalWrite(BLUE_LED_PIN, LOW); // on wifiManager.startConfigPortal("SENSOR_RIVM"); digitalWrite(BLUE_LED_PIN, HIGH); // off if (shouldSaveConfig) { // read the updated parameters strcpy(mqtt_server, custom_mqtt_server.getValue()); strcpy(mqtt_portStr, custom_mqtt_port.getValue()); mqtt_port = atoi(mqtt_portStr); strcpy(mqtt_username, custom_mqtt_username.getValue()); strcpy(mqtt_password, custom_mqtt_password.getValue()); strcpy(mqtt_topic, custom_mqtt_topic.getValue()); saveConfigJson(); shouldSaveConfig = false; } } Serial.println("Wifi connected..."); Serial.print("Wifi SSID = "); Serial.println(WiFi.SSID()); // Blink uitbundig met rood als we verbonden zijn .... for (i = 0 ; i < 15 ; i++) { digitalWrite(RED_LED_PIN, LOW); // off delay(100); digitalWrite(RED_LED_PIN, HIGH); // off delay(100); } mqttClient.setServer(mqtt_server, mqtt_port); chipid = ESP.getChipId(); //----------------------------------- // Some setup for the Shinyei ... starttime = millis(); pinMode(DUST_PM10_PIN, INPUT); randomSeed(analogRead(A0)); } //####################################################################### // // void DoInfluxdbPost() { int i, j, ii; char sret[IIMAX]; char *sok = "HTTP/1.1 204 No Content"; WiFiClient client; const char* host = "#HOST_NAME_ASK_RIVM#"; String PostData = InfluxThing + ",id=" + String( chipid ) ; PostData += " Temp="; PostData += x0; PostData += ",Pres="; PostData += x1; PostData += ",Hum="; PostData += x2; PostData += ",PM25="; PostData += x3; PostData += ",PM10="; PostData += x4; PostData += ",RSSI="; PostData += x5; PostData += ",ERROR="; PostData += x6; PostData += ",ECOUNT="; PostData += x7; PostData += ",SMPLS="; PostData += x8; // Both ON if (DoBlinkStatus > 1) { Serial.println("\nInfluxdbPost"); digitalWrite(RED_LED_PIN, LOW); // on digitalWrite(BLUE_LED_PIN, LOW); // on } Serial.println("\n\n"); Serial.println(PostData); Serial.println("\n\n"); Serial.println("Ready for InfluxdbPost"); int iret = client.connect(host, 8086); // Problem connecting to WiFi: RED ON if (iret < 0) { Serial.println("\nNO client.connect ??" ); if (DoBlinkStatus > 0) { digitalWrite(RED_LED_PIN, LOW); } Serial.println("\n=====================================================\n"); Serial.print("FAILED CONNECT InfluxdbPost, code = "); Serial.println( iret); Serial.println("TIMED_OUT -1 "); Serial.println("INVALID_SERVER -2 "); Serial.println("TRUNCATED -3 "); Serial.println("INVALID_RESPONSE -4 "); Serial.println("=====================================================\n"); Serial.println(" "); delay(20); return; } //####################################################################### // // IF YOU WANT TO SEND YOUR DATA TO THE RIVM DATA PORTAL PLEASE CONTACT // // SAMENMETEN@RIVM.NL // // FOR CREDENTIALS AND IMPLEMENTATION !!! // client.println("POST /write?db=#DBNAME#&u=#UNAME#&p=#PASSWRD# HTTP/1.1"); client.println("Host: #HOST_NAME_ASK_RIVM#:8086"); client.println("Cache-Control: no-cache"); client.println("Content-Type: application/x-www-form-urlencoded"); client.print("Content-Length: "); client.println(PostData.length()); client.println(); client.println(PostData); ii = 0; while (client.available()) { char c = client.read(); if (ii < IIMAX) { sret[ii++] = c; } Serial.print(c); } sret[ii] = '\n'; int sdif = 0; for (i = 0 ; i < strlen(sok) ; i++) { if (sret[i] != *(sok + i)) { sdif++; } } //---------------------------------- // Respons InFluxDB not OK if (sdif > 0) { iret = -100 * sdif; Serial.print("\nDId not get EXPECTED respons from InFluxDB "); Serial.println(iret); Serial.print("["); Serial.print(sret); Serial.println("]"); Serial.println(PostData); digitalWrite(RED_LED_PIN, HIGH); // off if (DoBlinkStatus > 0) { // BLUE BLINK 15 for (i = 0 ; i < 15 ; i++) { digitalWrite(BLUE_LED_PIN, LOW); // off delay(450); digitalWrite(BLUE_LED_PIN, HIGH); // off delay(150); } // BLUE ON digitalWrite(BLUE_LED_PIN, LOW); // off } } //---------------------------------- // UNDEFINED issue, BLUE BLINK 15 if (iret == 0 && DoBlinkStatus > 0) { Serial.print("Did not get ANY respons from InFluxDB "); digitalWrite(RED_LED_PIN, HIGH); // off for (i = 0 ; i < 15 ; i++) { digitalWrite(BLUE_LED_PIN, LOW); // off delay(150); digitalWrite(BLUE_LED_PIN, HIGH); // off delay(150); } } if (iret > 0 && DoBlinkStatus > 1) { // Communication OK, BLINK RED/BLUE 15 Serial.print("\nEverything seems OK ... "); for (i = 0 ; i < 15 ; i++) { digitalWrite(BLUE_LED_PIN, LOW); // off digitalWrite(RED_LED_PIN, HIGH); // off delay(150); digitalWrite(BLUE_LED_PIN, HIGH); // off digitalWrite(RED_LED_PIN, LOW); // off delay(150); } digitalWrite(RED_LED_PIN, HIGH); // on digitalWrite(BLUE_LED_PIN, HIGH); // on } if (iret > 0) { digitalWrite(RED_LED_PIN, HIGH); // off digitalWrite(BLUE_LED_PIN, HIGH); // off } Serial.print("\nSDif, IRet = "); Serial.print(sdif); Serial.print(", "); Serial.print(iret); } //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // void loop_bme() { x0 = -1.0; x1 = -1.0; x2 = -1.0; if (status_BME) { x0 = bme.readTemperature(); x1 = bme.readPressure() / 100.0F; x2 = bme.readHumidity(); } Serial.print("T = "); Serial.print(x0); Serial.print(" *C \t"); Serial.print("P = "); Serial.print(x1); Serial.print(" hPa \t"); Serial.print("RH = "); Serial.print(x2); Serial.print(" % \t"); } //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // void ProcessSerialData() { uint8_t mData = 0; uint8_t i = 0; uint8_t mPkt[10] = {0}; uint8_t mCheck = 0; Status = -1; // Default: no data availabe ... p10 = -1.0; p25 = -1.0; while (Serial.available() > 0) { // from www.inovafitness.com // packet format: AA C0 PM25_Low PM25_High PM10_Low PM10_High 0 0 CRC AB Status = 0; // There is data! mData = Serial.read(); delay(10);//wait until packet is received if (mData == 0xAA) // Head1 ok? { mPkt[0] = mData; mData = Serial.read(); if (mData == 0xc0) // Head2 ok? { mPkt[1] = mData; mCheck = 0; for (i = 0; i < 6; i++) // Get the content of the package! { mPkt[i + 2] = Serial.read(); delay(2); mCheck += mPkt[i + 2]; } mPkt[8] = Serial.read(); delay(5); mPkt[9] = Serial.read(); if (mPkt[9] != 0xAB) { Serial.print("\nmData[9] != 0xAB, but "); Serial.println(mPkt[9]); Status = 4; LastError = Status; ecnt++; } if (mCheck == mPkt[8]) // Check CRC { Serial.flush(); //Serial.write(mPkt,10); Pm25 = (uint16_t)mPkt[2] | (uint16_t)(mPkt[3] << 8); Pm10 = (uint16_t)mPkt[4] | (uint16_t)(mPkt[5] << 8); if (Pm25 > 9999) Pm25 = 9999; if (Pm10 > 9999) Pm10 = 9999; p25 = Pm25 / 10.0; p10 = Pm10 / 10.0; while (Serial.available() > 0) { // Zap buffer ... mData = Serial.read(); } return; // We now have one good packet :-)) } // CRC ?? else { Serial.print("\nCRC != OK, "); Serial.print(mCheck); Serial.print(" != "); Serial.println(mPkt[8]); Status = 3; LastError = Status; ecnt++; } } // Head2 ?? else { Serial.print("\nmData != 0xc0, but "); Serial.println(mData); Status = 2; LastError = Status; ecnt++; } } // Head1 ?? else { Serial.print("\nmData != 0xAA, but "); Serial.println(mData); Status = 1; LastError = Status; ecnt++; } } } //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // // The main loop that is continually called/executed. // void loop() { int aux; int i; int secs = 0; count++; Serial.print(count); Serial.print("\t"); // Measure if (count < SDS_ITER) { loop_bme(); x3 = -1.0; x4 = -1.0; ProcessSerialData(); x6 = LastError; if (p25 > -1.0 && p10 > -1.0) { Serial.print("PM2.5 = " + String(p25)); Serial.print("\tPM10 = " + String(p10)); x3 = p25; x4 = p10; s25 += p25; s10 += p10; cnt += 1; } else { x6 = (float) LastError; Serial.print("\tERROR= "); Serial.print(LastError); Serial.print("\t "); ecnt++; } } Serial.print("\tERROR= "); Serial.print(LastError); Serial.print("\tSMPLS= "); Serial.print(cnt); Serial.print("\tECOUNT= "); Serial.print(ecnt); if (count % 30 == 0 && DoBlinkStatus > 1) { Serial.print("\nHappily measuring ... "); digitalWrite(RED_LED_PIN, LOW); // on delay(100); digitalWrite(RED_LED_PIN, HIGH); // off } // Stop after NNN seconds and send to server: if (count == SDS_ITER) { s25 /= cnt; s10 /= cnt; x3 = s25; x4 = s10; // Send the data: if (DoBlinkStatus > 1) { Serial.print("\nStart send data "); digitalWrite(RED_LED_PIN, LOW); // off delay(250); digitalWrite(RED_LED_PIN, HIGH); // off } // Always show: // problem with WiFi, RED constant ON if (WiFi.RSSI() >= 0) { Serial.print("\nNo WiFi???? "); digitalWrite(RED_LED_PIN, HIGH); // off } rssi = WiFi.RSSI(); // RSSI = wifi signal strength x5 = rssi; x7 = ecnt; x8 = cnt; delay(100); DoInfluxdbPost(); TotCount++; Serial.print("\n\nTotCount = "); Serial.println(TotCount); if (TotCount > 1000000) TotCount = 1000; if (TotCount > 10 && DoBlinkStatus > 1) { DoBlinkStatus = 1; Serial.print("\nDoBlinkStatus reduced to 1 "); } count = 0; cnt = 0; ecnt = 0; LastError = 0; x6 = 0.0; s25 = 0.0; s10 = 0.0; delay(2500); } Serial.println(); delay(1000); }