Rev 4 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
//////////////////////////////// Include libraries /////////////////////////////////////////#include <Arduino.h>#include <ArduinoOTA.h>#include <EEPROM.h>#include <Ticker.h>#include <FS.h>#include <LittleFS.h>#include <ezButton.h>#include <PubSubClient.h> // https://github.com/knolleary/pubsubclient/#include <AsyncFsWebServer.h> //https://github.com/cotestatnt/async-esp-fs-webserver//////////////////////////////// Include settings /////////////////////////////////////////#include "settings.h"//////////////////////////////// Define constants /////////////////////////////////////////#ifndef LED_BUILTIN#define LED_BUILTIN 2#endif#define FILESYSTEM LittleFS#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3" // Timezone definition to get properly time from NTP server#ifndef Default_MQTT_Port#define Default_MQTT_Port "1883"#endif#define BTN_SAVE 5// added labels for /setup webpage#define USER_LABEL "Username"#define PASSWORD_LABEL "Password"#define EXTERNAL_ANTENNA_LABEL "External (Extra Internal) Antenna"#define MQTT_ENABLED_LABEL "MQTT Enabled"#define MQTT_CLIENT_LABEL "MQTT Client"#define MQTT_SERVER_LABEL "MQTT Server"#define MQTT_PORT_LABEL "MQTT Server Port"#define MQTT_USER_LABEL "MQTT User"#define MQTT_PASSWORD_LABEL "MQTT Password"#define MQTT_TOPIC_LABEL "MQTT Topic"#define SHORT_PRESS_TIME_MIN 1000 // 1 second#define SHORT_PRESS_TIME_MAX 2500 // 2.5 seconds#define LONG_PRESS_TIME 10000 // 10 secondsconst uint8_t logo_png[] PROGMEM = {0x89, 0x50, 0x4E, 0x47, /* ... */};//////////////////////////////// Create Objects /////////////////////////////////////////struct tm Time;Ticker ticker;AsyncFsWebServer server(FILESYSTEM, 80, "P1_Meter");ezButton button(9); // create ezButton object that attach to pin GPIO9// * Define variablesbool captiveRun = false;// Setup SettingsString Username = "admin";String Password = "admin";bool External_Antenna = true;// MQTT Settingsbool MQTT_Enabled = false;String MQTT_Client = "ESP32_P1_Meter";String MQTT_Server = "";//uint16_t MQTT_Port = Default_MQTT_Port;String MQTT_Port = Default_MQTT_Port;String MQTT_User = "";String MQTT_Password = "";String MQTT_Topic = "P1_Meter";int LEDSpeed = 0;bool isPressing = false;unsigned long pressedTime = 0;unsigned long releasedTime = 0;//////////////////////////////// Filesystem /////////////////////////////////////////bool startFilesystem() {if (FILESYSTEM.begin()){server.printFileList(FILESYSTEM, "/", 2), Serial;return true;}else {Serial.println("ERROR on mounting filesystem. It will be reformatted!");FILESYSTEM.format();ESP.restart();}return false;}/** Getting FS info (total and free bytes) is strictly related to* filesystem library used (LittleFS, FFat, SPIFFS etc etc) and ESP framework*/#ifdef ESP32void getFsInfo(fsInfo_t* fsInfo) {fsInfo->fsName = "LittleFS";fsInfo->totalBytes = LittleFS.totalBytes();fsInfo->usedBytes = LittleFS.usedBytes();}#endif//////////////////////////////// WebSocket Handler /////////////////////////////void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){switch (type) {case WS_EVT_DISCONNECT:Serial.print("WebSocket client disconnected!\n");break;case WS_EVT_CONNECT: {IPAddress ip = client->remoteIP();Serial.printf("WebSocket client %d.%d.%d.%d connected.\n", ip[0], ip[1], ip[2], ip[3]);client->printf("%s", "{\"Connected\": true}");}break;default:break;}}//////////////////////////////// NTP Time /////////////////////////////////////void getUpdatedtime(const uint32_t timeout){uint32_t start = millis();Serial.print("Sync time...");while (millis() - start < timeout && Time.tm_year <= (1970 - 1900)) {time_t now = time(nullptr);Time = *localtime(&now);delay(5);}Serial.println(" done.");}//////////////////// Load application options from filesystem ////////////////////bool loadOptions() {if (FILESYSTEM.exists(server.getConfiFileName())) {server.getOptionValue(USER_LABEL, Username);server.getOptionValue(PASSWORD_LABEL, Password);server.getOptionValue(EXTERNAL_ANTENNA_LABEL, External_Antenna);server.getOptionValue(MQTT_ENABLED_LABEL, MQTT_Enabled);server.getOptionValue(MQTT_CLIENT_LABEL, MQTT_Client);server.getOptionValue(MQTT_SERVER_LABEL, MQTT_Server);server.getOptionValue(MQTT_PORT_LABEL, MQTT_Port);server.getOptionValue(MQTT_USER_LABEL, MQTT_User);server.getOptionValue(MQTT_PASSWORD_LABEL, MQTT_Password);server.getOptionValue(MQTT_TOPIC_LABEL, MQTT_Topic);Serial.println("\nThis are the current values stored: \n");Serial.printf("MQTT Enabled: %s\n", MQTT_Enabled ? "true" : "false");Serial.printf("MQTT Client: %s\n", MQTT_Client.c_str());Serial.printf("MQTT Server: %s\n", MQTT_Server.c_str());// Serial.printf("MQTT Server Port: %d\n", MQTT_Port);Serial.printf("MQTT Server Port: %s\n", MQTT_Port.c_str());Serial.printf("MQTT User: %s\n", MQTT_User.c_str());Serial.printf("MQTT password: %s\n", MQTT_Password.c_str());Serial.printf("MQTT Topic: %s\n", MQTT_Topic.c_str());return true;}elseSerial.println(F("Config file not exist"));return false;}bool _was_connected = false;void saveOptions() {server.saveOptionValue(USER_LABEL, Username);server.saveOptionValue(PASSWORD_LABEL, Password);server.saveOptionValue(EXTERNAL_ANTENNA_LABEL, External_Antenna);server.saveOptionValue(MQTT_ENABLED_LABEL, MQTT_Enabled);server.saveOptionValue(MQTT_CLIENT_LABEL, MQTT_Client);server.saveOptionValue(MQTT_SERVER_LABEL, MQTT_Server);server.saveOptionValue(MQTT_PORT_LABEL, MQTT_Port);server.saveOptionValue(MQTT_USER_LABEL, MQTT_User);server.saveOptionValue(MQTT_PASSWORD_LABEL, MQTT_Password);server.saveOptionValue(MQTT_TOPIC_LABEL, MQTT_Topic);Serial.println(F("Application options saved."));}//////////////////////////// HTTP Request Handlers ////////////////////////////////////void handleLoadOptions(AsyncWebServerRequest *request) {request->send(200, "text/plain", "Options loaded");loadOptions();Serial.println("Application option loaded after web request");}// * ==========================================================================================// * = HIERONDER NOG NETJES MAKEN == HIERONDER NOG NETJES MAKEN == HIERONDER NOG NETJES MAKEN =// * ==========================================================================================//MQTT_Port_String = String(MQTT_Port);//sprintf(MQTT_Port_String, "%u", MQTT_Port);//MQTTRemote _mqtt_remote(MQTT_Client.c_str(), MQTT_Server.c_str(), MQTT_Port, MQTT_User.c_str(), MQTT_Password.c_str(),// {.rx_buffer_size = 2048, .tx_buffer_size = 2048, .keep_alive_s = 10});//////////////////////////////// SETUP /////////////////////////////////////////void setup() {Serial.begin(115200);button.setDebounceTime(50); // set debounce time to 50 millisecondspinMode(BTN_SAVE, INPUT_PULLUP);pinMode(LED_BUILTIN, OUTPUT);// FILESYSTEM INITif (startFilesystem()){// Load configuration (if not present, default will be created when webserver will start)if (loadOptions())Serial.println(F("Application option loaded"));elseSerial.println(F("Application options NOT loaded!"));}server.setSetupPageTitle("Instellingen P1 Meter");server.setSetupPageLogo(logo_png, sizeof(logo_png), "image/png", false);server.closeSetupConfiguration();// Try to connect to stored SSID, start AP with captive portal if fails after timeoutIPAddress myIP = server.startWiFi(15000);if (!myIP) {Serial.println("\n\nNo WiFi connection, start AP and Captive Portal\n");server.startCaptivePortal("ESP_AP", "123456789", "/setup");myIP = WiFi.softAPIP();captiveRun = true;LEDSpeed = 250;} else {LEDSpeed = 1000;}// Add custom page handlers to webserverserver.on("/reload", HTTP_GET, handleLoadOptions);// Configure /setup page and start Web Serverserver.addOptionBox("Device Setup");server.addOption(USER_LABEL, Username);server.addOption(PASSWORD_LABEL, Password);server.addOption(EXTERNAL_ANTENNA_LABEL, External_Antenna);server.addComment(EXTERNAL_ANTENNA_LABEL, "Restart is necessary after changing values.");server.addOptionBox("MQTT Setup");server.addOption(MQTT_ENABLED_LABEL, MQTT_Enabled);server.addOption(MQTT_CLIENT_LABEL, MQTT_Client);server.addOption(MQTT_SERVER_LABEL, MQTT_Server);server.addOption(MQTT_PORT_LABEL, MQTT_Port);server.addOption(MQTT_USER_LABEL, MQTT_User);server.addOption(MQTT_PASSWORD_LABEL, MQTT_Password);server.addOption(MQTT_TOPIC_LABEL, MQTT_Topic);server.addComment(MQTT_TOPIC_LABEL, "Restart is necessary after changing values.");// Enable ACE FS file web editor and add FS info callback functionserver.enableFsCodeEditor();#ifdef ESP32server.setFsInfoCallback(getFsInfo);#endif// set /setup and /edit page authenticationserver.setAuthentication(Username.c_str(), Password.c_str());// Start server with custom websocket event handlerserver.init(onWsEvent);Serial.print(F("ESP Web Server started on IP Address: "));Serial.println(server.getServerIP());if (External_Antenna) {pinMode(3, OUTPUT); // RF switch power ondigitalWrite(3, LOW);pinMode(14, OUTPUT); // select external antennadigitalWrite(14, HIGH);Serial.println("External antenna selected.");} else {pinMode(14, INPUT); // select on-board antennapinMode(3, INPUT); // RF switch power offSerial.println("Internal antenna selected.");}long rssi = WiFi.RSSI();Serial.print("WiFi Strength (RSSI): ");if ((rssi <= -30) && (rssi > -50)) {Serial.print("***** (");Serial.print(rssi);Serial.print("dBm.)");} else if ((rssi <= -50) && (rssi > -60)) {Serial.print("****. (");Serial.print(rssi);Serial.print("dBm.)");} else if ((rssi <= -60) && (rssi > -70)) {Serial.print("***.. (");Serial.print(rssi);Serial.print("dBm.)");} else if ((rssi <= -70) && (rssi > -80)) {Serial.print("**... (");Serial.print(rssi);Serial.print("dBm.)");} else if ((rssi <= -80) && (rssi > -90)) {Serial.print("*.... (");Serial.print(rssi);Serial.print("dBm.)");} else if ((rssi <= -90)) {Serial.print("..... (");Serial.print(rssi);Serial.print("dBm.)");}// if (MQTT_Enabled) {// }// if (MQTT_Enabled) {// _mqtt_remote.start([](bool connected) {// if (connected) {// _mqtt_remote.subscribe(// _mqtt_remote.publishMessageVerbose(_mqtt_remote.clientId() + "/initial_message", "oh hello!");// });// };}//////////////////////////////// LOOP /////////////////////////////////////////void loop() {// Send ESP system time (epoch) and heap stats to WS clientstatic uint32_t sendToClientTime;if (millis() - sendToClientTime > LEDSpeed ) {sendToClientTime = millis();digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));time_t now = time(nullptr);using namespace AsyncFSWebServer;CJSON::Json doc;doc.setBool("addPoint", true);doc.setNumber("timestamp", (double)now);#ifdef ESP32doc.setNumber("totalHeap", (double)heap_caps_get_free_size(0));doc.setNumber("maxBlock", (double)heap_caps_get_largest_free_block(0));#elif defined(ESP8266)uint32_t free;uint32_t max;ESP.getHeapStats(&free, &max, nullptr);doc.setNumber("totalHeap", (double)free);doc.setNumber("maxBlock", (double)max);#endifString msg = doc.serialize();server.wsBroadcast(msg.c_str());}if (captiveRun)server.updateDNS();// Savew options also on button clickif (! digitalRead(BTN_SAVE)) {saveOptions();delay(1000);}button.loop(); // MUST call the loop() function firstif (button.isPressed()) {pressedTime = millis();isPressing = true;}long pressingDuration = millis() - pressedTime;if ((isPressing == true) && (pressingDuration > LONG_PRESS_TIME))digitalWrite(LED_BUILTIN, LOW);if (button.isReleased()) {releasedTime = millis();isPressing = false;long pressDuration = releasedTime - pressedTime;if ((pressDuration > SHORT_PRESS_TIME_MIN) && (pressDuration < SHORT_PRESS_TIME_MAX)) {ESP.restart();}if (pressDuration > LONG_PRESS_TIME) {server.clearConfigFile();ESP.restart();}}}