11#include < ESPAsyncWebServer.h>
22#include < AsyncTCP.h>
3-
4-
3+ #include < HTTPClient.h>
54#include < WiFi.h>
65#include < SPIFFS.h>
7-
86#include < ArduinoJson.h>
97
8+ // External network (Internet)
9+ const char * ssid_sta = " NetworkName" ;
10+ const char * password_sta = " SecretPassword" ;
1011
12+ // Local AP (for players)
1113const char * ssid = " ViInvaders" ;
1214const char * password = " editorwar" ;
1315
14- AsyncWebServer server (80 );
16+ // static AP ip conf
17+ IPAddress apIP (192 , 168 , 4 , 1 );
18+ IPAddress apNetmask (255 , 255 , 255 , 0 );
19+ IPAddress apGateway (192 , 168 , 4 , 1 );
1520
16- AsyncWebSocket ws (" /ws" ); // websocket endpoint
21+ // WebServer WebSocket
22+ AsyncWebServer server (80 );
23+ AsyncWebSocket ws (" /ws" );
1724
18- // joystick pinout
25+ // joystick pinout config
1926#define JOY1_X 34
2027#define JOY1_SW 25
2128#define JOY2_X 35
2229#define JOY2_SW 26
2330
31+ // quotes
32+ const char * quoteCachePath = " /quote.json" ;
33+ const char * quoteAPI = " https://api.quotable.io/quotes/random?limit=20&maxLength=120&tags=technology|motivational|famous-quotes" ;
34+
35+
2436void notifyClients () {
2537 StaticJsonDocument<128 > doc;
26-
2738 doc[" j1x" ] = analogRead (JOY1_X);
2839 doc[" j1f" ] = digitalRead (JOY1_SW) == LOW;
2940 doc[" j2x" ] = analogRead (JOY2_X);
3041 doc[" j2f" ] = digitalRead (JOY2_SW) == LOW;
31-
3242 String msg;
3343 serializeJson (doc, msg);
3444 ws.textAll (msg);
3545}
3646
47+ // Get and cache quotes
48+ void fetchAndCacheQuotes () {
49+ HTTPClient http;
50+ http.begin (quoteAPI);
51+ int httpCode = http.GET ();
52+
53+ if (httpCode == 200 ) {
54+ String payload = http.getString ();
55+ File file = SPIFFS.open (quoteCachePath, FILE_WRITE);
56+ if (file) {
57+ file.print (payload);
58+ file.close ();
59+ Serial.println (" [Quote] 20 quotes cached." );
60+ } else {
61+ Serial.println (" [Quote] Cannot write to file." );
62+ }
63+ } else {
64+ Serial.printf (" [Quote] HTTP error: %d\n " , httpCode);
65+ }
66+
67+ http.end ();
68+ }
69+
70+ // WebSocket handle (for joystick communication)
3771void onWsEvent (AsyncWebSocket *server, AsyncWebSocketClient *client,
3872 AwsEventType type, void *arg, uint8_t *data, size_t len) {
3973 switch (type) {
@@ -47,41 +81,71 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client,
4781 Serial.printf (" [WS] Error on client %u\n " , client->id ());
4882 break ;
4983 case WS_EVT_DATA:
50- // Optional: handle incoming client messages here
51- break ;
52- default :
5384 break ;
5485 }
5586}
5687
57-
5888void setup () {
5989 Serial.begin (115200 );
6090 pinMode (JOY1_SW, INPUT_PULLUP);
6191 pinMode (JOY2_SW, INPUT_PULLUP);
6292
6393 // Start SPIFFS
64- if (!SPIFFS.begin (true )){
65- Serial.println (" Błąd SPIFFS" );
94+ if (!SPIFFS.begin (true )) {
95+ Serial.println (" [ SPIFFS] Mount failed " );
6696 return ;
6797 }
6898
69- // Access Point Mode
99+ // try to connect with external network
100+ WiFi.mode (WIFI_STA);
101+ WiFi.begin (ssid_sta, password_sta);
102+ Serial.print (" [WiFi] Connecting to WAN" );
103+
104+ for (int i = 0 ; i < 20 && WiFi.status () != WL_CONNECTED; ++i) {
105+ delay (300 );
106+ Serial.print (" ." );
107+ }
108+
109+ if (WiFi.status () == WL_CONNECTED) {
110+ Serial.println (" \n [WiFi] Connected to WAN:" );
111+ Serial.println (WiFi.localIP ());
112+ fetchAndCacheQuotes ();
113+ } else {
114+ Serial.println (" \n [WiFi] Failed to connect to Internet." );
115+ }
116+
117+ // Local AP
118+ WiFi.disconnect (true );
119+ delay (500 );
120+ WiFi.mode (WIFI_AP);
121+ WiFi.softAPConfig (apIP, apGateway, apNetmask);
70122 WiFi.softAP (ssid, password);
71- Serial.println (" Access Point uruchomiony" );
123+
124+ Serial.println (" [AP] Access Point started" );
125+ Serial.print (" [AP] IP: " );
72126 Serial.println (WiFi.softAPIP ());
73127
74128 // File serve
75129 server.serveStatic (" /" , SPIFFS, " /" );
76- server.on (" /" , HTTP_GET, [](AsyncWebServerRequest *request){
130+ server.on (" /" , HTTP_GET, [](AsyncWebServerRequest *request) {
77131 request->send (SPIFFS, " /index.html" , " text/html" );
78132 });
79133
80- // ws.onEvent([](AsyncWebSocket *server, AsyncWebSocketClient *client,
81- // AwsEventType type, void *arg, uint8_t *data, size_t len) {
82- // // optional: handle messages from clients
83- // });
84-
134+ // Endpoint: quotes
135+ server.on (" /quote" , HTTP_GET, [](AsyncWebServerRequest *request) {
136+ if (SPIFFS.exists (quoteCachePath)) {
137+ request->send (SPIFFS, quoteCachePath, " application/json" );
138+ } else {
139+ StaticJsonDocument<192 > doc;
140+ doc[" content" ] = " No internet. Stay sharp, Commander!" ;
141+ doc[" author" ] = " ESP32" ;
142+ String out;
143+ serializeJson (doc, out);
144+ request->send (200 , " application/json" , out);
145+ }
146+ });
147+
148+
85149 ws.onEvent (onWsEvent);
86150 server.addHandler (&ws);
87151
@@ -94,5 +158,6 @@ void loop() {
94158 notifyClients ();
95159 lastSend = millis ();
96160 }
97- ws.cleanupClients (); // rm unactive clients
161+
162+ ws.cleanupClients ();
98163}
0 commit comments