237 lines
8.0 KiB
Arduino
237 lines
8.0 KiB
Arduino
#include "esp_task_wdt.h" // watchdogs
|
|
#include <WiFi.h> // WiFi connection
|
|
#include <ESPAsyncWebServer.h>
|
|
#include <stdio.h>
|
|
#include "driver/gpio.h"
|
|
#include <ESPmDNS.h>
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// 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();
|
|
}
|
|
} |