Skip to content

Commit

Permalink
Merge branch 'melkati:development' into development
Browse files Browse the repository at this point in the history
  • Loading branch information
Coscolin authored May 20, 2024
2 parents bf1e77f + 31a5879 commit eed169f
Show file tree
Hide file tree
Showing 14 changed files with 345 additions and 43 deletions.
23 changes: 21 additions & 2 deletions CO2_Gadget.ino
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ String mqttClientId = UNITHOSTNAME;
String mqttBroker = MQTT_BROKER_SERVER;
String mqttUser = "";
String mqttPass = "";
String wifiSSID = WIFI_SSID_CREDENTIALS;
String wifiPass = WIFI_PW_CREDENTIALS;
String wifiSSID = "";
String wifiPass = "";
String MACAddress = "Unset";
uint8_t peerESPNowAddress[] = ESPNOW_PEER_MAC_ADDRESS;

Expand All @@ -45,6 +45,12 @@ uint64_t timeToRetryTroubledWIFI = 300; // Time in seconds to retry WIFI connec
uint16_t WiFiConnectionRetries = 0;
uint16_t maxWiFiConnectionRetries = 10;
bool wifiChanged = false;
bool useStaticIP = false; // Set to true if you want to use a static IP
IPAddress staticIP(192, 168, 1, 199); // Change this to the desired IP
IPAddress gateway(192, 168, 1, 1); // Change this to your network's gateway
IPAddress subnet(255, 255, 255, 0); // Change this to your network's subnet mask
IPAddress dns1(8, 8, 8, 8); // Change this to your preferred DNS server
IPAddress dns2(8, 8, 4, 4); // Change this to your secondary DNS server

// MQTT options
bool activeMQTT = true;
Expand Down Expand Up @@ -125,6 +131,12 @@ uint16_t co2RedRange = 1000;
bool waitingForImprov = true;
uint16_t timeToWaitForImprov = 0; // Time in seconds to wait for improv serial

// Variables for Captive Portal
#ifdef SUPPORT_CAPTIVE_PORTAL
bool captivePortalActive = false;
uint16_t timeToWaitForCaptivePortal = 60; // Time in seconds to wait for captive portal
#endif

#ifdef CUSTOM_I2C_SDA
#undef I2C_SDA
#define I2C_SDA CUSTOM_I2C_SDA
Expand All @@ -146,6 +158,9 @@ uint16_t timeToWaitForImprov = 0; // Time in seconds to wait for improv serial
#endif
// #include <WiFiUdp.h>
#include <AsyncTCP.h>
#ifdef SUPPORT_CAPTIVE_PORTAL
#include <DNSServer.h>
#endif
#include <ESPAsyncWebServer.h>

#include "AsyncJson.h"
Expand Down Expand Up @@ -597,6 +612,10 @@ void setup() {
Serial.println("");
printLargeASCII(WiFi.localIP().toString().c_str());
Serial.println("");
} else {
#ifdef SUPPORT_CAPTIVE_PORTAL
initCaptivePortal();
#endif
}
initImprov();
if (timeToWaitForImprov > 0) {
Expand Down
7 changes: 6 additions & 1 deletion CO2_Gadget_EINK.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ GxEPD2_BW<GxEPD2_213_BN, GxEPD2_213_BN::HEIGHT> display(GxEPD2_213_BN(EPD_CS, EP
#endif

#ifdef EINKBOARD_WEACT_GDEH0154D67
#include <Digits_NotoSans_Bold48pt7b.h>
#include <Digits_NotoSans_Bold38pt7b.h>
#include <NotoSans_SemiCondensed_Bold10pt7b.h>
const GFXfont SmallFont = NotoSans_SemiCondensed_Bold10pt7b;
const GFXfont BigFont = Digits_NotoSans_Bold38pt7b;
Expand Down Expand Up @@ -557,6 +557,11 @@ void showBLEIcon(int32_t posX, int32_t posY, bool forceRedraw) {

void showWiFiIcon(int32_t posX, int32_t posY, bool forceRedraw) {
display.fillRect(posX, posY, 16, 16, GxEPD_WHITE);
// If captivePortalActive = true; draw a circle instead of the WiFi icon
if (captivePortalActive) {
display.drawCircle(posX + 8, posY + 8, 6, GxEPD_BLACK);
return;
}
int8_t rssi = WiFi.RSSI();
if (troubledWIFI) {
display.drawBitmap(posX, posY, iconWiFi, 16, 16, GxEPD_BLACK);
Expand Down
2 changes: 2 additions & 0 deletions CO2_Gadget_Menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,8 @@ MENU(wifiConfigMenu, "WIFI Config", doNothing, noEvent, wrapStyle
#ifdef SUPPORT_OTA
,SUBMENU(activeOTAMenu)
#endif
,OP("Set fixed IP", doNothing, noEvent)
,OP("in WEB config.", doNothing, noEvent)
,EXIT("<Back"));


Expand Down
54 changes: 54 additions & 0 deletions CO2_Gadget_Preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,15 @@ void printPreferences() {
Serial.println("-->[PREF] wifiPass:\t#" + wifiPass + "#");
#endif
Serial.println("-->[PREF] hostName:\t#" + hostName + "#");

// Fixed IP
Serial.println("-->[PREF] useStaticIP:\t #" + String(useStaticIP) + "#");
Serial.println("-->[PREF] staticIP:\t #" + staticIP.toString() + "#");
Serial.println("-->[PREF] gateway:\t #" + gateway.toString() + "#");
Serial.println("-->[PREF] subnet:\t #" + subnet.toString() + "#");
Serial.println("-->[PREF] dns1:\t #" + dns1.toString() + "#");
Serial.println("-->[PREF] dns2:\t #" + dns2.toString() + "#");

Serial.println("-->[PREF] selCO2Sensor:\t #" + String(selectedCO2Sensor) + "#");
Serial.println("-->[PREF] debugSensors is:\t#" + String(debugSensors ? "Enabled" : "Disabled") + "# (" + String(debugSensors) + ")");
Serial.println("-->[PREF] displayReverse is:\t#" + String(displayReverse ? "Reversed" : "Normal") + "# (" + String(displayReverse) + ")");
Expand Down Expand Up @@ -287,6 +296,15 @@ void initPreferences() {
wifiSSID = preferences.getString("wifiSSID", wifiSSID).c_str();
wifiPass = preferences.getString("wifiPass", wifiPass).c_str();
hostName = preferences.getString("hostName", hostName).c_str();

// Fixed IP
useStaticIP = preferences.getBool("useStaticIP", false);
staticIP.fromString(preferences.getString("staticIP", staticIP.toString()).c_str());
gateway.fromString(preferences.getString("gateway", gateway.toString()).c_str());
subnet.fromString(preferences.getString("subnet", subnet.toString()).c_str());
dns1.fromString(preferences.getString("dns1", dns1.toString()).c_str());
dns2.fromString(preferences.getString("dns2", dns2.toString()).c_str());

selectedCO2Sensor = preferences.getUInt("selCO2Sensor", 0);
debugSensors = preferences.getBool("debugSensors", false);
displayReverse = preferences.getBool("displayReverse", false);
Expand Down Expand Up @@ -392,6 +410,15 @@ void putPreferences() {
preferences.putString("wifiSSID", wifiSSID);
preferences.putString("wifiPass", wifiPass);
preferences.putString("hostName", hostName);

// Fixed IP
preferences.putBool("useStaticIP", useStaticIP);
preferences.putString("staticIP", staticIP.toString());
preferences.putString("gateway", gateway.toString());
preferences.putString("subnet", subnet.toString());
preferences.putString("dns1", dns1.toString());
preferences.putString("dns2", dns2.toString());

preferences.putUInt("selCO2Sensor", selectedCO2Sensor);
preferences.putBool("debugSensors", debugSensors);
preferences.putBool("displayReverse", displayReverse);
Expand Down Expand Up @@ -479,6 +506,15 @@ String getPreferencesAsJson() {
doc["wifiSSID"] = preferences.getString("wifiSSID", wifiSSID);
// doc["wifiPass"] = preferences.getString("wifiPass", wifiPass);
doc["hostName"] = preferences.getString("hostName", hostName);

// Fixed IP
doc["useStaticIP"] = preferences.getBool("useStaticIP", false);
doc["staticIP"] = preferences.getString("staticIP", staticIP.toString());
doc["gateway"] = preferences.getString("gateway", gateway.toString());
doc["subnet"] = preferences.getString("subnet", subnet.toString());
doc["dns1"] = preferences.getString("dns1", dns1.toString());
doc["dns2"] = preferences.getString("dns2", dns2.toString());

doc["selCO2Sensor"] = preferences.getInt("selCO2Sensor", 0);
doc["debugSensors"] = preferences.getBool("debugSensors", false);
doc["displayReverse"] = preferences.getBool("displayReverse", false);
Expand Down Expand Up @@ -556,6 +592,15 @@ String getActualSettingsAsJson(bool includePasswords = false) {
doc["wifiPass"] = wifiPass;
}
doc["hostName"] = hostName;

// Fixed IP
doc["useStaticIP"] = useStaticIP;
doc["staticIP"] = staticIP.toString();
doc["gateway"] = gateway.toString();
doc["subnet"] = subnet.toString();
doc["dns1"] = dns1.toString();
doc["dns2"] = dns2.toString();

doc["selCO2Sensor"] = selectedCO2Sensor;
doc["debugSensors"] = debugSensors;
doc["displayReverse"] = displayReverse;
Expand Down Expand Up @@ -653,6 +698,15 @@ bool handleSavePreferencesFromJSON(String jsonPreferences) {
displayOffOnExternalPower = JsonDocument["dispOffOnExP"];
wifiSSID = JsonDocument["wifiSSID"].as<String>().c_str();
hostName = JsonDocument["hostName"].as<String>().c_str();

// Fixed IP
useStaticIP = JsonDocument["useStaticIP"];
staticIP.fromString(JsonDocument["staticIP"].as<String>());
gateway.fromString(JsonDocument["gateway"].as<String>());
subnet.fromString(JsonDocument["subnet"].as<String>());
dns1.fromString(JsonDocument["dns1"].as<String>());
dns2.fromString(JsonDocument["dns2"].as<String>());

selectedCO2Sensor = JsonDocument["selCO2Sensor"];
debugSensors = JsonDocument["debugSensors"];
displayReverse = JsonDocument["displayReverse"];
Expand Down
6 changes: 6 additions & 0 deletions CO2_Gadget_TFT.h
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,12 @@ void showBatteryIcon(int32_t posX, int32_t posY, bool forceRedraw) { // For TTG
}

void showWiFiIcon(int32_t posX, int32_t posY, bool forceRedraw) {
// If captivePortalActive = true; draw a white circle instead of the WiFi icon
if (captivePortalActive) {
tft.drawRoundRect(posX - 2, posY - 2, 16 + 4, 16 + 4, 2, TFT_DARKGREY);
tft.fillCircle(posX + 8, posY + 8, 6, TFT_WHITE);
return;
}
int8_t rssi = WiFi.RSSI();
if (troubledWIFI) {
tft.drawRoundRect(posX - 2, posY - 2, 16 + 4, 16 + 4, 2, TFT_RED);
Expand Down
124 changes: 116 additions & 8 deletions CO2_Gadget_WIFI.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
/*****************************************************************************************************/
// clang-format on

#if !defined WIFI_SSID_CREDENTIALS || !defined WIFI_PW_CREDENTIALS
// If not using enviroment variables, you must have a credentials.h file
#include "credentials.h"
#ifdef SUPPORT_CAPTIVE_PORTAL
DNSServer dnsServer;
#endif

WiFiClient espClient;
Expand Down Expand Up @@ -683,6 +682,7 @@ void WiFiStationGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
}

void WiFiStationDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
if (captivePortalActive) return;
++WiFiConnectionRetries;
Serial.println("-->[WiFi] Disconnected from WiFi access point. Reason: " + getWiFiDisconnectReason(info.wifi_sta_disconnected.reason) + " (" + String(info.wifi_sta_disconnected.reason) + ") Retries: " + String(WiFiConnectionRetries) + " of " + String(maxWiFiConnectionRetries));
#ifdef DEBUG_WIFI_EVENTS
Expand Down Expand Up @@ -724,6 +724,12 @@ String getCO2GadgetStatusAsJson() {
doc["RSSI"] = WiFi.RSSI();
doc["MACAddress"] = MACAddress;
doc["hostName"] = hostName;
doc["useStaticIP"] = useStaticIP;
doc["staticIP"] = staticIP.toString();
doc["gateway"] = gateway.toString();
doc["subnet"] = subnet.toString();
doc["dns1"] = dns1.toString();
doc["dns2"] = dns2.toString();
#ifdef SUPPORT_MQTT
doc["rootTopic"] = rootTopic;
doc["discoveryTopic"] = discoveryTopic;
Expand Down Expand Up @@ -813,10 +819,15 @@ void initWebServer() {
});

server.on("/preferences.html", HTTP_GET, [](AsyncWebServerRequest *request) {
/** GZIPPED CONTENT ***/
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/preferences.html.gz", "text/html");
response->addHeader("Content-Encoding", "gzip");
request->send(response);
if (captivePortalActive && !request->hasParam("relaxedSecurity")) {
// Redirigir a preferences.html con el parámetro ?relaxedSecurity
request->redirect("/preferences.html?relaxedSecurity");
} else {
// Servir la página preferences.html sin el parámetro
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/preferences.html.gz", "text/html");
response->addHeader("Content-Encoding", "gzip");
request->send(response);
}
});

server.on("/status.html", HTTP_GET, [](AsyncWebServerRequest *request) {
Expand Down Expand Up @@ -1023,7 +1034,18 @@ bool connectToWiFi() {
WiFi.disconnect(true); // disconnect form wifi to set new wifi connection
delay(100);
WiFi.mode(WIFI_STA);
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);

if (useStaticIP) {
if (!WiFi.config(staticIP, gateway, subnet, dns1, dns2)) {
Serial.println("-->[WiFi] Failed to configure static IP and DNS");
return false;
}
Serial.print("-->[WiFi] Configuring static IP: ");
Serial.println(staticIP);
} else {
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); // Use DHCP
}

WiFi.setHostname(hostName.c_str());
Serial.println("-->[WiFi] Setting hostname: " + hostName);
#ifdef WIFI_PRIVACY
Expand Down Expand Up @@ -1086,6 +1108,8 @@ void initOTA() {
}

void initWifi() {
if (captivePortalActive) return;

if (wifiSSID == "") {
activeWIFI = false;
}
Expand All @@ -1107,7 +1131,88 @@ void initWifi() {
}
}

#ifdef SUPPORT_CAPTIVE_PORTAL
class CaptiveRequestHandler : public AsyncWebHandler {
public:
CaptiveRequestHandler() {
// initWebServer();
Serial.println("-->[WiFi] CAPTIVE PORTAL STARTED");
}

virtual ~CaptiveRequestHandler() {}

bool canHandle(AsyncWebServerRequest *request) {
// request->addInterestingHeader("ANY");
return true;
}

void handleRequest(AsyncWebServerRequest *request) {
request->redirect("/index.html");
Serial.println("-->[WiFi] Captive portal request redirected to /index.html");
}

// void handleRequest(AsyncWebServerRequest *request) {
// request->redirect("/index.html");
// Serial.println("-->[WiFi] Captive portal request redirected to /index.html");
// }

// void handleRequest(AsyncWebServerRequest *request) {
// AsyncResponseStream *response = request->beginResponseStream("text/html");
// response->print("<!DOCTYPE html><html><head><title>Captive Portal</title></head><body>");
// response->print("<p>This is out captive portal front page.</p>");
// response->printf("<p>You were trying to reach: http://%s%s</p>", request->host().c_str(), request->url().c_str());
// response->printf("<p>Try opening <a href='http://%s'>this link</a> instead</p>", WiFi.softAPIP().toString().c_str());
// response->print("</body></html>");
// request->send(response);
// Serial.println("-->[WiFi] Captive portal request");
// }
};

static const void initCaptivePortal() {
if (WiFi.status() == WL_CONNECTED) {
Serial.println("-->[WiFi] Already connected to Wi-Fi");
return;
} else {
Serial.println("-->[WiFi] NOT CONNECTED TO WI-FI. STARTING CAPTIVE PORTAL FOR " + String(timeToWaitForCaptivePortal) + " SECONDS");
}
WiFi.disconnect(true);
delay(20);
WiFi.softAP("CO2-Gadget", NULL); // SSID, password
dnsServer.start(53, "*", WiFi.softAPIP());
server.end();
delay(20);
initWebServer();
server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER); // only when requested from AP

server.begin();
delay(100);
Serial.print("-->[WiFi] AP IP address: ");
Serial.println(WiFi.softAPIP());
captivePortalActive = true;
}
#endif // SUPPORT_CAPTIVE_PORTAL

void wifiCaptivePortalLoop() {
#ifdef SUPPORT_CAPTIVE_PORTAL
if (captivePortalActive) {
dnsServer.processNextRequest();
// int connectedStations = WiFi.softAPgetStationNum();
// Serial.println("-->[WiFi] Captive portal active. Connected stations: " + String(connectedStations));
if (millis() > timeInitializationCompleted + timeToWaitForCaptivePortal * 1000) {
captivePortalActive = false;
Serial.println("-->[WiFi] Captive portal timeout. Disabling captive portal");
}
}
#endif
}

void wifiClientLoop() {
#ifdef SUPPORT_CAPTIVE_PORTAL
if (captivePortalActive) {
wifiCaptivePortalLoop();
return;
}
#endif
if (isDownloadingBLE) return;
if (activeWIFI && troubledWIFI && (millis() - timeTroubledWIFI >= timeToRetryTroubledWIFI * 1000)) {
initWifi();
Expand Down Expand Up @@ -1135,6 +1240,9 @@ void wifiClientLoop() {

void OTALoop() {
#ifdef SUPPORT_OTA
#ifdef SUPPORT_CAPTIVE_PORTAL
if (captivePortalActive) return;
#endif
if (isDownloadingBLE) return;
if ((activeWIFI) && (activeOTA) && (!troubledWIFI) && (WiFi.status() == WL_CONNECTED)) {
AsyncElegantOTA.loop();
Expand Down
14 changes: 0 additions & 14 deletions credentials.h

This file was deleted.

Loading

0 comments on commit eed169f

Please sign in to comment.