I have an issue with the ESP32, working perfectly in Wi-Fi Station mode but not in the Access Point mode, especially with regards to reading charts, code below written in Visual Studio code, I can also send all the files and jason files from the data folder
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include “SPIFFS.h”
#include <Arduino_JSON.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include “SPIFFS.h”
#include <Arduino_JSON.h>
#define ONE_WIRE_BUS 4
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
///Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
///OLED pins
//#define I2C_SDA 26
//#define I2C_SCL 27
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
//Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
DeviceAddress sensor1 = { 0x28, 0x15, 0xE6, 0x1F, 0x25, 0x20, 0x01, 0x74 };
//28 15 E6 1F 25 20 1 74
DeviceAddress sensor2 = { 0x28, 0x53, 0x60, 0x58, 0x25, 0x20, 0x01, 0x82 };
//28 53 60 58 25 20 1 82
// Replace with your network credentials
////const char* ssid = “Repro Supplies WiFi”;
///const char* password = “g@vo246810”;
// Replace with your network credentials
const char* ssid = “Concrete O Meter”;
const char* password = “123456789”;
// Search for parameter in HTTP POST request
const char* PARAM_INPUT_1 = “input1”;
const char* PARAM_INPUT_2 = “input2”;
//Variables to save values from HTML form
String input1;
String input2;
// File paths to save input values permanently
const char* input1Path = “/input1.txt”;
const char* input2Path = “/input2.txt”;
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Create a WebSocket object
AsyncWebSocket ws(“/ws”);
// Set number of outputs
#define NUM_OUTPUTS 3
// Assign each GPIO to an output
int outputGPIOs[NUM_OUTPUTS] = {12, 13, 14};
// Create an Event Source on /events
AsyncEventSource events(“/events”);
// Json Variable to Hold Sensor Readings
JSONVar readings;
JSONVar values;
// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 5000;
// Create a sensor object
Adafruit_BME280 bme; // BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL)
//Init BME280
void initBME(){
if (!bme.begin(0x76)) {
Serial.println(“Could not find a valid BME280 sensor, check wiring!”);
while (1);
}
}
void initDS18B20(){
Serial.print(“Requesting temperatures…”);
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println(“DONE”);
Serial.print(“Sensor 1(*C): “);
Serial.print(sensors.getTempC(sensor1));
Serial.print(” Sensor 1(*F): “);
Serial.println(sensors.getTempF(sensor1));
Serial.print(“Sensor 2(*C): “);
Serial.print(sensors.getTempC(sensor2));
Serial.print(” Sensor 2(*F): “);
Serial.println(sensors.getTempF(sensor2));
}
// Get Sensor Readings and return JSON object
String getSensorReadings(){
Serial.print(“Requesting temperatures…”);
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println(“DONE”);
Serial.print(“Sensor 1(*C): “);
Serial.print(sensors.getTempC(sensor1));
Serial.print(” Sensor 1(*F): “);
Serial.println(sensors.getTempC(sensor1));
Serial.print(“Sensor 2(*C): “);
Serial.print(sensors.getTempC(sensor2));
Serial.print(” Sensor 2(*F): “);
Serial.println(sensors.getTempC(sensor2));
// display.clearDisplay();
// display.setTextColor(WHITE);
// display.setTextSize(2);
// display.setCursor(0,0);
// display.print(“T1: “);
// display.print(sensors.getTempC(sensor1));
// display.print(“C”);
// display.setCursor(0,20);
// display.print(“T2: “);
// display.print(sensors.getTempC(sensor2));
// display.print(“C”);
// display.setCursor(0,40);
// display.print(” “);
// display.display();
//if (sensors.getTempC(sensor1) > 29) { //jUST TESTING A SMALL COMPARISON
//display.clearDisplay();
//display.setTextColor(WHITE);
//display.setTextSize(2);
// display.setCursor(0,0);
//display.print(“HOT!”);
// display.display();
//Serial.println(“HOT! “);
//digitalWrite(relay,HIGH);
//}
//else{
//digitalWrite(relay,LOW);
//}
readings[“temperature”] = String(sensors.getTempC(sensor1));
readings[“temperature2”] = String(sensors.getTempC(sensor2));
readings[“temperature3”] = String(bme.readTemperature());
readings[“humidity”] = String(bme.readHumidity());
readings[“pressure”] = String(bme.readPressure()/100.0F);
String jsonString = JSON.stringify(readings);
return jsonString;
}
// Get Sensor Readings and return JSON object
String getOutputStates(){
JSONVar myArray;
for (int i =0; i<NUM_OUTPUTS; i++){
myArray[“gpios”][i][“output”] = String(outputGPIOs[i]);
myArray[“gpios”][i][“state”] = String(digitalRead(outputGPIOs[i]));
}
String jsonString = JSON.stringify(myArray);
return jsonString;
}
void notifyClients(String state) {
ws.textAll(state);
}
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
AwsFrameInfo *info = (AwsFrameInfo*)arg;
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
data[len] = 0;
if (strcmp((char*)data, “states”) == 0) {
notifyClients(getOutputStates());
}
else{
int gpio = atoi((char*)data);
digitalWrite(gpio, !digitalRead(gpio));
notifyClients(getOutputStates());
}
}
}
void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client,AwsEventType type,
void *arg, uint8_t *data, size_t len) {
switch (type) {
case WS_EVT_CONNECT:
Serial.printf(“WebSocket client #%u connected from %s\n”, client->id(), client->remoteIP().toString().c_str());
break;
case WS_EVT_DISCONNECT:
Serial.printf(“WebSocket client #%u disconnected\n”, client->id());
break;
case WS_EVT_DATA:
handleWebSocketMessage(arg, data, len);
break;
case WS_EVT_PONG:
case WS_EVT_ERROR:
break;
}
}
void initWebSocket() {
ws.onEvent(onEvent);
server.addHandler(&ws);
}
// Initialize SPIFFS
void initSPIFFS() {
if (!SPIFFS.begin()) {
Serial.println(“An error has occurred while mounting SPIFFS”);
}
Serial.println(“SPIFFS mounted successfully”);
}
// Read File from SPIFFS
String readFile(fs::FS &fs, const char * path){
Serial.printf(“Reading file: %s\r\n”, path);
File file = fs.open(path);
if(!file || file.isDirectory()){
Serial.println(“- failed to open file for reading”);
return String();
}
String fileContent;
while(file.available()){
fileContent = file.readStringUntil(‘\n’);
break;
}
return fileContent;
}
// Write file to SPIFFS
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf(“Writing file: %s\r\n”, path);
File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println(“- failed to open file for writing”);
return;
}
if(file.print(message)){
Serial.println(“- file written”);
} else {
Serial.println(“- frite failed”);
}
}
// Initialize WiFi
void initWiFi() {
/// WiFi.mode(WIFI_STA);
/// WiFi.begin(ssid, password);
/// Serial.print(“Connecting to WiFi ..”);
/// while (WiFi.status() != WL_CONNECTED) {
/// Serial.print(‘.’);
/// delay(1000);
/// }
/// Serial.println(WiFi.localIP());
///}
// Connect to Wi-Fi network with SSID and password
Serial.print(“Setting AP (Access Point)…”);
WiFi.mode(WIFI_AP);
// Remove the password parameter, if you want the AP (Access Point) to be open
WiFi.softAP(ssid, password);
IPAddress IP = WiFi.softAPIP();
Serial.print(“AP IP address: “);
Serial.println(IP);
server.begin();
}
String getCurrentInputValues(){
values[“textValue”] = input1;
values[“numberValue”] = input2;
String jsonString = JSON.stringify(values);
return jsonString;
}
void setup() {
// Serial port for debugging purposes
Serial.begin(115200);
// Set GPIOs as outputs
for (int i =0; i<NUM_OUTPUTS; i++){
pinMode(outputGPIOs[i], OUTPUT);
}
initBME();
initDS18B20();
initWiFi();
initSPIFFS();
initWebSocket();
//Wire.begin(I2C_SDA, I2C_SCL);
//if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)) { // Address 0x3C for 128×32
// Serial.println(F(“SSD1306 allocation failed”));
// for(;;); // Don’t proceed, loop forever
//}
server.serveStatic(“/”, SPIFFS, “/”);
// Web Server Root URL
server.on(“/”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, “/about.html”, “text/html”);
});
// Route for /sensors web page
server.on(“/sensors”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, “/sensors.html”, “text/html”);
});
// Request for the latest sensor readings
server.on(“/readings”, HTTP_GET, [](AsyncWebServerRequest *request){
String json = getSensorReadings();
request->send(200, “application/json”, json);
json = String();
});
// Route for /sensors web page
server.on(“/bme”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, “/bme.html”, “text/html”);
});
// Request for the latest sensor readings
server.on(“/readings”, HTTP_GET, [](AsyncWebServerRequest *request){
String json = getSensorReadings();
request->send(200, “application/json”, json);
json = String();
});
// Route for /outputs web page
server.on(“/outputs”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, “/outputs.html”, “text/html”,false);
});
// Route for /temo web page
server.on(“/temp”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, “/temp.html”, “text/html”);
});
events.onConnect([](AsyncEventSourceClient *client){
if(client->lastId()){
Serial.printf(“Client reconnected! Last message ID that it got is: %u\n”, client->lastId());
}
// send event with message “hello!”, id current millis
// and set reconnect delay to 1 second
client->send(“hello!”, NULL, millis(), 10000);
});
// Load values saved in SPIFFS
input1 = readFile(SPIFFS, input1Path);
input2 = readFile(SPIFFS, input2Path);
// Web Server Root URL
server.on(“/settings”, HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, “/settings.html”, “text/html”);
});
server.on(“/values”, HTTP_GET, [](AsyncWebServerRequest *request){
String json = getCurrentInputValues();
request->send(200, “application/json”, json);
json = String();
});
server.on(“/”, HTTP_POST, [](AsyncWebServerRequest *request) {
int params = request->params();
for(int i=0;i<params;i++){
AsyncWebParameter* p = request->getParam(i);
if(p->isPost()){
// HTTP POST input1 value
if (p->name() == PARAM_INPUT_1) {
input1 = p->value().c_str();
Serial.print(“Input 1 set to: “);
Serial.println(input1);
// Write file to save value
writeFile(SPIFFS, input1Path, input1.c_str());
}
// HTTP POST input2 value
if (p->name() == PARAM_INPUT_2) {
input2 = p->value().c_str();
Serial.print(“Input 2 set to: “);
Serial.println(input2);
// Write file to save value
writeFile(SPIFFS, input2Path, input2.c_str());
}
//Serial.printf(“POST[%s]: %s\n”, p->name().c_str(), p->value().c_str());
}
}
request->send(SPIFFS, “/settings.html”, “text/html”);
});
server.addHandler(&events);
// Start server
server.begin();
}
void loop() {
if ((millis() – lastTime) > timerDelay) {
// Send Events to the client with the Sensor Readings Every 3 seconds
events.send(“ping”,NULL,millis());
events.send(getSensorReadings().c_str(),”new_readings” ,millis());
lastTime = millis();
}
ws.cleanupClients();
}
Hi.
Unfortunately, that project is not compatible with access point mode.
We use a JavaScript library to build the charts.
The ESP32 loads that library from the web when we run the web server. See the following line in the HTML file:
<script src="https://code.highcharts.com/highcharts.js"></script>
The ESP32 can do that in station mode because it is connected to your router that has access to the internet.
When the ESP32 is set as an access point, it doesn’t have access to the internet and can’t load the Highcharts library.
So, it won’t be able to load the charts.
I hope my explanation is clear.
Regards,
Sara