//#######################################################################################
//
// 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);
}