// Arduino Environment Station for Wemos D1 Mini // BUSY -> D0 = GPIO16 // RST -> D4 = GPIO2 // DC -> D3 = GPIO0 // CS -> D8 = GPIO15 (ADD 1Kohm pulldown resistor !!!) // CLK -> D5 = GPIO14 // DIN -> D7 = GPIO13 // GND -> GND // 3.3V -> 3.3V #include #include #include #include #define BMP_SCK (13) #define BMP_MISO (12) #define BMP_MOSI (11) #define BMP_CS (10) #define HEAD_HEIGHT 18 #include "DHT.h" // DHT -> D6 #define DHTPIN 12 // DHT Sensor PIN #define DHTTYPE DHT22 // DHT Sensor Type #include "NTPtimeESP.h" #include #include #include GxEPD_BitmapExamples // FreeFonts from Adafruit_GFX #include #include #include #include #include #include #include char *ssid = "lauIOT"; // Set you WiFi SSID char *password = "superiot1"; // Set you WiFi password GxIO_Class io(SPI, /*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2); // arbitrary selection of D3(=0), D4(=2), selected for default of GxEPD_Class GxEPD_Class display(io, /*RST=D4*/ 2, /*BUSY=D0*/ 16); // default selection of D4(=2), D2(=4) /* Display config ---------------------------------- | header of 28 pixel height | ---------------------------------- | widget 0 | widget 1 | widget 2 | | 130x90 | 130x90 | 130x90 | | at 2,30 | at 135,30| at 138,30| ---------------------------------- | widget 3 | widget 4 | widget 5 | | 130x90 | 130x90 | 130x90 | | at 2,120 | at135,120| at138,120| ---------------------------------- | widget 6 | widget 7 | widget 8 | | 130x90 | 130x90 | 130x90 | | at 2,210 | at135,210| at138,210| ---------------------------------- TODOS ----- - Draw Head OK - - Draw Title OK - Draw Widget OK - Integrate TempS OK - - Draw T° OK - - Draw HR OK - Integrate Pressure OK - - Draw Press OK - Draw min max OK - Integrate Time OK - - Draw Time OK - Get variables private - Publish REST API - Show Temp & hydro graph - Make formatting nicer :) - Make it configurable (web interface) - Timezone - Wifi credentials - reset high low */ DHT dht(DHTPIN, DHTTYPE); // Initialize DHT sensor for normal 16mhz Arduino unsigned long ref_time; Adafruit_BMP280 bmp; // I2C NTPtime NTPch("ntp.belnet.be"); // Choose server pool as required WiFiServer server(80); class Environment { public: strDateTime dateTime; Environment() { this->temperature_min = 100.0; this->temperature_max = -100.0; this->humidity_min = 100.0; this->humidity_max = 0.0; this->pressure_min = 9999; this->pressure_max = 0; } void setDateTime(strDateTime d) { dateTime = d; } void setTemp(float t) { this->temperature = t; if(this->temperature < this->temperature_min ) this->temperature_min = this->temperature; if(this->temperature > this->temperature_max ) this->temperature_max = this->temperature; } void setPress(unsigned int p) { this->pressure = p; if(this->pressure < this->pressure_min ) this->pressure_min = this->pressure; if(this->pressure > this->pressure_max ) this->pressure_max = this->pressure; } void setHumid(float h) { this->humidity = h; if(this->humidity < this->humidity_min ) this->humidity_min = this->humidity; if(this->humidity > this->humidity_max ) this->humidity_max = this->humidity; } float getTemp() { return this->temperature; } float getTempMin() { return this->temperature_min; } float getTempMax() { return this->temperature_max; } unsigned int getPress() { return this->pressure; } unsigned int getPressMin() { return this->pressure_min; } unsigned int getPressMax() { return this->pressure_max; } float getHumid() { return this->humidity; } float getHumidMin() { return this->humidity_min; } float getHumidMax() { return this->humidity_max; } String formatDate() { char strdatetime[32]; if(this->dateTime.valid) { NTPch.printDateTime(this->dateTime); sprintf(strdatetime,"%02i/%02i/%04i %02i:%02i\0",this->dateTime.day,this->dateTime.month,this->dateTime.year,this->dateTime.hour,this->dateTime.minute); return String(strdatetime); } else { return String("invalid date"); } } private: float temperature; float temperature_min; float temperature_max; float humidity; float humidity_min; float humidity_max; unsigned int pressure; unsigned int pressure_min; unsigned int pressure_max; }; Environment E; void setup() { Serial.begin(115200); Serial.println(); Serial.println("Start setup"); /* SETUP WIFI */ Serial.println("Connecting to Wi-Fi"); WiFi.mode(WIFI_STA); WiFi.begin (ssid, password); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println("."); Serial.println("WiFi connected."); // Start the server server.begin(); Serial.println("Server started"); Serial.print("Use this URL : http://"); Serial.print(WiFi.localIP()); Serial.println("/"); /* SETUP TEMP SENSOR */ display.init(115200); // enable diagnostic output on Serial Serial.println("setup dht"); dht.begin(); /* SETUP PRESSURE SENSOR */ Serial.println("setup pressure sensor"); if (!bmp.begin()) { Serial.println(F("Could not find a valid BMP280 sensor, check wiring!")); while (1); } bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */ Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */ Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */ Adafruit_BMP280::FILTER_X16, /* Filtering. */ Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */ /* SETUP NTP */ NTPch.setSendInterval(1); // set interval to 3 seconds NTPch.setRecvTimeout(1); // in seconds /* INIT min/max to something that will be overwrited */ E = Environment(); Serial.println("setup done"); delay(1000); ref_time = millis(); } void loop() { WiFiClient client = server.available(); if ( (millis() - ref_time) >= 10000 ) { // On attends depuis plus de 10 secondes. Serial.println("Start Evt"); retreiveData(&E); drawDisplay(&E); ref_time = millis(); } if (!client) { return; } // Wait until the client sends some data Serial.println("new client"); while(!client.available()) { delay(1); } char request[256]; /* Path max length */ char xmlFeedback[256]; char delim[] = "/ "; client.readStringUntil('\r').toCharArray(request,128); char *ptr = strtok(request, delim); String path[8]; /* MAXIMUM DEPTH OF 6 */ for(int i=0;ptr != NULL;i++) { path[i] = ptr; ptr = strtok(NULL, delim); } Serial.println(" Request with arguments : [" + (String)path[1] + "][" + (String)path[2] + "][" + (String)path[3] + "] "); if(path[1].equals("GET")) { if(path[2].equals("ENVIR")) { sprintf(xmlFeedback,"%.2f%.2f%u",E.getTemp(),E.getHumid(),E.getPress()); client.println("" + (String)xmlFeedback + ""); } } /* * PATH 1 = GET or SET * PATH 2 = INSTRUCTION * PATH 3 = PARAMETER */ else { client.println("Message received !!!\n"); } delay(1); } void retreiveData(Environment *E) { /* RETREIVE DATA'S */ E->setDateTime(NTPch.getNTPtime(1.0, 1)); delay(400); E->setTemp( dht.readTemperature() ); E->setHumid( dht.readHumidity() ); E->setPress( (int)round(bmp.readPressure()/100) ); E->setDateTime( NTPch.getNTPtime(1.0, 1)); Serial.println("temp : " + String(E->getTemp())); Serial.println("humid : " + String(E->getHumid())); Serial.println("pressure : " + String(E->getPress())); } void drawDisplay(Environment *E) { /* DRAW DATA'S */ drawHead(E); drawWidget(0,"temperature", &FreeSansBold18pt7b, String(E->getTemp(),1)+"°c" , String(E->getTempMin(),1)+"c", String(E->getTempMax(),1)+"c"); drawWidget(1,"hygrometry" , &FreeSansBold18pt7b, String(E->getHumid() ,1)+"%" , String(E->getHumidMin(),1)+"%" , String(E->getHumidMax(),1)+"%" ); drawWidget(2,"pressure" , &FreeSansBold18pt7b, String(E->getPress() )+"Pa" , String(E->getPressMin() )+"pa" , String(E->getPressMax() )+"pa" ); /* drawWidget(3,"T min-max" , &FreeMonoBold12pt7b, "bbbb", String("0123"), String("1234")); drawWidget(4,"H min-max" , &FreeMonoBold12pt7b, "cccc", String("0123"), String("1234")); drawWidget(5,"F" , &FreeMonoBold12pt7b, "dddd", String("0123"), String("1234")); drawWidget(6,"G" , &FreeMonoBold12pt7b, "eeee", String("0123"), String("1234")); drawWidget(7,"H" , &FreeMonoBold12pt7b, "ffff", String("0123"), String("1234")); drawWidget(8,"I" , &FreeMonoBold12pt7b, "gggg", String("0123"), String("1234")); */ display.update(); } void drawHead(Environment *E) { // Serial.println("Draw Head"); int16_t x1, y1; uint16_t w, h; String mydate(E->formatDate()); display.fillScreen(GxEPD_BLACK); display.fillRect(0, HEAD_HEIGHT, 400, 2, GxEPD_BLACK); display.setTextColor(GxEPD_WHITE); display.setFont(&FreeMonoBold12pt7b); display.getTextBounds(mydate, 0, 0, &x1, &y1, &w, &h); display.setCursor( (int)((400-w)/2) , HEAD_HEIGHT-2 ); display.println(mydate); } void drawWidget(unsigned char widgetPos, String title, const GFXfont* f, String value, String vmin, String vmax) { /* Header 20px height, Value 70px height */ int16_t x1, y1; uint16_t w, h; Serial.print("Draw Widget "); Serial.println(widgetPos); uint16_t box_w = 130; uint16_t box_h = 86; uint16_t box_x = (int)(((widgetPos%3)*133)+2); uint16_t box_y = (int)(((widgetPos/3)*(box_h+2))+HEAD_HEIGHT+1); uint16_t cursor_y = box_y; display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE); //display.setCursor(box_x, box_y + 16 ); display.setFont(&FreeMonoBold9pt7b); display.setTextColor(GxEPD_BLACK); display.getTextBounds(title, 0, 0, &x1, &y1, &w, &h); display.setCursor( (int)(box_x + (130-w)/2) , (int)(box_y + h + 0 ) ); display.print(title); /* Display value */ display.setFont(f); display.getTextBounds(value, 0, 0, &x1, &y1, &w, &h); display.setCursor( (int)(box_x + (box_w-w)/2) , (int)(box_y + 40 + ((40-h)/2)) ); display.print(value); /* Display min value */ display.setFont(&FreeMonoBold9pt7b); display.getTextBounds(vmin, 0, 0, &x1, &y1, &w, &h); display.setCursor( (int)(box_x + 6) , (int)(box_y + 62) ); display.print("min:" + vmin); /* Display max value */ display.setFont(&FreeMonoBold9pt7b); display.getTextBounds(vmax, 0, 0, &x1, &y1, &w, &h); display.setCursor( (int)(box_x + 6) , (int)(box_y + 76) ); display.print("max:" + vmax); //vmin // display.updateWindow(box_x, box_y, box_w, box_h, true); }