How to set up an Access Point, and what it is good for

This commit is contained in:
Kosmo Obermayer 2024-04-11 07:25:47 +02:00
parent 9ff331ba66
commit 49f0510ce4

View File

@ -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 <Arduino.h>
// Load Wifi library //
#include <WiFi.h>
// 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("<!DOCTYPE html><html>");
_client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
_client.println("<link rel=\"icon\" href=\"data:,\">");
// Set up a button //
_client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
_client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
_client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
_client.println("</style></head>"); // closes the style tag.
if (_output_state=="off")
{
_client.println("<p><a href=\"Button on\"><button class=\"button\">ON</button></a></p>");
}
else
{
_client.println("<p><a href=\"Button off\"><button class=\"button button2\">OFF</button></a></p>");
}
// 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
// Still, since it needs an entire thread to run, it's far from the ideal way.