#include "esp_task_wdt.h" // watchdogs #include // WiFi connection #include #include #include "driver/gpio.h" #include /////////////////////////////////////////////////////////////////////////////// /// Watchdogs Settings #define WDT_TIMEOUT 60000 #define WDT_CONFIG_FREERTOS_NUMBER_OF_CORES 1 // If one core doesn't work, try 2 esp_task_wdt_config_t twdt_config = { .timeout_ms = WDT_TIMEOUT, .idle_core_mask = (1 << WDT_CONFIG_FREERTOS_NUMBER_OF_CORES) - 1, // Bitmask of all cores .trigger_panic = true, }; // Bugfixes for hardware watchdog on arduino-esp32 3.x /////////////////////////////////////////////////////////////////////////////// /// WiFi Settings //#define WIFI_SSID "FlannelFlat1" //#define WIFI_PASSWORD "CosySquares4Life:3" #define WIFI_SSID "Hacklab" #define WIFI_PASSWORD "piranhas" #define WIFI_HOSTNAME "MediaServerSwitch" /////////////////////////////////////////////////////////////////////////////// /// HTTP Server Setup AsyncWebServer server(80); /////////////////////////////////////////////////////////////////////////////// /// Pin Setup #define PIN_POWER_RELAY 23 #define PIN_RESTART_RELAY 19 #define PIN_STATUS_LED 35 #define PIN_POWER_BTN 27 const char* WiFiCodeToString(int code) { const char* status; switch (code) { case 0: status = "IDLE STATUS"; break; case 1: status = "NO SSID AVAILABLE"; break; case 2: status = "SCAN COMPLETE"; break; case 3: status = "CONNECTED"; break; case 4: status = "CONNECT FAILED"; break; case 5: status = "CONNECTION L\sOST"; break; case 6: status = "DISCONNECTED"; break; case 255: status = "NO SHIELD"; break; default: status = "UNKNOWN"; break; } return status; } void setup() { Serial.begin(9600); /////////////////////////////////////////////////////////////////////////// /// Watchdog Setup Serial.print("Configuring WDT... "); esp_task_wdt_deinit(); // WDT is enabled by default, deinit esp_task_wdt_init(&twdt_config); // Enable panic so ESP32 restarts esp_task_wdt_add(NULL); // Add current thread to WDT watch Serial.println("Success"); /////////////////////////////////////////////////////////////////////////// /// Pin Setup pinMode(PIN_POWER_RELAY, OUTPUT); // Power Button pinMode(PIN_RESTART_RELAY, OUTPUT); // Restart Button pinMode(PIN_STATUS_LED, INPUT); // Status LED pinMode(PIN_POWER_BTN, INPUT); // Power Button Passthrough /////////////////////////////////////////////////////////////////////////// /// WiFi Setup esp_task_wdt_reset(); // Feed the watchdog Serial.print("Setting up WiFi... "); WiFi.mode(WIFI_STA); WiFi.setHostname(WIFI_HOSTNAME); MDNS.begin(WIFI_HOSTNAME); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); Serial.print("Connecting to Network... "); unsigned short count = 0; unsigned long last = millis(); while (WiFi.status() != WL_CONNECTED) { if (count > 60) { Serial.println("Failed to connect, restarting"); ESP.restart(); } else if (millis() - last > 1000) { Serial.print("."); last = millis(); count++; } } WiFi.persistent(false); Serial.print(" Connected with IP: "); Serial.print(WiFi.localIP()); Serial.print(" and Hostname: "); Serial.println(WIFI_HOSTNAME); esp_task_wdt_reset(); // Feed the watchdog int ch = WiFi.channel(); bool is5GHz = (ch >= 36); Serial.printf("Channel: %d (%s GHz), RSSI: %d dBm\n", ch, is5GHz ? "5" : "2.4", WiFi.RSSI()); /////////////////////////////////////////////////////////////////////////// /// Web Server server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { request->send(200, "text/plain", "/ping Pong\n" "/status Get ESP and PC status\n" "/power Press the power button\n" "/power-long Hold down the power button (for force stops)\n" "/restart-pc Press the restart button on the PC\n" "/restart-ESP Shut down the server and restart the whole ESP\n"); }); server.on("/ping", HTTP_GET, [](AsyncWebServerRequest *request) { request->send(200, "text/plain", "pong"); }); server.on("/status", HTTP_GET, [ch, is5GHz](AsyncWebServerRequest *request) { char* result; asprintf(&result, "IP: %s, Hostname: %s, Status: %s, Channel: %d (%s GHz), RSSI: %d dBm\n", WiFi.localIP().toString().c_str(), WIFI_HOSTNAME, WiFiCodeToString(WiFi.status()), ch, is5GHz ? "5" : "2.4", WiFi.RSSI()); request->send(200, "text/plain", result); free(result); }); server.on("/power", HTTP_POST, [](AsyncWebServerRequest *request) { digitalWrite(PIN_POWER_RELAY, HIGH); delay(500); digitalWrite(PIN_POWER_RELAY, LOW); request->send(200, "text/plain", "200 OK"); }); server.on("/power-long", HTTP_POST, [](AsyncWebServerRequest *request) { digitalWrite(PIN_POWER_RELAY, HIGH); delay(5000); digitalWrite(PIN_POWER_RELAY, LOW); request->send(200, "text/plain", "200 OK"); }); server.on("/restart-pc", HTTP_POST, [](AsyncWebServerRequest *request) { digitalWrite(PIN_RESTART_RELAY, HIGH); delay(1000); digitalWrite(PIN_RESTART_RELAY, LOW); request->send(200, "text/plain", "200 OK"); }); server.on("/restart-ESP", HTTP_POST, [](AsyncWebServerRequest *request) { request->send(202, "text/plain", "202 Accepted. Good Night."); delay(500); server.end(); ESP.restart(); }); server.on("/activate", HTTP_POST, [](AsyncWebServerRequest *request) { if (!request->hasParam("pin", true) || !request->hasParam("duration", true)) { request->send(400, "text/plain", "400 Bad Request. Missing 'pin' or 'duration' parameter"); return; } int pin = request->getParam("pin", true)->value().toInt(); long duration = strtol(request->getParam("duration", true)->value().c_str(), NULL, 10); if (!GPIO_IS_VALID_GPIO((gpio_num_t)pin)) { request->send(400, "text/plain", "Invalid pin for this ESP32"); return; } if (duration <= 0 || duration > 3600000) { request->send(400, "text/plain", "400 Bad Request. Duration must be between 1ms and 3600000ms"); return; } gpio_io_config_t* pin_mode; gpio_get_io_config((gpio_num_t)pin, pin_mode); if (pin_mode->oe == true) { if (pin_mode->ie != true) { request->send(400, "text/plain", "Pin is configured as input"); return; } // Configure pin as output gpio_config_t config = {}; config.pin_bit_mask = (1ULL << pin); config.mode = GPIO_MODE_OUTPUT; config.pull_up_en = GPIO_PULLUP_DISABLE; config.pull_down_en = GPIO_PULLDOWN_DISABLE; config.intr_type = GPIO_INTR_DISABLE; if (gpio_config(&config) != ESP_OK) { request->send(400, "text/plain", "Bad Request. Cannot configure pin as output"); return; } } gpio_set_level((gpio_num_t)pin, HIGH); delay(duration); gpio_set_level((gpio_num_t)pin, LOW); delay(10); // allow change to propagate // unconfigure pin gpio_reset_pin((gpio_num_t)pin); request->send(200, "text/plain", "OK"); }); server.begin(); } unsigned long last = millis(); void loop() { if (millis() - last > 10000) { Serial.print("Heartbeat. WiFi Status: "); Serial.println(WiFiCodeToString(WiFi.status())); esp_task_wdt_reset(); // Feed the watchdog last = millis(); } if (WiFi.status() != WL_CONNECTED) { // you can use WiFi.setAutoReconnect(true); but i rather this for custom behaviour. Serial.println("Disconnected from network, restarting."); ESP.restart(); } }