Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /********* Pleasedontcode.com **********
- Pleasedontcode thanks you for automatic code generation! Enjoy your code!
- - Terms and Conditions:
- You have a non-exclusive, revocable, worldwide, royalty-free license
- for personal and commercial use. Attribution is optional; modifications
- are allowed, but you're responsible for code maintenance. We're not
- liable for any loss or damage. For full terms,
- please visit pleasedontcode.com/termsandconditions.
- - Project: # Torch Controller
- - Source Code NOT compiled for: ESP32 DevKit V1
- - Source Code created on: 2026-01-23 14:53:31
- ********* Pleasedontcode.com **********/
- /****** SYSTEM REQUIREMENTS *****/
- /****** SYSTEM REQUIREMENT 1 *****/
- /* perbaiki coding proyek THC_ESP32 saya agar bisa di */
- /* kontrol dan di monitor melalui web server */
- /****** SYSTEM REQUIREMENT 2 *****/
- /* Integrasikan web server HTTP pada ESP32 dengan */
- /* JSON API untuk memantau tegangan busur 0-250V */
- /* secara real-time, menampilkan status obor */
- /* (UP/DOWN) pada LCD I2C, dan mengontrol program 3 */
- /* parameter melalui encoder KY-040 lokal atau */
- /* endpoint web. */
- /****** END SYSTEM REQUIREMENTS *****/
- // **TORCH HEIGHT CONTROL (THC) SYSTEM - ESP32 IMPLEMENTATION**
- // Complete system with web server, JSON API, LCD display, and rotary encoder control
- #include <WiFi.h>
- #include <WebServer.h>
- #include <ArduinoJson.h>
- #include <EEPROM.h>
- #include <LiquidCrystal_I2C.h>
- #include <esp_timer.h>
- // ========== HARDWARE PIN DEFINITIONS ==========
- // Arc Voltage ADC Input
- const int arcVoltagePin = 35; // GPIO35 - ADC pin for arc voltage (0-250V mapped to 0-4095)
- // Output Control Pins
- const int outputUpPin = 17; // GPIO17 - Move torch UP
- const int outputOkPin = 16; // GPIO16 - Arc OK signal
- const int outputDnPin = 5; // GPIO5 - Move torch DOWN
- // Rotary Encoder Pins
- const int pinCLK = 12; // GPIO12 - Encoder CLK
- const int pinDT = 14; // GPIO14 - Encoder DT
- const int pinSW = 27; // GPIO27 - Encoder Switch (button)
- // LCD I2C Configuration
- #define LCD_ADDR 0x27
- #define LCD_COLS 16
- #define LCD_ROWS 2
- LiquidCrystal_I2C lcd(LCD_ADDR, LCD_COLS, LCD_ROWS);
- // ========== WIFI CONFIGURATION ==========
- const char* ssid = "ANLOG";
- const char* password = "serversatu1";
- WebServer server(80);
- // ========== SYSTEM CONTROL VARIABLES ==========
- // Global timer handle
- esp_timer_handle_t timer_handle = NULL;
- // THC Control Variables
- volatile bool Do = false; // Timer flag for 10ms interval
- unsigned int delayTime = 0; // Delay counter before arc OK
- unsigned int SetVx10 = 0; // Set voltage * 10 for comparison
- // Arc Voltage Monitoring
- volatile unsigned int ArcV = 0; // Arc voltage (0.1V units: 50-2500 = 50-250V)
- unsigned long lastArcVReading = 0;
- const int arcVoltageUpdateInterval = 100; // Read arc voltage every 100ms
- // LCD Display Management
- unsigned int LCDtime = 0; // LCD timeout counter
- unsigned int show = 0; // LCD refresh counter
- const unsigned int defaultLCDtime = 3000; // Return to default display after 30 seconds
- // Menu and UI Variables
- byte menu = 0; // Current menu state
- byte pos = 0; // Position in current menu
- volatile int encoderVal = 100; // Encoder value (0-250)
- int oldValue = -1; // Previous encoder value for change detection
- unsigned long lastButtonPress = 0; // Button debounce timer
- // THC Parameters - Program Storage
- byte program = 1; // Currently loaded program (1-3)
- byte ParamItem = 4; // Number of parameters per program
- // EEPROM Storage Addresses
- byte SetVa = 0; // Set Voltage address
- byte DTa = 1; // Delay Time address
- byte HySa = 2; // Hysteresis address
- byte StVa = 3; // Start Voltage address
- byte Param[4] = {100, 5, 80, 100}; // Parameter buffer [SetV, DT, HyS, StV]
- // THC Parameter Values
- unsigned int SetV = 100; // Set Voltage (50-250V)
- unsigned int DT = 5; // Delay Time (0.1-20s in 0.1s units)
- unsigned int HyS = 80; // Hysteresis (1-99 in 0.1V units)
- unsigned int StV = 100; // Start Voltage (50-250V)
- // Custom LCD Characters
- byte armsUpDn[8] = {
- B00000, B00100, B01110, B00100,
- B00000, B01110, B00000, B00000
- };
- byte customUp[8] = {
- B00100, B01110, B10101, B00100,
- B00100, B00100, B00100, B00000
- };
- byte customDown[8] = {
- B00100, B00100, B00100, B00100,
- B10101, B01110, B00100, B00000
- };
- // ========== ENCODER INTERRUPT HANDLING ==========
- // Interrupt handler for rotary encoder rotation
- void IRAM_ATTR isrEncoder() {
- int currentClkState = digitalRead(pinCLK);
- int dtState = digitalRead(pinDT);
- if (currentClkState == LOW) {
- if (dtState != currentClkState) {
- encoderVal++; // Clockwise
- } else {
- encoderVal--; // Counter-clockwise
- }
- }
- }
- // ========== TIMER CALLBACK ==========
- // Called every 10ms by the ESP timer
- void onTimerCallback(void* arg) {
- Do = true;
- }
- // ========== ARC VOLTAGE READING ==========
- // Read and process arc voltage from ADC
- void readArcVoltage() {
- unsigned long now = millis();
- if (now - lastArcVReading >= arcVoltageUpdateInterval) {
- lastArcVReading = now;
- // Read ADC value (0-4095) and convert to voltage units (0.1V)
- // Assuming 250V = 4095 ADC counts
- int rawValue = analogRead(arcVoltagePin);
- ArcV = (rawValue * 250 * 10) / 4095; // Convert to 0.1V units
- // Constrain to valid range
- if (ArcV < 0) ArcV = 0;
- if (ArcV > 2500) ArcV = 2500;
- }
- }
- // ========== THC CONTROL ALGORITHM ==========
- void Setup_THC() {
- // Initialize torch control output pins
- pinMode(outputUpPin, OUTPUT);
- pinMode(outputOkPin, OUTPUT);
- pinMode(outputDnPin, OUTPUT);
- // Set all outputs to LOW (off)
- digitalWrite(outputUpPin, LOW);
- digitalWrite(outputOkPin, LOW);
- digitalWrite(outputDnPin, LOW);
- }
- void doTHC() {
- // Main THC control algorithm - called every 10ms from timer callback
- if (Do) {
- Do = false;
- // Increment display refresh counters
- LCDtime++;
- show++;
- // Auto-return to default display after timeout
- if (LCDtime > defaultLCDtime) {
- menu = 0;
- pos = 0;
- LCDtime = 0;
- encoderVal = SetV;
- }
- // Arc voltage range check (500-2500 in 0.1V units = 50-250V)
- if ((500 < ArcV) && (ArcV < 2500)) {
- // Arc voltage is in valid range
- // Wait for arc to stabilize - count until delay time reached
- if (ArcV > StV * 10) {
- delayTime++;
- }
- // Only control torch height after delay time expires
- if (delayTime >= DT * 10) {
- SetVx10 = SetV * 10; // Convert SetV to same units as ArcV
- delayTime = DT * 10; // Prevent overflow - hold at max
- // Signal that arc is OK for cutting
- digitalWrite(outputOkPin, HIGH);
- // Compare measured arc voltage with setpoint and hysteresis band
- if (ArcV >= SetVx10 + HyS) {
- // Arc voltage too high - move torch DOWN to reduce voltage
- digitalWrite(outputUpPin, LOW);
- digitalWrite(outputDnPin, HIGH);
- }
- else if (ArcV <= SetVx10 - HyS) {
- // Arc voltage too low - move torch UP to increase voltage
- digitalWrite(outputDnPin, LOW);
- digitalWrite(outputUpPin, HIGH);
- }
- else {
- // Arc voltage within hysteresis band - STOP moving torch
- digitalWrite(outputUpPin, LOW);
- digitalWrite(outputDnPin, LOW);
- }
- }
- }
- // Arc voltage out of range or arc lost
- else if (menu != 12) { // Don't turn off if in test mode
- // Reset delay timer
- delayTime = 0;
- // Turn off all outputs - arc is lost
- digitalWrite(outputUpPin, LOW);
- digitalWrite(outputOkPin, LOW);
- digitalWrite(outputDnPin, LOW);
- }
- }
- }
- // ========== LCD INITIALIZATION ==========
- void Setup_LCD() {
- // Initialize LCD with I2C
- lcd.init();
- lcd.backlight();
- // Create custom characters
- lcd.createChar(0, armsUpDn);
- lcd.createChar(1, customUp);
- lcd.createChar(2, customDown);
- // Display splash screen
- lcd.setCursor(1, 0);
- lcd.print("MEHMET IBRAHIM");
- lcd.setCursor(3, 1);
- lcd.print("Plasma THC");
- delay(1500);
- lcd.clear();
- }
- // ========== LCD DISPLAY FUNCTIONS ==========
- void doLCD() {
- if (show >= 2) {
- show = 0;
- switch (menu) {
- case 0:
- doLCDDefault();
- break;
- case 1:
- doLCDMenu();
- break;
- case 11:
- doLCDMenuSetup();
- break;
- case 111:
- doLCDDelayTime();
- break;
- case 112:
- doLCDHysteresis();
- break;
- case 113:
- doLCDStartVoltage();
- break;
- case 114:
- doLCDLoadDefault();
- break;
- case 12:
- doLCDTest();
- break;
- case 115:
- doTestUp();
- break;
- case 116:
- doTestDown();
- break;
- case 13:
- doLCDProgramSelect();
- break;
- case 121:
- doProgramSet(1);
- break;
- case 122:
- doProgramSet(2);
- break;
- case 123:
- doProgramSet(3);
- break;
- default:
- doLCDDefault();
- }
- }
- }
- // Default display showing current SetV and ArcV
- void doLCDDefault() {
- if (encoderVal < 0) encoderVal = 0;
- else if (encoderVal > 250) encoderVal = 250;
- SetV = encoderVal;
- if (SetV != oldValue) {
- SaveData(SetVa, SetV);
- oldValue = SetV;
- }
- lcd.setCursor(0, 0);
- lcd.print("P ");
- if (digitalRead(outputUpPin) == HIGH) {
- lcd.write(1); // Up arrow
- } else {
- lcd.print(" ");
- }
- lcd.print(" ");
- lcd.setCursor(4, 0);
- lcd.print("Set.V: ");
- lcd.print(SetV);
- lcd.print(" ");
- lcd.setCursor(0, 1);
- lcd.print(program);
- lcd.print(" ");
- if (digitalRead(outputDnPin) == HIGH) {
- lcd.write(2); // Down arrow
- } else {
- lcd.print(" ");
- }
- lcd.print(" ");
- lcd.setCursor(4, 1);
- lcd.print("Arc.V: ");
- lcd.print(ArcV / 10);
- lcd.print(" ");
- }
- // Main menu navigation
- void doLCDMenu() {
- if (encoderVal < 0) encoderVal = 3;
- pos = encoderVal % 4;
- switch (pos) {
- case 0:
- lcd.setCursor(0, 0);
- lcd.print("> Exit ");
- lcd.setCursor(0, 1);
- lcd.print(" Program ");
- break;
- case 1:
- lcd.setCursor(0, 0);
- lcd.print("> Program ");
- lcd.setCursor(0, 1);
- lcd.print(" Setup ");
- break;
- case 2:
- lcd.setCursor(0, 0);
- lcd.print("> Setup ");
- lcd.setCursor(0, 1);
- lcd.print(" Test ");
- break;
- case 3:
- lcd.setCursor(0, 0);
- lcd.print("> Test ");
- lcd.setCursor(0, 1);
- lcd.print(" Exit ");
- break;
- }
- }
- // Program selection menu
- void doLCDProgramSelect() {
- if (encoderVal < 0) encoderVal = 3;
- pos = abs(encoderVal % 4);
- switch (pos) {
- case 0:
- lcd.setCursor(0, 0);
- lcd.print(">> Exit ");
- lcd.setCursor(0, 1);
- lcd.print(" Load Prog: 1 ");
- break;
- case 1:
- lcd.setCursor(0, 0);
- lcd.print(">> Load Prog: 1 ");
- lcd.setCursor(0, 1);
- lcd.print(" Load Prog: 2 ");
- break;
- case 2:
- lcd.setCursor(0, 0);
- lcd.print(">> Load Prog: 2 ");
- lcd.setCursor(0, 1);
- lcd.print(" Load Prog: 3 ");
- break;
- case 3:
- lcd.setCursor(0, 0);
- lcd.print(">> Load Prog: 3 ");
- lcd.setCursor(0, 1);
- lcd.print(" Exit ");
- break;
- }
- }
- // Setup menu
- void doLCDMenuSetup() {
- if (encoderVal < 0) encoderVal = 4;
- pos = abs(encoderVal % 5);
- switch (pos) {
- case 0:
- lcd.setCursor(0, 0);
- lcd.print(">> Exit ");
- lcd.setCursor(0, 1);
- lcd.print(" Delay Time ");
- break;
- case 1:
- lcd.setCursor(0, 0);
- lcd.print(">> Delay Time ");
- lcd.setCursor(0, 1);
- lcd.print(" Hysteresis ");
- break;
- case 2:
- lcd.setCursor(0, 0);
- lcd.print(">> Hysteresis ");
- lcd.setCursor(0, 1);
- lcd.print(" Start Voltage");
- break;
- case 3:
- lcd.setCursor(0, 0);
- lcd.print(">> Start Voltage");
- lcd.setCursor(0, 1);
- lcd.print(" Load Default ");
- break;
- case 4:
- lcd.setCursor(0, 0);
- lcd.print(">> Load Default ");
- lcd.setCursor(0, 1);
- lcd.print(" Exit ");
- break;
- }
- }
- // Test mode menu
- void doLCDTest() {
- if (encoderVal < 0) encoderVal = 2;
- pos = abs(encoderVal % 3);
- switch (pos) {
- case 0:
- lcd.setCursor(0, 0);
- lcd.print("Test > Exit ");
- lcd.setCursor(0, 1);
- lcd.print(" Torch Up ");
- digitalWrite(outputDnPin, LOW);
- digitalWrite(outputUpPin, LOW);
- digitalWrite(outputOkPin, LOW);
- break;
- case 1:
- lcd.setCursor(0, 0);
- lcd.print("Test > Torch Up ");
- lcd.setCursor(0, 1);
- lcd.print(" Torch Dn ");
- if (digitalRead(outputOkPin) == LOW) LCDtime = 0;
- if (LCDtime >= 200) { // 100 LCDtime = 1s
- digitalWrite(outputDnPin, LOW);
- digitalWrite(outputUpPin, LOW);
- digitalWrite(outputOkPin, LOW);
- }
- break;
- case 2:
- lcd.setCursor(0, 0);
- lcd.print("Test > Torch Dn ");
- lcd.setCursor(0, 1);
- lcd.print(" Exit ");
- if (digitalRead(outputOkPin) == LOW) LCDtime = 0;
- if (LCDtime >= 200) {
- digitalWrite(outputDnPin, LOW);
- digitalWrite(outputUpPin, LOW);
- digitalWrite(outputOkPin, LOW);
- }
- break;
- }
- }
- // Test torch UP function
- void doTestUp() {
- digitalWrite(outputDnPin, LOW);
- digitalWrite(outputUpPin, HIGH);
- digitalWrite(outputOkPin, HIGH);
- LCDtime = 0;
- menu = 12;
- encoderVal = 1;
- }
- // Test torch DOWN function
- void doTestDown() {
- digitalWrite(outputDnPin, HIGH);
- digitalWrite(outputUpPin, LOW);
- digitalWrite(outputOkPin, HIGH);
- LCDtime = 0;
- menu = 12;
- encoderVal = 2;
- }
- // Set Delay Time parameter
- void doLCDDelayTime() {
- if (encoderVal < 1) encoderVal = 1;
- else if (encoderVal > 200) encoderVal = 200;
- DT = encoderVal;
- if (DT != oldValue) {
- SaveData(DTa, DT);
- oldValue = DT;
- LCDtime = 0;
- }
- double x = DT / 10.00;
- lcd.setCursor(0, 0);
- lcd.print("Set > Delay Time");
- lcd.setCursor(0, 1);
- lcd.print(" : ");
- lcd.print(x, 1);
- lcd.print(" s ");
- }
- // Set Hysteresis parameter
- void doLCDHysteresis() {
- if (encoderVal < 1) encoderVal = 1;
- else if (encoderVal > 99) encoderVal = 99;
- HyS = encoderVal;
- if (HyS != oldValue) {
- SaveData(HySa, HyS);
- oldValue = HyS;
- LCDtime = 0;
- }
- double x = HyS / 10.00;
- lcd.setCursor(0, 0);
- lcd.print("Set > Hysteresis");
- lcd.setCursor(0, 1);
- lcd.print(" :");
- lcd.write(0);
- lcd.print(x, 1);
- lcd.print(" V ");
- }
- // Set Start Voltage parameter
- void doLCDStartVoltage() {
- if (encoderVal < 50) encoderVal = 50;
- else if (encoderVal > 250) encoderVal = 250;
- StV = encoderVal;
- if (StV != oldValue) {
- SaveData(StVa, StV);
- oldValue = StV;
- LCDtime = 0;
- }
- lcd.setCursor(0, 0);
- lcd.print("Set > Start Volt");
- lcd.setCursor(0, 1);
- lcd.print(" : ");
- lcd.print(StV);
- lcd.print(" V ");
- }
- // Load default parameters
- void doLCDLoadDefault() {
- Default();
- for (byte i = 0; i < 100; i++) {
- lcd.setCursor(0, 0);
- lcd.print(" Default ");
- lcd.setCursor(0, 1);
- lcd.print("Load ");
- lcd.print(i);
- lcd.print(" ");
- lcd.print("%");
- lcd.print(" ");
- delay(5);
- }
- lcd.setCursor(0, 0);
- lcd.print("Default: DONE ");
- lcd.setCursor(0, 1);
- lcd.print("Please Restart ");
- exit(0);
- }
- // Load program parameters
- void doProgramSet(int prg) {
- if (prg == 1) {
- SetVa = 0;
- DTa = 1;
- HySa = 2;
- StVa = 3;
- ReadDataProg_1();
- } else if (prg == 2) {
- SetVa = 4;
- DTa = 5;
- HySa = 6;
- StVa = 7;
- ReadDataProg_2();
- } else {
- SetVa = 8;
- DTa = 9;
- HySa = 10;
- StVa = 11;
- ReadDataProg_3();
- }
- SaveData(100, prg);
- program = prg;
- SetV = Param[0];
- DT = Param[1];
- HyS = Param[2];
- StV = Param[3];
- encoderVal = SetV;
- menu = 0;
- }
- // ========== EEPROM MANAGEMENT ==========
- void Default() {
- // Initialize all programs with default values
- SetVa = 0;
- DTa = 1;
- HySa = 2;
- StVa = 3;
- SetV = 100;
- DT = 5;
- HyS = 80;
- StV = 100;
- // Program 1
- EEPROM.write(0, SetV);
- EEPROM.write(1, DT);
- EEPROM.write(2, HyS);
- EEPROM.write(3, StV);
- // Program 2
- EEPROM.write(4, SetV);
- EEPROM.write(5, DT);
- EEPROM.write(6, HyS);
- EEPROM.write(7, StV);
- // Program 3
- EEPROM.write(8, SetV);
- EEPROM.write(9, DT);
- EEPROM.write(10, HyS);
- EEPROM.write(11, StV);
- EEPROM.write(12, 1); // Default program is 1
- EEPROM.commit();
- }
- void ReadProg() {
- program = EEPROM.read(12);
- }
- void ReadDataProg_1() {
- // Param Address: 0, 1, 2, 3
- for (int j = 0; j < ParamItem; j++) {
- Param[j] = EEPROM.read(j);
- }
- }
- void ReadDataProg_2() {
- // Param Address: 4, 5, 6, 7
- for (int j = 0; j < ParamItem; j++) {
- Param[j] = EEPROM.read(j + 4);
- }
- }
- void ReadDataProg_3() {
- // Param Address: 8, 9, 10, 11
- for (int j = 0; j < ParamItem; j++) {
- Param[j] = EEPROM.read(j + 8);
- }
- }
- void SaveData(int add, int value) {
- EEPROM.write(add, value);
- EEPROM.commit();
- }
- // ========== TIMER SETUP ==========
- void Setup_Timer() {
- // Create periodic timer configuration
- esp_timer_create_args_t timer_args = {
- .callback = &onTimerCallback,
- .name = "THC_Timer_10ms"
- };
- // Create the timer
- ESP_ERROR_CHECK(esp_timer_create(&timer_args, &timer_handle));
- // Start the timer - repeats every 10,000 microseconds (10ms)
- ESP_ERROR_CHECK(esp_timer_start_periodic(timer_handle, 10000));
- }
- // ========== ENCODER MENU CONTROL ==========
- void handleEncoderButton() {
- if (digitalRead(pinSW) == LOW) {
- if (millis() - lastButtonPress > 200) { // Debounce 200ms
- lastButtonPress = millis();
- // Handle button press based on current menu
- switch (menu) {
- case 0: // Default display - press to enter main menu
- menu = 1;
- encoderVal = 0;
- LCDtime = 0;
- break;
- case 1: // Main menu
- switch (pos) {
- case 0: // Exit
- menu = 0;
- encoderVal = SetV;
- break;
- case 1: // Program
- menu = 13;
- encoderVal = 0;
- break;
- case 2: // Setup
- menu = 11;
- encoderVal = 0;
- break;
- case 3: // Test
- menu = 12;
- encoderVal = 0;
- break;
- }
- break;
- case 11: // Setup menu
- switch (pos) {
- case 0: // Exit
- menu = 1;
- encoderVal = 1;
- break;
- case 1: // Delay Time
- menu = 111;
- encoderVal = DT;
- oldValue = -1;
- break;
- case 2: // Hysteresis
- menu = 112;
- encoderVal = HyS;
- oldValue = -1;
- break;
- case 3: // Start Voltage
- menu = 113;
- encoderVal = StV;
- oldValue = -1;
- break;
- case 4: // Load Default
- menu = 114;
- break;
- }
- break;
- case 13: // Program select
- switch (pos) {
- case 0: // Exit
- menu = 1;
- encoderVal = 1;
- break;
- case 1: // Program 1
- menu = 121;
- doProgramSet(1);
- break;
- case 2: // Program 2
- menu = 122;
- doProgramSet(2);
- break;
- case 3: // Program 3
- menu = 123;
- doProgramSet(3);
- break;
- }
- break;
- case 12: // Test mode
- switch (pos) {
- case 0: // Exit
- menu = 1;
- encoderVal = 3;
- break;
- case 1: // Torch Up
- menu = 115;
- break;
- case 2: // Torch Down
- menu = 116;
- break;
- }
- break;
- }
- }
- }
- }
- // ========== WEB SERVER SETUP ==========
- void Setup_WebServer() {
- // Initialize WiFi
- WiFi.mode(WIFI_STA);
- WiFi.begin(ssid, password);
- // Wait for WiFi connection
- int attempts = 0;
- while (WiFi.status() != WL_CONNECTED && attempts < 20) {
- delay(500);
- Serial.print(".");
- attempts++;
- }
- if (WiFi.status() == WL_CONNECTED) {
- Serial.println("");
- Serial.println("WiFi connected");
- Serial.print("IP address: ");
- Serial.println(WiFi.localIP());
- } else {
- Serial.println("WiFi connection failed!");
- }
- // Define web server routes
- server.on("/", HTTP_GET, handleWebRoot);
- server.on("/api/status", HTTP_GET, handleAPIStatus);
- server.on("/api/parameters", HTTP_GET, handleAPIParameters);
- server.on("/api/parameters", HTTP_POST, handleAPISetParameters);
- server.on("/api/program", HTTP_GET, handleAPIGetProgram);
- server.on("/api/program", HTTP_POST, handleAPISetProgram);
- server.on("/api/control", HTTP_POST, handleAPIControl);
- server.on("/api/arcvoltage", HTTP_GET, handleAPIArcVoltage);
- // Start the server
- server.begin();
- Serial.println("Web server started");
- }
- // ========== WEB HANDLERS ==========
- void handleWebRoot() {
- // Serve HTML dashboard
- String html = getHTMLDashboard();
- server.send(200, "text/html", html);
- }
- void handleAPIStatus() {
- // Return JSON status with all current parameters and readings
- StaticJsonDocument<512> doc;
- doc["program"] = program;
- doc["SetV"] = SetV;
- doc["ArcV"] = ArcV / 10.0; // Convert to voltage units
- doc["DT"] = DT / 10.0; // Convert to seconds
- doc["HyS"] = HyS / 10.0; // Convert to voltage units
- doc["StV"] = StV;
- doc["outputUp"] = digitalRead(outputUpPin);
- doc["outputDown"] = digitalRead(outputDnPin);
- doc["outputOk"] = digitalRead(outputOkPin);
- doc["arcStatus"] = (ArcV > 500 && ArcV < 2500) ? "OK" : "LOST";
- doc["torchStatus"] = digitalRead(outputUpPin) ? "UP" : (digitalRead(outputDnPin) ? "DOWN" : "STOP");
- String response;
- serializeJson(doc, response);
- server.send(200, "application/json", response);
- }
- void handleAPIParameters() {
- // GET: Return current parameters
- StaticJsonDocument<256> doc;
- doc["SetV"] = SetV;
- doc["DT"] = DT / 10.0;
- doc["HyS"] = HyS / 10.0;
- doc["StV"] = StV;
- doc["program"] = program;
- String response;
- serializeJson(doc, response);
- server.send(200, "application/json", response);
- }
- void handleAPISetParameters() {
- // POST: Set parameters via JSON
- if (!server.hasArg("plain")) {
- server.send(400, "application/json", "{\"error\":\"No body\"}");
- return;
- }
- String body = server.arg("plain");
- StaticJsonDocument<256> doc;
- DeserializationError error = deserializeJson(doc, body);
- if (error) {
- server.send(400, "application/json", "{\"error\":\"Invalid JSON\"}");
- return;
- }
- // Update parameters if provided
- if (doc.containsKey("SetV")) {
- SetV = constrain(doc["SetV"], 50, 250);
- SaveData(SetVa, SetV);
- }
- if (doc.containsKey("DT")) {
- DT = constrain((int)(doc["DT"] * 10), 1, 200);
- SaveData(DTa, DT);
- }
- if (doc.containsKey("HyS")) {
- HyS = constrain((int)(doc["HyS"] * 10), 1, 99);
- SaveData(HySa, HyS);
- }
- if (doc.containsKey("StV")) {
- StV = constrain(doc["StV"], 50, 250);
- SaveData(StVa, StV);
- }
- server.send(200, "application/json", "{\"status\":\"OK\"}");
- }
- void handleAPIGetProgram() {
- // Return currently loaded program number
- StaticJsonDocument<64> doc;
- doc["program"] = program;
- String response;
- serializeJson(doc, response);
- server.send(200, "application/json", response);
- }
- void handleAPISetProgram() {
- // POST: Load a program (1-3)
- if (!server.hasArg("plain")) {
- server.send(400, "application/json", "{\"error\":\"No body\"}");
- return;
- }
- String body = server.arg("plain");
- StaticJsonDocument<64> doc;
- DeserializationError error = deserializeJson(doc, body);
- if (error) {
- server.send(400, "application/json", "{\"error\":\"Invalid JSON\"}");
- return;
- }
- int prog = doc["program"];
- if (prog >= 1 && prog <= 3) {
- doProgramSet(prog);
- server.send(200, "application/json", "{\"status\":\"OK\"}");
- } else {
- server.send(400, "application/json", "{\"error\":\"Program must be 1-3\"}");
- }
- }
- void handleAPIControl() {
- // POST: Control torch manually (for test mode via web)
- if (!server.hasArg("plain")) {
- server.send(400, "application/json", "{\"error\":\"No body\"}");
- return;
- }
- String body = server.arg("plain");
- StaticJsonDocument<128> doc;
- DeserializationError error = deserializeJson(doc, body);
- if (error) {
- server.send(400, "application/json", "{\"error\":\"Invalid JSON\"}");
- return;
- }
- if (doc.containsKey("command")) {
- String cmd = doc["command"];
- if (cmd == "up") {
- digitalWrite(outputUpPin, HIGH);
- digitalWrite(outputDnPin, LOW);
- digitalWrite(outputOkPin, HIGH);
- server.send(200, "application/json", "{\"status\":\"UP\"}");
- } else if (cmd == "down") {
- digitalWrite(outputUpPin, LOW);
- digitalWrite(outputDnPin, HIGH);
- digitalWrite(outputOkPin, HIGH);
- server.send(200, "application/json", "{\"status\":\"DOWN\"}");
- } else if (cmd == "stop") {
- digitalWrite(outputUpPin, LOW);
- digitalWrite(outputDnPin, LOW);
- digitalWrite(outputOkPin, LOW);
- server.send(200, "application/json", "{\"status\":\"STOP\"}");
- } else {
- server.send(400, "application/json", "{\"error\":\"Unknown command\"}");
- }
- } else {
- server.send(400, "application/json", "{\"error\":\"No command\"}");
- }
- }
- void handleAPIArcVoltage() {
- // Real-time arc voltage monitoring
- StaticJsonDocument<128> doc;
- doc["arcVoltage"] = ArcV / 10.0;
- doc["unit"] = "V";
- doc["status"] = (ArcV > 500 && ArcV < 2500) ? "OK" : "LOST";
- doc["timestamp"] = millis();
- String response;
- serializeJson(doc, response);
- server.send(200, "application/json", response);
- }
- // ========== HTML DASHBOARD ==========
- String getHTMLDashboard() {
- String html = R"rawliteral(
- <!DOCTYPE html>
- <html>
- <head>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <title>THC ESP32 Control Panel</title>
- <style>
- * { margin: 0; padding: 0; box-sizing: border-box; }
- body {
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- min-height: 100vh;
- padding: 20px;
- }
- .container {
- max-width: 1200px;
- margin: 0 auto;
- background: white;
- border-radius: 15px;
- box-shadow: 0 20px 60px rgba(0,0,0,0.3);
- padding: 30px;
- }
- h1 {
- color: #333;
- margin-bottom: 10px;
- text-align: center;
- }
- .subtitle {
- text-align: center;
- color: #666;
- margin-bottom: 30px;
- }
- .grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
- gap: 20px;
- margin-bottom: 30px;
- }
- .card {
- background: #f8f9fa;
- border-left: 5px solid #667eea;
- padding: 20px;
- border-radius: 8px;
- box-shadow: 0 2px 8px rgba(0,0,0,0.1);
- }
- .card h2 {
- color: #667eea;
- font-size: 18px;
- margin-bottom: 15px;
- }
- .status-display {
- font-size: 32px;
- font-weight: bold;
- color: #333;
- text-align: center;
- padding: 20px;
- background: white;
- border-radius: 8px;
- margin-bottom: 10px;
- }
- .status-ok { color: #28a745; }
- .status-warning { color: #ffc107; }
- .status-danger { color: #dc3545; }
- .label {
- color: #666;
- font-size: 14px;
- margin-bottom: 5px;
- }
- .value {
- color: #333;
- font-size: 24px;
- font-weight: bold;
- }
- .param-input {
- margin-bottom: 15px;
- }
- label {
- display: block;
- color: #333;
- margin-bottom: 5px;
- font-weight: 500;
- }
- input[type="number"],
- input[type="range"],
- select {
- width: 100%;
- padding: 10px;
- border: 2px solid #ddd;
- border-radius: 5px;
- font-size: 16px;
- transition: border-color 0.3s;
- }
- input:focus, select:focus {
- outline: none;
- border-color: #667eea;
- box-shadow: 0 0 5px rgba(102, 126, 234, 0.3);
- }
- .btn {
- background: #667eea;
- color: white;
- padding: 12px 24px;
- border: none;
- border-radius: 5px;
- font-size: 16px;
- font-weight: 600;
- cursor: pointer;
- transition: all 0.3s;
- margin-right: 10px;
- margin-bottom: 10px;
- }
- .btn:hover {
- background: #5568d3;
- transform: translateY(-2px);
- box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
- }
- .btn-danger {
- background: #dc3545;
- }
- .btn-danger:hover {
- background: #c82333;
- }
- .btn-success {
- background: #28a745;
- }
- .btn-success:hover {
- background: #218838;
- }
- .btn-warning {
- background: #ffc107;
- color: #333;
- }
- .btn-warning:hover {
- background: #e0a800;
- }
- .torch-status {
- text-align: center;
- padding: 20px;
- background: white;
- border-radius: 8px;
- margin: 10px 0;
- }
- .torch-indicator {
- display: inline-block;
- width: 60px;
- height: 60px;
- border-radius: 50%;
- margin-bottom: 10px;
- animation: pulse 1s infinite;
- }
- .torch-up { background: #28a745; }
- .torch-down { background: #dc3545; }
- .torch-stop { background: #ffc107; }
- @keyframes pulse {
- 0%, 100% { opacity: 1; }
- 50% { opacity: 0.6; }
- }
- .graph-container {
- background: white;
- padding: 20px;
- border-radius: 8px;
- margin-bottom: 20px;
- }
- #voltageChart {
- width: 100%;
- height: 300px;
- }
- .control-buttons {
- display: flex;
- gap: 10px;
- flex-wrap: wrap;
- margin-top: 15px;
- }
- .table {
- width: 100%;
- border-collapse: collapse;
- margin-top: 10px;
- }
- .table td {
- padding: 10px;
- border-bottom: 1px solid #ddd;
- }
- .table td:first-child {
- font-weight: 600;
- color: #333;
- width: 40%;
- }
- .table td:last-child {
- color: #667eea;
- font-weight: 600;
- text-align: right;
- }
- .loading {
- display: none;
- text-align: center;
- padding: 20px;
- }
- .spinner {
- border: 4px solid #f3f3f3;
- border-top: 4px solid #667eea;
- border-radius: 50%;
- width: 40px;
- height: 40px;
- animation: spin 1s linear infinite;
- margin: 0 auto;
- }
- @keyframes spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
- }
- </style>
- </head>
- <body>
- <div class="container">
- <h1>🔥 THC ESP32 Control Panel</h1>
- <p class="subtitle">Torch Height Control System - Real-time Monitoring & Control</p>
- <div class="grid">
- <!-- Real-time Arc Voltage Monitoring -->
- <div class="card">
- <h2>Arc Voltage Monitor</h2>
- <div class="status-display status-ok" id="arcVoltageDisplay">-- V</div>
- <div class="label">Current Arc Voltage</div>
- <div class="value" id="arcVoltageValue">0.0 V</div>
- <div class="label" style="margin-top: 10px;">Status:</div>
- <div class="value" id="arcStatus">LOST</div>
- </div>
- <!-- Set Voltage Control -->
- <div class="card">
- <h2>Set Voltage</h2>
- <div class="param-input">
- <label for="setVoltage">Target Voltage (V):</label>
- <input type="number" id="setVoltage" min="50" max="250" value="100" step="1">
- <div style="margin-top: 5px; text-align: center; font-size: 20px; color: #667eea; font-weight: bold;" id="setVoltageDisplay">100 V</div>
- </div>
- </div>
- <!-- Program Selection -->
- <div class="card">
- <h2>Program Selection</h2>
- <div class="param-input">
- <label for="programSelect">Load Program:</label>
- <select id="programSelect">
- <option value="1">Program 1</option>
- <option value="2">Program 2</option>
- <option value="3">Program 3</option>
- </select>
- </div>
- <button class="btn btn-success" onclick="loadProgram()">Load Program</button>
- </div>
- <!-- Torch Status Display -->
- <div class="card">
- <h2>Torch Status</h2>
- <div class="torch-status">
- <div class="torch-indicator" id="torchIndicator" style="background: #ffc107;"></div>
- <div style="font-size: 20px; font-weight: bold; color: #333;" id="torchStatusText">STOP</div>
- </div>
- </div>
- <!-- Manual Control -->
- <div class="card">
- <h2>Manual Control</h2>
- <div class="control-buttons">
- <button class="btn btn-success" onclick="controlTorch('up')">⬆️ Move UP</button>
- <button class="btn btn-danger" onclick="controlTorch('down')">⬇️ Move DOWN</button>
- <button class="btn btn-warning" onclick="controlTorch('stop')">⏹️ STOP</button>
- </div>
- </div>
- <!-- Advanced Parameters -->
- <div class="card" style="grid-column: 1 / -1;">
- <h2>Advanced Parameters</h2>
- <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;">
- <div class="param-input">
- <label for="delayTime">Delay Time (s):</label>
- <input type="number" id="delayTime" min="0.1" max="20" value="0.5" step="0.1">
- <div style="margin-top: 5px; font-size: 14px; color: #666;" id="delayTimeDisplay">0.5 s</div>
- </div>
- <div class="param-input">
- <label for="hysteresis">Hysteresis (V):</label>
- <input type="number" id="hysteresis" min="0.1" max="9.9" value="8.0" step="0.1">
- <div style="margin-top: 5px; font-size: 14px; color: #666;" id="hysteresisDisplay">8.0 V</div>
- </div>
- <div class="param-input">
- <label for="startVoltage">Start Voltage (V):</label>
- <input type="number" id="startVoltage" min="50" max="250" value="100" step="1">
- <div style="margin-top: 5px; font-size: 14px; color: #666;" id="startVoltageDisplay">100 V</div>
- </div>
- </div>
- <button class="btn btn-success" onclick="saveParameters()">💾 Save Parameters</button>
- </div>
- </div>
- <!-- Status Information Table -->
- <div class="card">
- <h2>System Status</h2>
- <table class="table" id="statusTable">
- <tr>
- <td>Program</td>
- <td id="statusProgram">--</td>
- </tr>
- <tr>
- <td>Arc Voltage</td>
- <td id="statusArcV">0.0 V</td>
- </tr>
- <tr>
- <td>Set Voltage</td>
- <td id="statusSetV">100 V</td>
- </tr>
- <tr>
- <td>Torch Position</td>
- <td id="statusTorchPos">STOP</td>
- </tr>
- <tr>
- <td>Arc Status</td>
- <td id="statusArcStatus">LOST</td>
- </tr>
- </table>
- </div>
- </div>
- <script>
- // Auto-refresh status every 500ms
- const refreshInterval = setInterval(updateStatus, 500);
- // Update all displays from API
- async function updateStatus() {
- try {
- const response = await fetch('/api/status');
- const data = await response.json();
- // Update displays
- document.getElementById('arcVoltageDisplay').textContent = data.ArcV.toFixed(1) + ' V';
- document.getElementById('arcVoltageValue').textContent = data.ArcV.toFixed(1) + ' V';
- document.getElementById('arcStatus').textContent = data.arcStatus;
- document.getElementById('statusArcV').textContent = data.ArcV.toFixed(1) + ' V';
- document.getElementById('statusSetV').textContent = data.SetV + ' V';
- document.getElementById('statusProgram').textContent = data.program;
- document.getElementById('statusArcStatus').textContent = data.arcStatus;
- document.getElementById('torchStatusText').textContent = data.torchStatus;
- document.getElementById('statusTorchPos').textContent = data.torchStatus;
- // Update torch indicator color
- const indicator = document.getElementById('torchIndicator');
- if (data.torchStatus === 'UP') {
- indicator.className = 'torch-indicator torch-up';
- } else if (data.torchStatus === 'DOWN') {
- indicator.className = 'torch-indicator torch-down';
- } else {
- indicator.className = 'torch-indicator torch-stop';
- }
- // Update arc voltage display color
- const arcDisplay = document.getElementById('arcVoltageDisplay');
- if (data.arcStatus === 'OK') {
- arcDisplay.className = 'status-display status-ok';
- } else {
- arcDisplay.className = 'status-display status-danger';
- }
- } catch (error) {
- console.error('Error updating status:', error);
- }
- }
- // Save parameters to EEPROM via API
- async function saveParameters() {
- const params = {
- SetV: parseInt(document.getElementById('setVoltage').value),
- DT: parseFloat(document.getElementById('delayTime').value),
- HyS: parseFloat(document.getElementById('hysteresis').value),
- StV: parseInt(document.getElementById('startVoltage').value)
- };
- try {
- const response = await fetch('/api/parameters', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(params)
- });
- const result = await response.json();
- alert('Parameters saved!');
- } catch (error) {
- alert('Error saving parameters: ' + error);
- }
- }
- // Load program from API
- async function loadProgram() {
- const prog = parseInt(document.getElementById('programSelect').value);
- try {
- const response = await fetch('/api/program', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ program: prog })
- });
- const result = await response.json();
- alert('Program ' + prog + ' loaded!');
- updateStatus();
- } catch (error) {
- alert('Error loading program: ' + error);
- }
- }
- // Control torch manually
- async function controlTorch(command) {
- try {
- const response = await fetch('/api/control', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ command: command })
- });
- const result = await response.json();
- updateStatus();
- } catch (error) {
- alert('Error controlling torch: ' + error);
- }
- }
- // Update display values when inputs change
- document.getElementById('setVoltage').addEventListener('input', function() {
- document.getElementById('setVoltageDisplay').textContent = this.value + ' V';
- });
- document.getElementById('delayTime').addEventListener('input', function() {
- document.getElementById('delayTimeDisplay').textContent = this.value + ' s';
- });
- document.getElementById('hysteresis').addEventListener('input', function() {
- document.getElementById('hysteresisDisplay').textContent = this.value + ' V';
- });
- document.getElementById('startVoltage').addEventListener('input', function() {
- document.getElementById('startVoltageDisplay').textContent = this.value + ' V';
- });
- // Initial status update
- updateStatus();
- </script>
- </body>
- </html>
- )rawliteral";
- return html;
- }
- // ========== MAIN SETUP FUNCTION ==========
- void setup() {
- // Initialize Serial for debugging
- Serial.begin(115200);
- delay(1000);
- Serial.println("\n\n=== THC ESP32 System Starting ===");
- // Initialize EEPROM
- EEPROM.begin(512);
- // Initialize THC system
- Setup_THC();
- Serial.println("THC initialized");
- // Initialize Timer
- Setup_Timer();
- Serial.println("Timer initialized (10ms interval)");
- // Initialize LCD
- Setup_LCD();
- Serial.println("LCD initialized");
- // Initialize Encoder
- pinMode(pinCLK, INPUT_PULLUP);
- pinMode(pinDT, INPUT_PULLUP);
- pinMode(pinSW, INPUT_PULLUP);
- attachInterrupt(digitalPinToInterrupt(pinCLK), isrEncoder, CHANGE);
- Serial.println("Encoder initialized");
- // Configure ADC for arc voltage
- analogSetAttenuation(ADC_11db); // Full range: 0-3.3V
- Serial.println("ADC configured");
- // Load program from EEPROM
- ReadProg();
- if (program < 1 || program > 3) {
- program = 1;
- }
- doProgramSet(program);
- Serial.print("Program ");
- Serial.print(program);
- Serial.println(" loaded");
- // Initialize Web Server
- Setup_WebServer();
- Serial.println("Web server initialized");
- Serial.println("=== System Ready ===\n");
- }
- // ========== MAIN LOOP FUNCTION ==========
- void loop() {
- // Handle incoming HTTP requests
- server.handleClient();
- // Read arc voltage periodically
- readArcVoltage();
- // Execute THC control algorithm
- doTHC();
- // Update LCD display
- doLCD();
- // Handle encoder button press
- handleEncoderButton();
- // Small delay to prevent watchdog timeout
- delay(5);
- }
- /* END CODE */
Advertisement
Add Comment
Please, Sign In to add comment