/********* Rui Santos & Sara Santos - Random Nerd Tutorials Complete project details at https://RandomNerdTutorials.com/esp32-lora-sensor-web-server/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. *********/ // Import Wi-Fi library #include #include "ESPAsyncWebServer.h" #include //Libraries for LoRa #include #include //Libraries for OLED Display #include #include #include // Libraries to get time from NTP Server #include #include //define the pins used by the LoRa transceiver module #define SCK 5 #define MISO 19 #define MOSI 27 #define SS 18 #define RST 14 #define DIO0 26 //433E6 for Asia //866E6 for Europe //915E6 for North America #define BAND 866E6 //OLED pins #define OLED_SDA 4 #define OLED_SCL 15 #define OLED_RST 16 #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Replace with your network credentials const char* ssid = "REPLACE_WITH_YOUR_SSID"; const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // Define NTP Client to get time WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP); // Variables to save date and time String formattedDate; String day; String hour; String timestamp; // Initialize variables to get and save LoRa data int rssi; String loRaMessage; String temperature; String humidity; String pressure; String readingID; // Create AsyncWebServer object on port 80 AsyncWebServer server(80); Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RST); // Replaces placeholder with DHT values String processor(const String& var){ //Serial.println(var); if(var == "TEMPERATURE"){ return temperature; } else if(var == "HUMIDITY"){ return humidity; } else if(var == "PRESSURE"){ return pressure; } else if(var == "TIMESTAMP"){ return timestamp; } else if (var == "RRSI"){ return String(rssi); } return String(); } //Initialize OLED display void startOLED(){ //reset OLED display via software pinMode(OLED_RST, OUTPUT); digitalWrite(OLED_RST, LOW); delay(20); digitalWrite(OLED_RST, HIGH); //initialize OLED Wire.begin(OLED_SDA, OLED_SCL); if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) { // Address 0x3C for 128x32 Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } display.clearDisplay(); display.setTextColor(WHITE); display.setTextSize(1); display.setCursor(0,0); display.print("LORA SENDER"); } //Initialize LoRa module void startLoRA(){ int counter; //SPI LoRa pins SPI.begin(SCK, MISO, MOSI, SS); //setup LoRa transceiver module LoRa.setPins(SS, RST, DIO0); while (!LoRa.begin(BAND) && counter < 10) { Serial.print("."); counter++; delay(500); } if (counter == 10) { // Increment readingID on every new reading Serial.println("Starting LoRa failed!"); } Serial.println("LoRa Initialization OK!"); display.setCursor(0,10); display.clearDisplay(); display.print("LoRa Initializing OK!"); display.display(); delay(2000); } void connectWiFi(){ // Connect to Wi-Fi network with SSID and password Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } // Print local IP address and start web server Serial.println(""); Serial.println("WiFi connected."); Serial.println("IP address: "); Serial.println(WiFi.localIP()); display.setCursor(0,20); display.print("Access web server at: "); display.setCursor(0,30); display.print(WiFi.localIP()); display.display(); } // Read LoRa packet and get the sensor readings void getLoRaData() { Serial.print("Lora packet received: "); // Read packet while (LoRa.available()) { String LoRaData = LoRa.readString(); // LoRaData format: readingID/temperature&soilMoisture#batterylevel // String example: 1/27.43&654#95.34 Serial.print(LoRaData); // Get readingID, temperature and soil moisture int pos1 = LoRaData.indexOf('/'); int pos2 = LoRaData.indexOf('&'); int pos3 = LoRaData.indexOf('#'); readingID = LoRaData.substring(0, pos1); temperature = LoRaData.substring(pos1 +1, pos2); humidity = LoRaData.substring(pos2+1, pos3); pressure = LoRaData.substring(pos3+1, LoRaData.length()); } // Get RSSI rssi = LoRa.packetRssi(); Serial.print(" with RSSI "); Serial.println(rssi); } // Function to get date and time from NTPClient void getTimeStamp() { while(!timeClient.update()) { timeClient.forceUpdate(); } // The formattedDate comes with the following format: // 2018-05-28T16:00:13Z // We need to extract date and time formattedDate = timeClient.getFormattedDate(); Serial.println(formattedDate); // Extract date int splitT = formattedDate.indexOf("T"); day = formattedDate.substring(0, splitT); Serial.println(day); // Extract time hour = formattedDate.substring(splitT+1, formattedDate.length()-1); Serial.println(hour); timestamp = day + " " + hour; } void setup() { // Initialize Serial Monitor Serial.begin(115200); startOLED(); startLoRA(); connectWiFi(); if(!LittleFS.begin()){ Serial.println("An Error has occurred while mounting LittleFS"); return; } // Route for root / web page server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(LittleFS, "/index.html", String(), false, processor); }); server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/plain", temperature.c_str()); }); server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/plain", humidity.c_str()); }); server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/plain", pressure.c_str()); }); server.on("/timestamp", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/plain", timestamp.c_str()); }); server.on("/rssi", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/plain", String(rssi).c_str()); }); server.on("/winter", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(LittleFS, "/winter.jpg", "image/jpg"); }); // Start server server.begin(); // Initialize a NTPClient to get time timeClient.begin(); // Set offset time in seconds to adjust for your timezone, for example: // GMT +1 = 3600 // GMT +8 = 28800 // GMT -1 = -3600 // GMT 0 = 0 timeClient.setTimeOffset(0); } void loop() { // Check if there are LoRa packets available int packetSize = LoRa.parsePacket(); if (packetSize) { getLoRaData(); getTimeStamp(); } }