From 49f0510ce46403b4d3496e2b12b320176d734a5a Mon Sep 17 00:00:00 2001 From: Kosmo Obermayer Date: Thu, 11 Apr 2024 07:25:47 +0200 Subject: [PATCH] How to set up an Access Point, and what it is good for --- src/main.cpp | 170 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 137 insertions(+), 33 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 880f465..a05b900 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,50 +1,154 @@ //--------------------------------------------------------------------------------------------------------------------------// -// Handling Interrupts correctly +// Setting up an Access Point hosted by the ESP32 //--------------------------------------------------------------------------------------------------------------------------// -// What are Interrupts? // -// You can see them as certain parts of a programm reacting to a condition at ANY time and place your programm is currently in. -// You use them to time reads for example, or for signals, etc etc. +// What is the difference between an Access Point and using the ESP as a client? // +// Well, there's a big difference as to how either work, and what is needed. As an Access Point, you can create your own little "network" hosted +// over the small WLAN module on the developing board. That let's you access a website on the ESP for example, without +// having to go over any of your internet provider's servers since it's purely local. +// When hosting an Access Point, you CANNOT log into another Wlan network. Clients (for example your phone) can log into the one on the ESP though. +// If you want to use an async Webserver, that works better with the use of a router inbetween, and has more advantages all in all. +// If no internet connection is required and it's for little displayment, a local Access Point should be enough. #include +// Load Wifi library // +#include + +// Set your network credentials (you are entirely free to choose anything) // +const char* _ssid = "ESP32-Access-Point"; // for example +const char* _password = "1234IamAPassword"; // that's a bad example, but you get the gist + +// Set up instance and the right port (default: 80) // +WiFiServer server(80); + +// String to save the http adress in // +String _http = ""; + +// State variable for the example following in the loop() function later // +String _output_state = "off"; + void setup() { - // Initializing the timer // - void IRAM_ATTR onTimer(); + Serial.println("Setting up access point..."); + WiFi.softAP(_ssid, _password); + IPAddress _IP = WiFi.softAPIP(); // You can see what is hosted on the ESP over this IP address. + Serial.print("AP IP Address: "); + Serial.println(_IP); - hw_timer_t *My_timer = 0; - My_timer = timerBegin(0, 80, true); - timerAttachInterrupt(My_timer, &onTimer, true); - timerAlarmWrite(My_timer, 5000, true); - timerAlarmEnable(My_timer); - - // This is crutial and has to be in the setup. - // You can change the frequency as to when it gets called (Check it out online), as well as the reason. - - // You can attach a timer to a Pin for example as well. - // That would look something like this: - // - // pinMode(SWITCH_PIN, INPUT_PULLUP); - // attachInterrupt(digitalPinToInterrupt(SWITCH_PIN), switchChanged, CHANGE); - // But it's not necessary if you're using Interrupts as a timer. + server.begin(); // starts WiFi server. } void loop() { + // Listen for any incoming clients, you can also create a thread extra for this if little processing power is needed // + WiFiClient _client = server.available(); + // If that is the case, make sure to keep the service running. It should not be stopped or interrupted at all if the programm is still running, + // I'd advice to use an exeption / interrupt that is listening in on whether or not a new client or http request has been received. + // Be careful with that in general if you try it. + if(_client) + { + String _current_line = ""; + while(_client.connected()) // As long as the client is connected... + { + if(_client.available()) // Checks whether or not there is bites to read from. + { + char _c = _client.read(); // reads a single bite. + _http += _c; // assembling the full http request one by one. + + if(_c != 10) // Listen in for LF (new line / line feat) since that is + // a signal for the end of the request. + // (Side note: Using '\n' here should technicall work here, but can create some errors.) + // (Use 10 (ASCII) instead to avoid any misleading errors.) + { + // Send a response here, since every request needs a response. + // If something went wrong, be sure to send an error message instead of nothing. + + // Replying: // + if(_current_line.length() == 0) + { + // HTTP headers always start a certain way. So be sure to keep the following format. + _client.println("HTTP/1.1 200 OK"); + _client.println("Content-type:text/html"); + _client.println("Connection: close"); + _client.println(); + // And there you go, a correct response that a client can work with! + + // Now you can technically compute whatever changes the client might have requested, + // whether that was a press of a button or a press on a link. Any action needs to be responded to, + // or else one might end up in the void of white like a blank page, or nothing happens. + // The following is an example of how you would process requests with a html button. + + // NOTE! This is html code written inside a C/C++ code. It's far from optional, and SPIFFS is therefor recommended if a + // seperate html & css file is prefered. You can read about that in the tutorial branch to the Async Server. + // For now, this is purely for demonstration. + + // Handling the change of the example button // + if (_http.indexOf("GET Button on") >= 0) + { + Serial.println("Button turned on"); + _output_state = "on"; + // digitalWrite(PIN, HIGH); // == how you would pull a Pin up when the button activates. + } + else if (_http.indexOf("GET Button off") >= 0) + { + Serial.println("Button turned off"); + _output_state = "off"; + // digitalWrite(PIN, LOW); // again for example. + } + + // Displaying the site // + _client.println(""); + _client.println(""); + _client.println(""); + + // Set up a button // + _client.println(""); // closes the style tag. + + if (_output_state=="off") + { + _client.println("

"); + } + else + { + _client.println("

"); + } + + // End the HTTP response with a LF as well // + _client.println(); + break; + } + else // received a LF, clear the current line for input. + { + _current_line = ""; + } + } // end of if() + else if(_c != 13) // Handles the exeption for if you got anything but a carriage return. + // NOTE! Technically, '\r' should also work, but like '\n', it can cause issues. + // (Once more use 13 (ASCII) instead) + { + _current_line += _c; + } + } // end of if() + } // end of while() + + // Clear the request variable for later use // + _http = ""; + + // Close the connection to the client // + _client.stop(); + Serial.println("Client disconnected."); + Serial.println(); + + // For every time the loop repeats, a new client and a new http request is being processed. + } } -// Handling the function // -void IRAM_ATTR onTimer() -{ - // This function is called when the interrupt has been triggered. - - // Keep your operations in here as SIMPLE as possible, and as quick as possible. - // DO NOT do heavy processing on this threat, or perform long lasting operations. - // ^ That includes any sort of printing or writing to a file for example. - // Also refrain from using while(1) AT ALL COSTS. Short lasting while loops are fine, but also make sure they don't take too long to break out again. -} +// As said, the example is a tedious an impractical way to host reactive html code. +// Yet, it's enough for simple and fast displaying of values over a local WiFi Webserver. -// That is basically it for now regarding simple interrupts. -// It's useful regarding sending data only like every 5 minutes, or every 10 milliseconds for example. Use it carefully, and happy coding. :D \ No newline at end of file +// Still, since it needs an entire thread to run, it's far from the ideal way. \ No newline at end of file