{"id":777,"date":"2026-01-23T13:50:03","date_gmt":"2026-01-23T11:50:03","guid":{"rendered":"https:\/\/avlos.gr\/wpress\/?p=777"},"modified":"2026-04-11T05:39:18","modified_gmt":"2026-04-11T03:39:18","slug":"esp32-web-server-2","status":"publish","type":"post","link":"https:\/\/avlos.gr\/wpress\/en\/esp32-web-server-2\/","title":{"rendered":"ESP32 Web Server &#8211; Weather station"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In this article we will see how to build a Web Server with ESP32. This Web Server will give us information about its environment such as temperature, humidity and atmospheric pressure. We will also have the ability to give it and execute commands, which in our case is to turn on and off some LEDs.<br>Visual Studio was used to implement the software with the addition of PlatformIO. We will then see the materials used, how they were connected to each other and finally the programming part that made all of this work as a single construction.<br><br>The skills that someone needs to have to implement this construction are to be able to distinguish the materials needed for the construction and to be able to make simple soldering on a board. Also, familiarity with Visual Studio and the C language is needed to proceed with programming the device.<br>I believe the photos of the construction will help you.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><br><strong>How does construction work<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">During the setup process, the construction displays the IP address with which it connected to the local wifi in the Serial Monitor. By entering this address in the browser of your computer or mobile phone, you get the image shown in the photo. You see in order the date, time, temperature, humidity, pressure and the status of the LEDs. From the three buttons that follow, you can turn on and off any LED you want. You can operate from multiple locations, computers or mobile phones at the same time. The status of the sensors and LEDs is updated automatically every 30 seconds.<br>Locally, with each short press on the ON-OFF switch button, you activate the LCD and take the measurements of the next card shown in the browser.<br>With a long press on the button, the LCD is deactivated or otherwise it is automatically deactivated in 30 seconds<br>The switch button activates an interrupt on the ESP32, gives values \u200b\u200bto some variables and ends. Then, in the loop() processing loop, the values \u200b\u200bare examined to allow the application to decide whether the press was short or long and whether it timed out to turn off the LCD.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><br><strong>Materials<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The materials needed are<br>an ESP\u201132 Dev Kit C V4<br>three LEDs, red, green, yellow<br>three 220\u03a9 resistors for connecting the LEDs<br>an LCD Serial Interface Module with I2C interface. The LCD is 16 characters and two lines<br>a DS3231 RTC is accessed with I2C interface<br>a DHT22 Digital Humidity &amp; Temperature Sensor Module<br>a BMP280 Atmospheric Pressure Sensor Module with I2C interface<br>a Push Button switch<br>and a 1k\u03a9 resistor for connecting the switch<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><br><strong>Connections<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><br>The connections of the LEDs and the switch are made to GPIO 2,3,33 and 27 as shown below. The switch in the ON state connects GPIO27 to GND through the 1k\u03a9 resistor.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">LED 1 \u2192 GPIO 2<br>LED 2 \u2192 GPIO 4<br>LED 3 \u2192 GPIO 33<br>ON-OFF switch \u2192 GPIO 27<\/p>\n\n\n\n<div class=\"wp-block-group is-vertical is-layout-flex wp-container-core-group-is-layout-4fc3f8e1 wp-block-group-is-layout-flex\">\n<p class=\"wp-block-paragraph\"><br>The LCD, DS3231 and BMP280 components are connected to a common I2C bus since they have different addresses. To create the I2C bus, GPIO21 is used for SDA and GPIO22 for SCL, so we have the following connections.<br>SDA -> GPIO 21<br>SCL \u2192 GPIO 22<br>GND \u2192 GND<br>VCC \u2192 3.3V Be careful we use 3.3 V for VCC on the sensors and LCD<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><br><strong>Devices on the same bus<\/strong><br>Device Protocol Address<br>LCD I2C I2C usually 0x27 or 0x3F<br>DS3231 I2C 0x68<br>BMP280 I2C 0x76 or 0x77<br><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>The DHT22 sensor<\/strong> (Temperature \/ Humidity)<br>Requires 1 digital pin.<br>We use the GPIO 25 pin<br>DATA \u2192 GPIO 25 (which is general purpose)<br>So we have the connection<br>VCC -> 3.3V<br>DATA \u2192 GPIO 25<br>GND \u2192 GND<br>Pull-up 4.7k\u03a9 \u2013 10k\u03a9 from DATA \u2192 VCC (many modules already have this resistor)<\/p>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><br>The Final Connection Board is<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Hardware &#8211; GPIO<br>LED 1 &#8212;  GPIO 2<br>LED 2 &#8212;  GPIO 4<br>LED 3 &#8212;  GPIO 33<br>Switch &#8212;  GPIO 27<br>I2C SDA &#8211; GPIO 21<br>I2C SCL &#8211; GPIO 22<br>DHT22 DATA &#8211; GPIO 25<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Software<\/strong><br><strong>New project<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If you do not have Visual Studio installed, you can download it from here https:\/\/visualstudio.microsoft.com\/vs\/ . After installing, go to Extensions and install PlatformIO.<br>Using Visual Studio, you enter PlatformIO and create a new project. You will be asked for the development environment, write ESP32. When creating the new project, you will notice a delay, this is due to the fact that in PlatformIO the development environment is created from scratch and thus many downloads are made.<br>In the platformio.ini file you will find the development environment created by PlatformIO. There you will add the libraries that will be used to develop the application. The content of this file for our application will be as follows.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = arduino\nmonitor_speed = 115200\n\nlib_deps =\n\u00a0 \u00a0 adafruit\/RTClib\n\u00a0 \u00a0 adafruit\/DHT sensor library\n\u00a0 \u00a0 adafruit\/Adafruit Unified Sensor\n\u00a0 \u00a0 adafruit\/Adafruit BMP280 Library\n\u00a0 \u00a0 bblanchon\/ArduinoJson\n\u00a0 \u00a0 marcoschwartz\/LiquidCrystal_I2C<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><br><strong>Application code<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Although until recently I was using the Ardiuno IDE, which is the first integrated environment that appeared for programming microcontrollers, its latest version 2.3.7 has a problematic download loader and did not allow me to install boards for the ESP32. This led me to start with Visual Studio, which was also familiar to me from other applications. From the Extensions I installed PlatformIO, which is more professional for creating such applications with microcontrollers.<br>The two main files you will use are platformio.ini, mentioned above, and main.cpp. In the main.cpp file you write your code in C language with almost the same structure as written in the Arduino IDE. By creating the main.cpp file, PlatformIO creates the structure where you will place the parts of the code.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><br><strong>Libraries to be used<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;Arduino.h>\n#include &lt;WiFi.h>\n#include &lt;WebServer.h>\n#include &lt;Wire.h>\n#include &lt;RTClib.h>\n#include &lt;DHT.h>\n#include &lt;Adafruit_BMP280.h>\n#include &lt;time.h>\n#include &lt;LiquidCrystal_I2C.h>\n#include &lt;ArduinoJson.h>\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>The connections you made to the board<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Next, the connections you made to the board are defined in the program\n<strong>\/\/ LEDs<\/strong>\n#define LED1 2\n#define LED2 4\n#define LED3 33\n\n<strong>\/\/ Push button<\/strong>\n#define BUTTON_PIN 27\n#define LONG_PRESS_TIME 1000 \u00a0 \/\/ ms\n#define DEBOUNCE_TIME \u00a0 200 \u00a0 \u00a0\/\/ ms\n\n<strong>\/\/ DHT22<\/strong>\n#define DHTPIN 25\n#define DHTTYPE DHT22\n\n<strong>\/\/ I2C<\/strong>\n#define SDA_PIN 21\n#define SCL_PIN 22\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><br><strong>Connecting to your network&#8217;s WiFi<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>const char* ssid = \"my ssid\";\nconst char* password = \"my password\";\n\nWebServer server(80);\nRTC_DS3231 rtc;\nDHT dht(DHTPIN, DHTTYPE);\nAdafruit_BMP280 bmp;\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><br><strong>Global variables<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>unsigned long lcdTimeout = 0;\nbool lcdOn = false;\nint displayMode = 0; \/\/ 0=RTC, 1=DHT22, 2=BMP280\n\nvolatile bool buttonEvent = false;\nvolatile unsigned long pressStartTime = 0;\nvolatile unsigned long lastInterruptTime = 0;\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><br><strong>Function declarations<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>int myFunction(int, int);\t\nvoid setupRTCfromNTP();\n\/\/void handleButton();\nString getRTC();\nString getDHT();\nString getBMP();\nvoid handleRoot();\nvoid toggleLED(int );\nvoid IRAM_ATTR handleButtonInterrupt();\nvoid updateLCD();\nvoid handleData();\nString getDateGR();\nString getTimeGR();\nString getTemp();\nString getHum();\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Remaining structure<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Setup Paragraph<\/strong><br>The contents of this paragraph are executed only once during system startup.<br>void setup() {<br>}<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Loop Paragraph<\/strong><br>The content of this paragraph is executed continuously and implements the logic of the application.<br>In the application code you will find the complete content of loop()<br>void loop() {<br>}<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Function definitions<\/strong><br>This is the place where the functions that implement the application are placed<br>\/\/ put function definitions here:<br>Here we see a typical function that we also encountered in function declarations. PlatformIO places it in the project creation phase to show us the structure that we will follow in writing our code.<br>int myFunction(int x, int y) {<br>return x + y;<br>}<br>In the application code you will find all the complete functions that implement the application.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><br><strong>Notes<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">1. The date and time are given to the Real Time Clock by the NTP (Network Time Protocol) server with the setupRTCfromNTP() function in the setup() phase of the application<br>2. The routine table of the ERP32 server that we implement is given in the setup() phase of the application, before starting the server and is<br>server.on(&#8220;\/&#8221;, handleRoot);<br>server.on(&#8220;\/led1&#8221;, [](){ toggleLED(LED1); });<br>server.on(&#8220;\/led2&#8221;, [](){ toggleLED(LED2); });<br>server.on(&#8220;\/led3&#8221;, [](){ toggleLED(LED3); });<br>server.on(&#8220;\/data&#8221;, handleData);<br>3. The void handleRoot() function implements the creation of the image in the browser and its update is done using the AJAX technique (without reload), i.e. without being reloaded by the updateData() script every 30 sec.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Full application code<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Here is the complete content of the main.cpp file<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>#include &lt;Arduino.h>\n#include &lt;WiFi.h>\n#include &lt;WebServer.h>\n#include &lt;Wire.h>\n#include &lt;RTClib.h>\n#include &lt;DHT.h>\n#include &lt;Adafruit_BMP280.h>\n#include &lt;time.h>\n#include &lt;LiquidCrystal_I2C.h>\n#include &lt;ArduinoJson.h>\n\n\n\/\/ LEDs\n#define LED1 2\n#define LED2 4\n#define LED3 33\n\n\/\/ Push button\n#define BUTTON_PIN 27\n#define LONG_PRESS_TIME 1000   \/\/ ms\n#define DEBOUNCE_TIME   200    \/\/ ms\n\n\n\/\/ DHT22\n#define DHTPIN 25\n#define DHTTYPE DHT22\n\n\/\/ I2C\n#define SDA_PIN 21\n#define SCL_PIN 22\n\n\/\/ LCD\nLiquidCrystal_I2C lcd(0x27, 16, 2); \/\/ \u03ac\u03bb\u03bb\u03b1\u03be\u03b5 0x27 \u03b1\u03bd \u03c7\u03c1\u03b5\u03b9\u03ac\u03b6\u03b5\u03c4\u03b1\u03b9\n\n\nconst char* ssid = \"your-ssid\";\nconst char* password = \"your-password\";\n\nWebServer server(80);\nRTC_DS3231 rtc;\nDHT dht(DHTPIN, DHTTYPE);\nAdafruit_BMP280 bmp;\n\nunsigned long lcdTimeout = 0;\nbool lcdOn = false;\nint displayMode = 0; \/\/ 0=RTC, 1=DHT22, 2=BMP280\n\nvolatile bool buttonEvent = false;\nvolatile unsigned long pressStartTime = 0;\nvolatile unsigned long lastInterruptTime = 0;\n\n\n\/\/ -----------------------------------------------------\n\n\/\/ put function declarations here:\nint myFunction(int, int);\nvoid setupRTCfromNTP();\n\/\/void handleButton();\nString getRTC();\nString getDHT();\nString getBMP();\nvoid handleRoot();\nvoid toggleLED(int );\nvoid IRAM_ATTR handleButtonInterrupt();\nvoid updateLCD();\nvoid handleData();\nString getDateGR();\nString getTimeGR();\nString getTemp();\nString getHum();\n\n\/\/ ------------------------------------------------------\n\nvoid setup() {\n  \/\/ put your setup code here, to run once:\n  int result = myFunction(2, 3);\n\n   Serial.begin(115200);\n\n    pinMode(LED1, OUTPUT);\n    pinMode(LED2, OUTPUT);\n    pinMode(LED3, OUTPUT);\n    pinMode(BUTTON_PIN, INPUT_PULLUP);\n\n    attachInterrupt(\n        digitalPinToInterrupt(BUTTON_PIN),\n        handleButtonInterrupt,\n        CHANGE   \/\/  press + release\n    );\n\n    Wire.begin(SDA_PIN, SCL_PIN);\n\n    lcd.init();\n    lcd.backlight();\n\n    lcd.setCursor(0,0);\n    lcd.print(\"ESP32 OK\");\n    lcd.setCursor(0,1);\n    lcd.print(\"LCD I2C 1602\");\n\n    rtc.begin();\n    dht.begin();\n    bmp.begin(0x76);\n\n    WiFi.begin(ssid, password);\n    while (WiFi.status() != WL_CONNECTED) delay(500);\n\n    setupRTCfromNTP();\n\n    server.on(\"\/\", handleRoot);\n    server.on(\"\/led1\", &#91;](){ toggleLED(LED1); });\n    server.on(\"\/led2\", &#91;](){ toggleLED(LED2); });\n    server.on(\"\/led3\", &#91;](){ toggleLED(LED3); });\n    server.on(\"\/data\", handleData);\n\n    server.begin();\n    Serial.println(WiFi.localIP());\n    \n\n}\n\n\/\/ ------------------------------------------------------\n\nvoid loop() {\n  \/\/ put your main code here, to run repeatedly:\n\n    if (buttonEvent) {\n        buttonEvent = false;\n\n        unsigned long pressDuration =\n            millis() - pressStartTime;\n\n        if (pressDuration >= LONG_PRESS_TIME) {\n            \/\/  LONG PRESS \u2192 LCD OFF\n            lcdOn = false;\n            lcd.clear();\n            lcd.noBacklight();\n        } else {\n            \/\/  SHORT PRESS \u2192 change screen\n            lcdOn = true;\n            lcdTimeout = millis() + 30000;\n            displayMode = (displayMode + 1) % 3;\n            updateLCD();\n        }\n    }\n\n    server.handleClient();\n    \/\/handleButton();\n\n    if (lcdOn &amp;&amp; millis() > lcdTimeout) {\n        lcdOn = false;\n        lcd.clear();\n        lcd.noBacklight();\n    }\n    \n}\n\n\/\/ -------------------------------------------------------\n\n\/\/ put function definitions here:\nint myFunction(int x, int y) {\n  return x + y;\n}\n\n\nvoid setupRTCfromNTP() {\n    configTime(0, 0, \"pool.ntp.org\", \"time.nist.gov\");\n    struct tm timeinfo;\n\n    if (getLocalTime(&amp;timeinfo)) {\n        rtc.adjust(DateTime(\n            timeinfo.tm_year + 1900,\n            timeinfo.tm_mon + 1,\n            timeinfo.tm_mday,\n            timeinfo.tm_hour,\n            timeinfo.tm_min,\n            timeinfo.tm_sec\n        ));\n        Serial.println(\"RTC synchronized from NTP\");\n    } else {\n        Serial.println(\"Failed to get NTP time\");\n    }\n}\n\n\/*\nvoid handleButton() {\n    static bool lastState = HIGH;\n    bool state = digitalRead(BUTTON_PIN);\n\n    if (lastState == HIGH &amp;&amp; state == LOW) {\n        lcdOn = true;\n        lcdTimeout = millis() + 30000;\n        displayMode = (displayMode + 1) % 3;\n    }\n    lastState = state;\n}\n*\/\n\nString getRTC() {\n    DateTime now = rtc.now();\n    return now.timestamp(DateTime::TIMESTAMP_FULL);\n}\n\nString getDHT() {\n    float t = dht.readTemperature();\n    float h = dht.readHumidity();\n    return \"Temp: \" + String(t) + \" \u00b0C&lt;br>Hum: \" + String(h) + \" %\";\n}\n\nString getTemp() {\nfloat t = dht.readTemperature();\nreturn \"Temp: \" + String(t);\n}\n\n\nString getHum() {\nfloat h = dht.readHumidity();\nreturn \"Hum:  \" + String(h) + \" %\";\n}\n\n\n\nString getBMP() {\n    return  String(bmp.readPressure() \/ 100.0) + \" hPa\";\n}\n\nvoid handleRoot() {\n\n  String page = R\"rawliteral(\n&lt;!DOCTYPE html>\n&lt;html lang=\"el\">\n&lt;head>\n&lt;meta charset=\"UTF-8\">\n&lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n&lt;title>ESP32 Dashboard&lt;\/title>\n\n&lt;style>\nbody {\n  font-family: Arial, sans-serif;\n  background: #f2f2f2;\n  margin: 0;\n  padding: 5px;\n  text-align: center;\n}\nh2 { margin-top: 5px; margin-bottom: 5px; }\nh2 { font-size: 20px; }\nh3 { font-size: 16px; margin: 6px 0; }\nh4 { font-size: 14px; margin: 4px 0; }\n\n\n.card {\n  background: #ffffff;\n  padding: 8px;\n  margin: 6px auto;\n  border-radius: 12px;\n  max-width: 420px;\n  box-shadow: 0 2px 6px rgba(0,0,0,0.2);\n}\n\n.status {\n  font-weight: bold;\n  font-size: 18px;\n}\n\nbutton {\n  width: 90%;\n  padding: 8px;\n  margin: 4px 0;\n  font-size: 14px;\n  border-radius: 8px;\n  border: none;\n  background: #1976d2;\n  color: white;\n}\nbutton:active {\n  background: #0d47a1;\n}\n&lt;\/style>\n&lt;\/head>\n\n&lt;body>\n\n&lt;h2>ESP32 \u03a0\u03af\u03bd\u03b1\u03ba\u03b1\u03c2 \u0395\u03bb\u03ad\u03b3\u03c7\u03bf\u03c5&lt;\/h2>\n\n&lt;div class=\"card\">\n  &lt;h4>\u0397\u03bc\u03b5\u03c1\u03bf\u03bc\u03b7\u03bd\u03af\u03b1&lt;\/h4>\n  &lt;div id=\"date\">--&lt;\/div>\n  &lt;h4>\u038f\u03c1\u03b1&lt;\/h4>\n  &lt;div id=\"time\">--&lt;\/div>\n&lt;\/div>\n\n&lt;div class=\"card\">\n  &lt;h4>\u0398\u03b5\u03c1\u03bc\u03bf\u03ba\u03c1\u03b1\u03c3\u03af\u03b1&lt;\/h4>\n  &lt;div id=\"dht-temp\"> -- \u00b0C&lt;\/div>\n   &lt;h4>\u03a5\u03b3\u03c1\u03b1\u03c3\u03af\u03b1&lt;\/h4>\n  &lt;div id=\"dht-hum\"> -- %&lt;\/div>\n&lt;\/div>\n\n\n&lt;div class=\"card\">\n  &lt;h4>\u03a0\u03af\u03b5\u03c3\u03b7&lt;\/h4>\n  &lt;div id=\"bmp\">--&lt;\/div>\n&lt;\/div>\n\n&lt;div class=\"card\">\n  &lt;h3>\u039a\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 LED&lt;\/h3>\n  LED 1: &lt;span id=\"l1\" class=\"status\">--&lt;\/span>&lt;br>\n  LED 2: &lt;span id=\"l2\" class=\"status\">--&lt;\/span>&lt;br>\n  LED 3: &lt;span id=\"l3\" class=\"status\">--&lt;\/span>\n&lt;\/div>\n\n&lt;div class=\"card\">\n  &lt;h3>\u0388\u03bb\u03b5\u03b3\u03c7\u03bf\u03c2 LED&lt;\/h3>\n  &lt;button onclick=\"toggleLed(1)\">LED 1 ON \/ OFF&lt;\/button>\n  &lt;button onclick=\"toggleLed(2)\">LED 2 ON \/ OFF&lt;\/button>\n  &lt;button onclick=\"toggleLed(3)\">LED 3 ON \/ OFF&lt;\/button>\n&lt;\/div>\n\n&lt;script>\nasync function updateData() {\n  try {\n    const response = await fetch('\/data');\n    const d = await response.json();\n\n    document.getElementById('date').innerText = d.date;\n    document.getElementById('time').innerText = d.time;\n\n    document.getElementById('dht-temp').textContent =\n    d.dht.temp.toFixed(1);\n\n    document.getElementById('dht-hum').textContent =\n    d.dht.hum.toFixed(1);\n\n\n    document.getElementById('bmp').innerText =\n    d.bmp.toFixed(1) + \" hPa\";\n\n    setLed('l1', d.led1);\n    setLed('l2', d.led2);\n    setLed('l3', d.led3);\n\n  } catch (e) {\n    console.log(\"AJAX error:\", e);\n  }\n}\n\nfunction setLed(id, state) {\n  const el = document.getElementById(id);\n  el.innerText = state ? \"ON\" : \"OFF\";\n  el.style.color = state ? \"green\" : \"red\";\n}\n\nfunction toggleLed(n) {\n  fetch('\/led' + n).then(() => updateData());\n}\n\nupdateData();\nsetInterval(updateData, 30000);\n&lt;\/script>\n\n&lt;\/body>\n&lt;\/html>\n)rawliteral\";\n\n  server.send(200, \"text\/html\", page);\n}\n\n\n\n\n\nvoid toggleLED(int pin) {\n    digitalWrite(pin, !digitalRead(pin));\n    server.sendHeader(\"Location\", \"\/\");\n    server.send(303);\n}\n\nvoid IRAM_ATTR handleButtonInterrupt() {\n    unsigned long now = millis();\n\n    if (now - lastInterruptTime &lt; DEBOUNCE_TIME) return;\n\n    if (digitalRead(BUTTON_PIN) == LOW) {\n        pressStartTime = now;          \/\/ button pressed\n    } else {\n        buttonEvent = true;            \/\/ button released\n    }\n\n    lastInterruptTime = now;\n}\n\nvoid updateLCD() {\n    lcd.clear();\n    lcd.backlight();\n\n    if (displayMode == 0) {\n        DateTime now = rtc.now();\n        lcd.print(now.day()); \n        lcd.print(\"\/\");\n\n        lcd.print(now.month()); \n        lcd.print(\"\/\");\n       \n        lcd.print(now.year()); \n        \n        lcd.setCursor(0,1);\n        lcd.print(getTimeGR());\n\n    } else if (displayMode == 1) {\n        \/\/lcd.print(\"DHT22:\");\n        lcd.print(getTemp());\n        lcd.setCursor(0,1);\n        \/\/lcd.print(getDHT());\n        lcd.print(getHum());\n    } else {\n        lcd.print(\"Pressure:\");\n        lcd.setCursor(0,1);\n        lcd.print(getBMP());\n    }\n}\n\nvoid handleData() {\n    JsonDocument doc;\n    \n    doc&#91;\"date\"] = getDateGR();\n    doc&#91;\"time\"] = getTimeGR();\n\n    doc&#91;\"dht\"]&#91;\"temp\"] = dht.readTemperature();\n    doc&#91;\"dht\"]&#91;\"hum\"]  = dht.readHumidity();\n    doc&#91;\"bmp\"] = bmp.readPressure() \/ 100.0;\n\n    doc&#91;\"led1\"] = digitalRead(LED1);\n    doc&#91;\"led2\"] = digitalRead(LED2);\n    doc&#91;\"led3\"] = digitalRead(LED3);\n\n    String json;\n    serializeJson(doc, json);\n\n    server.send(200, \"application\/json\", json);\n}\n\nString getDateGR() {\n    const char* daysGR&#91;] = {\n        \"\u039a\u03c5\u03c1\u03b9\u03b1\u03ba\u03ae\", \"\u0394\u03b5\u03c5\u03c4\u03ad\u03c1\u03b1\", \"\u03a4\u03c1\u03af\u03c4\u03b7\",\n        \"\u03a4\u03b5\u03c4\u03ac\u03c1\u03c4\u03b7\", \"\u03a0\u03ad\u03bc\u03c0\u03c4\u03b7\", \"\u03a0\u03b1\u03c1\u03b1\u03c3\u03ba\u03b5\u03c5\u03ae\", \"\u03a3\u03ac\u03b2\u03b2\u03b1\u03c4\u03bf\"\n    };\n\n    DateTime now = rtc.now();\n\n    char buf&#91;32];\n    sprintf(buf, \"%s %02d\/%02d\/%04d\",\n        daysGR&#91;now.dayOfTheWeek()],\n        now.day(),\n        now.month(),\n        now.year()\n    );\n\n    return String(buf);\n}\n\nString getTimeGR() {\n    DateTime now = rtc.now();\n\n    char buf&#91;10];\n    sprintf(buf, \"%02d:%02d:%02d\",\n        now.hour(),\n        now.minute(),\n        now.second()\n    );\n\n    return String(buf);\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>In this article we will see how to build a Web Server with ESP32. This Web Server will give us information about its environment such as temperature, humidity and atmospheric pressure. We will also have the ability to give it&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[29,199],"tags":[],"class_list":["post-777","post","type-post","status-publish","format-standard","hentry","category-home","category-iot"],"_links":{"self":[{"href":"https:\/\/avlos.gr\/wpress\/wp-json\/wp\/v2\/posts\/777","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/avlos.gr\/wpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/avlos.gr\/wpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/avlos.gr\/wpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/avlos.gr\/wpress\/wp-json\/wp\/v2\/comments?post=777"}],"version-history":[{"count":11,"href":"https:\/\/avlos.gr\/wpress\/wp-json\/wp\/v2\/posts\/777\/revisions"}],"predecessor-version":[{"id":841,"href":"https:\/\/avlos.gr\/wpress\/wp-json\/wp\/v2\/posts\/777\/revisions\/841"}],"wp:attachment":[{"href":"https:\/\/avlos.gr\/wpress\/wp-json\/wp\/v2\/media?parent=777"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/avlos.gr\/wpress\/wp-json\/wp\/v2\/categories?post=777"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/avlos.gr\/wpress\/wp-json\/wp\/v2\/tags?post=777"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}